From 1a1f52918c31a7cb573e2027e49b25526b507b58 Mon Sep 17 00:00:00 2001 From: Eric Schultz Date: Wed, 1 May 2019 17:17:15 -0500 Subject: [PATCH] Add SelectableTableRow component --- .../SelectableTableRow.spec.tsx | 46 +++++++++++++++ .../SelectableTableRow.tsx | 31 ++++++++++ .../common/selectable_table_row/connect.tsx | 59 +++++++++++++++++++ package-lock.json | 10 ++++ package.json | 2 + 5 files changed, 148 insertions(+) create mode 100644 javascripts/src/components/common/selectable_table_row/SelectableTableRow.spec.tsx create mode 100644 javascripts/src/components/common/selectable_table_row/SelectableTableRow.tsx create mode 100644 javascripts/src/components/common/selectable_table_row/connect.tsx diff --git a/javascripts/src/components/common/selectable_table_row/SelectableTableRow.spec.tsx b/javascripts/src/components/common/selectable_table_row/SelectableTableRow.spec.tsx new file mode 100644 index 00000000..38b6100a --- /dev/null +++ b/javascripts/src/components/common/selectable_table_row/SelectableTableRow.spec.tsx @@ -0,0 +1,46 @@ +// License: LGPL-3.0-or-later +import * as React from 'react'; +import 'jest'; +import SelectableTableRow from './SelectableTableRow' +import { ReactWrapper, mount } from 'enzyme'; +import { connectTableRowSelectHandler, TableRowSelectHandlerContext } from './connect'; + + +class TestReceivedProviderComponent extends React.Component<{m:string} & TableRowSelectHandlerContext, {}>{ + render() { + return ; + } +} + +const ReceivedComponent = connectTableRowSelectHandler(TestReceivedProviderComponent) + +describe('SelectableTableRow', () => { + let providerAndRow: ReactWrapper + let onSelect: any; + beforeEach(() => { + onSelect = jest.fn() + providerAndRow = mount( + +
) + }) + + function getTr(): ReactWrapper { + return providerAndRow.find('tr') + } + + function getProviderComponent() { + return providerAndRow.find('TestReceivedProviderComponent').instance() as any + } + + it('processes the click properly', () => { + getTr().simulate('click') + + expect(onSelect).toBeCalled() + }) + + it('sends the provider down', () => { + const c = getProviderComponent() + expect(c.props.selectHandler.onSelect).toBeTruthy() + expect(c.props.selectHandler.onSelect).toBe(onSelect) + }) +}) \ No newline at end of file diff --git a/javascripts/src/components/common/selectable_table_row/SelectableTableRow.tsx b/javascripts/src/components/common/selectable_table_row/SelectableTableRow.tsx new file mode 100644 index 00000000..dc2e28d7 --- /dev/null +++ b/javascripts/src/components/common/selectable_table_row/SelectableTableRow.tsx @@ -0,0 +1,31 @@ +// License: LGPL-3.0-or-later +import * as React from 'react'; +import { TableRowSelectHandlerProvider } from './connect'; + +export interface SelectableTableRowProps + {/** + * Action you want to take when the row is selected + * @memberof SelectableTableRowProps + */ + onSelect: () => void +} + +/** + * So you want a table row that fires an action when any part of the row is clicked. Well that's what the SelectableTableRow does for you. Is it Aria compatible? Not yet! + * @class SelectableTableRow + * @extends React.Component + */ +class SelectableTableRow extends React.Component { + render() { + return + + {this.props.children} + + ; + } +} + +export default SelectableTableRow + + + diff --git a/javascripts/src/components/common/selectable_table_row/connect.tsx b/javascripts/src/components/common/selectable_table_row/connect.tsx new file mode 100644 index 00000000..a5423a9a --- /dev/null +++ b/javascripts/src/components/common/selectable_table_row/connect.tsx @@ -0,0 +1,59 @@ +//License: LGPL-3.0-or-later +//https://github.com/jaredpalmer/formik/blob/master/src/connect.tsx +import React = require("react"); +import hoistNonReactStatics = require('hoist-non-react-statics'); + + +/** + * Passed via provider to children of the SelectableTableRow + * @interface TableRowSelectHandler + */ +export interface TableRowSelectHandlerContext { + + /** + * Action to take on selection. A child of SelectableTableRow needs this + * because there needs to be a focusable element for keyboard users to use + * @memberof TableRowSelectHandler + */ + selectHandler: { + onSelect: () => void + } +} + +export const { + Provider: TableRowSelectHandlerProvider, + Consumer: TableRowSelectHandlerConsumer, + } = React.createContext<{ + onSelect: () => void + }>({} as any); + + +/** + * Connect any component to Formik context, and inject as a prop called `modal`; + * @param Comp React Component + */ +export function connectTableRowSelectHandler( + Comp: React.ComponentType + ) { + const C: React.SFC = (props: OuterProps) => ( + + {selectHandler => } + + ); + const componentDisplayName = + Comp.displayName || + 'Component'; + + // Assign Comp to C.WrappedComponent so we can access the inner component in tests + // For example, gets us + (C as React.SFC & { + WrappedComponent: React.ReactNode; + }).WrappedComponent = Comp; + + C.displayName = `TableRowSelectHandlerConnect(${componentDisplayName})`; + + return hoistNonReactStatics( + C, + Comp as React.ComponentClass // cast type to ComponentClass (even if SFC) + ); + } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 903db1be..205e12ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5026,6 +5026,16 @@ "es6-promise": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dev": true, + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.0.tgz", diff --git a/package.json b/package.json index a4cb5c71..43afabd0 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@types/enzyme": "^3.1.9", "@types/enzyme-to-json": "^1.5.1", "@types/es6-promise": "^3.3.0", + "@types/hoist-non-react-statics": "^3.3.1", "@types/jest": "^22.2.2", "@types/jquery": "^3.3.1", "@types/jsdom": "^11.0.4", @@ -110,6 +111,7 @@ "focus-group": "^0.3.1", "form-serialize": "0.7.0", "format-number": "2.0.2", + "hoist-non-react-statics": "^3.3.0", "i18n-js": "^3.0.3", "iban": "0.0.8", "imagesloaded": "4.1.1",