Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

wicg-focus-ring

Package Overview
Dependencies
Maintainers
2
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wicg-focus-ring - npm Package Compare versions

Comparing version 1.0.1 to 2.0.0

206

dist/focus-ring.js

@@ -174,74 +174,23 @@ (function (global, factory) {

/**
* Determine if a DOM element matches a CSS selector
*
* @param {Element} elem
* @param {String} selector
* @return {Boolean}
* @api public
* https://github.com/WICG/focus-ring
*/
function matches(elem, selector) {
// Vendor-specific implementations of `Element.prototype.matches()`.
var proto = window.Element.prototype;
var nativeMatches = proto.matches ||
proto.mozMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector ||
proto.webkitMatchesSelector;
if (!elem || elem.nodeType !== 1) {
return false;
}
var parentElem = elem.parentNode;
// use native 'matches'
if (nativeMatches) {
return nativeMatches.call(elem, selector);
}
// native support for `matches` is missing and a fallback is required
var nodes = parentElem.querySelectorAll(selector);
var len = nodes.length;
for (var i = 0; i < len; i++) {
if (nodes[i] === elem) {
return true;
}
}
return false;
}
/**
* Expose `matches`
*/
var index$1 = matches;
/* https://github.com/WICG/focus-ring */
document.addEventListener('DOMContentLoaded', function() {
function init() {
var hadKeyboardEvent = false;
var keyboardThrottleTimeoutID = 0;
var elWithFocusRing;
// These elements should always have a focus ring drawn, because they are
// associated with switching to a keyboard modality.
var keyboardModalityWhitelist = [
'input:not([type])',
'input[type=text]',
'input[type=search]',
'input[type=url]',
'input[type=tel]',
'input[type=email]',
'input[type=password]',
'input[type=number]',
'input[type=date]',
'input[type=month]',
'input[type=week]',
'input[type=time]',
'input[type=datetime]',
'input[type=datetime-local]',
'textarea',
'[role=textbox]',
].join(',');
var inputTypesWhitelist = {
'text': true,
'search': true,
'url': true,
'tel': true,
'email': true,
'password': true,
'number': true,
'date': true,
'month': true,
'week': true,
'time': true,
'datetime': true,
'datetime-local': true,
};

@@ -256,3 +205,15 @@ /**

function focusTriggersKeyboardModality(el) {
return index$1(el, keyboardModalityWhitelist) && index$1(el, ':not([readonly])');
var type = el.type;
var tagName = el.tagName;
if (tagName == 'INPUT' && inputTypesWhitelist[type] && !el.readonly)
return true;
if (tagName == 'TEXTAREA' && !el.readonly)
return true;
if (el.contentEditable == 'true')
return true;
return false;
}

@@ -285,19 +246,14 @@

/**
* On `keydown`, set `hadKeyboardEvent`, to be removed 100ms later if there
* are no further keyboard events. The 100ms throttle handles cases where
* focus is redirected programmatically after a keyboard event, such as
* opening a menu or dialog.
* On `keydown`, set `hadKeyboardEvent`, add `focus-ring` class if the
* key was Tab.
* @param {Event} e
*/
function onKeyDown() {
function onKeyDown(e) {
if (e.altKey || e.ctrlKey || e.metaKey)
return;
if (e.keyCode != 9)
return;
hadKeyboardEvent = true;
// `activeElement` defaults to document.body if nothing focused,
// so check the active element is actually focused.
if (index$1(document.activeElement, ':focus'))
addFocusRingClass(document.activeElement);
if (keyboardThrottleTimeoutID !== 0)
clearTimeout(keyboardThrottleTimeoutID);
keyboardThrottleTimeoutID = setTimeout(function() {
hadKeyboardEvent = false;
keyboardThrottleTimeoutID = 0;
}, 100);
}

@@ -307,10 +263,15 @@

* On `focus`, add the `focus-ring` class to the target if:
* - a keyboard event happened in the past 100ms, or
* - the focus event target triggers "keyboard modality" and should always
* have a focus ring drawn.
* - the target received focus as a result of keyboard navigation
* - the event target is an element that will likely require interaction
* via the keyboard (e.g. a text box)
* @param {Event} e
*/
function onFocus(e) {
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target))
if (e.target == document)
return;
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {
addFocusRingClass(e.target);
hadKeyboardEvent = false;
}
}

@@ -323,10 +284,69 @@

function onBlur(e) {
if (e.target == document)
return;
removeFocusRingClass(e.target);
}
document.body.addEventListener('keydown', onKeyDown, true);
document.body.addEventListener('focus', onFocus, true);
document.body.addEventListener('blur', onBlur, true);
});
/**
* When the window regains focus, restore the focus-ring class to the element
* to which it was previously applied.
*/
function onWindowFocus() {
if (document.activeElement == elWithFocusRing)
addFocusRingClass(elWithFocusRing);
elWithFocusRing = null;
}
/**
* When switching windows, keep track of the focused element if it has a
* focus-ring class.
*/
function onWindowBlur() {
if (document.activeElement.classList.contains('focus-ring')) {
// Keep a reference to the element to which the focus-ring class is applied
// so the focus-ring class can be restored to it if the window regains
// focus after being blurred.
elWithFocusRing = document.activeElement;
}
}
document.addEventListener('keydown', onKeyDown, true);
document.addEventListener('focus', onFocus, true);
document.addEventListener('blur', onBlur, true);
window.addEventListener('focus', onWindowFocus, true);
window.addEventListener('blur', onWindowBlur, true);
document.body.classList.add('js-focus-ring');
}
/**
* Subscription when the DOM is ready
* @param {Function} callback
*/
function onDOMReady(callback) {
if (document.readyState === 'complete') {
callback();
} else {
var loaded = false;
/**
* Callback wrapper for check loaded state
*/
function load() {
if (!loaded) {
loaded = true;
callback();
}
}
document.addEventListener('DOMContentLoaded', load, false);
window.addEventListener('load', load, false);
}
}
onDOMReady(init);
})));
{
"name": "wicg-focus-ring",
"version": "1.0.1",
"version": "2.0.0",
"description": "Polyfill for :focus-ring pseudo-selector",

@@ -32,5 +32,4 @@ "scripts": {

"dependencies": {
"dom-classlist": "^1.0.1",
"dom-matches": "^2.0.0"
"dom-classlist": "^1.0.1"
}
}

@@ -1,2 +0,2 @@

[![Build Status](https://travis-ci.org/WICG/focus-ring.svg?branch=gh-pages)](https://travis-ci.org/WICG/focus-ring)
[![Build Status](https://travis-ci.org/WICG/focus-ring.svg?branch=master)](https://travis-ci.org/WICG/focus-ring)

@@ -19,7 +19,8 @@ Based on the proposed CSS

selectively disable the default focus style
by selecting for the case when `.focus-ring` is _not_ applied:
by selecting for the case when the polyfill is loaded
and `.focus-ring` is _not_ applied to the element:
```html
:focus:not(.focus-ring) {
outline: none;
.js-focus-ring :focus:not(.focus-ring) {
outline-width: 0;
}

@@ -67,3 +68,3 @@ ```

:focus {
outline: none;
outline-width: 0;
}

@@ -128,4 +129,5 @@

normatively. An example heuristic is to update modality on each style recalc:
if the most recent user interaction was via the keyboard; and less than 100ms
has elapsed since the last input event; then the modality is keyboard. Otherwise,
if the most recent user interaction was via the keyboard;
and the key pressed was either `Tab` or `Shift + Tab`;
then the modality is keyboard. Otherwise,
the modality is not keyboard.

@@ -140,5 +142,8 @@

in order for developers to be able to try it out, understand it and provide feedback.
It simply sets a `.focus-ring` class on the active element
It sets a `.js-focus-ring` class on the body element
to provide a way to disable focus styles only when the polyfill is loaded.
It also sets a `.focus-ring` class on the active element
if the script determines that the keyboard is being used.
This attribute is removed on any `blur` event.
This allows authors to write rules

@@ -153,3 +158,4 @@ which show a focus style only when it would be relevant to the user.

- a `focus` event immediately following a `keydown` event
- a `focus` event immediately following a `keydown` event where the key pressed was either `Tab`
or `Shift + Tab`.
- focus moves into an element which requires keyboard interaction,

@@ -156,0 +162,0 @@ such as a text field

import classList from 'dom-classlist';
import matches from 'dom-matches';
/* https://github.com/WICG/focus-ring */
document.addEventListener('DOMContentLoaded', function() {
/**
* https://github.com/WICG/focus-ring
*/
function init() {
var hadKeyboardEvent = false;
var keyboardThrottleTimeoutID = 0;
var elWithFocusRing;
// These elements should always have a focus ring drawn, because they are
// associated with switching to a keyboard modality.
var keyboardModalityWhitelist = [
'input:not([type])',
'input[type=text]',
'input[type=search]',
'input[type=url]',
'input[type=tel]',
'input[type=email]',
'input[type=password]',
'input[type=number]',
'input[type=date]',
'input[type=month]',
'input[type=week]',
'input[type=time]',
'input[type=datetime]',
'input[type=datetime-local]',
'textarea',
'[role=textbox]',
].join(',');
var inputTypesWhitelist = {
'text': true,
'search': true,
'url': true,
'tel': true,
'email': true,
'password': true,
'number': true,
'date': true,
'month': true,
'week': true,
'time': true,
'datetime': true,
'datetime-local': true,
};

@@ -38,3 +34,15 @@ /**

function focusTriggersKeyboardModality(el) {
return matches(el, keyboardModalityWhitelist) && matches(el, ':not([readonly])');
var type = el.type;
var tagName = el.tagName;
if (tagName == 'INPUT' && inputTypesWhitelist[type] && !el.readonly)
return true;
if (tagName == 'TEXTAREA' && !el.readonly)
return true;
if (el.contentEditable == 'true')
return true;
return false;
}

@@ -67,19 +75,14 @@

/**
* On `keydown`, set `hadKeyboardEvent`, to be removed 100ms later if there
* are no further keyboard events. The 100ms throttle handles cases where
* focus is redirected programmatically after a keyboard event, such as
* opening a menu or dialog.
* On `keydown`, set `hadKeyboardEvent`, add `focus-ring` class if the
* key was Tab.
* @param {Event} e
*/
function onKeyDown() {
function onKeyDown(e) {
if (e.altKey || e.ctrlKey || e.metaKey)
return;
if (e.keyCode != 9)
return;
hadKeyboardEvent = true;
// `activeElement` defaults to document.body if nothing focused,
// so check the active element is actually focused.
if (matches(document.activeElement, ':focus'))
addFocusRingClass(document.activeElement);
if (keyboardThrottleTimeoutID !== 0)
clearTimeout(keyboardThrottleTimeoutID);
keyboardThrottleTimeoutID = setTimeout(function() {
hadKeyboardEvent = false;
keyboardThrottleTimeoutID = 0;
}, 100);
}

@@ -89,10 +92,15 @@

* On `focus`, add the `focus-ring` class to the target if:
* - a keyboard event happened in the past 100ms, or
* - the focus event target triggers "keyboard modality" and should always
* have a focus ring drawn.
* - the target received focus as a result of keyboard navigation
* - the event target is an element that will likely require interaction
* via the keyboard (e.g. a text box)
* @param {Event} e
*/
function onFocus(e) {
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target))
if (e.target == document)
return;
if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {
addFocusRingClass(e.target);
hadKeyboardEvent = false;
}
}

@@ -105,8 +113,67 @@

function onBlur(e) {
if (e.target == document)
return;
removeFocusRingClass(e.target);
}
document.body.addEventListener('keydown', onKeyDown, true);
document.body.addEventListener('focus', onFocus, true);
document.body.addEventListener('blur', onBlur, true);
});
/**
* When the window regains focus, restore the focus-ring class to the element
* to which it was previously applied.
*/
function onWindowFocus() {
if (document.activeElement == elWithFocusRing)
addFocusRingClass(elWithFocusRing);
elWithFocusRing = null;
}
/**
* When switching windows, keep track of the focused element if it has a
* focus-ring class.
*/
function onWindowBlur() {
if (document.activeElement.classList.contains('focus-ring')) {
// Keep a reference to the element to which the focus-ring class is applied
// so the focus-ring class can be restored to it if the window regains
// focus after being blurred.
elWithFocusRing = document.activeElement;
}
}
document.addEventListener('keydown', onKeyDown, true);
document.addEventListener('focus', onFocus, true);
document.addEventListener('blur', onBlur, true);
window.addEventListener('focus', onWindowFocus, true);
window.addEventListener('blur', onWindowBlur, true);
document.body.classList.add('js-focus-ring');
}
/**
* Subscription when the DOM is ready
* @param {Function} callback
*/
function onDOMReady(callback) {
if (document.readyState === 'complete') {
callback();
} else {
var loaded = false;
/**
* Callback wrapper for check loaded state
*/
function load() {
if (!loaded) {
loaded = true;
callback();
}
}
document.addEventListener('DOMContentLoaded', load, false);
window.addEventListener('load', load, false);
}
}
onDOMReady(init);

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc