Skip to content

Commit

Permalink
feat(plugin): add focus tracker plugin
Browse files Browse the repository at this point in the history
closes #127
  • Loading branch information
ericrallen committed Mar 16, 2019
1 parent 00a3159 commit 467bd28
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 4 deletions.
4 changes: 2 additions & 2 deletions plugins/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ let InfoPanel = require("./shared/info-panel");
require("./style.less");

class Plugin {
constructor() {
this.panel = new InfoPanel(this);
constructor(options = {}) {
this.panel = new InfoPanel(this, options.panel);
this.$checkbox = null;
}

Expand Down
97 changes: 97 additions & 0 deletions plugins/focus-tracker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Allows users to see what screen readers would see.
*/

let Plugin = require("../base");

const FOCUS_EVENT = "focusin";
const BLUR_EVENT = "focusout";

// this will let us get a shorter info panel that just
// lets the user know we are tracking their focus
const PANEL_OPTIONS = {
statusPanelView: true
};

// we're going to use focusin and focusout because they bubble
const FOCUS_STATES = {
[FOCUS_EVENT]: "tota11y-outlined",
[BLUR_EVENT]: "tota11y-was-focused"
};

// we'll use this to make sure we don't apply the was-focused
// indicator to our tota11y panels
const IGNORE_WAS_FOCUSED_CLASS = "tota11y";

// convenient method to quickly remove any classes this
// plugin applied
// it is outside of the class because it doesn't really need
// to access this and it lets us now worry about binding
// our event handlers
const removeFocusClasses = (element) => {
element.classList.remove(...Object.values(FOCUS_STATES));
};

require("./style.less");

class FocusTracker extends Plugin {
constructor(...args) {
const options = Object.assign({}, args, { panel: PANEL_OPTIONS });

super(options);
}

getTitle() {
return "Focus Tracker";
}

getDescription() {
return "Keep track of what's been focused as you tab through the page";
}

applyFocusClass(event) {
// get the event target and event name
const { target, type } = event;

// remove any focused or was-focused indicators on the element
removeFocusClasses(target);

// choose the class we want to add to this element
// based on whether this is the focusin or focusout event
const classToAdd = FOCUS_STATES[type];

// we want to ignore our tota11y toggle and panel because
// the user probably only cares about focusable elements on
// their page getting this visual treatment
if (type === FOCUS_EVENT || target.closest(`.${IGNORE_WAS_FOCUSED_CLASS}`) === null) {
target.classList.add(classToAdd);
}
}

run() {
// pop up our info panel to let the user know what we're doing
this.summary("Tracking Focus");
this.panel.render();

// dynamically apply our event listeners by looping through
// our defined focus states and adding an event handler
Object.keys(FOCUS_STATES).forEach((key) => {
document.addEventListener(key, this.applyFocusClass);
});
}

cleanup() {
// dynamically remove our event listeners by looping through
// our defined focus states and removing the event handler
Object.keys(FOCUS_STATES).forEach((key) => {
document.removeEventListener(key, this.applyFocusClass);

// we'll also want to clean up all of the classes we added
[...document.querySelectorAll(`.${FOCUS_STATES[key]}`)].forEach((element) => {
removeFocusClasses(element);
});
});
}
}

module.exports = FocusTracker;
9 changes: 9 additions & 0 deletions plugins/focus-tracker/style.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "../../less/variables.less";

.tota11y-outlined {
outline: 2px solid fadein(@highlightColor, 100%);
}

.tota11y-was-focused {
outline: 2px dashed fadein(@highlightColor, 80%);
}
2 changes: 2 additions & 0 deletions plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ let LabelsPlugin = require("./labels");
let LandmarksPlugin = require("./landmarks");
let LinkTextPlugin = require("./link-text");
let A11yTextWand = require("./a11y-text-wand");
let FocusTracker = require("./focus-tracker");

module.exports = {
default: [
Expand All @@ -24,5 +25,6 @@ module.exports = {

experimental: [
new A11yTextWand(),
new FocusTracker(),
],
};
12 changes: 10 additions & 2 deletions plugins/shared/info-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ require("./style.less");
const INITIAL_PANEL_MARGIN_PX = 10;
const COLLAPSED_CLASS_NAME = "tota11y-collapsed";
const HIDDEN_CLASS_NAME = "tota11y-info-hidden";
const STATUS_PANEL_VIEW_CLASS_NAME = "tota11y-info-status-panel-view";

class InfoPanel {
constructor(plugin) {
constructor(plugin, options = {}) {
this.plugin = plugin;
this.options = options;

this.about = null;
this.summary = null;
Expand Down Expand Up @@ -187,8 +189,14 @@ class InfoPanel {

let hasContent = false;

const classNames = ["tota11y", "tota11y-info"];

if (this.options.statusPanelView) {
classNames.push(STATUS_PANEL_VIEW_CLASS_NAME);
}

this.$el = (
<div className="tota11y tota11y-info" tabindex="-1">
<div className={classNames.join(" ")} tabindex="-1">
<header className="tota11y-info-title">
{this.plugin.getTitle()}
<span className="tota11y-info-controls">
Expand Down
14 changes: 14 additions & 0 deletions plugins/shared/info-panel/style.less
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
@panelBodyWidth: 400px;
@panelBodyHeight: 270px;

@statusPanelHeight: 35px;

@tabHoverColor: #555;
@tabActiveColor: @white;

Expand Down Expand Up @@ -86,12 +88,20 @@
&.active &-anchor-text {
color: @darkGray;
}

.tota11y-info-status-panel-view & {
display: none;
}
}

&-sections {
position: relative;
height: @panelBodyHeight;
width: @panelBodyWidth;

.tota11y-info-status-panel-view & {
height: @statusPanelHeight;
}
}

&-section {
Expand All @@ -109,6 +119,10 @@
&.active {
display: block;
}

.tota11y-info-status-panel-view & {
overflow: hidden;
}
}

&-errors {
Expand Down

0 comments on commit 467bd28

Please sign in to comment.