Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat add focus management for toolbar #30

Merged
merged 28 commits into from
Apr 2, 2020
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
4516834
test: add a focussable link ahead of markdown-toolbar in example
keithamus Mar 17, 2020
a19ded0
feat: add focus management for toolbar
keithamus Mar 17, 2020
987b5a2
test: change example link to button
keithamus Mar 18, 2020
72c0c73
feat: use `data-md-button` to select for focus management
keithamus Mar 18, 2020
fc01316
feat: use delegated event listener for keyboard focus
keithamus Mar 18, 2020
bf0fde1
fix: remove MarkDownButtonElement instance check
keithamus Mar 18, 2020
fa869bd
fix: check currentTarget is closest to button invoking keypress
keithamus Mar 18, 2020
95b19a5
refactor: drop unecessary binding on focusKeydown
keithamus Mar 18, 2020
538ff34
refactor: use md-* selectors where possible
keithamus Mar 19, 2020
311e8c6
refactor: move tabIndex assigment to markdown-toolbar
keithamus Mar 19, 2020
054b4c3
test: add test for generic data-md-button elements
keithamus Mar 19, 2020
98ed87f
refactor: DRY up indexOf calls
keithamus Mar 19, 2020
abafcb6
style: drop erroneous console.log
keithamus Mar 19, 2020
f1bfaba
refactor: DRY up buttons.length
keithamus Mar 19, 2020
7fef62f
refactor: move needless if condition out of loop
keithamus Mar 19, 2020
014e98f
style: add return type annotation for getButtons function
keithamus Mar 24, 2020
e6e2ae0
style: add type guard to buttons
keithamus Mar 24, 2020
33a7ceb
refactor: move element selectors to assignment
keithamus Mar 26, 2020
baa5138
fix: filter out hidden elements
keithamus Mar 26, 2020
715efc8
fix: do not focus on buttons that are hidden via CSS
keithamus Mar 27, 2020
85206b2
fix: make focus management lazy, on focus of toolbar.
keithamus Mar 31, 2020
ee95e9d
fix: Home/End shortcuts should preventDefault
keithamus Mar 31, 2020
4d6dbc8
test: add hidden toolbar to examples
keithamus Mar 31, 2020
44edfbc
test: fixup example & test html
keithamus Apr 1, 2020
d91d2f0
fix: apply focus event listener only once
keithamus Apr 1, 2020
434e68c
style: move let binding closer to first use
keithamus Apr 1, 2020
b8777de
docs: add README note about data-md-button
keithamus Apr 1, 2020
dcfdbd7
docs: clarify focus management in readme
keithamus Apr 2, 2020
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
Prev Previous commit
Next Next commit
feat: use delegated event listener for keyboard focus
This allows for non-MarkdownButtonElement members to also handle focus
management keyboard shortcuts, as the event binding is per-toolbar not
per-button
  • Loading branch information
keithamus committed Mar 18, 2020
commit fc013162963ff2cfc5968f77141d8a560777a10c
59 changes: 35 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,10 @@

function keydown(fn: KeyboardEventHandler): KeyboardEventHandler {
return function(event: KeyboardEvent) {
const key = event.key
if (key === ' ' || key === 'Enter') {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault()
fn(event)
}
if (key === 'ArrowRight' || key === 'ArrowLeft' || key === 'Home' || key === 'End') {
const target = event.currentTarget
if (!(target instanceof HTMLElement)) return
if (!target.hasAttribute('data-md-button')) return
const toolbar = target.closest('markdown-toolbar')
if (!(toolbar instanceof MarkdownToolbarElement)) return

const buttons = []
for (const button of toolbar.querySelectorAll('[data-md-button]')) {
button.setAttribute('tabindex', '-1')
buttons.push(button)
}
let i = 0
if (key === 'ArrowLeft') i = buttons.indexOf(target) - 1
if (key === 'ArrowRight') i = buttons.indexOf(target) + 1
if (key === 'End') i = buttons.length - 1
if (i < 0) i = buttons.length - 1
if (i > buttons.length - 1) i = 0

buttons[i].setAttribute('tabindex', '0')
buttons[i].focus()
}
}
}

Expand Down Expand Up @@ -248,6 +225,9 @@ class MarkdownToolbarElement extends HTMLElement {
if (!this.hasAttribute('role')) {
this.setAttribute('role', 'toolbar')
}
const focusKeydownfn = focusKeydown.bind(null, this)
this.addEventListener('keydown', focusKeydownfn)
focusListeners.set(this, focusKeydownfn)
const fn = shortcut.bind(null, this)
if (this.field) {
this.field.addEventListener('keydown', fn)
Expand All @@ -263,6 +243,10 @@ class MarkdownToolbarElement extends HTMLElement {
this.field.removeEventListener('keydown', fn)
shortcutListeners.delete(this)
}
const focusKeydownfn = focusListeners.get(this)
if (focusKeydownfn) {
this.removeEventListener('keydown', focusKeydownfn)
}
}

get field(): ?HTMLTextAreaElement {
Expand All @@ -273,6 +257,33 @@ class MarkdownToolbarElement extends HTMLElement {
}
}

const focusListeners = new WeakMap()

function focusKeydown(toolbar: MarkdownToolbarElement, event: KeyboardEvent) {
const key = event.key
if (key !== 'ArrowRight' && key !== 'ArrowLeft' && key !== 'Home' && key !== 'End') return
const target = event.target
if (!(target instanceof HTMLElement)) return
if (!target.hasAttribute('data-md-button')) return
if (target.closest('markdown-toolbar') !== toolbar) return

const buttons = []
for (const button of toolbar.querySelectorAll('[data-md-button]')) {
if (!(button instanceof MarkdownButtonElement)) continue
button.setAttribute('tabindex', '-1')
buttons.push(button)
}
let i = 0
if (key === 'ArrowLeft') i = buttons.indexOf(target) - 1
if (key === 'ArrowRight') i = buttons.indexOf(target) + 1
if (key === 'End') i = buttons.length - 1
if (i < 0) i = buttons.length - 1
if (i > buttons.length - 1) i = 0

buttons[i].setAttribute('tabindex', '0')
buttons[i].focus()
}

const shortcutListeners = new WeakMap()

function shortcut(toolbar: Element, event: KeyboardEvent) {
Expand Down