diff --git a/.changeset/proud-wasps-travel.md b/.changeset/proud-wasps-travel.md new file mode 100644 index 0000000000..4df118858f --- /dev/null +++ b/.changeset/proud-wasps-travel.md @@ -0,0 +1,10 @@ +--- +"@stackoverflow/stacks": patch +"@stackoverflow/stacks-svelte": patch +--- + +fix(navigation): make vertical navigation more accessible + +BREAKING CHANGES: +* Navigation markup has been updated +* Svelte NavigationTitle component has been renamed to NavigationGroup diff --git a/packages/stacks-classic/lib/components/navigation/navigation.a11y.test.ts b/packages/stacks-classic/lib/components/navigation/navigation.a11y.test.ts index 23af1a8741..eb92922df2 100644 --- a/packages/stacks-classic/lib/components/navigation/navigation.a11y.test.ts +++ b/packages/stacks-classic/lib/components/navigation/navigation.a11y.test.ts @@ -2,7 +2,14 @@ import { html } from "@open-wc/testing"; import { runA11yTests } from "../../test/a11y-test-utils"; import "../../index"; -const items = [ +interface NavigationItem { + label: string; + title?: boolean; + selected?: boolean; + dropdown?: boolean; +} + +const items: NavigationItem[] = [ { label: "Group 1", title: true, @@ -38,20 +45,43 @@ const items = [ }, ]; -const getChildren = (includeTitles = false): string => - items - .map((item) => { +const getChildren = (includeTitles = false): string => { + const getClasses = function (item: NavigationItem) { + return `s-navigation--item${ + item.selected ? " is-selected" : "" + }${item.dropdown ? " s-navigation--item__dropdown" : ""}`; + }; + + if (!includeTitles) { + return items + .map((item) => { + if (item.title) { + return ""; //don't print title + } + return `
  • ${item.label}
  • `; + }) + .join(""); + } else { + //Vertical nav + let html = ""; + for (const item of items) { if (item.title) { - return includeTitles - ? `
  • ${item.label}
  • ` - : ""; + if (html.length > 0) { + html += ""; + } + const groupName = item.label.replace(" ", ""); + html += `
  • + +
  • "; + return html; + } +}; describe("navigation", () => { runA11yTests({ diff --git a/packages/stacks-classic/lib/components/navigation/navigation.less b/packages/stacks-classic/lib/components/navigation/navigation.less index 24e07ad0d2..2bfcb816c8 100644 --- a/packages/stacks-classic/lib/components/navigation/navigation.less +++ b/packages/stacks-classic/lib/components/navigation/navigation.less @@ -1,4 +1,5 @@ -.s-navigation { +.s-navigation, +.s-navigation ul { --_na-fd: row; --_na-fw: wrap; --_na-p: var(--su2) 0; @@ -15,7 +16,6 @@ --_na-item-selected-bg-hover: var(--_na-item-bg-hover); --_na-item-selected-h: var(--su2); --_na-item-text-ta: center; - --_na-title-mt: var(--su24); --_na-after-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M11.35 4.35 6 9.71.65 4.35l.7-.7L6 8.29l4.65-4.64z'/%3E%3C/svg%3E"); --_na-after-bg-color: var(--black-400); @@ -42,7 +42,8 @@ --_na-item-p: var(--su6) var(--su4); } - &&__vertical { + &&__vertical, + &&__vertical ul { --_na-fd: column; --_na-gap: 0; --_na-p: 0; @@ -51,6 +52,7 @@ --_na-item-selected-h: 0; --_na-item-p: var(--su6) var(--su8); --_na-item-fc: var(--black-600); + & .s-navigation--item { &.is-selected { --_na-item-bg: var(--black-150); @@ -151,20 +153,22 @@ } & &--title { - &:first-child { - --_na-title-mt: 0; - } - & .s-btn { color: var(--black-400); } - margin-top: var(--_na-title-mt); + margin-bottom: 0; font-size: var(--fs-fine); + font-weight: normal; color: var(--black-400); padding: calc(var(--su16) + var(--su2)) var(--su8); } + //Add top margin to titles except the first one + & > li ~ li .s-navigation--title { + margin-top: var(--su24); + } + & &--icon { color: inherit; margin-right: var(--su4); diff --git a/packages/stacks-classic/lib/components/navigation/navigation.visual.test.ts b/packages/stacks-classic/lib/components/navigation/navigation.visual.test.ts index 38285937e3..3d0520e54c 100644 --- a/packages/stacks-classic/lib/components/navigation/navigation.visual.test.ts +++ b/packages/stacks-classic/lib/components/navigation/navigation.visual.test.ts @@ -9,7 +9,14 @@ const filledIcon = IconHomeFill.replace( 'class="s-navigation--icon ' ); -const items = [ +interface NavigationItem { + label: string; + title?: boolean; + selected?: boolean; + dropdown?: boolean; +} + +const items: NavigationItem[] = [ { label: "Group 1", title: true, @@ -45,25 +52,47 @@ const items = [ }, ]; -const getChildren = (includeTitles = false, includeIcons = false): string => - items - .map((item) => { +const getChildren = (includeTitles = false, includeIcons = false): string => { + const getClasses = function (item: NavigationItem) { + return `s-navigation--item${ + item.selected ? " is-selected" : "" + }${item.dropdown ? " s-navigation--item__dropdown" : ""}`; + }; + + const getIcon = function (item: NavigationItem) { + return includeIcons ? (item.selected ? filledIcon : outlineIcon) : ""; + }; + + if (!includeTitles) { + return items + .map((item) => { + if (item.title) { + return ""; //don't print title + } + return `
  • ${getIcon(item)}${item.label}
  • `; + }) + .join(""); + } else { + //Vertical nav + let html = ""; + for (const item of items) { if (item.title) { - return includeTitles - ? `
  • ${item.label}
  • ` - : ""; + if (html.length > 0) { + html += ""; + } + const groupName = item.label.replace(" ", ""); + html += `
  • + +
  • "; + return html; + } +}; describe("navigation", () => { runVisualTests({ diff --git a/packages/stacks-docs/_includes/layouts/home.html b/packages/stacks-docs/_includes/layouts/home.html index 40e3194b91..46351c20bc 100644 --- a/packages/stacks-docs/_includes/layouts/home.html +++ b/packages/stacks-docs/_includes/layouts/home.html @@ -202,11 +202,11 @@

    Stacks