Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/a11y-admin-nav.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"apostrophe": patch
---

Accessibility: corrected ARIA semantics on the top admin navigation bar.
5 changes: 5 additions & 0 deletions .changeset/a11y-context-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"apostrophe": patch
---

Accessibility: improvements to the document context title (admin bar middle group) and the underlying `AposContextMenu` machinery.
5 changes: 5 additions & 0 deletions .changeset/a11y-locale-switcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"apostrophe": patch
---

Accessibility: improve the locale switcher (`AposLocalePicker`).
5 changes: 5 additions & 0 deletions .changeset/a11y-recently-edited-icon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"apostrophe": patch
---

Accessibility: the Recently Edited Documents tray icon (admin bar) now exposes its action through `aria-label`.
5 changes: 5 additions & 0 deletions .changeset/a11y-sr-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"apostrophe": patch
---

Accessibility: fix `.apos-sr-only` so screen-reader-only content is exposed to the accessibility tree.
5 changes: 5 additions & 0 deletions .changeset/a11y-tray-aria.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"apostrophe": patch
---

Accessibility: icon-only context-utility buttons in the admin bar tray (e.g. the global settings cog) now expose their action through `aria-label`.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
<nav
ref="adminBar"
:class="classes"
role="menubar"
aria-label="Apostrophe Admin Bar"
>
<div class="apos-admin-bar__row">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<template>
<ol
class="apos-admin-bar__items"
role="menu"
>
<ol class="apos-admin-bar__items">
<li
v-if="pageTree"
class="apos-admin-bar__item"
Expand All @@ -12,7 +9,6 @@
label="apostrophe:pages"
class="apos-admin-bar__btn"
:modifiers="['no-motion']"
role="menuitem"
action-test-label="page-manager-button"
@click="emitEvent({ action: '@apostrophecms/page:manager' })"
/>
Expand All @@ -33,7 +29,6 @@
class: 'apos-admin-bar__btn',
type: 'subtle'
}"
role="menuitem"
@item-clicked="emitEvent"
/>
<Component
Expand All @@ -44,7 +39,6 @@
:modifiers="['no-motion']"
class="apos-admin-bar__btn"
:action-test-label="`${item.name}-manager-button`"
role="menuitem"
@click="emitEvent(item)"
/>
</li>
Expand All @@ -62,7 +56,6 @@
type: 'primary',
modifiers: ['round', 'no-motion']
}"
role="menuitem"
@item-clicked="emitEvent"
/>
</li>
Expand All @@ -89,6 +82,7 @@
:label="item.label"
:action="item.action"
:state="trayItemState[item.name] ? [ 'active' ] : []"
:attrs="trayItemAttrs(item)"
@click="emitEvent(item)"
/>
</template>
Expand Down Expand Up @@ -185,6 +179,29 @@ export default {
} else {
return item.options.tooltip;
}
},
// Tray utility buttons render icon-only, so the visible label
// (e.g. "Global Content") is sr-only and doesn't describe what the
// button does. Make them accessible by providing an aria-label based on
// the tooltip content.
trayItemAttrs(item) {
const tooltip = item.options?.tooltip;
let key = null;
if (item.options?.toggle) {
if (this.trayItemState[item.name] && tooltip?.deactivate) {
key = tooltip.deactivate;
} else if (tooltip?.activate) {
key = tooltip.activate;
}
} else if (typeof tooltip === 'string') {
key = tooltip;
} else if (tooltip && typeof tooltip.content === 'string') {
key = tooltip.content;
}
if (!key) {
return {};
}
return { 'aria-label': this.$t(key) };
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
:label="screen.label"
:tooltip="$t(screen.label)"
:title="$t(screen.label)"
:attrs="shortcutAttrs(screen)"
:icon="screen.icon"
:icon-only="true"
type="subtle"
Expand All @@ -36,6 +37,7 @@
:active-item="mode"
:center-on-icon="true"
menu-placement="bottom-end"
:dialog-label="'apostrophe:breakpointPreviewSelectMenu'"
@item-clicked="selectBreakpoint"
/>
<Transition>
Expand Down Expand Up @@ -320,6 +322,13 @@ export default {
},
setShowDropdown() {
this.showDropdown = Object.values(this.screens).some(({ shortcut }) => !shortcut);
},
shortcutAttrs(screen) {
return {
'aria-label': this.$t('apostrophe:breakpointPreviewShortcut', {
breakpoint: this.$t(screen.label)
})
};
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
:disabled="hasCustomUi || isUnpublished"
:center-on-icon="true"
menu-placement="bottom-end"
:dialog-label="'apostrophe:publicationStatusMenu'"
:trigger-aria-label="draftTriggerAriaLabel"
@item-clicked="switchDraftMode"
/>
<AposLabel
Expand Down Expand Up @@ -91,6 +93,13 @@ export default {
type: 'quiet'
};
},
draftTriggerAriaLabel() {
return this.$t('apostrophe:publicationStatusTrigger', {
status: this.$t(
this.draftMode === 'draft' ? 'apostrophe:draft' : 'apostrophe:published'
)
});
},
isUnpublished() {
return !this.context.lastPublishedAt;
},
Expand Down
6 changes: 6 additions & 0 deletions packages/apostrophe/modules/@apostrophecms/i18n/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
"breakpointPreviewExit": "Exit",
"breakpointPreviewMobile": "Mobile",
"breakpointPreviewSelect": "Select Breakpoint",
"breakpointPreviewSelectMenu": "Breakpoint preview menu",
"breakpointPreviewShortcut": "Preview at {{ breakpoint }} breakpoint",
"breakpointPreviewTablet": "Tablet",
"browse": "Browse",
"browseDocType": "Browse {{ type }}",
Expand Down Expand Up @@ -387,6 +389,7 @@
"mediaUploadViaDrop": "Drop ’em when you’re ready",
"mediaUploadViaExplorer": "Or click to open the file explorer",
"mergeCells": "Merge Cells",
"menu": "Menu",
"minLabel": "Min:",
"minSize": "Min size of {{ width }}x{{ height }}",
"minimumSize": "Minimum size of {{ width }} x {{ height }} px",
Expand Down Expand Up @@ -475,6 +478,8 @@
"publishBeforeUsingTooltip": "Publish this content before using it in a relationship",
"publishType": "Publish {{ type }}",
"published": "Published",
"publicationStatusMenu": "Publication status",
"publicationStatusTrigger": "Publication status: {{ status }}. Change publication status.",
"publishingBatchConfirmation": "Are you sure you want to publish {{ count }} {{ type }}?",
"publishingBatchConfirmationButton": "Yes, publish content.",
"rawCssAndJs": "Raw CSS and JS",
Expand All @@ -490,6 +495,7 @@
"recentlyEditedActionSubmitted": "Submitted",
"recentlyEditedCurrentUser": "Me ({{ user }})",
"recentlyEditedDocuments": "Recently edited documents",
"recentlyEditedManagerOpen": "Open recently edited documents manager",
"recentlyEditedEditedBy": "Edited by",
"recentlyEditedClearAllFilters": "Clear all filters",
"recentlyEditedClearSearch": "Clear search",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
:modifiers="['small', 'no-motion']"
:tooltip="$t('apostrophe:recentlyEditedDocuments')"
:icon-only="true"
:label="'apostrophe:recentlyEditedManagerOpen'"
:attrs="{ 'aria-label': $t('apostrophe:recentlyEditedManagerOpen') }"
@click="open"
/>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:tooltip="tooltip"
:icon-only="true"
:action="action"
:attrs="{ 'aria-label': $t(tooltip) }"
@click="open"
>
<template #label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,15 @@ export default {
}
}

