mirror of https://github.com/coder/coder.git
67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
import type { FC, HTMLAttributes } from "react";
|
|
|
|
export type Pronunciation = "shorthand" | "acronym" | "initialism";
|
|
|
|
type AbbrProps = HTMLAttributes<HTMLElement> & {
|
|
children: string;
|
|
title: string;
|
|
pronunciation?: Pronunciation;
|
|
};
|
|
|
|
/**
|
|
* A more sophisticated version of the native <abbr> element.
|
|
*
|
|
* Features:
|
|
* - Better type-safety (requiring you to include certain properties)
|
|
* - All built-in HTML styling is stripped away by default
|
|
* - Better integration with screen readers (like exposing the title prop to
|
|
* them), with more options for influencing how they pronounce text
|
|
*/
|
|
export const Abbr: FC<AbbrProps> = ({
|
|
children,
|
|
title,
|
|
pronunciation = "shorthand",
|
|
...delegatedProps
|
|
}) => {
|
|
return (
|
|
<abbr
|
|
// Title attributes usually aren't natively available to screen readers;
|
|
// always have to supplement with aria-label
|
|
title={title}
|
|
aria-label={getAccessibleLabel(children, title, pronunciation)}
|
|
css={{
|
|
textDecoration: "inherit",
|
|
letterSpacing: children === children.toUpperCase() ? "0.02em" : "0",
|
|
}}
|
|
{...delegatedProps}
|
|
>
|
|
<span aria-hidden>{children}</span>
|
|
</abbr>
|
|
);
|
|
};
|
|
|
|
function getAccessibleLabel(
|
|
abbreviation: string,
|
|
title: string,
|
|
pronunciation: Pronunciation,
|
|
): string {
|
|
if (pronunciation === "initialism") {
|
|
return `${initializeText(abbreviation)} (${title})`;
|
|
}
|
|
|
|
if (pronunciation === "acronym") {
|
|
return `${flattenPronunciation(abbreviation)} (${title})`;
|
|
}
|
|
|
|
return title;
|
|
}
|
|
|
|
function initializeText(text: string): string {
|
|
return text.trim().toUpperCase().replaceAll(/\B/g, ".") + ".";
|
|
}
|
|
|
|
function flattenPronunciation(text: string): string {
|
|
const trimmed = text.trim();
|
|
return (trimmed[0] ?? "").toUpperCase() + trimmed.slice(1).toLowerCase();
|
|
}
|