feat: add accessible text alternative in SVG (#62)

* feat: accessible text alternative in SVG

* fix: change alt text strategy to support IE 11
pull/63/head
Evelyn Hathaway 2020-07-06 07:52:07 -07:00 zatwierdzone przez GitHub
rodzic 49f8e3d9b4
commit 179a1d3c2a
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
2 zmienionych plików z 60 dodań i 30 usunięć

Wyświetl plik

@ -49,14 +49,16 @@ export function badgen ({
label = sanitize(label)
status = sanitize(status)
const accessibleText = createAccessibleText({label, status})
if (style === 'flat') {
return `<svg width="${scale * width / 10}" height="${scale * 20}" viewBox="0 0 ${width} 200" xmlns="http://www.w3.org/2000/svg"${xlink}>
return `<svg width="${scale * width / 10}" height="${scale * 20}" viewBox="0 0 ${width} 200" xmlns="http://www.w3.org/2000/svg"${xlink} role="img" aria-label="${sanitizeAttribute(accessibleText)}">
<title>${accessibleText}</title>
<g>
<rect fill="#${labelColor}" width="${sbRectWidth}" height="200"/>
<rect fill="#${color}" x="${sbRectWidth}" width="${stRectWidth}" height="200"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="${sbTextStart + 10}" y="148" textLength="${sbTextWidth}" fill="#000" opacity="0.1">${label}</text>
<text x="${sbTextStart}" y="138" textLength="${sbTextWidth}">${label}</text>
<text x="${sbRectWidth + 55}" y="148" textLength="${stTextWidth}" fill="#000" opacity="0.1">${status}</text>
@ -66,7 +68,8 @@ export function badgen ({
</svg>`
}
return `<svg width="${scale * width / 10}" height="${scale * 20}" viewBox="0 0 ${width} 200" xmlns="http://www.w3.org/2000/svg"${xlink}>
return `<svg width="${scale * width / 10}" height="${scale * 20}" viewBox="0 0 ${width} 200" xmlns="http://www.w3.org/2000/svg"${xlink} role="img" aria-label="${sanitizeAttribute(accessibleText)}">
<title>${accessibleText}</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -77,7 +80,7 @@ export function badgen ({
<rect width="${stRectWidth}" height="200" fill="#${color}" x="${sbRectWidth}"/>
<rect width="${width}" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="${sbTextStart + 10}" y="148" textLength="${sbTextWidth}" fill="#000" opacity="0.25">${label}</text>
<text x="${sbTextStart}" y="138" textLength="${sbTextWidth}">${label}</text>
<text x="${sbRectWidth + 55}" y="148" textLength="${stTextWidth}" fill="#000" opacity="0.25">${status}</text>
@ -97,18 +100,20 @@ function bare ({ status, color, style }) {
status = sanitize(status)
if (style === 'flat') {
return `<svg width="${stRectWidth / 10}" height="20" viewBox="0 0 ${stRectWidth} 200" xmlns="http://www.w3.org/2000/svg">
return `<svg width="${stRectWidth / 10}" height="20" viewBox="0 0 ${stRectWidth} 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-labeled="${sanitizeAttribute(status)}">
<title>${status}</title>
<g>
<rect fill="#${color}" x="0" width="${stRectWidth}" height="200"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="${stTextWidth}" fill="#000" opacity="0.1">${status}</text>
<text x="55" y="138" textLength="${stTextWidth}">${status}</text>
</g>
</svg>`
}
return `<svg width="${stRectWidth / 10}" height="20" viewBox="0 0 ${stRectWidth} 200" xmlns="http://www.w3.org/2000/svg">
return `<svg width="${stRectWidth / 10}" height="20" viewBox="0 0 ${stRectWidth} 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-labeled="${sanitizeAttribute(status)}">
<title>${status}</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -118,7 +123,7 @@ function bare ({ status, color, style }) {
<rect width="${stRectWidth}" height="200" fill="#${color}" x="0"/>
<rect width="${stRectWidth}" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="${stTextWidth}" fill="#000" opacity="0.25">${status}</text>
<text x="55" y="138" textLength="${stTextWidth}">${status}</text>
</g>
@ -129,6 +134,20 @@ function sanitize (str: string): string {
return str.replace(/\u0026/g, '&amp;').replace(/\u003C/g, '&lt;')
}
function sanitizeAttribute (str: string): string {
return str.replace(/\u0022/g, '\"')
}
interface AccessibleTextProps {
status: string;
label?: string;
}
function createAccessibleText({label, status}: AccessibleTextProps): string {
const labelPrefix = label ? `${label}: ` : '';
return labelPrefix + status;
}
function typeAssert (assertion: boolean, message: string): void {
if (!assertion) throw new TypeError(message)
}

Wyświetl plik

@ -6,7 +6,8 @@
*/
'use strict'
exports[`test/badgen.spec.ts TAP generate badge with { label, status } > snapshot 1`] = `
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg">
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="npm: v1.0.0">
<title>npm: v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -17,7 +18,7 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status } > snapsho
<rect width="455" height="200" fill="#08C" x="349"/>
<rect width="804" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="60" y="148" textLength="249" fill="#000" opacity="0.25">npm</text>
<text x="50" y="138" textLength="249">npm</text>
<text x="404" y="148" textLength="355" fill="#000" opacity="0.25">v1.0.0</text>
@ -28,7 +29,8 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status } > snapsho
`
exports[`test/badgen.spec.ts TAP generate badge with { label, status, color } > snapshot 1`] = `
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg">
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="npm: v1.0.0">
<title>npm: v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -39,7 +41,7 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, color } >
<rect width="455" height="200" fill="#ADF" x="349"/>
<rect width="804" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="60" y="148" textLength="249" fill="#000" opacity="0.25">npm</text>
<text x="50" y="138" textLength="249">npm</text>
<text x="404" y="148" textLength="355" fill="#000" opacity="0.25">v1.0.0</text>
@ -50,12 +52,13 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, color } >
`
exports[`test/badgen.spec.ts TAP generate badge with { label, status, color, style } > snapshot 1`] = `
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg">
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="npm: v1.0.0">
<title>npm: v1.0.0</title>
<g>
<rect fill="#555" width="349" height="200"/>
<rect fill="#ADF" x="349" width="455" height="200"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="60" y="148" textLength="249" fill="#000" opacity="0.1">npm</text>
<text x="50" y="138" textLength="249">npm</text>
<text x="404" y="148" textLength="355" fill="#000" opacity="0.1">v1.0.0</text>
@ -66,7 +69,8 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, color, sty
`
exports[`test/badgen.spec.ts TAP generate badge with { label, status, icon } > snapshot 1`] = `
<svg width="95.5" height="20" viewBox="0 0 955 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="95.5" height="20" viewBox="0 0 955 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="docker: icon">
<title>docker: icon</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -77,7 +81,7 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, icon } > s
<rect width="324" height="200" fill="#08C" x="631"/>
<rect width="955" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="220" y="148" textLength="371" fill="#000" opacity="0.25">docker</text>
<text x="210" y="138" textLength="371">docker</text>
<text x="686" y="148" textLength="224" fill="#000" opacity="0.25">icon</text>
@ -88,12 +92,13 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, icon } > s
`
exports[`test/badgen.spec.ts TAP generate badge with { label, status, icon, style } > snapshot 1`] = `
<svg width="95.5" height="20" viewBox="0 0 955 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="95.5" height="20" viewBox="0 0 955 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="docker: icon">
<title>docker: icon</title>
<g>
<rect fill="#555" width="631" height="200"/>
<rect fill="#08C" x="631" width="324" height="200"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="220" y="148" textLength="371" fill="#000" opacity="0.1">docker</text>
<text x="210" y="138" textLength="371">docker</text>
<text x="686" y="148" textLength="224" fill="#000" opacity="0.1">icon</text>
@ -104,12 +109,13 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, icon, styl
`
exports[`test/badgen.spec.ts TAP generate badge with { label, status, style } > snapshot 1`] = `
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg">
<svg width="80.4" height="20" viewBox="0 0 804 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="npm: v1.0.0">
<title>npm: v1.0.0</title>
<g>
<rect fill="#555" width="349" height="200"/>
<rect fill="#08C" x="349" width="455" height="200"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="60" y="148" textLength="249" fill="#000" opacity="0.1">npm</text>
<text x="50" y="138" textLength="249">npm</text>
<text x="404" y="148" textLength="355" fill="#000" opacity="0.1">v1.0.0</text>
@ -120,7 +126,8 @@ exports[`test/badgen.spec.ts TAP generate badge with { label, status, style } >
`
exports[`test/badgen.spec.ts TAP generate badge with { status, icon } > snapshot 1`] = `
<svg width="53.6" height="20" viewBox="0 0 536 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="53.6" height="20" viewBox="0 0 536 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="icon">
<title>icon</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -131,7 +138,7 @@ exports[`test/badgen.spec.ts TAP generate badge with { status, icon } > snapshot
<rect width="324" height="200" fill="#08C" x="212"/>
<rect width="536" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="172" y="148" textLength="0" fill="#000" opacity="0.25"></text>
<text x="162" y="138" textLength="0"></text>
<text x="267" y="148" textLength="224" fill="#000" opacity="0.25">icon</text>
@ -142,7 +149,8 @@ exports[`test/badgen.spec.ts TAP generate badge with { status, icon } > snapshot
`
exports[`test/badgen.spec.ts TAP generate badge with { status, icon, iconWidth } > snapshot 1`] = `
<svg width="59.6" height="20" viewBox="0 0 596 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="59.6" height="20" viewBox="0 0 596 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" role="img" aria-label="icon">
<title>icon</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -153,7 +161,7 @@ exports[`test/badgen.spec.ts TAP generate badge with { status, icon, iconWidth }
<rect width="324" height="200" fill="#08C" x="272"/>
<rect width="596" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="232" y="148" textLength="0" fill="#000" opacity="0.25"></text>
<text x="222" y="138" textLength="0"></text>
<text x="327" y="148" textLength="224" fill="#000" opacity="0.25">icon</text>
@ -164,7 +172,8 @@ exports[`test/badgen.spec.ts TAP generate badge with { status, icon, iconWidth }
`
exports[`test/badgen.spec.ts TAP generate bare badge with { status } > snapshot 1`] = `
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg">
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-labeled="v1.0.0">
<title>v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -174,7 +183,7 @@ exports[`test/badgen.spec.ts TAP generate bare badge with { status } > snapshot
<rect width="470" height="200" fill="#08C" x="0"/>
<rect width="470" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="355" fill="#000" opacity="0.25">v1.0.0</text>
<text x="55" y="138" textLength="355">v1.0.0</text>
</g>
@ -182,7 +191,8 @@ exports[`test/badgen.spec.ts TAP generate bare badge with { status } > snapshot
`
exports[`test/badgen.spec.ts TAP generate bare badge with { status, color } > snapshot 1`] = `
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg">
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-labeled="v1.0.0">
<title>v1.0.0</title>
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-opacity=".1" stop-color="#EEE"/>
<stop offset="1" stop-opacity=".1"/>
@ -192,7 +202,7 @@ exports[`test/badgen.spec.ts TAP generate bare badge with { status, color } > sn
<rect width="470" height="200" fill="#ADF" x="0"/>
<rect width="470" height="200" fill="url(#a)"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="355" fill="#000" opacity="0.25">v1.0.0</text>
<text x="55" y="138" textLength="355">v1.0.0</text>
</g>
@ -200,11 +210,12 @@ exports[`test/badgen.spec.ts TAP generate bare badge with { status, color } > sn
`
exports[`test/badgen.spec.ts TAP generate bare badge with { status, style } > snapshot 1`] = `
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg">
<svg width="47" height="20" viewBox="0 0 470 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-labeled="v1.0.0">
<title>v1.0.0</title>
<g>
<rect fill="#08C" x="0" width="470" height="200"/>
</g>
<g fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<g aria-hidden="true" fill="#fff" text-anchor="start" font-family="Verdana,DejaVu Sans,sans-serif" font-size="110">
<text x="65" y="148" textLength="355" fill="#000" opacity="0.1">v1.0.0</text>
<text x="55" y="138" textLength="355">v1.0.0</text>
</g>