Skip to content
Merged
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@data-fair/lib-common-types": "^1.21.0",
"@data-fair/lib-express": "^1.23.0",
"@data-fair/lib-node": "^2.12.1",
"@data-fair/lib-utils": "^1.12.1",
"@data-fair/lib-utils": "^1.12.2",
"@data-fair/portals-shared-markdown": "*",
"cheerio": "^1.0.0",
"config": "^4.4.1",
Expand Down
22 changes: 11 additions & 11 deletions package-lock.json

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

30 changes: 30 additions & 0 deletions patches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,36 @@ stays valid.

**Removal criterion**: when Vuetify stops emitting `aria-hidden="false"` on labels.

### `lib/components/VImg/VImg.js` — W3C HTML validity for decorative images

`VImg` mirrors its `alt` prop onto its root element, next to a `role` that is guarded on
the same value:

```js
'aria-label': props.alt,
role: props.alt ? 'img' : undefined
```

A decorative image is declared with `alt=""` — the empty string is falsy, so the root
gets no role, but the attribute is still emitted and the element renders as
`<div class="v-img" aria-label="">`. W3C rejects that: `aria-label` must not be used on
a `div` whose role is `generic`. RGAA 8.2. Four occurrences on the portal visualisation
catalogue (one per card thumbnail), twenty on a full catalogue page.

This patch emits the attribute only when `alt` is non-empty (`props.alt || undefined`),
the guard the neighbouring `role` binding already applies. Nothing changes for
informative images: they keep `role="img"` and their label. Decorative ones lose an
attribute that carried no name anyway — the inner `img` keeps its `alt=""`, which is
what makes it decorative, so restitution is unchanged.

There is no userland fix: the object holding `aria-label` is the last argument of the
root's `mergeProps`, so it overrides any `aria-label` passed by the caller, and dropping
the `alt` prop instead would leave the inner `img` without an `alt` attribute — one W3C
error traded for another.

**Removal criterion**: when Vuetify guards `aria-label` like it guards `role` — reported
as vuetifyjs/vuetify#23111, fix proposed upstream in vuetifyjs/vuetify#23112.

### `lib/components/VSelect/VSelect.js` — W3C HTML validity for the hidden native select

