]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Remove explicit use of aria-hidden for offcanvas when closed (#35589)
authorPatrick H. Lauke <redux@splintered.co.uk>
Wed, 5 Jan 2022 17:20:15 +0000 (17:20 +0000)
committerGitHub <noreply@github.com>
Wed, 5 Jan 2022 17:20:15 +0000 (19:20 +0200)
 Remove explicit use of aria-hidden & visibility for offcanvas when closed, handling it with css

Co-authored-by: GeoSot <geo.sotis@gmail.com>
Co-authored-by: Gaƫl Poupard <ffoodd@users.noreply.github.com>
js/src/offcanvas.js
js/tests/unit/offcanvas.spec.js
scss/_offcanvas.scss

index acc0971fa256cfd307d3780c92b56bd78ca68bfa..db6534039151e97e2ec928e67cf4f1a1851f6b82 100644 (file)
@@ -31,6 +31,8 @@ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
 const ESCAPE_KEY = 'Escape'
 
 const CLASS_NAME_SHOW = 'show'
+const CLASS_NAME_SHOWING = 'showing'
+const CLASS_NAME_HIDING = 'hiding'
 const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'
 const OPEN_SELECTOR = '.offcanvas.show'
 
@@ -99,24 +101,23 @@ class Offcanvas extends BaseComponent {
     }
 
     this._isShown = true
-    this._element.style.visibility = 'visible'
-
     this._backdrop.show()
 
     if (!this._config.scroll) {
       new ScrollBarHelper().hide()
     }
 
-    this._element.removeAttribute('aria-hidden')
     this._element.setAttribute('aria-modal', true)
     this._element.setAttribute('role', 'dialog')
-    this._element.classList.add(CLASS_NAME_SHOW)
+    this._element.classList.add(CLASS_NAME_SHOWING)
 
     const completeCallBack = () => {
       if (!this._config.scroll) {
         this._focustrap.activate()
       }
 
+      this._element.classList.add(CLASS_NAME_SHOW)
+      this._element.classList.remove(CLASS_NAME_SHOWING)
       EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })
     }
 
@@ -137,14 +138,13 @@ class Offcanvas extends BaseComponent {
     this._focustrap.deactivate()
     this._element.blur()
     this._isShown = false
-    this._element.classList.remove(CLASS_NAME_SHOW)
+    this._element.classList.add(CLASS_NAME_HIDING)
     this._backdrop.hide()
 
     const completeCallback = () => {
-      this._element.setAttribute('aria-hidden', true)
+      this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)
       this._element.removeAttribute('aria-modal')
       this._element.removeAttribute('role')
-      this._element.style.visibility = 'hidden'
 
       if (!this._config.scroll) {
         new ScrollBarHelper().reset()
index f4b0b64828d42215d99058107a4e1f531e812894..f87527fb2f817bc0c785adfed9b97a93d4acdd6a 100644 (file)
@@ -242,23 +242,46 @@ describe('Offcanvas', () => {
       expect(offCanvas.show).toHaveBeenCalled()
     })
 
-    it('should call hide method if show class is present', () => {
+    it('should call hide method if show class is present', done => {
       fixtureEl.innerHTML = '<div class="offcanvas"></div>'
 
       const offCanvasEl = fixtureEl.querySelector('.offcanvas')
       const offCanvas = new Offcanvas(offCanvasEl)
-      offCanvas.show()
-      expect(offCanvasEl).toHaveClass('show')
 
-      spyOn(offCanvas, 'hide')
+      offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
+        expect(offCanvasEl).toHaveClass('show')
+        spyOn(offCanvas, 'hide')
 
-      offCanvas.toggle()
+        offCanvas.toggle()
 
-      expect(offCanvas.hide).toHaveBeenCalled()
+        expect(offCanvas.hide).toHaveBeenCalled()
+        done()
+      })
+
+      offCanvas.show()
     })
   })
 
   describe('show', () => {
+    it('should add `showing` class during opening and `show` class on end', done => {
+      fixtureEl.innerHTML = '<div class="offcanvas"></div>'
+      const offCanvasEl = fixtureEl.querySelector('.offcanvas')
+      const offCanvas = new Offcanvas(offCanvasEl)
+
+      offCanvasEl.addEventListener('show.bs.offcanvas', () => {
+        expect(offCanvasEl).not.toHaveClass('show')
+      })
+
+      offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
+        expect(offCanvasEl).not.toHaveClass('showing')
+        expect(offCanvasEl).toHaveClass('show')
+        done()
+      })
+
+      offCanvas.show()
+      expect(offCanvasEl).toHaveClass('showing')
+    })
+
     it('should do nothing if already shown', () => {
       fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
 
@@ -353,6 +376,30 @@ describe('Offcanvas', () => {
   })
 
   describe('hide', () => {
+    it('should add `hiding` class during closing and remover `show` & `hiding` classes on end', done => {
+      fixtureEl.innerHTML = '<div class="offcanvas"></div>'
+      const offCanvasEl = fixtureEl.querySelector('.offcanvas')
+      const offCanvas = new Offcanvas(offCanvasEl)
+
+      offCanvasEl.addEventListener('hide.bs.offcanvas', () => {
+        expect(offCanvasEl).not.toHaveClass('showing')
+        expect(offCanvasEl).toHaveClass('show')
+      })
+
+      offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
+        expect(offCanvasEl).not.toHaveClass('hiding')
+        expect(offCanvasEl).not.toHaveClass('show')
+        done()
+      })
+
+      offCanvas.show()
+      offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
+        offCanvas.hide()
+        expect(offCanvasEl).not.toHaveClass('showing')
+        expect(offCanvasEl).toHaveClass('hiding')
+      })
+    })
+
     it('should do nothing if already shown', () => {
       fixtureEl.innerHTML = '<div class="offcanvas"></div>'
 
index a089c2a08178afe7196e3c5cdfca1f57b5c7c0dd..5288fa9ce68b0834b7d7812c1e56c0f6b82acfc2 100644 (file)
   outline: 0;
   @include box-shadow($offcanvas-box-shadow);
   @include transition(transform $offcanvas-transition-duration ease-in-out);
+
+  &.showing,
+  &.show:not(.hiding) {
+    transform: none;
+  }
+
+  &.showing,
+  &.hiding,
+  &.show {
+    visibility: visible;
+  }
 }
 
 .offcanvas-backdrop {
@@ -77,7 +88,3 @@
   border-top: $offcanvas-border-width solid $offcanvas-border-color;
   transform: translateY(100%);
 }
-
-.offcanvas.show {
-  transform: none;
-}