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/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..ffcb7b65 --- /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" + +``` + +### Single 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..b3a7e591 --- /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/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/Shortcut.tsx b/packages/module/src/Shortcut/Shortcut.tsx new file mode 100644 index 00000000..b5fa9bfd --- /dev/null +++ b/packages/module/src/Shortcut/Shortcut.tsx @@ -0,0 +1,105 @@ +import * as React from 'react'; +import { MouseIcon } from '@patternfly/react-icons'; +import { Chip } from '@patternfly/react-core'; +import { createUseStyles } from 'react-jss'; +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 useStyles = createUseStyles({ + shortcut: { + marginRight: 'var(--pf-v5-global--spacer--lg)' + } +}) + +const Shortcut: React.FunctionComponent = ({ + keys = [], + description = null, + showSymbols = true, + hover, + click, + drag, + rightClick, + dragAndDrop, + className +}: ShortcutProps) => { + const classes = useStyles(); + 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/__snapshots__/Shortcut.test.tsx.snap b/packages/module/src/Shortcut/__snapshots__/Shortcut.test.tsx.snap new file mode 100644 index 00000000..2e683f6e --- /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/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'; diff --git a/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx b/packages/module/src/ShortcutGrid/ShortcutGrid.test.tsx new file mode 100644 index 00000000..6146aaa7 --- /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/ShortcutGrid.tsx b/packages/module/src/ShortcutGrid/ShortcutGrid.tsx new file mode 100644 index 00000000..8be0206d --- /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({ + shortcutGridItem: { + 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/__snapshots__/ShortcutGrid.test.tsx.snap b/packages/module/src/ShortcutGrid/__snapshots__/ShortcutGrid.test.tsx.snap new file mode 100644 index 00000000..886a1c1e --- /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 + + +
+ + +
+ + + T + + +
+
+
+
+ Open in a new tab +
+
+ +
+ + + ⌥ + Opt + + +
+ + +
+ + + N + + +
+
+
+
+ Open new page +
+
+ +
+ + + ^ + Ctrl + + +
+ + +
+ + + + Drag + + +
+
+
+
+ Move object +
+
+
+ , + "container":
+
+
+ +
+ + + ⌘ + Cmd + + +
+ + +
+ + + ⇧ + Shift + + +
+ + +
+ + + T + + +
+
+
+
+ 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], +} +`; 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';