From c57d541883d919823980006e06afbef0a390e6b1 Mon Sep 17 00:00:00 2001 From: Filip Hlavac Date: Tue, 13 Feb 2024 17:25:36 +0100 Subject: [PATCH 1/5] Create Shortcut component --- .../examples/ShortcutGrid/ShortcutExample.tsx | 4 + packages/module/src/Shortcut/Shortcut.tsx | 97 +++++++++++++++++++ packages/module/src/Shortcut/index.ts | 2 + 3 files changed, 103 insertions(+) create mode 100644 packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutExample.tsx create mode 100644 packages/module/src/Shortcut/Shortcut.tsx create mode 100644 packages/module/src/Shortcut/index.ts diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutExample.tsx b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutExample.tsx new file mode 100644 index 00000000..5715bf23 --- /dev/null +++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutExample.tsx @@ -0,0 +1,4 @@ +import React from 'react'; +import Shortcut from '@patternfly/react-component-groups/dist/dynamic/Shortcut'; + +export const BasicExample: React.FunctionComponent = () => ; diff --git a/packages/module/src/Shortcut/Shortcut.tsx b/packages/module/src/Shortcut/Shortcut.tsx new file mode 100644 index 00000000..ebd66792 --- /dev/null +++ b/packages/module/src/Shortcut/Shortcut.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +import { MouseIcon } from '@patternfly/react-icons'; +import { Chip } from '@patternfly/react-core'; +import clsx from 'clsx'; + +export interface ShortcutProps { + /** Array of shortcut keys */ + keys: string[]; + /** Shortcut description */ + description?: React.ReactNode; + /** Indicates whether symbols should be displayed for certain keys */ + showSymbols?: boolean; + /** Show hover in the shortcut */ + hover?: boolean; + /** Show click in the shortcut */ + click?: boolean; + /** Show right click in the shortcut */ + rightClick?: boolean; + /** Show drag in the shortcut */ + drag?: boolean; + /** Show drag and drop in the shortcut */ + dragAndDrop?: boolean; + /** Shortcut className */ + className?: string; +} + +const symbols = { + 'shift': '⇧', + 'opt': '⌥', + 'cmd': '⌘', + 'enter': '↵', + 'ctrl': '^', + 'caps lock': '⇪', + 'tab': '↹', + 'win': '⊞', + 'backspace': '⌫' +} + +const Shortcut: React.FunctionComponent = ({ + keys = [], + description = null, + showSymbols = true, + hover, + click, + drag, + rightClick, + dragAndDrop, + className +}: ShortcutProps) => { + const badges = [ + ...(hover ? [ + + Hover + + ] : []), + ...keys.map((key) => { + const trimmedKey = key.trim().toLowerCase(); + return( + + {showSymbols && symbols[trimmedKey] ? `${symbols[trimmedKey]} ` : '' } + {key.length === 1 ? key.toUpperCase() : key[0].toUpperCase() + key.slice(1).toLowerCase()} + + )}), + ...(click ? [ + + Click + + ] : []), + ...(rightClick ? [ + + Right click + + ] : []), + ...(drag ? [ + + Drag + + ] : []), + ...(dragAndDrop ? [ + + Drag + Drop + + ] : []) + ] + + return ( + <> + + {badges.length > 0 && badges.reduce((prev, curr) => ( + <>{[ prev, ' + ', curr ]} + ))} + + {description} + + );} + +export default Shortcut; \ No newline at end of file diff --git a/packages/module/src/Shortcut/index.ts b/packages/module/src/Shortcut/index.ts new file mode 100644 index 00000000..6fff158c --- /dev/null +++ b/packages/module/src/Shortcut/index.ts @@ -0,0 +1,2 @@ +export { default } from './Shortcut'; +export * from './Shortcut'; From 5166bf2320b7523b5c53fbca70d9f5f2219650a6 Mon Sep 17 00:00:00 2001 From: Filip Hlavac Date: Tue, 13 Feb 2024 17:25:53 +0100 Subject: [PATCH 2/5] Create ShortcutGrid component --- .../examples/ShortcutGrid/ShortcutGrid.md | 47 +++++++++++++++++++ .../ShortcutGrid/ShortcutGridExample.tsx | 12 +++++ .../module/src/ShortcutGrid/ShortcutGrid.tsx | 37 +++++++++++++++ packages/module/src/ShortcutGrid/index.ts | 2 + packages/module/src/index.ts | 6 +++ 5 files changed, 104 insertions(+) create mode 100644 packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md create mode 100644 packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx create mode 100644 packages/module/src/ShortcutGrid/ShortcutGrid.tsx create mode 100644 packages/module/src/ShortcutGrid/index.ts diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md new file mode 100644 index 00000000..ee29ce9c --- /dev/null +++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md @@ -0,0 +1,47 @@ +--- +# Sidenav top-level section +# should be the same for all markdown files +section: extensions +subsection: Component groups +# Sidenav secondary level section +# should be the same for all markdown files +id: Shortcut grid +# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility) +source: react +# If you use typescript, the name of the interface to display props for +# These are found through the sourceProps function provided in patternfly-docs.source.js +propComponents: [ + 'ShortcutGrid', + 'Shortcut' +] +sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md +--- + +import ShortcutGrid from '@patternfly/react-component-groups/dist/dynamic/ShortcutGrid'; +import Shortcut from '@patternfly/react-component-groups/dist/dynamic/Shortcut'; + +A **shortcut grid** component displays keyboard shortcuts with their description in a grid. + +## Examples + +### Basic shortcut grid + +A basic shortcut grid can be used to display shortcuts available to the user together with their description. + +You can customize displayed shortcuts using `shortcuts` props. For mouse actions with given shortcuts, there are separate props to be enabled. You can customize showing symbols for control keys using `showSymbols`. The component also accepts all properties of the [grid layout](/layouts/grid). + +```js file="./ShortcutGridExample.tsx" + +``` + +### Shortcut + +Shortcut component can be also used outside of the grid. + +Appearance of the component can be customized using the `className` property. + +```js file="./ShortcutExample.tsx" + +``` + + diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx new file mode 100644 index 00000000..46f2873a --- /dev/null +++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import ShortcutGrid from '@patternfly/react-component-groups/dist/dynamic/ShortcutGrid'; + +export const BasicExample: React.FunctionComponent = () => ( + +); diff --git a/packages/module/src/ShortcutGrid/ShortcutGrid.tsx b/packages/module/src/ShortcutGrid/ShortcutGrid.tsx new file mode 100644 index 00000000..94353b13 --- /dev/null +++ b/packages/module/src/ShortcutGrid/ShortcutGrid.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { createUseStyles } from 'react-jss'; +import Shortcut, { ShortcutProps } from '../Shortcut/Shortcut'; +import { Grid, GridItem, GridItemProps, GridProps } from '@patternfly/react-core'; + +export interface ShortcutGridProps extends GridProps { + /** Array of shortcuts to be displayed in the grid */ + shortcuts: ShortcutProps[]; + /** Shortcut GridItem props */ + gridItemProps?: GridItemProps +} + +const useStyles = createUseStyles({ + shortcutItem: { + textAlign: 'right', + marginRight: 'var(--pf-v5-global--spacer--sm)' + } +}) + +const ShortcutGrid: React.FunctionComponent = ({ shortcuts, gridItemProps, ...rest }: ShortcutGridProps) => { + const classes = useStyles(); + return ( + + {shortcuts.map((shortcut, index) => { + const { description, ...props } = shortcut; + return( + + + + + {description} + + )})} + ) +} + +export default ShortcutGrid; \ No newline at end of file diff --git a/packages/module/src/ShortcutGrid/index.ts b/packages/module/src/ShortcutGrid/index.ts new file mode 100644 index 00000000..4ab64b8b --- /dev/null +++ b/packages/module/src/ShortcutGrid/index.ts @@ -0,0 +1,2 @@ +export { default } from './ShortcutGrid'; +export * from './ShortcutGrid'; diff --git a/packages/module/src/index.ts b/packages/module/src/index.ts index c208f474..a10cdf31 100644 --- a/packages/module/src/index.ts +++ b/packages/module/src/index.ts @@ -42,6 +42,12 @@ export * from './NotAuthorized'; export { default as NotFoundIcon } from './NotFoundIcon'; export * from './NotFoundIcon'; +export { default as Shortcut } from './Shortcut'; +export * from './Shortcut'; + +export { default as ShortcutGrid } from './ShortcutGrid'; +export * from './ShortcutGrid'; + export { default as SkeletonTable } from './SkeletonTable'; export * from './SkeletonTable'; From 4927ad9b0cc7e667d714882071b0e4eb610bf4ad Mon Sep 17 00:00:00 2001 From: Filip Hlavac Date: Tue, 13 Feb 2024 17:26:01 +0100 Subject: [PATCH 3/5] feat(shortcut): Add tests for ShortcutGrid --- .../module/src/Shortcut/Shortcut.test.tsx | 9 + .../__snapshots__/Shortcut.test.tsx.snap | 216 +++++++++ .../src/ShortcutGrid/ShortcutGrid.test.tsx | 17 + .../__snapshots__/ShortcutGrid.test.tsx.snap | 444 ++++++++++++++++++ 4 files changed, 686 insertions(+) create mode 100644 packages/module/src/Shortcut/Shortcut.test.tsx create mode 100644 packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap create mode 100644 packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx create mode 100644 packages/module/src/ShortcutGrid/__snapshots__/ShortcutGrid.test.tsx.snap diff --git a/packages/module/src/Shortcut/Shortcut.test.tsx b/packages/module/src/Shortcut/Shortcut.test.tsx new file mode 100644 index 00000000..0b46be5b --- /dev/null +++ b/packages/module/src/Shortcut/Shortcut.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Shortcut from './Shortcut'; + +describe('Shortcut component', () => { + it('should render correctly', () => { + expect(render()).toMatchSnapshot(); + }); +}); diff --git a/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap b/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap new file mode 100644 index 00000000..4a2d6e0e --- /dev/null +++ b/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap @@ -0,0 +1,216 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Shortcut component should render correctly 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+ +
+ + + ⌘ + Cmd + + +
+ + +
+ + + ⇧ + Shift + + +
+ + +
+ + + + Click + + +
+
+ Shortcut description +
+ , + "container":
+ +
+ + + ⌘ + Cmd + + +
+ + +
+ + + ⇧ + Shift + + +
+ + +
+ + + + Click + + +
+
+ Shortcut description +
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx b/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx new file mode 100644 index 00000000..03697089 --- /dev/null +++ b/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import ShortcutGrid from './ShortcutGrid'; + +describe('ShortcutGrid component', () => { + it('should render correctly', () => { + expect(render( + + )).toMatchSnapshot(); + }); +}); diff --git a/packages/module/src/ShortcutGrid/__snapshots__/ShortcutGrid.test.tsx.snap b/packages/module/src/ShortcutGrid/__snapshots__/ShortcutGrid.test.tsx.snap new file mode 100644 index 00000000..8505d631 --- /dev/null +++ b/packages/module/src/ShortcutGrid/__snapshots__/ShortcutGrid.test.tsx.snap @@ -0,0 +1,444 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ShortcutGrid component should render correctly 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+
+ +
+ + + ⌘ + Cmd + + +
+ + +
+ + + ⇧ + Shift + + +
+ + +
+ + + N + + +
+
+
+
+ Open in a new tab +
+
+ +
+ + + ⌥ + Opt + + +
+ + +
+ + + N + + +
+
+
+
+ Open new page +
+
+ +
+ + + ^ + Ctrl + + +
+ + +
+ + + + Drag + + +
+
+
+
+ Move object +
+
+
+ , + "container":
+
+
+ +
+ + + ⌘ + Cmd + + +
+ + +
+ + + ⇧ + Shift + + +
+ + +
+ + + N + + +
+
+
+
+ Open in a new tab +
+
+ +
+ + + ⌥ + Opt + + +
+ + +
+ + + N + + +
+
+
+
+ Open new page +
+
+ +
+ + + ^ + Ctrl + + +
+ + +
+ + + + Drag + + +
+
+
+
+ Move object +
+
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; From 5703ce2f49bf98769e6b59c993915b496ca2273f Mon Sep 17 00:00:00 2001 From: Filip Hlavac Date: Wed, 14 Feb 2024 18:33:26 +0100 Subject: [PATCH 4/5] Fix a11y issue and classNames --- .../examples/ShortcutGrid/ShortcutGrid.md | 2 +- .../examples/ShortcutGrid/ShortcutGridExample.tsx | 2 +- packages/module/src/Shortcut/Shortcut.tsx | 12 ++++++++++-- .../module/src/ShortcutGrid/ShortcutGrid.test.tsx | 2 +- packages/module/src/ShortcutGrid/ShortcutGrid.tsx | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md index ee29ce9c..ffcb7b65 100644 --- a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md +++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGrid.md @@ -34,7 +34,7 @@ You can customize displayed shortcuts using `shortcuts` props. For mouse actions ``` -### Shortcut +### Single shortcut Shortcut component can be also used outside of the grid. diff --git a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx index 46f2873a..b3a7e591 100644 --- a/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx +++ b/packages/module/patternfly-docs/content/extensions/component-groups/examples/ShortcutGrid/ShortcutGridExample.tsx @@ -4,7 +4,7 @@ import ShortcutGrid from '@patternfly/react-component-groups/dist/dynamic/Shortc export const BasicExample: React.FunctionComponent = () => ( = ({ keys = [], description = null, @@ -47,6 +54,7 @@ const Shortcut: React.FunctionComponent = ({ dragAndDrop, className }: ShortcutProps) => { + const classes = useStyles(); const badges = [ ...(hover ? [ @@ -56,7 +64,7 @@ const Shortcut: React.FunctionComponent = ({ ...keys.map((key) => { const trimmedKey = key.trim().toLowerCase(); return( - + {showSymbols && symbols[trimmedKey] ? `${symbols[trimmedKey]} ` : '' } {key.length === 1 ? key.toUpperCase() : key[0].toUpperCase() + key.slice(1).toLowerCase()} @@ -85,7 +93,7 @@ const Shortcut: React.FunctionComponent = ({ return ( <> - + {badges.length > 0 && badges.reduce((prev, curr) => ( <>{[ prev, ' + ', curr ]} ))} diff --git a/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx b/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx index 03697089..6146aaa7 100644 --- a/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx +++ b/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx @@ -7,7 +7,7 @@ describe('ShortcutGrid component', () => { expect(render( = ({ shortcuts, g const { description, ...props } = shortcut; return( - + {description} From 87e6bbc2c5f07bf87d7bfedd8064a8a38205fa0d Mon Sep 17 00:00:00 2001 From: Filip Hlavac Date: Wed, 14 Feb 2024 20:24:33 +0100 Subject: [PATCH 5/5] Update snapshots --- .../__snapshots__/Shortcut.test.tsx.snap | 12 +++--- .../__snapshots__/ShortcutGrid.test.tsx.snap | 40 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap b/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap index 4a2d6e0e..2e683f6e 100644 --- a/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap +++ b/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap @@ -6,14 +6,14 @@ exports[`Shortcut component should render correctly 1`] = ` "baseElement":
, "container":
- N + T
@@ -80,7 +80,7 @@ exports[`ShortcutGrid component should render correctly 1`] = ` Open in a new tab
- N + T
@@ -273,7 +273,7 @@ exports[`ShortcutGrid component should render correctly 1`] = ` Open in a new tab