Skip to content

Commit

Permalink
feat: adding labelledby and describedby attributes for post card (#142)
Browse files Browse the repository at this point in the history
* feat: adding labelledby and describedby attributes
  • Loading branch information
Kyzyl-ool authored Oct 30, 2023
1 parent cc971a9 commit 7079de4
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 14 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
},
"peerDependencies": {
"@doc-tools/transform": "^3.3.2",
"@gravity-ui/page-constructor": "^4.26.0",
"@gravity-ui/page-constructor": "^4.31.0",
"@gravity-ui/uikit": "^5.12.0",
"react": "^16.0.0 || ^17.0.0 || ^18.0.0"
},
Expand Down
35 changes: 30 additions & 5 deletions src/components/PostCard/PostCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, {useContext, useMemo} from 'react';

import {CardBase, HTML, MetrikaGoal, YFMWrapper} from '@gravity-ui/page-constructor';
import {useUniqId} from '@gravity-ui/uikit';

import {LikesContext} from '../../contexts/LikesContext';
import {PostCardSize, PostCardTitleHeadingLevel, PostData} from '../../models/common';
import {block} from '../../utils/cn';
import {SuggestPostInfo} from '../PostInfo/SuggestPostInfo';
import {useAriaAttributes} from '../../hooks/useAriaAttributes';

import './PostCard.scss';

Expand Down Expand Up @@ -62,22 +63,43 @@ export const PostCard = ({
: undefined,
[hasUserLike, likes, toggleLike, hasLikes],
);
const titleId = useUniqId();
const descriptionId = useUniqId();
const dateId = useUniqId();
const tagId = useUniqId();
const readingTimeId = useUniqId();
const isTagVisible = showTag && tags?.[0]?.name;
const ariaAttributes = useAriaAttributes({
labelIds: [isTagVisible && tagId, title && titleId],
descriptionIds: [
description && descriptionId,
date && dateId,
readingTime && readingTimeId,
],
});

return (
<CardBase url={url} metrikaGoals={metrikaGoals} className={b('card', {fullWidth})}>
<CardBase
url={url}
metrikaGoals={metrikaGoals}
className={b('card', {fullWidth})}
extraProps={ariaAttributes}
>
<CardBase.Header image={image} className={b('header', {fullWidth})}>
<div className={b('image-container')} data-qa="blog-suggest-header" />
</CardBase.Header>
<CardBase.Content>
{showTag && tags?.[0]?.name && (
<div className={b('tag', {size})}>{tags[0].name}</div>
{isTagVisible && (
<div id={tagId} className={b('tag', {size})}>
{tags[0].name}
</div>
)}
{title &&
React.createElement(
titleHeadingLevel,
{className: b('title', {size})},
<span>
<HTML>{title}</HTML>
<HTML id={titleId}>{title}</HTML>
</span>,
)}
{description && (
Expand All @@ -88,6 +110,7 @@ export const PostCard = ({
blog: size === 'm',
blogCard: true,
}}
id={descriptionId}
/>
)}
</CardBase.Content>
Expand All @@ -100,6 +123,8 @@ export const PostCard = ({
likes={likesProps}
size={size}
qa="blog-suggest-block"
dateId={dateId}
readingTimeId={readingTimeId}
/>
</CardBase.Footer>
</CardBase>
Expand Down
13 changes: 10 additions & 3 deletions src/components/PostInfo/SuggestPostInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {block} from '../../utils/cn';
import {Date} from './components/Date';
import {ReadingTime} from './components/ReadingTime';
import {Save} from './components/Save';

import './PostInfo.scss';

const b = block('post-info');
Expand All @@ -22,6 +21,8 @@ export interface SuggestPostInfoProps
hasUserLike?: boolean;
toggleLike?: ToggleLikeCallbackType;
};
dateId?: string;
readingTimeId?: string;
}

/**
Expand All @@ -35,6 +36,8 @@ export interface SuggestPostInfoProps
* @param qa - test-attr
* @param size - text size
* @param isModernIcon - flag what we need render 'bookmark' icon
* @param dateId - id value for element with post date. Useful when providing accessible description
* @param readingTimeId - id value for element with reading time. Useful when providing accessible description
*
* @returns jsx
*/
Expand All @@ -45,6 +48,8 @@ export const SuggestPostInfo = ({
likes,
size = PostCardSize.SMALL,
qa,
dateId,
readingTimeId,
}: SuggestPostInfoProps) => {
const {hasUserLike, likesCount, handleLike} = useLikes({
hasLike: likes?.hasUserLike,
Expand All @@ -56,8 +61,10 @@ export const SuggestPostInfo = ({
return (
<div className={b('container')}>
<div className={b('suggest-container')}>
{date && <Date date={date} size={size} />}
{readingTime && <ReadingTime readingTime={readingTime} size={size} />}
{date && <Date date={date} size={size} id={dateId} />}
{readingTime && (
<ReadingTime readingTime={readingTime} size={size} id={readingTimeId} />
)}
</div>
{likes && postId && (
<Save
Expand Down
9 changes: 7 additions & 2 deletions src/components/PostInfo/components/Date.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ const b = block('post-info');
type DateProps = {
date: string | number;
size?: PostCardSize;
id?: string;
};

export const Date = ({date, size = PostCardSize.SMALL}: DateProps) => {
export const Date = ({date, size = PostCardSize.SMALL, id}: DateProps) => {
const {locale} = useContext(LocaleContext);

return <div className={b('item', {size})}>{format(date, 'longDate', locale?.code)}</div>;
return (
<div className={b('item', {size})} id={id}>
{format(date, 'longDate', locale?.code)}
</div>
);
};
5 changes: 3 additions & 2 deletions src/components/PostInfo/components/ReadingTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ const ICON_SIZE = 16;
type ReadingTimeProps = {
readingTime: number;
size?: 's' | 'm';
id?: string;
};

export const ReadingTime = ({readingTime, size = 's'}: ReadingTimeProps) => (
<div className={b('item', {size})}>
export const ReadingTime = ({readingTime, size = 's', id}: ReadingTimeProps) => (
<div className={b('item', {size})} id={id}>
<span className={b('icon')}>
<Icon data={Time} size={ICON_SIZE} className={b('icon-color')} />
</span>
Expand Down
24 changes: 24 additions & 0 deletions src/hooks/useAriaAttributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {useMemo} from 'react';

type Labels = string | number | boolean | undefined;
type Description = string | number | boolean | undefined;
interface UseAriaAttributesProps {
labelIds?: Labels[];
descriptionIds: Description[];
}

/**
* Returns aria-attributes
* @param labelIds - labels ids. Falsy values will be ignored
* @param descriptionIds - descriptions ids. Falsy values will be ignored
* @returns aria attributes for the element to be labelled
*/
export const useAriaAttributes = ({labelIds = [], descriptionIds = []}: UseAriaAttributesProps) => {
const labelledBy = useMemo(() => labelIds.filter(Boolean).join(' '), [labelIds]);
const describedBy = useMemo(() => descriptionIds.filter(Boolean).join(' '), [descriptionIds]);

return {
'aria-labelledby': labelledBy,
'aria-describedby': describedBy,
};
};

0 comments on commit 7079de4

Please sign in to comment.