`VSelect` mirrors its items into a `<select hidden>` so the value is submitted with a
Expand Down
15 changes: 15 additions & 0 deletions patches/vuetify+4.1.9.patch
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ index 5b75eb8..bef9f28 100644
for: ariaHidden ? undefined : id.value
};
});
diff --git a/node_modules/vuetify/lib/components/VImg/VImg.js b/node_modules/vuetify/lib/components/VImg/VImg.js
index 7aab774..18ca7f3 100644
--- a/node_modules/vuetify/lib/components/VImg/VImg.js
+++ b/node_modules/vuetify/lib/components/VImg/VImg.js
@@ -295,7 +295,9 @@ export const VImg = genericComponent()({
}, backgroundColorStyles.value, roundedStyles.value, props.style]
}, responsiveProps, rootAttrs, {
"aspectRatio": aspectRatio.value,
- "aria-label": props.alt,
+ // an empty `alt` (decorative image) must not emit `aria-label`: the root would
+ // then carry it without a role, which W3C rejects (same guard as `role` below)
+ "aria-label": props.alt || undefined,
"role": props.alt ? 'img' : undefined
}), {
additional: () => _createElementVNode(_Fragment, null, [_createVNode(__image, imageAttrs, null), _createVNode(__preloadImage, null, null), _createVNode(__gradient, null, null), _createVNode(__placeholder, null, null), _createVNode(__error, null, null)]),
diff --git a/node_modules/vuetify/lib/components/VSelect/VSelect.js b/node_modules/vuetify/lib/components/VSelect/VSelect.js
index 42d2a00..08c6f77 100644
--- a/node_modules/vuetify/lib/components/VSelect/VSelect.js
Expand Down
1 change: 1 addition & 0 deletions portal/app/components/error/error-forbidden.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
width="1145.57"
height="819.91"
viewBox="0 0 1145.57 819.91"
aria-hidden="true"
>
<path
d="M1154.4,591.26c-26.57,54.81-80.52,91.46-136.43,115.63-75.27,32.55-158.16,45.46-239.91,40q-21.49-1.43-42.85-4.57a540.44,540.44,0,0,1-143.27-41.72q-19.74-8.89-38.68-19.41a494.85,494.85,0,0,1-60.46-39.54q-7.23-5.52-14.26-11.32c-3.25-2.68-6.47-5.42-9.74-8.08-6.9-5.61-14-10.94-21.92-14.93a78.31,78.31,0,0,0-7.34-3.24c-25.08-9.54-54-5.94-80.11,1.5-19.86,5.66-39.22,13.41-59.06,18.94a196,196,0,0,1-26.91,5.72A143.21,143.21,0,0,1,213,624.93l-1.67-.52q-4.2-1.32-8.33-2.89l-1.67-.64q-4-1.54-7.83-3.31l-1.67-.76q-4-1.86-7.83-3.93c-.92-.48-1.83-1-2.73-1.49a163.67,163.67,0,0,1-39.16-30.49c-.33-.33-.64-.67-1-1-1.59-1.72-3.15-3.47-4.66-5.26-.56-.66-1.12-1.32-1.67-2q-2.69-3.28-5.19-6.71c-.25-.33-.49-.67-.73-1A144.59,144.59,0,0,1,112,534.44c-.14-.33-.27-.67-.39-1q-2-5.15-3.65-10.47c-.45-1.48-.88-3-1.26-4.48-.13-.44-.25-.89-.36-1.33-5.52-21.73-6.15-44.32-6.15-66.78q0-3.93,0-7.85c.16-36.33.72-73.28,6.08-109.11,0-.25.07-.5.11-.74a340.76,340.76,0,0,1,7.31-35.82A264.25,264.25,0,0,1,126,260.56c12.33-29,30.26-55.39,50.17-79.85C226.32,119.16,292.09,67.49,369.07,48.15c82.95-20.83,175.14-.87,242.05,52.4,20.4,16.24,38.73,35.47,61.64,47.92,20,10.84,43.41,15.33,64.83,6.8,17.7-7.05,29.22-10.55,49.1-9.48A411.56,411.56,0,0,1,907.05,171c1.56.57,3.12,1.16,4.67,1.75C1012.43,211.28,1099,287.83,1144,386.2q1.79,3.9,3.47,7.86C1174.3,456.73,1184,530.18,1154.4,591.26Z"
Expand Down
1 change: 1 addition & 0 deletions portal/app/components/error/error-not-found.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
width="1074.392"
height="584.231"
viewBox="0 0 1074.392 584.231"
aria-hidden="true"
>
<ellipse
cx="540.64346"
Expand Down
1 change: 1 addition & 0 deletions portal/app/components/error/error-server.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
width="1032.24"
height="832.63"
viewBox="0 0 1032.24 832.63"
aria-hidden="true"
>
<ellipse
cx="530.99"
Expand Down
1 change: 1 addition & 0 deletions portal/app/components/icon/icon-bluesky.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
width="24"
height="24"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
fill="currentColor"
Expand Down
1 change: 1 addition & 0 deletions portal/app/components/icon/icon-x.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
width="24"
height="24"
viewBox="0 0 24 24"
aria-hidden="true"
>
<g fill="currentColor">
<path d="M1 2h2.5L18.5 22h-2.5z" />
Expand Down
8 changes: 7 additions & 1 deletion portal/app/components/layout/layout-full-app-bar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
:color="portalConfig.navBar.color"
flat
>
<!-- Logo -->
<!--
Logo: hidden between the sm and md breakpoints, where it shares this fixed-height bar
with the breadcrumbs. A wide logo leaves too little room there and pushes the end of the
trail out of the window, with no way to scroll to it (RGAA 10.11 and 10.12). Below sm the
breadcrumbs are hidden, so the logo gets the bar back.
-->
<layout-header-logo
v-if="logo"
:height="(appBarHeight || 64) - 10"
:logo="logo"
class="d-sm-none d-md-flex"
/>

<!-- Breadcrumbs -->
Expand Down
Loading
Loading