Skip to content

Commit

Permalink
feat: Questions block keyboard access improved (#505)
Browse files Browse the repository at this point in the history
* feat: improved Questions block accessibility
  • Loading branch information
Kyzyl-ool authored Aug 23, 2023
1 parent 684a855 commit 3a7c146
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 119 deletions.
8 changes: 4 additions & 4 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
Expand Up @@ -103,7 +103,7 @@
},
"peerDependencies": {
"@doc-tools/transform": "^3.3.2",
"@gravity-ui/uikit": "^5.1.0",
"@gravity-ui/uikit": "^5.4.1",
"react": "^16.0.0 || ^17.0.0 || ^18.0.0"
},
"devDependencies": {
Expand All @@ -119,7 +119,7 @@
"@gravity-ui/prettier-config": "^1.0.1",
"@gravity-ui/stylelint-config": "^1.0.0",
"@gravity-ui/tsconfig": "^1.0.0",
"@gravity-ui/uikit": "^5.1.0",
"@gravity-ui/uikit": "^5.4.1",
"@storybook/addon-actions": "^7.1.0",
"@storybook/addon-essentials": "^7.1.0",
"@storybook/addon-knobs": "^7.0.2",
Expand Down
42 changes: 42 additions & 0 deletions src/blocks/Questions/QuestionBlockItem/QuestionBlockItem.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@import '../../../../styles/variables';
@import '../../../../styles/mixins';

$block: '.#{$ns}QuestionsBlockItem';

#{$block} {
padding-bottom: $indentM;
border-bottom: 1px solid var(--g-color-line-generic);

& + & {
padding-top: $indentM;
}

&__title {
@include heading4();

position: relative;
padding-right: 24px;
cursor: pointer;

a {
@include link();
}
}

&__arrow {
position: absolute;
right: 0;
top: 0;
color: var(--g-color-text-primary);
}

&__link {
@include text-size(body-2);
}

&__text {
@include text-size(body-2);

margin-top: $indentXXS;
}
}
72 changes: 72 additions & 0 deletions src/blocks/Questions/QuestionBlockItem/QuestionBlockItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react';

import {useActionHandlers} from '@gravity-ui/uikit';

import {Foldable, HTML, ToggleArrow, YFMWrapper} from '../../../components';
import Link from '../../../components/Link/Link';
import {QuestionBlockItemProps} from '../../../models';
import {block} from '../../../utils';
import {FaqMicrodataValues} from '../models';

import './QuestionBlockItem.scss';

const b = block('QuestionsBlockItem');

export const QuestionBlockItem = ({
title: itemTitle,
text: itemText,
link,
listStyle = 'dash',
isOpened,
onClick,
}: QuestionBlockItemProps) => {
const {onKeyDown} = useActionHandlers(onClick);

return (
<div
className={b()}
itemScope
itemProp={FaqMicrodataValues.QuestionProp}
itemType={FaqMicrodataValues.QuestionType}
role={'listitem'}
>
<h3
className={b('title')}
onClick={onClick}
aria-expanded={isOpened}
role={'button'}
tabIndex={0}
onKeyDown={onKeyDown}
>
<HTML itemProp={FaqMicrodataValues.QuestionNameProp}>{itemTitle}</HTML>
<ToggleArrow
open={isOpened}
size={16}
type={'vertical'}
iconType="navigation"
className={b('arrow')}
/>
</h3>
<Foldable isOpened={isOpened}>
<div
className={b('text')}
itemScope
itemProp={FaqMicrodataValues.AnswerProp}
itemType={FaqMicrodataValues.AnswerType}
aria-hidden={!isOpened}
>
<YFMWrapper
content={itemText}
modifiers={{
constructor: true,
constructorListStyle: true,
constructorListStyleDash: listStyle === 'dash',
}}
itemProp={FaqMicrodataValues.QuestionTextProp}
/>
{link && <Link {...link} tabIndex={isOpened ? 0 : -1} className={b('link')} />}
</div>
</Foldable>
</div>
);
};
39 changes: 0 additions & 39 deletions src/blocks/Questions/Questions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,6 @@ $block: '.#{$ns}QuestionsBlock';
margin-right: $indentXL;
}

&__item {
padding-bottom: $indentM;
border-bottom: 1px solid var(--g-color-line-generic);

& + & {
padding-top: $indentM;
}
}

&__item-title {
@include heading4();

position: relative;
padding-right: 24px;

cursor: pointer;

a {
@include link();
}
}

&__text {
@include text-size(body-2);

margin-top: $indentXXS;
}

&__arrow {
position: absolute;
right: 0;
top: 0;
color: var(--g-color-text-primary);
}

&__link {
@include text-size(body-2);
}

