Skip to content

Commit

Permalink
feat(a11y/QMenu/QDialog/QTabs): Add KeyGroupNavigation directive; Wra…
Browse files Browse the repository at this point in the history
…p arround keyboard navigation quasarframework#5266, quasarframework#4068, quasarframework#6736, quasarframework#6562, quasarframework#6560, quasarframework#12464, quasarframework#12506, quasarframework#12505

- allow unique TAB target point in a group
- allow key navigation in group
- improve initial focusing on QMenu and QDialog
- tab goes from the end of the menu/dialog to the start
- shift+tab goes from the start of the menu/dialog to the end
- key navigation in tabs
  • Loading branch information
pdanpdan committed Apr 27, 2023
1 parent c1d1cb7 commit 601e3ca
Show file tree
Hide file tree
Showing 41 changed files with 1,417 additions and 132 deletions.
5 changes: 5 additions & 0 deletions docs/src/assets/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,11 @@ const directives = [
name: 'Go Back (Handling Back Button)',
path: 'go-back'
},
{
name: 'Key Group Navigation',
badge: 'new',
path: 'key-group-navigation'
},
{
name: 'Intersection',
path: 'intersection'
Expand Down
8 changes: 6 additions & 2 deletions docs/src/components/DocApi.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ q-card.doc-api.q-my-lg(flat bordered)
transition-next="slide-up"
)
q-tab-panel.q-pa-none(v-for="innerTab in innerTabsList[tab]" :name="innerTab" :key="innerTab")
DocApiEntry(:type="tab" :definition="filteredApi[tab][innerTab]")
DocApiEntry(:type="tab" :definition="filteredApi[tab][innerTab]" tabindex="0")

.api-container(v-else)
DocApiEntry(:type="tab" :definition="filteredApi[tab][defaultInnerTabName]")
DocApiEntry(:type="tab" :definition="filteredApi[tab][defaultInnerTabName]" tabindex="0")
</template>

