Skip to content

Commit

Permalink
Etter brukertest kom det frem at pilnavigasjon var en forbedring, men…
Browse files Browse the repository at this point in the history
… litt mangelfull opplevelse for de med skjermlesere.

Det var litt ulogiske at hovedenheter ble auto ekspandert.
En bedre opplevelse oppnås nå med navigering lik som et tree:
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/tree_role#keyboard_interactions
  • Loading branch information
kenglxn committed Dec 19, 2023
1 parent 31cfc58 commit 17339f4
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 109 deletions.
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@navikt/bedriftsmeny",
"version": "6.13.0-rc4",
"version": "6.13.0-rc5",
"description": "Bedriftsvelger og -meny for innlogget arbeidsgiver. Laget av TAG (Tjenester for Arbeidsgivere).",
"author": "NAVIKT",
"license": "MIT",
Expand Down Expand Up @@ -56,7 +56,7 @@
"postcss-import": "^15.1.0",
"prettier": "2.2.1",
"process": "^0.11.10",
"typescript": "^4.1.3"
"typescript": "^5.3.3"
},
"dependencies": {
"fuzzysort": "^1.1.4",
Expand Down
4 changes: 4 additions & 0 deletions src/bedriftsmeny/velger/JuridiskEnhet.css
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
width: 100%;
padding: var(--a-spacing-3) var(--a-spacing-4);
}
.navbm-virksomhetsvelger__underenhet-innhold:focus {
/* liten hack da programmatisk focus ikke funker på ds-react lenger. usikker på hvorfor */
box-shadow: inset 0 0 0 2px var(--ac-button-tertiary-focus-border, var(--a-border-action)), var(--a-shadow-focus);
}
.navbm-virksomhetsvelger__underenhet-innhold > span {
width: 100%;
}
Expand Down
76 changes: 40 additions & 36 deletions src/bedriftsmeny/velger/JuridiskEnhet.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,69 @@
import React, {ForwardedRef, forwardRef, useState} from 'react';
import React, {ForwardedRef, forwardRef} from 'react';
import {Office1, Success} from '@navikt/ds-icons';
import {Accordion, BodyShort, Button} from '@navikt/ds-react';
import {JuridiskEnhetMedUnderEnheterArray, Organisasjon} from '../organisasjon';
import {Organisasjon} from '../organisasjon';
import {a11yOrgnr} from "./utils";
import {OrganisasjonMedState} from "./useTastaturNavigasjon";

type Props = {
juridiskEnhet: JuridiskEnhetMedUnderEnheterArray;
fokusertEnhet: Organisasjon;
organisasjonerMedState: OrganisasjonMedState[];
onUnderenhetClick: (underenhet: Organisasjon) => void;
onHovedenhetClick: (hovedenhet: Organisasjon) => void;
onFocus: (enhet: Organisasjon) => void;
enhetRef: ForwardedRef<HTMLButtonElement>;
forceTabbable: boolean;
};

