diff --git a/pages/code-view/with-line-numbers.page.tsx b/pages/code-view/with-line-numbers.page.tsx index e2f8d72..46d839d 100644 --- a/pages/code-view/with-line-numbers.page.tsx +++ b/pages/code-view/with-line-numbers.page.tsx @@ -3,17 +3,24 @@ import { Button, SpaceBetween } from "@cloudscape-design/components"; -import { CodeView } from "../../lib/components"; +import { CodeView, CodeViewProps } from "../../lib/components"; import { ScreenshotArea } from "../screenshot-area"; + +const i18nStrings: CodeViewProps.I18nStrings = { + lineNumberLabel: `Line number`, + codeLabel: `Code`, +}; + export default function CodeViewPage() { return (

Code View

- - + + } /> @@ -21,7 +28,8 @@ export default function CodeViewPage() {
`This is line number #${i + 1}.`).join("\n")} + i18nStrings={i18nStrings} + content={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map((i) => `This is line number #${i}.`).join("\n")} />
diff --git a/src/__tests__/__snapshots__/documenter.test.ts.snap b/src/__tests__/__snapshots__/documenter.test.ts.snap index 06fea56..6c20128 100644 --- a/src/__tests__/__snapshots__/documenter.test.ts.snap +++ b/src/__tests__/__snapshots__/documenter.test.ts.snap @@ -42,6 +42,31 @@ exports[`definition for 'code-view' matches the snapshot 1`] = ` "optional": true, "type": "((code: string) => React.ReactNode)", }, + { + "description": "An object containing all the necessary localized strings required by the component. The object should contain: + +* \`lineNumberLabel\` - Label for the column that displays line numbers (when line numbers are visible) +* \`codeLabel\` - Label for the column that displays the code content (when line numbers are visible)", + "inlineType": { + "name": "CodeViewProps.I18nStrings", + "properties": [ + { + "name": "codeLabel", + "optional": true, + "type": "string", + }, + { + "name": "lineNumberLabel", + "optional": true, + "type": "string", + }, + ], + "type": "object", + }, + "name": "i18nStrings", + "optional": true, + "type": "CodeViewProps.I18nStrings", + }, { "description": "Controls the display of line numbers. diff --git a/src/code-view/__tests__/code-view.test.tsx b/src/code-view/__tests__/code-view.test.tsx index 0f2bd8e..437aed6 100644 --- a/src/code-view/__tests__/code-view.test.tsx +++ b/src/code-view/__tests__/code-view.test.tsx @@ -26,6 +26,25 @@ describe("CodeView", () => { expect(content.getElement()).toHaveTextContent("# Hello World This is a markdown example."); }); + test("correctly renders table markup with line numbers", () => { + render( + , + ); + const wrapper = createWrapper()!.findCodeView()!; + const table = wrapper.find("table")!.getElement(); + expect(table).not.toHaveAttribute("role"); + const lineNumberColumn = wrapper.find("th:nth-child(1)")!.getElement(); + expect(lineNumberColumn).toHaveTextContent("Line number"); + const contentColumn = wrapper.find("th:nth-child(2)")!.getElement(); + expect(contentColumn).toHaveTextContent("Code"); + const lineNumberCell = wrapper.find("td:nth-child(1)")!.getElement(); + expect(lineNumberCell).not.toHaveAttribute("aria-hidden", "true"); + }); + test("correctly renders copy button slot", () => { render(Copy}>); const wrapper = createWrapper()!.findCodeView(); diff --git a/src/code-view/interfaces.ts b/src/code-view/interfaces.ts index e27e995..213852b 100644 --- a/src/code-view/interfaces.ts +++ b/src/code-view/interfaces.ts @@ -39,7 +39,21 @@ export interface CodeViewProps { /** * A function to perform custom syntax highlighting. - * */ highlight?: (code: string) => React.ReactNode; + + /** + * An object containing all the necessary localized strings required by the component. The object should contain: + * + * * `lineNumberLabel` - Label for the column that displays line numbers (when line numbers are visible) + * * `codeLabel` - Label for the column that displays the code content (when line numbers are visible) + */ + i18nStrings?: CodeViewProps.I18nStrings; +} + +export namespace CodeViewProps { + export interface I18nStrings { + lineNumberLabel?: string; + codeLabel?: string; + } } diff --git a/src/code-view/internal.tsx b/src/code-view/internal.tsx index b434c51..978f69f 100644 --- a/src/code-view/internal.tsx +++ b/src/code-view/internal.tsx @@ -39,6 +39,7 @@ export function InternalCodeView({ highlight, ariaLabel, ariaLabelledby, + i18nStrings, __internalRootRef = null, ...props }: InternalCodeViewProps) { @@ -47,6 +48,7 @@ export function InternalCodeView({ const darkMode = useCurrentMode(containerRef) === "dark"; const regionProps = ariaLabel || ariaLabelledby ? { role: "region" } : {}; + const accessibleLineNumbers = lineNumbers && i18nStrings?.lineNumberLabel && i18nStrings?.codeLabel; // Create tokenized React nodes of the content. const code = highlight ? highlight(content) : textHighlight(content); @@ -66,7 +68,7 @@ export function InternalCodeView({ >
+ {accessibleLineNumbers && ( + + + {lineNumbers && } + + + + )} {Children.map(codeElement.props.children, (child, index) => { return ( {lineNumbers && ( -
{i18nStrings.lineNumberLabel}{i18nStrings.codeLabel}
+ {index + 1} diff --git a/src/code-view/styles.scss b/src/code-view/styles.scss index d3604b8..0c7f604 100644 --- a/src/code-view/styles.scss +++ b/src/code-view/styles.scss @@ -14,7 +14,7 @@ $color-background-code-view-dark: #282c34; border-start-end-radius: cs.$border-radius-tiles; border-end-start-radius: cs.$border-radius-tiles; border-end-end-radius: cs.$border-radius-tiles; - + background-color: $color-background-code-view-light; :global(.awsui-dark-mode) &, :global(.awsui-polaris-dark-mode) & { @@ -43,6 +43,12 @@ $color-background-code-view-dark: #282c34; padding-inline-end: cs.$space-static-xxl; } +.screenreader-only { + position: absolute; + inset-block-start: -9999px; + inset-inline-start: -9999px; +} + .line-number { vertical-align: text-top; white-space: nowrap;