Преглед изворни кода

Dashboard: disallow clicking on buttons and links in Dashboard disabled mode (#4292)

* Disallow clicking on buttons and links in Dashboard disabled mode

* Add disabled attr to all interactive elements instead of tabindex=-1

* Test and apply Antoine’s suggestions

* Account for links, use aria-disabled and pointer-events

* Rename disableAllFocusableElements --> disableInteractiveElements

* Add role="button" just in case for the future
Artur Paikin пре 2 година
родитељ
комит
a602f1e5b1
2 измењених фајлова са 39 додато и 22 уклоњено
  1. 30 21
      packages/@uppy/dashboard/src/Dashboard.jsx
  2. 9 1
      packages/@uppy/dashboard/src/style.scss

+ 30 - 21
packages/@uppy/dashboard/src/Dashboard.jsx

@@ -8,7 +8,6 @@ import toArray from '@uppy/utils/lib/toArray'
 import getDroppedFiles from '@uppy/utils/lib/getDroppedFiles'
 import { nanoid } from 'nanoid/non-secure'
 import memoizeOne from 'memoize-one'
-import FOCUSABLE_ELEMENTS from '@uppy/utils/lib/FOCUSABLE_ELEMENTS'
 import * as trapFocus from './utils/trapFocus.js'
 import createSuperFocus from './utils/createSuperFocus.js'
 import DashboardUI from './components/Dashboard.jsx'
@@ -44,6 +43,8 @@ function defaultPickerIcon () {
 export default class Dashboard extends UIPlugin {
   static VERSION = packageJson.version
 
+  #disabledNodes = null
+
   constructor (uppy, opts) {
     super(uppy, opts)
     this.id = this.opts.id || 'Dashboard'
@@ -456,26 +457,34 @@ export default class Dashboard extends UIPlugin {
     }
   }
 
-  disableAllFocusableElements = (disable) => {
-    const focusableNodes = toArray(this.el.querySelectorAll(FOCUSABLE_ELEMENTS))
+  disableInteractiveElements = (disable) => {
+    const NODES_TO_DISABLE = [
+      'a[href]',
+      'input:not([disabled])',
+      'select:not([disabled])',
+      'textarea:not([disabled])',
+      'button:not([disabled])',
+      '[role="button"]:not([disabled])',
+    ]
+
+    const nodesToDisable = this.#disabledNodes ?? toArray(this.el.querySelectorAll(NODES_TO_DISABLE))
+      .filter(node => !node.classList.contains('uppy-Dashboard-close'))
+
+    for (const node of nodesToDisable) {
+      // Links can’t have `disabled` attr, so we use `aria-disabled` for a11y
+      if (node.tagName === 'A') {
+        node.setAttribute('aria-disabled', disable)
+      } else {
+        node.disabled = disable
+      }
+    }
+
     if (disable) {
-      focusableNodes.forEach((node) => {
-        // save previous tabindex in a data-attribute, to restore when enabling
-        const currentTabIndex = node.getAttribute('tabindex')
-        if (currentTabIndex) {
-          node.dataset.inertTabindex = currentTabIndex // eslint-disable-line no-param-reassign
-        }
-        node.setAttribute('tabindex', '-1')
-      })
+      this.#disabledNodes = nodesToDisable
     } else {
-      focusableNodes.forEach((node) => {
-        if ('inertTabindex' in node.dataset) {
-          node.setAttribute('tabindex', node.dataset.inertTabindex)
-        } else {
-          node.removeAttribute('tabindex')
-        }
-      })
+      this.#disabledNodes = null
     }
+
     this.dashboardIsDisabled = disable
   }
 
@@ -831,12 +840,12 @@ export default class Dashboard extends UIPlugin {
 
   afterUpdate = () => {
     if (this.opts.disabled && !this.dashboardIsDisabled) {
-      this.disableAllFocusableElements(true)
+      this.disableInteractiveElements(true)
       return
     }
 
     if (!this.opts.disabled && this.dashboardIsDisabled) {
-      this.disableAllFocusableElements(false)
+      this.disableInteractiveElements(false)
     }
 
     this.superFocusOnEachUpdate()
@@ -944,7 +953,7 @@ export default class Dashboard extends UIPlugin {
       activePickerPanel: pluginState.activePickerPanel,
       showFileEditor: pluginState.showFileEditor,
       saveFileEditor: this.saveFileEditor,
-      disableAllFocusableElements: this.disableAllFocusableElements,
+      disableInteractiveElements: this.disableInteractiveElements,
       animateOpenClose: this.opts.animateOpenClose,
       isClosing: pluginState.isClosing,
       progressindicators,

+ 9 - 1
packages/@uppy/dashboard/src/style.scss

@@ -190,7 +190,7 @@
     opacity: 0.6;
     filter: grayscale(100%);
     user-select: none;
-    pointer-events: none;
+    cursor: not-allowed;
   }
 }
 
@@ -198,6 +198,14 @@
   fill: #9f9f9f;
 }
 
+// Disallow clicking on all interactive elements
+.uppy-Dashboard--isDisabled {
+  [disabled], [aria-disabled] {
+    pointer-events: none;
+    cursor: not-allowed;
+  }
+}
+
 .uppy-Dashboard--modal .uppy-Dashboard-inner {
   position: fixed;
   top: 35px;