show outlines, interate focusable elements, tabindex="-1" to overlay

This commit is contained in:
Artur Paikin 2017-10-27 16:01:11 -04:00
parent 806a333736
commit abfd1c72aa
7 changed files with 78 additions and 21 deletions

View file

@ -46,11 +46,11 @@ const uppy = Uppy({
// maxWidth: 350,
// maxHeight: 400,
inline: false,
disableStatusBar: false,
disableInformer: false,
// disableStatusBar: true,
// disableInformer: true,
getMetaFromForm: true,
replaceTargetContent: true,
target: '.MyForm',
// replaceTargetContent: true,
// target: '.MyForm',
hideUploadButton: false,
closeModalOnClickOutside: false,
locale: {

View file

@ -2,7 +2,7 @@ const html = require('yo-yo')
module.exports = (props) => {
const input = html`
<input class="UppyDashboard-input" type="file" name="files[]" multiple="true"
<input class="UppyDashboard-input" aria-hidden="true" type="file" name="files[]" multiple="true"
onchange=${props.handleInputChange} />
`

View file

@ -58,18 +58,17 @@ module.exports = function Dashboard (props) {
aria-label="${!props.inline
? props.i18n('dashboardWindowTitle')
: props.i18n('dashboardTitle')}"
role="dialog"
onpaste=${handlePaste}
onload=${() => props.updateDashboardElWidth()}>
onpaste=${handlePaste}>
<div class="UppyDashboard-overlay" onclick=${props.handleClickOutside}></div>
<div class="UppyDashboard-overlay" tabindex="-1" onclick=${props.handleClickOutside}></div>
<div class="UppyDashboard-inner"
tabindex="0"
aria-modal="true"
role="dialog"
style="
${props.inline && props.maxWidth ? `max-width: ${props.maxWidth}px;` : ''}
${props.inline && props.maxHeight ? `max-height: ${props.maxHeight}px;` : ''}
">
${props.inline && props.maxHeight ? `max-height: ${props.maxHeight}px;` : ''}"
onload=${() => props.updateDashboardElWidth()}>
<button class="UppyDashboard-close"
type="button"
aria-label="${props.i18n('closeModal')}"

View file

@ -20,7 +20,7 @@ module.exports = (props) => {
? html`<p class="UppyDashboard-note">${props.note}</p>`
: ''
}
<input class="UppyDashboard-input" type="file" name="files[]" multiple="true"
<input class="UppyDashboard-input" aria-hidden="true" type="file" name="files[]" multiple="true"
onchange=${props.handleInputChange} />
</div>`
: null

View file

@ -8,6 +8,20 @@ const { findAllDOMElements } = require('../../core/Utils')
const prettyBytes = require('prettier-bytes')
const { defaultTabIcon } = require('./icons')
const FOCUSABLE_ELEMENTS = [
'a[href]',
'area[href]',
'input:not([disabled]):not([type="hidden"])',
'select:not([disabled])',
'textarea:not([disabled])',
'button:not([disabled])',
'iframe',
'object',
'embed',
'[contenteditable]',
'[tabindex]:not([tabindex^="-"])'
]
/**
* Modal Dialog & Dashboard
*/
@ -77,6 +91,10 @@ module.exports = class DashboardUI extends Plugin {
this.actions = this.actions.bind(this)
this.hideAllPanels = this.hideAllPanels.bind(this)
this.showPanel = this.showPanel.bind(this)
this.getFocusableNodes = this.getFocusableNodes.bind(this)
this.setFocusToFirstNode = this.setFocusToFirstNode.bind(this)
this.maintainFocus = this.maintainFocus.bind(this)
this.initEvents = this.initEvents.bind(this)
this.handleEscapeKeyPress = this.handleEscapeKeyPress.bind(this)
this.handleClickOutside = this.handleClickOutside.bind(this)
@ -142,6 +160,10 @@ module.exports = class DashboardUI extends Plugin {
})
}
// setModalElement (element) {
// this.modal = element
// }
requestCloseModal () {
if (this.opts.onRequestCloseModal) {
return this.opts.onRequestCloseModal()
@ -150,6 +172,32 @@ module.exports = class DashboardUI extends Plugin {
}
}
getFocusableNodes () {
const nodes = this.modal.querySelectorAll(FOCUSABLE_ELEMENTS)
return Object.keys(nodes).map((key) => nodes[key])
}
setFocusToFirstNode () {
const focusableNodes = this.getFocusableNodes()
console.log(focusableNodes[0])
if (focusableNodes.length) focusableNodes[0].focus()
}
maintainFocus (event) {
var focusableNodes = this.getFocusableNodes()
var focusedItemIndex = focusableNodes.indexOf(document.activeElement)
if (event.shiftKey && focusedItemIndex === 0) {
focusableNodes[focusableNodes.length - 1].focus()
event.preventDefault()
}
if (!event.shiftKey && focusedItemIndex === focusableNodes.length - 1) {
focusableNodes[0].focus()
event.preventDefault()
}
}
openModal () {
this.setPluginState({
isHidden: false
@ -163,12 +211,17 @@ module.exports = class DashboardUI extends Plugin {
document.body.classList.add('is-UppyDashboard-open')
document.body.style.top = `-${this.savedDocumentScrollPosition}px`
// focus on modal inner block
this.target.querySelector('.UppyDashboard-inner').focus()
this.setFocusToFirstNode()
// this.updateDashboardElWidth()
// focus on modal inner block
// console.log(this.target)
// console.log(this.target.querySelector('.UppyDashboard-focus'))
// console.log(this.modal)
// this.modal.querySelector('.UppyDashboard-focus').focus()
this.updateDashboardElWidth()
// to be sure, sometimes when the function runs, container size is still 0
setTimeout(this.updateDashboardElWidth, 500)
// setTimeout(this.updateDashboardElWidth, 500)
}
closeModal () {
@ -432,6 +485,8 @@ module.exports = class DashboardUI extends Plugin {
this.initEvents()
this.actions()
this.modal = document.querySelector('.UppyDashboard--modal')
}
uninstall () {

View file

@ -1,5 +1,5 @@
const yo = require('yo-yo')
const nanoraf = require('nanoraf')
// const nanoraf = require('nanoraf')
const { findDOMElement } = require('../core/Utils')
const getFormData = require('get-form-data')
@ -63,9 +63,12 @@ module.exports = class Plugin {
const targetElement = findDOMElement(target)
// Set up nanoraf.
this.updateUI = nanoraf((state) => {
// this.updateUI = nanoraf((state) => {
// this.el = yo.update(this.el, this.render(state))
// })
this.updateUI = (state) => {
this.el = yo.update(this.el, this.render(state))
})
}
if (targetElement) {
this.core.log(`Installing ${callerPluginName} to a DOM element`)

View file

@ -21,7 +21,7 @@
padding: 0;
margin: 0;
border: 0;
outline: none;
// outline: none;
color: inherit;
}