diff --git a/packages/pxweb2/public/locales/ar/translation.json b/packages/pxweb2/public/locales/ar/translation.json index 0e70037cc..a8a02106d 100644 --- a/packages/pxweb2/public/locales/ar/translation.json +++ b/packages/pxweb2/public/locales/ar/translation.json @@ -24,6 +24,7 @@ } }, "skip_to_main": "انتقل إلى المحتوى الرئيسي", + "skip_to_toolsmenu": " انتقل إلى قائمة الأدوات", "switch_language_landmark": "اختر اللغة", "footer": { "language_header": "اللغة", diff --git a/packages/pxweb2/public/locales/en/translation.json b/packages/pxweb2/public/locales/en/translation.json index 69c8fe6ca..f0e88f593 100644 --- a/packages/pxweb2/public/locales/en/translation.json +++ b/packages/pxweb2/public/locales/en/translation.json @@ -24,6 +24,7 @@ } }, "skip_to_main": "Skip to main content", + "skip_to_toolsmenu": "Skip to tool menu for table", "switch_language_landmark": "Select language", "footer": { "language_header": "Language", diff --git a/packages/pxweb2/public/locales/no/translation.json b/packages/pxweb2/public/locales/no/translation.json index b2b39deba..34ad01bff 100644 --- a/packages/pxweb2/public/locales/no/translation.json +++ b/packages/pxweb2/public/locales/no/translation.json @@ -23,7 +23,8 @@ "action_text": "Last siden på nytt" } }, - "skip_to_main": "Hopp til hovedinnhold", + "skip_to_main": "Gå til hovedinnhold", + "skip_to_toolsmenu": "Gå til verktøymeny for tabell", "switch_language_landmark": "Velg språk", "footer": { "language_header": "Språk", diff --git a/packages/pxweb2/public/locales/sv/translation.json b/packages/pxweb2/public/locales/sv/translation.json index 19e74aef6..30c2e4451 100644 --- a/packages/pxweb2/public/locales/sv/translation.json +++ b/packages/pxweb2/public/locales/sv/translation.json @@ -24,6 +24,7 @@ } }, "skip_to_main": "Gå direkt till huvudinnehållet", + "skip_to_toolsmenu": "Gå direkt till verktygsmeny för tabell", "switch_language_landmark": "Välj språk", "footer": { "language_header": "Språk", diff --git a/packages/pxweb2/src/@types/resources.d.ts b/packages/pxweb2/src/@types/resources.d.ts index 6329c3a87..ad70c200b 100644 --- a/packages/pxweb2/src/@types/resources.d.ts +++ b/packages/pxweb2/src/@types/resources.d.ts @@ -58,6 +58,7 @@ interface Resources { logo_alt: 'To the front page'; }; skip_to_main: 'Skip to main content'; + skip_to_toolsmenu: 'Skip to tool menu for table'; status_messages: { drawer_edit: 'More tools for editing the table are under construction.'; drawer_help: 'The help section is under construction. It will be possible to set up links that point directly to your own help pages.'; diff --git a/packages/pxweb2/src/app/components/SkipToContent/SkipToContent.tsx b/packages/pxweb2/src/app/components/SkipToContent/SkipToContent.tsx deleted file mode 100644 index f59e7c9a1..000000000 --- a/packages/pxweb2/src/app/components/SkipToContent/SkipToContent.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import cl from 'clsx'; -import { useLocation, useSearchParams } from 'react-router'; -import { useTranslation } from 'react-i18next'; - -import classes from './SkipToContent.module.scss'; -import { Link } from '@pxweb2/pxweb2-ui'; -import { getConfig } from '../../util/config/getConfig'; -import { getLanguagePath } from '../../util/language/getLanguagePath'; - -export type SkipToContentProps = React.HTMLAttributes & { - // Jump to - targetId?: string; - - // label for the link - label?: string; - - containerRef?: React.Ref; -}; - -export function SkipToContent(props: SkipToContentProps) { - const { targetId, label, containerRef, ...rest } = props; - const { i18n } = useTranslation(); - const config = getConfig(); - const location = useLocation().pathname; - const [searchParams] = useSearchParams(); - - const basePath = getLanguagePath( - location, - i18n.language, - config.language.supportedLanguages, - config.language.defaultLanguage, - config.language.showDefaultLanguageInPath, - config.baseApplicationPath, - config.language.positionInPath, - ); - - // build a single, URL-encoded query string from the search params - const paramsString = searchParams.toString(); // URLSearchParams handles encoding - const params = paramsString ? `?${paramsString}` : ''; - const hash = targetId ? `#${targetId}` : ''; - const path = `${basePath}${params}${hash}`; - - return ( -
- - {label} - -
- ); -} - -SkipToContent.displayName = 'SkipToContent'; diff --git a/packages/pxweb2/src/app/components/SkipToMain/SkipToMain.module.scss b/packages/pxweb2/src/app/components/SkipToMain/SkipToMain.module.scss deleted file mode 100644 index 087bf7b6c..000000000 --- a/packages/pxweb2/src/app/components/SkipToMain/SkipToMain.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -.skip-to-main { - &:focus-within { - display: flex; - background-color: var(--px-color-surface-inverted); - width: 100%; - height: 48px; - justify-content: center; - } -} - -.skip-to-main a { - justify-content: center; - background-color: var(--px-color-surface-inverted); - color: var(--px-color-text-on-inverted); - height: 44px; - - &:focus-visible { - outline: 3px solid var(--px-color-border-focus-outline-on-inverted); - outline-offset: -6px; - padding: 0px 12px; - box-shadow: none; - } - - &:hover, - &:active { - background-color: var(--px-color-surface-inverted); - color: var(--px-color-text-on-inverted); - } -} - -.screen-reader-only { - &:not(:focus-within) { - width: 1px !important; - height: 1px !important; - padding: 0 !important; - margin: -1px !important; - overflow: hidden !important; - clip: rect(0, 0, 0, 0) !important; - white-space: nowrap !important; - border: 0 !important; - } -} diff --git a/packages/pxweb2/src/app/components/SkipToMain/SkipToMain.tsx b/packages/pxweb2/src/app/components/SkipToMain/SkipToMain.tsx deleted file mode 100644 index bdb66f42d..000000000 --- a/packages/pxweb2/src/app/components/SkipToMain/SkipToMain.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import cl from 'clsx'; -import { useTranslation } from 'react-i18next'; -import { useLocation, useSearchParams } from 'react-router'; - -import classes from './SkipToMain.module.scss'; -import { Link } from '@pxweb2/pxweb2-ui'; -import { getConfig } from '../../util/config/getConfig'; -import { getLanguagePath } from '../../util/language/getLanguagePath'; - -export const SkipToMain = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->((props, ref) => { - const { t, i18n } = useTranslation(); - const config = getConfig(); - const location = useLocation().pathname; - const [searchParams] = useSearchParams(); - - const basePath = getLanguagePath( - location, - i18n.language, - config.language.supportedLanguages, - config.language.defaultLanguage, - config.language.showDefaultLanguageInPath, - config.baseApplicationPath, - config.language.positionInPath, - ); - - // build a single, URL-encoded query string from the search params - const paramsString = searchParams.toString(); // URLSearchParams handles encoding - const params = paramsString ? `?${paramsString}` : ''; - const path = `${basePath}${params}#px-main-content`; - - return ( -
- - {t('common.skip_to_main')} - -
- ); -}); - -SkipToMain.displayName = 'SkipToMain'; diff --git a/packages/pxweb2/src/app/components/SkipToContent/SkipToContent.module.scss b/packages/pxweb2/src/app/components/SkipToTarget/SkipToTarget.module.scss similarity index 67% rename from packages/pxweb2/src/app/components/SkipToContent/SkipToContent.module.scss rename to packages/pxweb2/src/app/components/SkipToTarget/SkipToTarget.module.scss index 5e187826c..157163e21 100644 --- a/packages/pxweb2/src/app/components/SkipToContent/SkipToContent.module.scss +++ b/packages/pxweb2/src/app/components/SkipToTarget/SkipToTarget.module.scss @@ -1,3 +1,14 @@ +.skip-to-main { + &:focus-within { + display: flex; + background-color: var(--px-color-surface-inverted); + width: 100%; + height: 48px; + justify-content: center; + margin: -1px; + } +} + .skip-to-content { &:focus-within { display: flex; @@ -8,6 +19,7 @@ } } +.skip-to-main a, .skip-to-content a { justify-content: center; background-color: var(--px-color-surface-inverted); @@ -28,16 +40,16 @@ } } -.screen-reader-only { +.screen-reader-only-main { + &:not(:focus-within) { + position: absolute; + left: -99999px; + } +} + +.screen-reader-only-content { &:not(:focus-within) { - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; position: absolute; + left: -99999px; } } diff --git a/packages/pxweb2/src/app/components/SkipToTarget/SkipToTarget.tsx b/packages/pxweb2/src/app/components/SkipToTarget/SkipToTarget.tsx new file mode 100644 index 000000000..4933a43ca --- /dev/null +++ b/packages/pxweb2/src/app/components/SkipToTarget/SkipToTarget.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import cl from 'clsx'; +import { useTranslation } from 'react-i18next'; +import { useLocation, useSearchParams } from 'react-router'; + +import classes from './SkipToTarget.module.scss'; +import { Link } from '@pxweb2/pxweb2-ui'; +import { getConfig } from '../../util/config/getConfig'; +import { getLanguagePath } from '../../util/language/getLanguagePath'; + +type SkipTranslationKey = 'common.skip_to_main' | 'common.skip_to_toolsmenu'; + +export type SkipToTargetProps = React.HTMLAttributes & { + targetId: string; + translationKey?: SkipTranslationKey; + label?: string; + styleVariant?: 'main' | 'content'; +}; + +export const SkipToTarget = React.forwardRef( + ( + { + targetId, + translationKey, + label, + styleVariant = 'main', + className = '', + ...props + }, + ref, + ) => { + const { t, i18n } = useTranslation(); + const config = getConfig(); + const location = useLocation().pathname; + const [searchParams] = useSearchParams(); + + const basePath = getLanguagePath( + location, + i18n.language, + config.language.supportedLanguages, + config.language.defaultLanguage, + config.language.showDefaultLanguageInPath, + config.baseApplicationPath, + config.language.positionInPath, + ); + + // Build a single, URL-encoded query string from the search params. + const paramsString = searchParams.toString(); + const params = paramsString ? `?${paramsString}` : ''; + const path = `${basePath}${params}#${targetId}`; + const linkText = label ?? (translationKey ? t(translationKey) : ''); + + return ( +
+ + {linkText} + +
+ ); + }, +); + +SkipToTarget.displayName = 'SkipToTarget'; diff --git a/packages/pxweb2/src/app/pages/StartPage/StartPage.tsx b/packages/pxweb2/src/app/pages/StartPage/StartPage.tsx index 61393342d..2779b9bd1 100644 --- a/packages/pxweb2/src/app/pages/StartPage/StartPage.tsx +++ b/packages/pxweb2/src/app/pages/StartPage/StartPage.tsx @@ -33,7 +33,7 @@ import { Header } from '../../components/Header/Header'; import { Footer } from '../../components/Footer/Footer'; import { ErrorMessage } from '../../components/ErrorMessage/ErrorMessage'; import { FilterSidebar } from '../../components/FilterSidebar/FilterSidebar'; -import { SkipToContent } from '../../components/SkipToContent/SkipToContent'; +import { SkipToTarget } from '../../components/SkipToTarget/SkipToTarget'; import { ActionType } from './StartPageTypes'; import { getSubjectTree, @@ -736,11 +736,13 @@ const StartPage = () => { return ( <>