// Keyboard-focus indicator for the `quiet` modifier
.apos-button--quiet {
&:focus-visible {
box-shadow: 0 0 0 2px var(--a-primary-light-40);
outline: none;
border-radius: var(--a-border-radius);
}
}

.apos-button--subtle {
padding: 11px 10px; // extra pixel keeps them aligned with border'd buttons
color: var(--a-text-primary);
Expand Down Expand Up @@ -757,11 +766,14 @@ export default {
}

.apos-button--no-motion {
&:hover:not([disabled]),
&:focus:not([disabled]) {
&:hover:not([disabled]) {
transform: none;
box-shadow: none;
}

&:focus:not([disabled]) {
transform: none;
}
}

.apos-button__wrapper {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,11 @@
v-bind="button"
ref="dropdownButton"
class="apos-context-menu__btn"
role="button"
:data-apos-test="identifier"
:state="buttonState"
:disabled="disabled"
:tooltip="btnTooltip"
:attrs="{
'aria-haspopup': 'menu',
'aria-expanded': isOpen ? true : false
}"
:attrs="triggerAttrs"
@icon="setIconToCenterTo"
@click.stop="buttonClicked($event)"
/>
Expand All @@ -52,6 +48,7 @@
:active-item="activeItem"
:is-open="isOpen"
:has-tip="hasTip"
:dialog-label="dialogLabel"
@item-clicked="menuItemClicked"
@set-arrow="setArrow"
>
Expand Down Expand Up @@ -87,6 +84,7 @@
:is-open="isOpen"
:has-tip="hasTip"
:ignore-unfocus="ignoreUnfocus"
:dialog-label="dialogLabel"
@item-clicked="menuItemClicked"
@set-arrow="setArrow"
>
Expand Down Expand Up @@ -215,6 +213,21 @@ const props = defineProps({
ignoreUnfocus: {
type: Boolean,
default: false
},
// Accessible name for the popover dialog. Pass an i18n key describing
// the menu's purpose. Defaults to a generic "Menu" label.
dialogLabel: {
type: String,
default: 'apostrophe:menu'
},
// Optional accessible name for the trigger button. When provided, it
// overrides the visible button label as the button's accessible name
// (useful when the visible label alone does not convey the trigger's
// purpose, e.g. when the label only shows the current value of a
// setting the menu changes). Pass an already-translated string.
triggerAriaLabel: {
type: String,
default: null
}
});

Expand Down Expand Up @@ -320,6 +333,17 @@ const menuAttrs = computed(() => {
};
});

const triggerAttrs = computed(() => {
const attrs = {
'aria-haspopup': 'menu',
'aria-expanded': isOpen.value
};
if (props.triggerAriaLabel) {
attrs['aria-label'] = props.triggerAriaLabel;
}
return attrs;
});

const teleportedStyle = computed(() => {
// For teleported content, we need to ensure positioning is always fresh
// The positioning is already calculated correctly by setDropdownPosition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class="apos-primary-scrollbar apos-context-menu__dialog"
:class="classes"
role="dialog"
:aria-label="$t(props.dialogLabel)"
:data-apos-ignore-unfocus="props.ignoreUnfocus"
>
<AposContextMenuTip
Expand Down Expand Up @@ -71,6 +72,13 @@ const props = defineProps({
activeItem: {
type: String,
default: null
},
// Accessible name for the dialog wrapper (role="dialog"). Pass an i18n
// key describing the menu's purpose for the most useful screen-reader
// announcement. Defaults to a generic "Menu" label.
dialogLabel: {
type: String,
default: 'apostrophe:menu'
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<li
class="apos-context-menu__item"
:class="menuItem.separator ? 'apos-context-menu__item--separator' : null"
role="presentation"
>
<hr
v-if="menuItem.separator"
Expand Down Expand Up @@ -178,7 +179,9 @@ export default {
}

&--disabled {
color: var(--a-base-3);
// Use --a-base-2 (#6f6f6f) so the disabled label still meets WCAG AA
// contrast against the menu background (--a-background-primary, #fff).
color: var(--a-base-2);

&:focus,
&:active {
Expand All @@ -189,7 +192,7 @@ export default {
&:focus,
&:active {
cursor: not-allowed;
color: var(--a-base-5);
color: var(--a-base-2);
background-color: var(--a-base-9);
}
}
Expand Down
Loading
Loading