Skip to content

Commit

Permalink
Convert class components into functional components with hooks.
Browse files Browse the repository at this point in the history
  • Loading branch information
the-nathan-smith authored and Joshua Bates committed Apr 8, 2024
1 parent 3d8fe18 commit e5b85cd
Show file tree
Hide file tree
Showing 103 changed files with 1,088 additions and 1,293 deletions.
16 changes: 8 additions & 8 deletions src/components/content-presentation/details/Details.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';

interface DetailsProps extends HTMLProps<HTMLDetailsElement> {
expander?: boolean;
}

interface Details extends React.FC<DetailsProps> {
Summary: React.FC<HTMLProps<HTMLDivElement>>;
Text: React.FC<HTMLProps<HTMLDivElement>>;
ExpanderGroup: React.FC<HTMLProps<HTMLDivElement>>;
interface Details extends FC<DetailsProps> {
Summary: FC<HTMLProps<HTMLDivElement>>;
Text: FC<HTMLProps<HTMLDivElement>>;
ExpanderGroup: FC<HTMLProps<HTMLDivElement>>;
}

// TODO: Check if standard NHS.UK polyfill "details.polyfill.js" is required
Expand All @@ -19,17 +19,17 @@ const Details: Details = ({ className, expander, ...rest }) => (
/>
);

const DetailsSummary: React.FC<HTMLProps<HTMLDivElement>> = ({ className, children, ...rest }) => (
const DetailsSummary: FC<HTMLProps<HTMLDivElement>> = ({ className, children, ...rest }) => (
<summary className={classNames('nhsuk-details__summary', className)} {...rest}>
<span className="nhsuk-details__summary-text">{children}</span>
</summary>
);

const DetailsText: React.FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
const DetailsText: FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
<div className={classNames('nhsuk-details__text', className)} {...rest} />
);

const ExpanderGroup: React.FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
const ExpanderGroup: FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
<div className={classNames('nhsuk-expander-group', className)} {...rest} />
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client';
import React, { HTMLProps, createContext, useContext, ReactNode } from 'react';
import React, { FC, HTMLProps, createContext, useContext, ReactNode } from 'react';
import classNames from 'classnames';
import { Tick, Cross } from '@components/icons';
import HeadingLevel, { HeadingLevelType } from '@util/HeadingLevel';
Expand All @@ -12,8 +12,8 @@ interface DoAndDontListProps extends HTMLProps<HTMLDivElement> {
headingLevel?: HeadingLevelType;
}

interface DoAndDontList extends React.FC<DoAndDontListProps> {
Item: React.FC<DoAndDontItemProps>;
interface DoAndDontList extends FC<DoAndDontListProps> {
Item: FC<DoAndDontItemProps>;
}

const DoAndDontListContext = createContext<ListType>('do');
Expand Down Expand Up @@ -49,12 +49,7 @@ interface DoAndDontItemProps extends HTMLProps<HTMLLIElement> {
prefixText?: ReactNode;
}

const DoAndDontItem: React.FC<DoAndDontItemProps> = ({
prefixText,
listItemType,
children,
...rest
}) => {
const DoAndDontItem: FC<DoAndDontItemProps> = ({ prefixText, listItemType, children, ...rest }) => {
const listItem = useContext(DoAndDontListContext);
const defaultPrefix = (listItemType || listItem) === 'do' ? null : 'do not ';
const actualPrefix = prefixText === undefined ? defaultPrefix : prefixText;
Expand Down
4 changes: 2 additions & 2 deletions src/components/content-presentation/images/Images.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';

interface ImageProps extends HTMLProps<HTMLImageElement> {
Expand All @@ -8,7 +8,7 @@ interface ImageProps extends HTMLProps<HTMLImageElement> {
caption?: string;
}

const Images: React.FC<ImageProps> = ({ className, caption, ...rest }) => (
const Images: FC<ImageProps> = ({ className, caption, ...rest }) => (
<figure className="nhsuk-image">
{/* eslint-disable-next-line jsx-a11y/alt-text */}
<img className={classNames('nhsuk-image__img', className)} {...rest} />
Expand Down
4 changes: 2 additions & 2 deletions src/components/content-presentation/inset-text/InsetText.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';

interface InsetTextProps extends HTMLProps<HTMLDivElement> {
visuallyHiddenText?: string | false;
}

const InsetText: React.FC<InsetTextProps> = ({
const InsetText: FC<InsetTextProps> = ({
className,
children,
visuallyHiddenText = 'Information: ',
Expand Down
20 changes: 10 additions & 10 deletions src/components/content-presentation/summary-list/SummaryList.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';

const SummaryListRow: React.FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
const SummaryListRow: FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
<div className={classNames('nhsuk-summary-list__row', className)} {...rest} />
);

const SummaryListKey: React.FC<HTMLProps<HTMLDListElement>> = ({ className, ...rest }) => (
const SummaryListKey: FC<HTMLProps<HTMLDListElement>> = ({ className, ...rest }) => (
<dt className={classNames('nhsuk-summary-list__key', className)} {...rest} />
);

const SummaryListValue: React.FC<HTMLProps<HTMLDListElement>> = ({ className, ...rest }) => (
const SummaryListValue: FC<HTMLProps<HTMLDListElement>> = ({ className, ...rest }) => (
<dd className={classNames('nhsuk-summary-list__value', className)} {...rest} />
);

const SummaryListActions: React.FC<HTMLProps<HTMLDListElement>> = ({ className, ...rest }) => (
const SummaryListActions: FC<HTMLProps<HTMLDListElement>> = ({ className, ...rest }) => (
<dd className={classNames('nhsuk-summary-list__actions', className)} {...rest} />
);

interface SummaryListProps extends HTMLProps<HTMLDListElement> {
noBorder?: boolean;
}

interface SummaryList extends React.FC<SummaryListProps> {
Row: React.FC<HTMLProps<HTMLDivElement>>;
Key: React.FC<HTMLProps<HTMLDListElement>>;
Value: React.FC<HTMLProps<HTMLDListElement>>;
Actions: React.FC<HTMLProps<HTMLDListElement>>;
interface SummaryList extends FC<SummaryListProps> {
Row: FC<HTMLProps<HTMLDivElement>>;
Key: FC<HTMLProps<HTMLDListElement>>;
Value: FC<HTMLProps<HTMLDListElement>>;
Actions: FC<HTMLProps<HTMLDListElement>>;
}

const SummaryList: SummaryList = ({ className, noBorder, ...rest }) => (
Expand Down
109 changes: 46 additions & 63 deletions src/components/content-presentation/table/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { ComponentProps, HTMLProps, ReactNode } from 'react';
import React, { FC, ComponentProps, HTMLProps, ReactNode, useState } from 'react';
import classNames from 'classnames';
import TableBody from './components/TableBody';
import TableCaption from './components/TableCaption';
import TableCell from './components/TableCell';
import TableCell, { TableCellProps } from './components/TableCell';
import TableContainer from './components/TableContainer';
import TableHead from './components/TableHead';
import TablePanel, { TablePanelProps } from './components/TablePanel';
import TableRow from './components/TableRow';
import TablePanel from './components/TablePanel';
import TableContext, { ITableContext } from './TableContext';

interface TableProps extends HTMLProps<HTMLTableElement> {
Expand All @@ -15,69 +15,52 @@ interface TableProps extends HTMLProps<HTMLTableElement> {
captionProps?: ComponentProps<typeof TableCaption>;
}

interface TableState {
headings: string[];
interface Table extends FC<TableProps> {
Body: FC<HTMLProps<HTMLTableSectionElement>>;
Cell: FC<TableCellProps>;
Container: FC<HTMLProps<HTMLDivElement>>;
Head: FC<HTMLProps<HTMLTableSectionElement>>;
Panel: FC<TablePanelProps>;
Row: FC<HTMLProps<HTMLTableRowElement>>;
}

// TODO - turn into functional component
class Table extends React.PureComponent<TableProps, TableState> {
static defaultProps = {
responsive: false,
const Table: Table = ({
className,
responsive = false,
children,
caption,
captionProps,
...rest
}) => {
const [headings, setHeadings] = useState<string[]>([]);
const contextValue: ITableContext = {
isResponsive: Boolean(responsive),
headings,
setHeadings,
};

static Container = TableContainer;

static Head = TableHead;

static Row = TableRow;

static Cell = TableCell;

static Body = TableBody;

static Panel = TablePanel;

constructor(props: TableProps) {
super(props);
this.state = {
headings: [],
};
}

setHeadings = (headings: string[]): void => {
const isEqual = headings.reduce(
(prevValue, heading, index) => prevValue && heading === this.state.headings[index],
true,
);

if (!isEqual) this.setState({ headings });
};

render(): JSX.Element {
const { className, responsive, children, caption, captionProps, ...rest } = this.props;

const contextValue: ITableContext = {
isResponsive: Boolean(responsive),
headings: this.state.headings,
setHeadings: this.setHeadings,
};

return (
<TableContext.Provider value={contextValue}>
<table
className={classNames(
{ 'nhsuk-table': !responsive },
{ 'nhsuk-table-responsive': responsive },
className,
)}
{...rest}
>
{caption && <TableCaption {...captionProps}>{caption}</TableCaption>}
{children}
</table>
</TableContext.Provider>
);
}
}
return (
<TableContext.Provider value={contextValue}>
<table
className={classNames(
{ 'nhsuk-table': !responsive },
{ 'nhsuk-table-responsive': responsive },
className,
)}
{...rest}
>
{caption && <TableCaption {...captionProps}>{caption}</TableCaption>}
{children}
</table>
</TableContext.Provider>
);
};

Table.Body = TableBody;
Table.Cell = TableCell;
Table.Container = TableContainer;
Table.Head = TableHead;
Table.Panel = TablePanel;
Table.Row = TableRow;

export default Table;
4 changes: 2 additions & 2 deletions src/components/content-presentation/table/TableHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { isValidElement, ReactElement, ReactNode } from 'react';
import { Children, isValidElement, ReactElement, ReactNode } from 'react';
import TableCell from './components/TableCell';

export const isTableCell = (child: ReactNode): child is ReactElement => {
Expand All @@ -7,7 +7,7 @@ export const isTableCell = (child: ReactNode): child is ReactElement => {

export const getHeadingsFromChildren = (children: ReactNode): string[] => {
const headings: string[] = [];
React.Children.map(children, (child) => {
Children.map(children, (child) => {
if (isTableCell(child)) {
headings.push(child.props.children.toString());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import classNames from 'classnames';
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import TableSectionContext, { TableSection } from '../TableSectionContext';

const TableBody: React.FC<HTMLProps<HTMLTableSectionElement>> = ({
className,
children,
...rest
}) => (
const TableBody: FC<HTMLProps<HTMLTableSectionElement>> = ({ className, children, ...rest }) => (
<tbody className={classNames('nhsuk-table__body', className)} {...rest}>
<TableSectionContext.Provider value={TableSection.BODY}>
{children}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';

const TableCaption: React.FC<HTMLProps<HTMLTableCaptionElement>> = ({ className, ...rest }) => (
const TableCaption: FC<HTMLProps<HTMLTableCaptionElement>> = ({ className, ...rest }) => (
<caption className={classNames('nhsuk-table__caption', className)} {...rest} />
);
TableCaption.displayName = 'Table.Caption';
Expand Down
23 changes: 9 additions & 14 deletions src/components/content-presentation/table/components/TableCell.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';
import classNames from 'classnames';
import React, { HTMLProps, useContext } from 'react';
import React, { FC, HTMLProps, useContext } from 'react';
import useDevWarning from '@util/hooks/UseDevWarning';
import TableSectionContext, { TableSection } from '../TableSectionContext';

Expand All @@ -13,7 +12,7 @@ export interface TableCellProps extends HTMLProps<HTMLTableCellElement> {
isNumeric?: boolean;
}

const TableCell: React.FC<TableCellProps> = ({
const TableCell: FC<TableCellProps> = ({
className,
_responsive = false,
_responsiveHeading = '',
Expand All @@ -27,26 +26,22 @@ const TableCell: React.FC<TableCellProps> = ({
const cellClass = section === TableSection.HEAD ? 'nhsuk-table__header' : 'nhsuk-table__cell';
const classes = classNames(cellClass, { [`${cellClass}--numeric`]: isNumeric }, className);

switch (section) {
case TableSection.HEAD:
return (
return (
<>
{section === TableSection.HEAD ? (
<th className={classes} scope="col" {...rest}>
{children}
</th>
);

case TableSection.BODY:
case TableSection.NONE:
default:
return (
) : (
<td className={classes} role={_responsive ? 'cell' : undefined} {...rest}>
{_responsive && (
<span className="nhsuk-table-responsive__heading">{_responsiveHeading}</span>
)}
{children}
</td>
);
}
)}
</>
);
};

TableCell.displayName = 'Table.Cell';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';

const TableContainer: React.FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
const TableContainer: FC<HTMLProps<HTMLDivElement>> = ({ className, ...rest }) => (
<div className={classNames('nhsuk-table-container', className)} {...rest} />
);
TableContainer.displayName = 'Table.Container';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import React, { HTMLProps } from 'react';
import React, { FC, HTMLProps } from 'react';
import classNames from 'classnames';
import TableSectionContext, { TableSection } from '../TableSectionContext';

const TableHead: React.FC<HTMLProps<HTMLTableSectionElement>> = ({
className,
children,
...rest
}) => (
const TableHead: FC<HTMLProps<HTMLTableSectionElement>> = ({ className, children, ...rest }) => (
<thead className={classNames('nhsuk-table__head', className)} {...rest}>
<TableSectionContext.Provider value={TableSection.HEAD}>
{children}
Expand Down
Loading

0 comments on commit e5b85cd

Please sign in to comment.