Browse Source

followup #9100: made sdm switch pretty, accessible

- followed all accessibility guidelines I could find. only thing missing
  is that it still might be a bit small for an interactive button
telamonian 4 years ago
parent
commit
0c4ee1a649
2 changed files with 77 additions and 16 deletions
  1. 26 16
      packages/application/src/shell.ts
  2. 51 0
      packages/application/style/buttons.css

+ 26 - 16
packages/application/src/shell.ts

@@ -302,26 +302,36 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
     spacer.id = 'jp-top-spacer';
     this.add(spacer, 'top', { rank: 1000 });
 
-    const label = document.createElement('label');
-    label.textContent = 'Single-Document Mode';
-    label.title = 'Single-Document Mode';
-    const checkbox = document.createElement('input');
-    checkbox.type = 'checkbox';
-    checkbox.value = 'single-document';
-    checkbox.title = 'Single-Document Mode';
+    // switch accessibility refs:
+    // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Switch_role
+    // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Accessibility_concerns
+    const sdmSwitch = document.createElement('button');
+    sdmSwitch.className = 'jp-slider jp-slider-sdm';
+    sdmSwitch.setAttribute("role", "switch");
+    sdmSwitch.value = 'single-document';
+    sdmSwitch.title = 'Single-Document Mode';
     this.modeChanged.connect((_, mode) => {
-      checkbox.checked = mode === 'single-document';
+      sdmSwitch.setAttribute("aria-checked", mode === 'single-document' ? 'true' : 'false');
     });
-    checkbox.checked = this.mode === 'single-document';
-    checkbox.addEventListener('change', () => {
-      this.mode = checkbox.checked ? 'single-document' : 'multiple-document';
+    sdmSwitch.setAttribute("aria-checked", this.mode === 'single-document' ? 'true' : 'false');
+    sdmSwitch.addEventListener('click', () => {
+      this.mode = sdmSwitch.getAttribute("aria-checked") === "true" ?'multiple-document' : 'single-document';
     });
-    label.appendChild(checkbox);
 
-    const checkWidget = new Widget();
-    checkWidget.node.appendChild(label);
-    checkWidget.id = 'jp-single-document-mode';
-    this.add(checkWidget, 'top', { rank: 1010 });
+    const sdmLabel = document.createElement('label');
+    sdmLabel.className = 'jp-slider-label'
+    sdmLabel.textContent = 'Single-Document Mode';
+    sdmLabel.title = 'Single-Document Mode';
+    const sdmTrack = document.createElement('div');
+    sdmTrack.className = "jp-slider-track";
+    sdmTrack.setAttribute('aria-hidden', 'true');
+    sdmSwitch.appendChild(sdmLabel);
+    sdmSwitch.appendChild(sdmTrack);
+
+    const sdmSwitchWidget = new Widget();
+    sdmSwitchWidget.node.appendChild(sdmSwitch);
+    sdmSwitchWidget.id = 'jp-single-document-mode';
+    this.add(sdmSwitchWidget, 'top', { rank: 1010 });
 
     // Wire up signals to update the title panel of the single document mode to
     // follow the title of this.currentWidget

+ 51 - 0
packages/application/style/buttons.css

@@ -79,3 +79,54 @@ button.jp-mod-styled.jp-mod-warn:active {
   box-shadow: none;
   background-color: rgba(153, 153, 153, 0.2);
 }
+
+.jp-slider {
+  display: flex;
+  align-items: center;
+}
+
+.jp-slider-sdm {
+  border: none;
+  height: 20px;
+}
+
+.jp-slider:hover {
+  background-color: var(--jp-layout-color2);
+}
+
+.jp-slider-label {
+  margin-right: 5px;
+}
+
+.jp-slider-track {
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  background-color: var(--jp-border-color1);
+  -webkit-transition: 0.4s;
+  transition: 0.4s;
+  border-radius: 34px;
+  height: 15px;
+  width: 35px;
+}
+
+.jp-slider-track::before {
+  content: '';
+  height: 10px;
+  width: 10px;
+  margin-left: 5px;
+  margin-right: 50%;
+  background-color: white;
+  -webkit-transition: 0.4s;
+  transition: 0.4s;
+  border-radius: 50%;
+}
+
+.jp-slider[aria-checked="true"] .jp-slider-track {
+  background-color: var(--jp-warn-color0);
+}
+
+.jp-slider[aria-checked="true"] .jp-slider-track::before {
+  margin-left: 50%;
+  margin-right: 5px;
+}