<script>
Expand Down Expand Up @@ -365,4 +365,8 @@ export default {
color: $grey
font-size: .8em
font-style: italic
.api-rows:focus-visible
outline: auto
outline-offset: -1px
</style>
2 changes: 1 addition & 1 deletion docs/src/components/DocExample.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ q-card.doc-example.q-my-lg(:class="classes", flat, bordered)

q-space

div.col-auto
div.col-auto(v-key-group-navigation)
q-btn(dense, flat, round, :icon="fabGithub", @click="openGitHub")
q-tooltip View on GitHub
q-btn.q-ml-sm(v-if="noEdit === false", dense, flat, round, :icon="fabCodepen", @click="openCodepen")
Expand Down
3 changes: 3 additions & 0 deletions docs/src/components/DocLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export default {
&:hover
opacity: .8
&:focus-visible
border-bottom-style: solid
.q-icon
margin-top: -3px
margin-left: 4px
Expand Down
54 changes: 35 additions & 19 deletions docs/src/components/DocPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ q-page.doc-page
span Caught a mistake? Edit page in browser
q-icon.q-ml-xs(:name="mdiFlash" size="2em")

.doc-page-nav.text-brand-primary(v-if="related !== void 0")
.doc-page-nav.text-brand-primary(v-if="related !== void 0" v-key-group-navigation)
.q-gutter-md.flex
router-link.q-link.doc-page-related.rounded-borders.q-pa-md.cursor-pointer.column.justify-center.bg-grey-3(
v-for="link in related"
Expand All @@ -33,7 +33,7 @@ q-page.doc-page

slot

.doc-page-nav.doc-page-nav__footer.text-brand-primary.q-pb-xl(v-if="nav !== void 0")
.doc-page-nav.doc-page-nav__footer.text-brand-primary.q-pb-xl(v-if="nav !== void 0" v-key-group-navigation)
.text-h6.q-pb-md Ready for more?
.q-gutter-md.flex
router-link.q-link.doc-page-related.doc-page-related-bordered.rounded-borders.q-pa-md.cursor-pointer.column.justify-center.bg-grey-1(
Expand All @@ -59,30 +59,31 @@ q-page.doc-page
span Caught a mistake?
doc-link.q-ml-xs(:to="editHref") Edit this page in browser

.doc-page-footer__icons.row.items-center.q-gutter-sm
a(href="https://github.com/pdanpdan/quasar", target="_blank", rel="noopener")
q-icon(:name="fabGithub")
.doc-page-footer__icons(v-key-group-navigation)
div.row.items-center.q-gutter-sm
a(href="https://github.com/pdanpdan/quasar", target="_blank", rel="noopener")
q-icon(:name="fabGithub")

a(href="https://blog.quasar.dev", target="_blank", rel="noopener")
q-icon(:name="mdiPost")
a(href="https://blog.quasar.dev", target="_blank", rel="noopener")
q-icon(:name="mdiPost")

a(href="https://chat.quasar.dev", rel="noopener", target="_blank")
q-icon(:name="mdiChat")
a(href="https://chat.quasar.dev", rel="noopener", target="_blank")
q-icon(:name="mdiChat")

a(href="https://forum.quasar.dev/", rel="noopener", target="_blank")
q-icon(:name="mdiForum")
a(href="https://forum.quasar.dev/", rel="noopener", target="_blank")
q-icon(:name="mdiForum")

a(href="https://twitter.quasar.dev", target="_blank", rel="noopener")
q-icon(:name="fabTwitter")
a(href="https://twitter.quasar.dev", target="_blank", rel="noopener")
q-icon(:name="fabTwitter")

a(href="https://facebook.quasar.dev", target="_blank", rel="noopener")
q-icon(:name="fabFacebook")
a(href="https://facebook.quasar.dev", target="_blank", rel="noopener")
q-icon(:name="fabFacebook")

a(href="https://github.com/sponsors/pdanpdan", rel="sponsored", target="_blank")
q-icon(:name="mdiCharity")
a(href="https://github.com/sponsors/pdanpdan", rel="sponsored", target="_blank")
q-icon(:name="mdiCharity")

a(href="https://donate.quasar.dev", rel="sponsored", target="_blank")
q-icon(:name="mdiCharity")
a(href="https://donate.quasar.dev", rel="sponsored", target="_blank")
q-icon(:name="mdiCharity")

div.q-mt-md
| <doc-link to="https://github.com/quasarframework/quasar/blob/dev/LICENSE">MIT LICENSE</doc-link> | <doc-link to="https://www.iubenda.com/privacy-policy/40685560">Privacy Policy</doc-link> | <doc-link to="https://github.com/quasarframework/quasar-art">Quasar Artwork</doc-link>
Expand Down Expand Up @@ -182,6 +183,10 @@ export default {
color: inherit
text-decoration: none
outline: 0
border-bottom: 2px solid transparent
&:focus-visible
border-bottom-color: currentColor
&__badge
vertical-align: super
Expand Down Expand Up @@ -209,16 +214,27 @@ export default {
&__icons
font-size: 28px
&.q-key-group-navigation--active
overflow: hidden
outline-offset: 8px
a
text-decoration: none
outline: 0
color: $brand-primary
border-bottom: 2px solid transparent
transition: color .28s
&:hover
color: $grey-8
&:focus-visible
border-bottom-color: currentColor
.doc-page-nav
&.q-key-group-navigation--active
overflow: hidden
outline-offset: 8px
&__footer
margin: 68px 0 0
Expand Down
91 changes: 91 additions & 0 deletions docs/src/examples/KeyGroupNavigation/Bar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<template>
<div class="q-pa-md column no-wrap q-gutter-y-md" style="max-width: 500px">
<q-btn color="black" label="First focusable element" />

<q-bar v-key-group-navigation>
<q-btn flat dense color="black" no-caps label="File" class="q-px-sm">
<q-menu>
<q-list dense style="min-width: 100px" v-key-group-navigation>
<q-item clickable v-close-popup>
<q-item-section>Open...</q-item-section>
</q-item>
<q-item clickable v-close-popup>
<q-item-section>New</q-item-section>
</q-item>

<q-separator />

<q-item clickable>
<q-item-section>Preferences</q-item-section>
<q-item-section side>
<q-icon name="keyboard_arrow_right" />
</q-item-section>

<q-menu anchor="top right" self="top left">
<q-list v-key-group-navigation>
<q-item
v-for="n in 3"
:key="n"
dense
clickable
>
<q-item-section>Submenu Label</q-item-section>
<q-item-section side>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu auto-close anchor="top right" self="top left">
<q-list v-key-group-navigation>
<q-item
v-for="n in 3"
:key="n"
dense
clickable
>
<q-item-section>3rd level Label</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
</q-list>
</q-menu>
</q-item>

<q-separator />

<q-item clickable v-close-popup>
<q-item-section>Quit</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>

<q-btn flat dense color="black" no-caps label="Edit" class="q-px-sm q-ml-md">
<q-menu auto-close>
<q-list dense style="min-width: 100px" v-key-group-navigation>
<q-item clickable>
<q-item-section>Cut</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>Copy</q-item-section>
</q-item>
<q-item clickable>
<q-item-section>Paste</q-item-section>
</q-item>
<q-separator />
<q-item clickable>
<q-item-section>Select All</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>

<q-space />

<q-btn dense flat icon="minimize" />
<q-btn dense flat icon="crop_square" />
<q-btn dense flat icon="close" />
</q-bar>

<q-btn color="black" label="Last focusable element" />
</div>
</template>
24 changes: 24 additions & 0 deletions docs/src/examples/KeyGroupNavigation/FormControls.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<div class="q-pa-md column no-wrap q-gutter-y-md" style="max-width: 500px">
<q-btn color="black" label="First focusable element" />

<!-- QEditor already uses the keyboard navigation inside -->
<q-editor v-model="editor" min-height="5rem" />

<!-- QDate already uses the keyboard navigation inside -->
<q-date v-model="date" />

<q-btn color="black" label="Last focusable element" />
</div>
</template>

<script>
export default {
data () {
return {
editor: 'What you see is <b>what</b> you get.',
date: '2019/02/01'
}
}
}
</script>
71 changes: 71 additions & 0 deletions docs/src/examples/KeyGroupNavigation/List.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<template>
<div class="q-pa-md column no-wrap q-gutter-y-md" style="max-width: 500px">
<q-btn color="black" label="First focusable element" />

<q-list bordered padding v-key-group-navigation.vertical>
<q-item-label header>List with controls</q-item-label>

<q-item clickable v-ripple>
<q-item-section>
<q-item-label>Vertical navigation</q-item-label>
<q-item-label caption>
Navigate using <kbd>PG_UP</kbd>, <kbd>ARROW_UP</kbd>, <kbd>ARROW_DOWN</kbd>, <kbd>PG_DOWN</kbd>
</q-item-label>
</q-item-section>
</q-item>

<q-item clickable v-ripple>
<q-item-section>
<q-item-label>Horizontal navigation</q-item-label>
<q-item-label caption>
Navigate using <kbd>HOME</kbd>, <kbd>ARROW_LEFT</kbd>, <kbd>ARROW_RIGHT</kbd>, <kbd>END</kbd>
</q-item-label>
</q-item-section>
</q-item>

<q-item clickable v-ripple>
<q-item-section>
<q-item-label>Default</q-item-label>
<q-item-label caption>
Navigate using any of the above keys
</q-item-label>
</q-item-section>
</q-item>

<q-item tag="label" v-ripple>
<q-item-section side top>
<q-checkbox v-model="check" />
</q-item-section>

<q-item-section>
<q-item-label>Notifications</q-item-label>
<q-item-label caption>
Notify me about updates to apps or games that I downloaded
</q-item-label>
</q-item-section>
</q-item>

<q-item tag="label" v-ripple>
<q-item-section>
<q-item-label>Battery too low</q-item-label>
</q-item-section>
<q-item-section side >
<q-toggle color="blue" v-model="notif" val="battery" />
</q-item-section>
</q-item>
</q-list>

<q-btn color="black" label="Last focusable element" />
</div>
</template>

<script>
export default {
data () {
return {
check: true,
notif: true
}
}
}
</script>
Loading

0 comments on commit 601e3ca

Please sign in to comment.