diff options
Diffstat (limited to 'src/components/molecules')
| -rw-r--r-- | src/components/molecules/buttons/back-to-top.module.scss | 5 | ||||
| -rw-r--r-- | src/components/molecules/buttons/back-to-top.stories.tsx | 6 | ||||
| -rw-r--r-- | src/components/molecules/buttons/back-to-top.test.tsx | 11 | ||||
| -rw-r--r-- | src/components/molecules/buttons/back-to-top.tsx | 28 | ||||
| -rw-r--r-- | src/components/molecules/buttons/help-button.tsx | 4 | ||||
| -rw-r--r-- | src/components/molecules/layout/card.tsx | 31 | ||||
| -rw-r--r-- | src/components/molecules/nav/pagination.tsx | 40 |
7 files changed, 69 insertions, 56 deletions
diff --git a/src/components/molecules/buttons/back-to-top.module.scss b/src/components/molecules/buttons/back-to-top.module.scss index f5b3acd..7eae03b 100644 --- a/src/components/molecules/buttons/back-to-top.module.scss +++ b/src/components/molecules/buttons/back-to-top.module.scss @@ -4,6 +4,7 @@ .link { width: clamp(#{fun.convert-px(48)}, 8vw, #{fun.convert-px(55)}); height: clamp(#{fun.convert-px(48)}, 8vw, #{fun.convert-px(55)}); + padding: 0; svg { width: 100%; @@ -18,7 +19,9 @@ .arrow-bar { opacity: 0; transform: translateY(30%) scaleY(0); - transition: transform 0.45s ease-in-out 0s, opacity 0.1s linear 0.2s; + transition: + transform 0.45s ease-in-out 0s, + opacity 0.1s linear 0.2s; } } diff --git a/src/components/molecules/buttons/back-to-top.stories.tsx b/src/components/molecules/buttons/back-to-top.stories.tsx index 5de12d4..40acd33 100644 --- a/src/components/molecules/buttons/back-to-top.stories.tsx +++ b/src/components/molecules/buttons/back-to-top.stories.tsx @@ -1,4 +1,4 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; +import type { ComponentMeta, ComponentStory } from '@storybook/react'; import { BackToTop as BackToTopComponent } from './back-to-top'; /** @@ -21,7 +21,7 @@ export default { required: false, }, }, - target: { + to: { control: { type: 'text', }, @@ -43,5 +43,5 @@ const Template: ComponentStory<typeof BackToTopComponent> = (args) => ( */ export const BackToTop = Template.bind({}); BackToTop.args = { - target: 'top', + to: 'top', }; diff --git a/src/components/molecules/buttons/back-to-top.test.tsx b/src/components/molecules/buttons/back-to-top.test.tsx index aaae3ef..a775841 100644 --- a/src/components/molecules/buttons/back-to-top.test.tsx +++ b/src/components/molecules/buttons/back-to-top.test.tsx @@ -1,11 +1,14 @@ import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; +import { render, screen as rtlScreen } from '../../../../tests/utils'; import { BackToTop } from './back-to-top'; describe('BackToTop', () => { it('renders a BackToTop link', () => { - render(<BackToTop target="top" />); - expect(screen.getByRole('link')).toHaveAccessibleName('Back to top'); - expect(screen.getByRole('link')).toHaveAttribute('href', '#top'); + const id = 'top'; + + render(<BackToTop to={id} />); + + expect(rtlScreen.getByRole('link')).toHaveAccessibleName('Back to top'); + expect(rtlScreen.getByRole('link')).toHaveAttribute('href', `#${id}`); }); }); diff --git a/src/components/molecules/buttons/back-to-top.tsx b/src/components/molecules/buttons/back-to-top.tsx index d28d6c1..6ca6f10 100644 --- a/src/components/molecules/buttons/back-to-top.tsx +++ b/src/components/molecules/buttons/back-to-top.tsx @@ -1,13 +1,13 @@ -import { FC } from 'react'; +import type { FC, HTMLAttributes } from 'react'; import { useIntl } from 'react-intl'; -import { Arrow, ButtonLink, type ButtonLinkProps } from '../../atoms'; +import { Arrow, ButtonLink } from '../../atoms'; import styles from './back-to-top.module.scss'; -export type BackToTopProps = Pick<ButtonLinkProps, 'target'> & { +export type BackToTopProps = HTMLAttributes<HTMLDivElement> & { /** - * Set additional classnames to the button wrapper. + * Define the element id to us as anchor. */ - className?: string; + to: string; }; /** @@ -15,23 +15,31 @@ export type BackToTopProps = Pick<ButtonLinkProps, 'target'> & { * * Render a back to top link. */ -export const BackToTop: FC<BackToTopProps> = ({ className = '', target }) => { +export const BackToTop: FC<BackToTopProps> = ({ + className = '', + to, + ...props +}) => { const intl = useIntl(); const linkName = intl.formatMessage({ defaultMessage: 'Back to top', description: 'BackToTop: link text', id: 'm+SUSR', }); + const btnClass = `${styles.wrapper} ${className}`; + const anchor = `#${to}`; return ( - <div className={`${styles.wrapper} ${className}`}> + <div {...props} className={btnClass}> <ButtonLink - shape="square" - target={`#${target}`} aria-label={linkName} className={styles.link} + // eslint-disable-next-line react/jsx-no-literals -- Shape allowed + shape="square" + to={anchor} > - <Arrow aria-hidden={true} direction="top" /> + {/* eslint-disable-next-line react/jsx-no-literals -- Direction allowed */} + <Arrow aria-hidden direction="top" /> </ButtonLink> </div> ); diff --git a/src/components/molecules/buttons/help-button.tsx b/src/components/molecules/buttons/help-button.tsx index 1234835..7a01b14 100644 --- a/src/components/molecules/buttons/help-button.tsx +++ b/src/components/molecules/buttons/help-button.tsx @@ -1,11 +1,11 @@ -import { forwardRef, ForwardRefRenderFunction } from 'react'; +import { forwardRef, type ForwardRefRenderFunction } from 'react'; import { useIntl } from 'react-intl'; import { Button, type ButtonProps } from '../../atoms'; import styles from './help-button.module.scss'; export type HelpButtonProps = Pick< ButtonProps, - 'aria-pressed' | 'className' | 'onClick' + 'className' | 'isPressed' | 'onClick' >; const HelpButtonWithRef: ForwardRefRenderFunction< diff --git a/src/components/molecules/layout/card.tsx b/src/components/molecules/layout/card.tsx index c342d0e..f39a430 100644 --- a/src/components/molecules/layout/card.tsx +++ b/src/components/molecules/layout/card.tsx @@ -1,9 +1,9 @@ -import { FC } from 'react'; -import { type Image } from '../../../types'; +import type { FC } from 'react'; +import type { Image as Img } from '../../../types'; import { ButtonLink, Heading, type HeadingLevel } from '../../atoms'; import { ResponsiveImage } from '../images'; -import { Meta, type MetaData } from './meta'; import styles from './card.module.scss'; +import { Meta, type MetaData } from './meta'; export type CardProps = { /** @@ -13,7 +13,7 @@ export type CardProps = { /** * The card cover. */ - cover?: Image; + cover?: Img; /** * The card id. */ @@ -55,29 +55,32 @@ export const Card: FC<CardProps> = ({ titleLevel, url, }) => { + const cardClass = `${styles.wrapper} ${className}`; + const headingId = `${id}-heading`; + return ( - <ButtonLink - aria-labelledby={`${id}-heading`} - className={`${styles.wrapper} ${className}`} - target={url} - > + <ButtonLink aria-labelledby={headingId} className={cardClass} to={url}> <article className={styles.article}> <header className={styles.header}> - {cover && <ResponsiveImage {...cover} className={styles.cover} />} + {cover ? ( + <ResponsiveImage {...cover} className={styles.cover} /> + ) : null} <Heading + // eslint-disable-next-line react/jsx-no-literals -- Hardcoded config alignment="center" className={styles.title} - id={`${id}-heading`} + id={headingId} level={titleLevel} > {title} </Heading> </header> - {tagline && <div className={styles.tagline}>{tagline}</div>} - {meta && ( + {tagline ? <div className={styles.tagline}>{tagline}</div> : null} + {meta ? ( <footer className={styles.footer}> <Meta data={meta} + // eslint-disable-next-line react/jsx-no-literals -- Hardcoded config layout="inline" className={styles.list} groupClassName={styles.meta__item} @@ -85,7 +88,7 @@ export const Card: FC<CardProps> = ({ valueClassName={styles.meta__value} /> </footer> - )} + ) : null} </article> </ButtonLink> ); diff --git a/src/components/molecules/nav/pagination.tsx b/src/components/molecules/nav/pagination.tsx index 6fa69f0..27ef1ec 100644 --- a/src/components/molecules/nav/pagination.tsx +++ b/src/components/molecules/nav/pagination.tsx @@ -1,4 +1,5 @@ -import { FC, Fragment, ReactNode } from 'react'; +/* eslint-disable max-statements */ +import { type FC, Fragment, type ReactNode } from 'react'; import { useIntl } from 'react-intl'; import { ButtonLink } from '../../atoms'; import styles from './pagination.module.scss'; @@ -78,11 +79,8 @@ export const Pagination: FC<PaginationProps> = ({ * @param {number} end - The last value. * @returns {number[]} An array from start value to end value. */ - const range = (start: number, end: number): number[] => { - const length = end - start + 1; - - return Array.from({ length }, (_, index) => index + start); - }; + const range = (start: number, end: number): number[] => + Array.from({ length: end - start + 1 }, (_, index) => index + start); /** * Get the pagination range. @@ -138,21 +136,17 @@ export const Pagination: FC<PaginationProps> = ({ const getItem = (id: string, body: ReactNode, link?: string): JSX.Element => { const linkModifier = id.startsWith('page') ? 'link--number' : ''; const kind = id === 'previous' || id === 'next' ? 'tertiary' : 'secondary'; + const linkClass = `${styles.link} ${styles[linkModifier]}`; + const disabledLinkClass = `${styles.link} ${styles['link--disabled']}`; return ( <li className={styles.item}> {link ? ( - <ButtonLink - kind={kind} - target={link} - className={`${styles.link} ${styles[linkModifier]}`} - > + <ButtonLink className={linkClass} kind={kind} to={link}> {body} </ButtonLink> ) : ( - <span className={`${styles.link} ${styles['link--disabled']}`}> - {body} - </span> + <span className={disabledLinkClass}>{body}</span> )} </li> ); @@ -187,6 +181,7 @@ export const Pagination: FC<PaginationProps> = ({ { number: page, a11y: (chunks: ReactNode) => ( + // eslint-disable-next-line react/jsx-no-literals <span className="screen-reader-text"> {page === currentPage && currentPagePrefix} {chunks} @@ -199,19 +194,20 @@ export const Pagination: FC<PaginationProps> = ({ ? undefined : `${baseUrl}${page}`; - return <Fragment key={`item-${id}`}>{getItem(id, body, url)}</Fragment>; + return <Fragment key={id}>{getItem(id, body, url)}</Fragment>; }); }; + const navClass = `${styles.wrapper} ${className}`; + const listClass = `${styles.list} ${styles['list--pages']}`; return ( - <nav {...props} className={`${styles.wrapper} ${className}`}> - <ul className={`${styles.list} ${styles['list--pages']}`}> - {getPages(current, totalPages)} - </ul> + <nav {...props} className={navClass}> + <ul className={listClass}>{getPages(current, totalPages)}</ul> <ul className={styles.list}> - {hasPreviousPage && - getItem('previous', previousPageName, previousPageUrl)} - {hasNextPage && getItem('next', nextPageName, nextPageUrl)} + {hasPreviousPage + ? getItem('previous', previousPageName, previousPageUrl) + : null} + {hasNextPage ? getItem('next', nextPageName, nextPageUrl) : null} </ul> </nav> ); |
