From 2dc384eea89caaad426ff46613429226b9eba21b Mon Sep 17 00:00:00 2001 From: Andrea Stagi Date: Wed, 4 Dec 2024 11:00:35 +0100 Subject: [PATCH] feat: nav mode for skiplinks --- src/Skiplink/Skiplink.tsx | 19 ++++++-- src/Skiplink/SkiplinkItem.tsx | 13 +++++- stories/Components/Skiplinks.stories.tsx | 32 +++++++++++++ stories/Documentation/Skiplinks.mdx | 15 +++++- test/__snapshots__/Storybook.test.tsx.snap | 53 ++++++++++++++++------ 5 files changed, 114 insertions(+), 18 deletions(-) diff --git a/src/Skiplink/Skiplink.tsx b/src/Skiplink/Skiplink.tsx index fe6441b8d..268917c7c 100644 --- a/src/Skiplink/Skiplink.tsx +++ b/src/Skiplink/Skiplink.tsx @@ -2,16 +2,29 @@ import React, { FC, HTMLAttributes, ElementType } from 'react'; import classNames from 'classnames'; export interface SkiplinkProps extends HTMLAttributes { + ariaLabel?: string; /** Utilizzarlo in caso di utilizzo di componenti personalizzati */ tag?: ElementType; + /** Utilizzare il componente in modalità `nav` */ + nav?: boolean; /** Classi aggiuntive da usare per il componente Skiplink */ className?: string; testId?: string; } -export const Skiplink: FC = ({ className, tag = 'div', testId, ...attributes }) => { - const Tag = tag; +export const Skiplink: FC = ({ ariaLabel=null, className, tag = 'div', nav=false, testId, children, ...attributes }) => { + const Tag = nav ? 'nav' : tag; const classes = classNames(className, 'skiplinks'); + if (nav) { + return ( + +
    + {children} +
+
+ ) - return ; + } else { + return ; + } }; diff --git a/src/Skiplink/SkiplinkItem.tsx b/src/Skiplink/SkiplinkItem.tsx index 52113db5c..2b88d18e5 100644 --- a/src/Skiplink/SkiplinkItem.tsx +++ b/src/Skiplink/SkiplinkItem.tsx @@ -4,6 +4,8 @@ import classNames from 'classnames'; export interface SkiplinkItemProps extends AnchorHTMLAttributes { /** Utilizzarlo in caso di utilizzo di componenti personalizzati */ tag?: ElementType; + /** Utilizzare il componente come elemento di uno Skiplink in modalità `nav` */ + navItem?: boolean; /** Classi aggiuntive da usare per il componente Skiplink */ className?: string; /** Abilitare questo attributo per renderizzare lo SkipLinkItem al focus */ @@ -15,6 +17,7 @@ export const SkiplinkItem: FC = ({ className, tag = 'a', focusable = true, + navItem = false, testId, ...attributes }) => { @@ -26,5 +29,13 @@ export const SkiplinkItem: FC = ({ // Add an extra href for focusable if the user passes an onClick rather than href prop const extraHref = attributes.onClick ? { href: '#' } : {}; - return ; + if (navItem) { + return ( +
  • + +
  • + ); + } else { + return ; + } }; diff --git a/stories/Components/Skiplinks.stories.tsx b/stories/Components/Skiplinks.stories.tsx index 3225e2d6c..0015294c0 100644 --- a/stories/Components/Skiplinks.stories.tsx +++ b/stories/Components/Skiplinks.stories.tsx @@ -44,6 +44,38 @@ const EsempiWithHooks = () => { ); }; +const EsempiWithNav = () => { + const containerRef = useRef(null); + const footerRef = useRef(null); + + useEffect(() => { + // We focus the container here since it is hosted inside Storybook's iframe + // @ts-expect-error: with no types annotated, never is inferred here + containerRef.current?.focus(); + }, []); + + const onClick = () => { + // @ts-expect-error: with no types annotated, never is inferred here + footerRef.current?.scrollIntoView(); + }; + + return ( +
    +
    +
    + + + Skip to main content + Skip to footer + +
    + ); +}; + export const _Esempi: Story = { render: () => }; + +export const _EsempiWithNav: Story = { + render: () => +}; \ No newline at end of file diff --git a/stories/Documentation/Skiplinks.mdx b/stories/Documentation/Skiplinks.mdx index 071e74b00..ee7ab9923 100644 --- a/stories/Documentation/Skiplinks.mdx +++ b/stories/Documentation/Skiplinks.mdx @@ -5,7 +5,7 @@ import * as SkiplinksStories from '../Components/Skiplinks.stories'; # Skiplinks -## Gli Skiplink sono collegamento interno alla pagina che consentono agli utenti di accedere direttamente al contenuto principale della pagina saltando il menu di navigazione. +Gli Skiplink sono collegamento interno alla pagina che consentono agli utenti di accedere direttamente al contenuto principale della pagina saltando il menu di navigazione. È un componente particolarmente utile per coloro che accedono con screen reader e/o da tastiera. @@ -47,3 +47,16 @@ return ( ); ``` + + +## Elenco +Se la pagina è particolarmente complessa si possono inserire più collegamenti che permettano di saltare direttamente ai blocchi principali. + +Nell'esempio che segue, implementato per il sito [Designers Italia](https://designers.italia.it), sono inseriti due collegamenti che è utile approfondire: + +- un salto ad un **modulo per chiedere alle persone come stanno valutando l'esperienza d'uso** della pagina. Il testo dello skiplink anticipa già la domanda; +- un **collegamento diretto alla Dichiarazione di accessibilità disponibile sul form AgID**, che accompagnerà il necessario link presente anche nel piede di pagina, per permettere a chi naviga con strumenti assistivi di trovarla facilmente senza dover scansionare tutti i contennuti. + +Consigliamo di non eccedere con il numero di elementi scorciatoia, altrimenti emergerebbe il bisogno di poter saltare le stesse scorciatoie. + + \ No newline at end of file diff --git a/test/__snapshots__/Storybook.test.tsx.snap b/test/__snapshots__/Storybook.test.tsx.snap index 615ca6391..6bfae8baa 100644 --- a/test/__snapshots__/Storybook.test.tsx.snap +++ b/test/__snapshots__/Storybook.test.tsx.snap @@ -12150,20 +12150,47 @@ exports[`Stories Snapshots Documentazione/Componenti/Skiplinks _Esempi 1`] = ` /> +`; + +exports[`Stories Snapshots Documentazione/Componenti/Skiplinks _EsempiWithNav 1`] = ` + `;