@media (max-width: map-get($gridBreakpoints, 'md')) {
&__title {
margin-right: 0;
Expand Down
70 changes: 14 additions & 56 deletions src/blocks/Questions/Questions.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
import React, {useState} from 'react';

import {Foldable, HTML, ToggleArrow, YFMWrapper} from '../../components';
import Link from '../../components/Link/Link';
import {Col, Row} from '../../grid';
import {QuestionsProps} from '../../models';
import {Content} from '../../sub-blocks';
import {block} from '../../utils';

import {QuestionBlockItem} from './QuestionBlockItem/QuestionBlockItem';
import {FaqMicrodataValues} from './models';

import './Questions.scss';

const b = block('QuestionsBlock');

const FaqMicrodataValues = {
PageType: 'https://schema.org/FAQPage',
QuestionType: 'https://schema.org/Question',
QuestionProp: 'mainEntity',
QuestionNameProp: 'name',
QuestionTextProp: 'text',
AnswerType: 'https://schema.org/Answer',
AnswerProp: 'acceptedAnswer',
AnswerTextProp: 'text',
} as const;

const QuestionsBlock = (props: QuestionsProps) => {
const {title, text, additionalInfo, links, buttons, items} = props;
const [opened, setOpened] = useState<number[]>([0]);
Expand All @@ -30,7 +20,7 @@ const QuestionsBlock = (props: QuestionsProps) => {
let newState;

if (opened.includes(index)) {
newState = opened.filter((intemIndex: number) => intemIndex !== index);
newState = opened.filter((itemIndex: number) => itemIndex !== index);
} else {
newState = [...opened, index];
}
Expand All @@ -53,54 +43,22 @@ const QuestionsBlock = (props: QuestionsProps) => {
/>
</div>
</Col>
<Col sizes={{all: 12, md: 8}}>
<Col sizes={{all: 12, md: 8}} role={'list'}>
{items.map(
({title: itemTitle, text: itemText, link, listStyle = 'dash'}, index) => {
const isOpened = opened.includes(index);
const onClick = () => toggleItem(index);

return (
<div
<QuestionBlockItem
key={itemTitle}
className={b('item')}
itemScope
itemProp={FaqMicrodataValues.QuestionProp}
itemType={FaqMicrodataValues.QuestionType}
>
<h3
className={b('item-title')}
onClick={() => toggleItem(index)}
>
<HTML itemProp={FaqMicrodataValues.QuestionNameProp}>
{itemTitle}
</HTML>
<ToggleArrow
open={isOpened}
size={16}
type={'vertical'}
iconType="navigation"
className={b('arrow')}
/>
</h3>
<Foldable isOpened={isOpened}>
<div
className={b('text')}
itemScope
itemProp={FaqMicrodataValues.AnswerProp}
itemType={FaqMicrodataValues.AnswerType}
>
<YFMWrapper
content={itemText}
modifiers={{
constructor: true,
constructorListStyle: true,
constructorListStyleDash: listStyle === 'dash',
}}
itemProp={FaqMicrodataValues.QuestionTextProp}
/>
{link && <Link {...link} className={b('link')} />}
</div>
</Foldable>
</div>
title={itemTitle}
text={itemText}
link={link}
listStyle={listStyle}
isOpened={isOpened}
onClick={onClick}
/>
);
},
)}
Expand Down
10 changes: 10 additions & 0 deletions src/blocks/Questions/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const FaqMicrodataValues = {
PageType: 'https://schema.org/FAQPage',
QuestionType: 'https://schema.org/Question',
QuestionProp: 'mainEntity',
QuestionNameProp: 'name',
QuestionTextProp: 'text',
AnswerType: 'https://schema.org/Answer',
AnswerProp: 'acceptedAnswer',
AnswerTextProp: 'text',
} as const;
6 changes: 4 additions & 2 deletions src/components/BackLink/BackLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {Button, ButtonSize, Icon} from '@gravity-ui/uikit';
import {LocationContext} from '../../context/locationContext';
import {useAnalytics} from '../../hooks';
import {ArrowSidebar} from '../../icons';
import {DefaultEventNames} from '../../models';
import {DefaultEventNames, Tabbable} from '../../models';

export type Theme = 'default' | 'special';

export interface BackLinkProps {
export interface BackLinkProps extends Tabbable {
url: string;
title: ReactNode;
theme?: Theme;
Expand All @@ -29,6 +29,7 @@ export default function BackLink(props: BackLinkProps) {
className,
shouldHandleBackAction = false,
onClick,
tabIndex,
} = props;
const handleAnalytics = useAnalytics(DefaultEventNames.ShareButton, url);

Expand Down Expand Up @@ -57,6 +58,7 @@ export default function BackLink(props: BackLinkProps) {
size={size}
href={shouldHandleBackAction ? undefined : url}
onClick={shouldHandleBackAction ? backActionHandler : undefined}
tabIndex={tabIndex}
>
<Icon data={ArrowSidebar} size={24} />
<span>{title}</span>
Expand Down
8 changes: 7 additions & 1 deletion src/components/FileLink/FileLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const FileLink = (props: WithChildren<FileLinkProps>) => {
className,
theme = 'default',
onClick,
tabIndex,
} = props;
const fileExt = getFileExt(href) as FileExtension;
const labelTheme = (FileExtensionThemes[fileExt] || 'unknown') as LabelProps['theme'];
Expand All @@ -66,7 +67,12 @@ const FileLink = (props: WithChildren<FileLinkProps>) => {
{fileExt}
</Label>
<div className={b('link')}>
<a href={href} {...getLinkProps(href, hostname)} onClick={onClick}>
<a
href={href}
onClick={onClick}
tabIndex={tabIndex}
{...getLinkProps(href, hostname)}
>
{text}
</a>
</div>
Expand Down
Loading

0 comments on commit 3a7c146

Please sign in to comment.