const JuridiskEnhet = (
{
juridiskEnhet,
fokusertEnhet,
organisasjonerMedState,
onUnderenhetClick,
onHovedenhetClick,
enhetRef,
forceTabbable,
onFocus,
}: Props
) => {
const {JuridiskEnhet, Underenheter} = juridiskEnhet;
const juridiskEnhetErValgt =
fokusertEnhet.OrganizationNumber ===
JuridiskEnhet.OrganizationNumber;
const underenhetErValgt = Underenheter.some(
(enhet: Organisasjon) => enhet.OrganizationNumber === fokusertEnhet.OrganizationNumber
);
const juridiskEnhetErAktiv = underenhetErValgt || juridiskEnhetErValgt;
const [open, setOpen] = useState(juridiskEnhetErAktiv);
const [juridiskEnhet, ...underenheter] = organisasjonerMedState;

return (
const valgt = organisasjonerMedState.some(({valgt}) => valgt);
return juridiskEnhet && (
<li className='navbm-virksomhetsvelger__juridisk-enhet'>
<Accordion.Item open={underenhetErValgt || open} role="group">
<Accordion.Item open={juridiskEnhet.ekspandert} role="group">
<Accordion.Header
tabIndex={juridiskEnhetErAktiv || forceTabbable ? 0 : -1}
ref={juridiskEnhetErValgt ? enhetRef : null}
tabIndex={valgt ? 0 : -1}
ref={juridiskEnhet.fokusert ? enhetRef : null}
onClick={() => {
setOpen(!open);
onHovedenhetClick(juridiskEnhet);
}}
onFocus={() => {
if (!juridiskEnhet.fokusert) {
onFocus(juridiskEnhet)
}
}}
aria-owns={`underenheter-${JuridiskEnhet.OrganizationNumber}`}
style={{backgroundColor: open ? 'var(--a-surface-action-subtle' : 'transparent'}}
aria-owns={`underenheter-${juridiskEnhet.OrganizationNumber}`}
style={{backgroundColor: juridiskEnhet.ekspandert ? 'var(--a-surface-action-subtle' : 'transparent'}}
>
<Hovedenhet
hovedenhet={JuridiskEnhet}
valgt={underenhetErValgt}
antallUnderenheter={Underenheter.length}
hovedenhet={juridiskEnhet}
valgt={valgt}
antallUnderenheter={underenheter.length}
/>
</Accordion.Header>
<Accordion.Content>
<ul className='navbm-virksomhetsvelger__underenheter'
id={`underenheter-${JuridiskEnhet.OrganizationNumber}`}>
{Underenheter.map((virksomhet) => {
const underenhetErValgt = fokusertEnhet.OrganizationNumber === virksomhet.OrganizationNumber

id={`underenheter-${juridiskEnhet.OrganizationNumber}`}>
{underenheter.map((underenhetMedState) => {
return (
<li key={virksomhet.OrganizationNumber}>
<li key={underenhetMedState.OrganizationNumber}>
<Underenhet
underenhet={virksomhet}
valgt={underenhetErValgt}
ref={underenhetErValgt ? enhetRef : null}
underenhet={underenhetMedState}
valgt={underenhetMedState.valgt}
ref={underenhetMedState.fokusert ? enhetRef : null}
onClick={onUnderenhetClick}
onFocus={() => {
if (!underenhetMedState.fokusert) {
onFocus(underenhetMedState)
}
}}
/>
</li>
);
Expand All @@ -76,17 +78,19 @@ const JuridiskEnhet = (
type UnderenhetProps = {
valgt: boolean;
onClick: (underenhet: Organisasjon) => void;
onFocus: (e: React.FocusEvent<HTMLButtonElement>) => void;
underenhet: Organisasjon;
}

const Underenhet = forwardRef<HTMLButtonElement, UnderenhetProps>(({valgt, onClick, underenhet}, ref) =>
const Underenhet = forwardRef<HTMLButtonElement, UnderenhetProps>(({valgt, onClick, underenhet, onFocus}, ref) =>
<Button
type="button"
ref={ref}
tabIndex={valgt ? 0 : -1}
aria-pressed={valgt}
variant='tertiary'
onClick={() => onClick(underenhet)}
onFocus={onFocus}
className='navbm-virksomhetsvelger__underenhet-innhold'
>
<div className='navbm-virksomhetsvelger__enhet'>
Expand Down
140 changes: 79 additions & 61 deletions src/bedriftsmeny/velger/Virksomhetsvelger.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,49 @@
import React, {KeyboardEventHandler, useContext, useEffect, useRef, useState} from 'react';
import {Button, BodyShort, Search, Accordion, Detail} from '@navikt/ds-react';
import React, {useContext, useEffect, useRef, useState} from 'react';
import {Accordion, BodyShort, Button, Detail, Search} from '@navikt/ds-react';
import {Organisasjon} from '../organisasjon';
import {Expand, Collapse, Office1, Close} from '@navikt/ds-icons';
import {Close, Collapse, Expand, Office1} from '@navikt/ds-icons';
import {VirksomhetsvelgerContext} from './VirksomhetsvelgerProvider';
import JuridiskEnhet from './JuridiskEnhet';
import Dropdown from "./Dropdown";
import FocusTrap from 'focus-trap-react';
import {a11yOrgnr} from "./utils";
import {useTastaturNavigasjon} from "./useTastaturNavigasjon";


const Velger = ({friKomponent} : {friKomponent: boolean} ) => {
const buttonRef = useRef<HTMLButtonElement>(null);
const valgtEnhetRef = useRef<HTMLButtonElement>(null);
const [åpen, setÅpen] = useState<boolean>(false);

const {
velgUnderenhet,
valgtOrganisasjon,
aktivtOrganisasjonstre,
søketekst,
setSøketekst,
} = useContext(VirksomhetsvelgerContext);
const [fokusertEnhet, setFokusertEnhet] = useState<Organisasjon>(valgtOrganisasjon)
const enheterflat = aktivtOrganisasjonstre.flatMap(({JuridiskEnhet, Underenheter }) => [JuridiskEnhet,...Underenheter]);
const antallTreff = enheterflat.length;
const gjørFørsteElementTabbable = søketekst.length > 0 && antallTreff > 0 && !enheterflat.some(({OrganizationNumber}) => OrganizationNumber === fokusertEnhet.OrganizationNumber);

const onKeyDown: KeyboardEventHandler<HTMLUListElement> = (e) => {
if (e.key === 'Home') {
setFokusertEnhet(enheterflat[0])
e.preventDefault()
}

if (e.key === 'End') {
setFokusertEnhet(enheterflat[enheterflat.length - 1])
e.preventDefault()
}

if (e.key === 'ArrowUp' || e.key === 'Up') {
const index = enheterflat.findIndex(({OrganizationNumber}) => OrganizationNumber === fokusertEnhet.OrganizationNumber)
const nextIndex = Math.max(0, index - 1)
setFokusertEnhet(enheterflat[nextIndex])
e.preventDefault()
}

if (e.key === 'ArrowDown' || e.key === 'Down') {
const index = enheterflat.findIndex(({OrganizationNumber}) => OrganizationNumber === fokusertEnhet.OrganizationNumber)
const nextIndex = Math.min(enheterflat.length - 1, index + 1)
setFokusertEnhet(enheterflat[nextIndex])
e.preventDefault()
}
};

const onUnderenhetClick = (virksomhet: Organisasjon) => {
setFokusertEnhet(virksomhet);
velgUnderenhet(virksomhet.OrganizationNumber)
setÅpen(false);
};
const {
fokusertEnhet,
organisasjonerMedState,
fokuserFørsteEnhet,
fokuserSisteEnhet,
pilOpp,
pilNed,
pilHøyre,
pilVenstre,
toggleEkspander,
fokuserEnhet,
resetState,
} = useTastaturNavigasjon();
const antallTreff = organisasjonerMedState.length;

useEffect(() => {
if (åpen) {
valgtEnhetRef.current?.focus();
} else {
setSøketekst('')
setFokusertEnhet(valgtOrganisasjon)
resetState()
}
}, [åpen, fokusertEnhet]);
useEffect(() => {
setFokusertEnhet(valgtOrganisasjon)
}, [valgtOrganisasjon]);
}, [åpen, fokusertEnhet.OrganizationNumber]);

return (
<div className={`${friKomponent ? "navbm-virksomhetsvelger-fri-komponent" : ""}`}>
Expand Down Expand Up @@ -130,11 +106,9 @@ const Velger = ({friKomponent} : {friKomponent: boolean} ) => {
label="Søk på virksomhet"
autoComplete="organization"
onKeyDown={(e) => {
if (søketekst.length > 0 && enheterflat.length > 0) {
if (e.key === 'ArrowDown' || e.key === 'Down') {
setFokusertEnhet(enheterflat[0])
e.preventDefault()
}
if (e.key === 'ArrowDown' || e.key === 'Down') {
fokuserFørsteEnhet()
e.preventDefault()
}
}}
/>
Expand All @@ -148,18 +122,62 @@ const Velger = ({friKomponent} : {friKomponent: boolean} ) => {
<Accordion style={{display: "flex", overflow: "auto"}}>
<ul
className="navbm-virksomhetsvelger__juridiske-enheter"
onKeyDown={onKeyDown}
onKeyDown={(e) => {
if (e.key === 'Home') {
fokuserFørsteEnhet();
e.preventDefault()
}

if (e.key === 'End') {
fokuserSisteEnhet();
e.preventDefault()
}

if (e.key === 'ArrowUp' || e.key === 'Up') {
pilOpp();
e.preventDefault()
}

if (e.key === 'ArrowDown' || e.key === 'Down') {
pilNed();
e.preventDefault()
}

if (e.key === 'ArrowRight' || e.key === 'Right') {
pilHøyre();
e.preventDefault()
}

if (e.key === 'ArrowLeft' || e.key === 'Left') {
pilVenstre();
e.preventDefault()
}
}}
>
{aktivtOrganisasjonstre.map((juridiskEnhet, i) => (
<JuridiskEnhet
forceTabbable={i === 0 && gjørFørsteElementTabbable}
enhetRef={valgtEnhetRef}
key={juridiskEnhet.JuridiskEnhet.OrganizationNumber}
juridiskEnhet={juridiskEnhet}
fokusertEnhet={fokusertEnhet}
onUnderenhetClick={onUnderenhetClick}
/>
))}
{aktivtOrganisasjonstre.map(({JuridiskEnhet: HovedEnhet, Underenheter}) => {
const flatSubtreMedState = organisasjonerMedState.filter(
({OrganizationNumber}) =>
OrganizationNumber === HovedEnhet.OrganizationNumber
|| Underenheter.some((underenhet) => OrganizationNumber === underenhet.OrganizationNumber)
);
return (
<JuridiskEnhet
enhetRef={valgtEnhetRef}
key={HovedEnhet.OrganizationNumber}
organisasjonerMedState={flatSubtreMedState}
onUnderenhetClick={(virksomhet: Organisasjon) => {
velgUnderenhet(virksomhet.OrganizationNumber);
setÅpen(false);
}}
onHovedenhetClick={(hovedenhet: Organisasjon) => {
toggleEkspander(hovedenhet)
}}
onFocus={(enhet: Organisasjon) => {
fokuserEnhet(enhet)
}}
/>
);
})}
</ul>
</Accordion>
</div>
Expand Down
Loading

0 comments on commit 17339f4

Please sign in to comment.