test: expand exporter/css/a11y/i18n regressions and add e2e skip-link focus check
CI / test (pull_request) Successful in 52s
CI / test (pull_request) Successful in 52s
This commit is contained in:
+55
-11
@@ -40,6 +40,20 @@ function renderFeatures(section: { props: { items: string[] } }) {
|
||||
`
|
||||
}
|
||||
|
||||
function renderBenefits(section: { props: { items: string[] } }) {
|
||||
const items: string[] = Array.isArray(section.props?.items) ? section.props.items : []
|
||||
return `
|
||||
<section class="benefits" aria-labelledby="benefits-heading">
|
||||
<div class="container">
|
||||
<h2 id="benefits-heading">Benefits</h2>
|
||||
<ul class="benefits-list">
|
||||
${items.map((it) => `<li class="benefit-item">${escapeHtml(String(it))}</li>`).join('')}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
`
|
||||
}
|
||||
|
||||
function renderTestimonials(section: { props: { items: Array<{ author: string; quote: string }> } }) {
|
||||
const items: Array<{ author: string; quote: string }> = Array.isArray(section.props?.items)
|
||||
? section.props.items
|
||||
@@ -102,45 +116,74 @@ function renderHero(section: { props: { heading: string; subheading?: string; im
|
||||
}
|
||||
|
||||
function renderField(field: FormField) {
|
||||
const id = `field-${escapeHtml(field.name)}`
|
||||
const helpId = `field-${escapeHtml(field.name)}-help`
|
||||
const hasHelp = !!field.help
|
||||
const helpHtml = hasHelp ? `<div id="${helpId}" class="form-help">${escapeHtml(field.help!)}</div>` : ''
|
||||
|
||||
const pat = 'pattern' in field && field.pattern ? ` pattern="${escapeHtml(field.pattern)}"` : ''
|
||||
const max = 'maxLength' in field && field.maxLength ? ` maxlength="${field.maxLength}"` : ''
|
||||
const common = `name="${escapeHtml(field.name)}" aria-label="${escapeHtml(field.label)}" ${field.required ? 'required' : ''}${pat}${max}`
|
||||
const describedBy = hasHelp ? ` aria-describedby="${helpId}"` : ''
|
||||
const common = `id="${id}" name="${escapeHtml(field.name)}" aria-label="${escapeHtml(field.label)}" ${field.required ? 'required' : ''}${pat}${max}${describedBy}`
|
||||
|
||||
switch (field.type) {
|
||||
case 'text':
|
||||
case 'email':
|
||||
case 'tel':
|
||||
case 'date':
|
||||
return `<label>${escapeHtml(field.label)}<input type="${field.type}" ${common} /></label>`
|
||||
return `
|
||||
<div class="form-control">
|
||||
<label for="${id}">${escapeHtml(field.label)}</label>
|
||||
<input type="${field.type}" ${common} />
|
||||
${helpHtml}
|
||||
</div>
|
||||
`
|
||||
case 'textarea':
|
||||
return `<label>${escapeHtml(field.label)}<textarea ${common}></textarea></label>`
|
||||
return `
|
||||
<div class="form-control">
|
||||
<label for="${id}">${escapeHtml(field.label)}</label>
|
||||
<textarea ${common}></textarea>
|
||||
${helpHtml}
|
||||
</div>
|
||||
`
|
||||
case 'checkbox':
|
||||
return `<label><input type="checkbox" ${common} />${escapeHtml(field.label)}</label>`
|
||||
return `
|
||||
<div class="form-control">
|
||||
<label for="${id}">${escapeHtml(field.label)}</label>
|
||||
<input type="checkbox" ${common} />
|
||||
${helpHtml}
|
||||
</div>
|
||||
`
|
||||
case 'radio': {
|
||||
const { options } = field as Extract<FormField, { type: 'radio' }>
|
||||
const fsDescribed = hasHelp ? ` aria-describedby="${helpId}"` : ''
|
||||
return `
|
||||
<fieldset>
|
||||
<fieldset${fsDescribed}>
|
||||
<legend>${escapeHtml(field.label)}</legend>
|
||||
${options
|
||||
.map(
|
||||
(opt: string) =>
|
||||
`<label><input type="radio" ${common} value="${escapeHtml(
|
||||
opt
|
||||
)}" />${escapeHtml(opt)}</label>`
|
||||
(opt: string, i: number) => {
|
||||
const optId = `${id}-opt-${i}`
|
||||
return `<div><input id="${optId}" type="radio" name="${escapeHtml(field.name)}" aria-label="${escapeHtml(field.label)}" value="${escapeHtml(opt)}" ${field.required ? 'required' : ''}${pat}${max} /><label for="${optId}">${escapeHtml(opt)}</label></div>`
|
||||
}
|
||||
)
|
||||
.join('')}
|
||||
${helpHtml}
|
||||
</fieldset>
|
||||
`
|
||||
}
|
||||
case 'select': {
|
||||
const { options } = field as Extract<FormField, { type: 'select' }>
|
||||
return `
|
||||
<label>${escapeHtml(field.label)}
|
||||
<div class="form-control">
|
||||
<label for="${id}">${escapeHtml(field.label)}</label>
|
||||
<select ${common}>
|
||||
${options
|
||||
.map((opt: string) => `<option value="${escapeHtml(opt)}">${escapeHtml(opt)}</option>`)
|
||||
.join('')}
|
||||
</select>
|
||||
</label>
|
||||
${helpHtml}
|
||||
</div>
|
||||
`
|
||||
}
|
||||
default:
|
||||
@@ -250,6 +293,7 @@ export function exportPage(page: Page, opts?: ExportOptions): Exported {
|
||||
if (s.type === 'faq') return renderFaq(s)
|
||||
if (s.type === 'cta') return renderCta(s)
|
||||
if (s.type === 'features') return renderFeatures(s)
|
||||
if (s.type === 'benefits') return renderBenefits(s)
|
||||
if (s.type === 'testimonials') return renderTestimonials(s)
|
||||
return ''
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user