focus-within-polyfill
Advanced tools
Comparing version 3.1.0 to 4.0.0
@@ -0,1 +1,13 @@ | ||
# [4.0.0](https://github.com/matteobad/focus-within-polyfill/compare/v3.1.0...v4.0.0) (2019-05-01) | ||
### Features | ||
* add new option and polyfill with attribute ([0d8bfeb](https://github.com/matteobad/focus-within-polyfill/commit/0d8bfeb)), closes [#11](https://github.com/matteobad/focus-within-polyfill/issues/11) | ||
### BREAKING CHANGES | ||
* attributes support | ||
# [3.1.0](https://github.com/matteobad/focus-within-polyfill/compare/v3.0.1...v3.1.0) (2019-04-26) | ||
@@ -2,0 +14,0 @@ |
@@ -1,2 +0,2 @@ | ||
!function(o,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((o=o||self).focusWithin={})}(this,function(o){"use strict";var e,n;function t(o){var n,t;t||(window.requestAnimationFrame(function(){if(n=document.activeElement,t=!1,Array.prototype.slice.call(document.getElementsByClassName(e)).forEach(function(o){o.classList.remove(e)}),"focus"===o.type&&n&&n!==document.body)for(var i=n;i&&1===i.nodeType;i=i.parentNode)i.classList.add(e)}),t=!0)}o.loadPolyfill=function(o){!function(o){return"string"!=typeof o?(console.error("focus-within-polyfill:"+o+" is not a string"),!1):/[\s]/.test(o)?(console.error('focus-within-polyfill: class name "className" cannot contain white spaces.'),!1):/-?[_a-zA-Z]+[_-a-zA-Z0-9]*/.test(o)}(e=o||"focus-within")?console.warn("focus-within-polyfill: cannot load. "+e+" is not a valid class name"):n||function(){try{return document.querySelector(":focus-within"),console.info("focus-within-polyfill: focus-within supported"),!0}catch(o){return console.info("focus-within-polyfill: focus-within not supported"),!1}}()||(document.addEventListener("focus",t,!0),document.addEventListener("blur",t,!0),n=!0,console.info("focus-within-polyfill: loaded."))},o.unloadPolyfill=function(){n?(document.removeEventListener("focus",t,!0),document.removeEventListener("blur",t,!0),n=!1,console.info("focus-within-polyfill: unloaded.")):console.warn("focus-within-polyfill: cannot unload. Polyfill was never loaded.")},Object.defineProperty(o,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).focusWithin=t()}(this,function(){"use strict";function e(e,t,o){var n=e.getAttribute(t)||"";-1===n.indexOf(o)&&(n=(n+" "+o).trim(),e.setAttribute(t,n))}return{polyfill:function(t){if(t){if("string"!=typeof t)throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a string.')`);if("."!==t.charAt(0)&&"["!==t.charAt(0)&&"]"!==t.charAt(t.length-1))throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a valid selector.')`);try{document.querySelector(t)}catch(e){throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a valid selector.')`)}}var o,n,r,i;r=0===(t=t||"[focus-within]").indexOf("."),o=r?"class":t.replace(/[[\]']+/g,""),n=r?t.replace(".",""):o;var c=function(r){var i,c;c||(window.requestAnimationFrame(function(){if(i=document.activeElement,c=!1,Array.prototype.slice.call(document.querySelectorAll(t)).forEach(function(e){var t,r,i,c;r=o,i=n,-1!==(c=(t=e).getAttribute(r)||"").indexOf(i)&&(""!==(c=c.replace(i,"").trim())?t.setAttribute(r,c):t.removeAttribute(r))}),"focus"===r.type&&i&&i!==document.body)for(var u=i;u&&1===u.nodeType;u=u.parentNode)e(u,o,n)}),c=!0)};return(i=!function(){try{return document.querySelector(":focus-within"),console.info("focus-within-polyfill: focus-within supported"),!0}catch(e){return console.info("focus-within-polyfill: focus-within not supported"),!1}}())&&(document.addEventListener("focus",c,!0),document.addEventListener("blur",c,!0)),i}}}); | ||
//# sourceMappingURL=focus-within-polyfill.js.map |
{ | ||
"name": "focus-within-polyfill", | ||
"version": "3.1.0", | ||
"version": "4.0.0", | ||
"description": "focus-within pseudo selector polyfill", | ||
@@ -11,3 +11,4 @@ "main": "dist/focus-within-polyfill.js", | ||
"clean": "rimraf dist", | ||
"lint": "eslint src test", | ||
"lint": "eslint src/** test/**", | ||
"lint:fix": "eslint src/** test/** --fix", | ||
"build": "rollup -c rollup.config.js --environment BUILD:production", | ||
@@ -45,2 +46,3 @@ "watch": "rollup -c rollup.config.js --environment BUILD:development -w", | ||
"@semantic-release/git": "^7.0.8", | ||
"@semantic-release/github": "^5.2.10", | ||
"@semantic-release/npm": "^5.1.4", | ||
@@ -51,2 +53,7 @@ "@semantic-release/release-notes-generator": "^7.1.4", | ||
"eslint": "^5.16.0", | ||
"eslint-config-standard": "^12.0.0", | ||
"eslint-plugin-import": "^2.17.2", | ||
"eslint-plugin-node": "^8.0.1", | ||
"eslint-plugin-promise": "^4.1.1", | ||
"eslint-plugin-standard": "^4.0.0", | ||
"husky": "^2.1.0", | ||
@@ -53,0 +60,0 @@ "npm-check": "^5.9.0", |
# `:focus-within` Pseudo-Class Polyfill | ||
[![npm version](https://badge.fury.io/js/focus-within-polyfill.svg)](https://badge.fury.io/js/focus-within-polyfill) [![Build Status](https://travis-ci.org/matteobad/focus-within-polyfill.svg?branch=master)](https://travis-ci.org/matteobad/focus-within-polyfill/) | ||
[![npm version](https://badge.fury.io/js/focus-within-polyfill.svg)](https://badge.fury.io/js/focus-within-polyfill) [![Build Status](https://travis-ci.org/matteobad/focus-within-polyfill.svg?branch=master)](https://travis-ci.org/matteobad/focus-within-polyfill/) ![David](https://img.shields.io/david/dev/matteobad/focus-within-polyfill.svg) ![David](https://img.shields.io/david/matteobad/focus-within-polyfill.svg) [![Greenkeeper badge](https://badges.greenkeeper.io/matteobad/focus-within-polyfill.svg)](https://greenkeeper.io/) | ||
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) ![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-blue.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) | ||
* [How to use](#hot-to-use) | ||
* [Notes](#notes) | ||
* [Browser support](#browser-support) | ||
* [:focus-within MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within) | ||
* [`:focus-within`](#focus-within) | ||
This package will add two event listeners, one on the *focus* event and one on the *blur* event to trigger the automatic apply and remove of a custom attribute to indicate wheter the Element should have a `:focus-within` pseudo-class. In order to do so and be compatible with older version of IE and Edge the `setAttribute` method is used to set both attributes and classes. This will prevent error like: *`classList` is undefined for SVG Element*. | ||
## `:focus-within` | ||
The `:focus-within` CSS pseudo-class represents an element that has received focus or contains an element that has received focus. In other words, it represents an element that is itself matched by the :focus pseudo-class or has a descendant that is matched by :focus. | ||
@@ -25,19 +31,26 @@ | ||
When the polyfill is included via a script tag it will create a `focusWithin` object with `loadPolyfill(string)` and `unloadPolyfill()` methods to initialize and removed the polyfill. In addition this library is available as a es6 module that can be imported and bundled up with any build tools. | ||
When including the polyfill in a script tag, call `window.focusWithin.polyfill(string)` method to initialize the polyfill: | ||
After import and initialization the polyfill will kick in *only* if `:focus-within` is not supported in the current context. The `.focus-within` class will be added to every element that should have the pseudo-class as needed. Additionally in the initialization fase a custom class can be specified like in the example below. | ||
```javascript | ||
/* ES5 */ | ||
<script src='https://unpkg.com/focus-within-polyfill/dist/focus-within-polyfill.js'></script> | ||
focusWithin.polyfill() | ||
``` | ||
In addition this library is available as a es6 module that can be imported and bundled up with any build tool. If you are importing it as a dependency, make sure to call the polyfill method: | ||
```javascript | ||
/* ES6 */ | ||
import { loadPolyfill, unloadPolyfill } from 'focus-within-polyfill' | ||
import focusWithin from 'focus-within-polyfill' | ||
loadPolyfill('my-class') // load polyfill | ||
unloadPolyfill() // unload polyfill | ||
focusWithin.polyfill() | ||
``` | ||
After import and initialization the polyfill will kick in **only** if `:focus-within` is not supported in the current browser. By default the `[focus-within]` attribute will be added automatically to every element that should have the pseudo-class. Additionally in the initialization fase a **custom class** or **custom attribute** can be specified like in the example below: | ||
/* ES5 */ | ||
<script src='path/to/focus-within-polyfill.js'></script> | ||
focusWithin.loadPolyfill() // load polyfill | ||
focusWithin.unloadPolyfill() // unload polyfill | ||
```javascript | ||
focusWithin.polyfill('[focus-within]'); // default | ||
focusWithin.polyfill('[focus-inside]'); // custom attribute | ||
focusWithin.polyfill('.focus-within'); // custom class | ||
``` | ||
@@ -44,0 +57,0 @@ |
@@ -1,65 +0,81 @@ | ||
import { supportsFocusWithin, validClassName } from './utils' | ||
import supportsFocusWithin from './utils/supportsFocusWithin' | ||
import addAttribute from './utils/addAttribute' | ||
import removeAttribute from './utils/removeAttribute' | ||
var focusWithinClass, loaded | ||
/** | ||
* Update focus-within class on focus and blur events | ||
* @param {FocusEvent} e | ||
* Load polyfill and return loading state boolean | ||
* | ||
* @param {String} selector | ||
* @returns {Boolean} | ||
* @throws {TypeError} | ||
*/ | ||
function update(e) { | ||
var element, running | ||
function polyfill (selector) { | ||
if (selector) { | ||
// check if selector is a string | ||
if (typeof selector !== 'string') { | ||
throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a string.')`) | ||
} | ||
var action = function() { | ||
element = document.activeElement | ||
running = false | ||
// check if selector is class or attribute | ||
if (selector.charAt(0) !== '.' && (selector.charAt(0) !== '[' && selector.charAt(selector.length - 1) !== ']')) { | ||
throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a valid selector.')`) | ||
} | ||
Array.prototype.slice | ||
.call(document.getElementsByClassName(focusWithinClass)) | ||
.forEach(function(el) { el.classList.remove(focusWithinClass) }) | ||
if (e.type === 'focus' && element && element !== document.body) | ||
for (var el = element; el && el.nodeType === 1; el = el.parentNode) | ||
el.classList.add(focusWithinClass) | ||
// check if valid selector | ||
try { | ||
document.querySelector(selector) | ||
} catch (error) { | ||
throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a valid selector.')`) | ||
} | ||
} | ||
if (!running) { | ||
window.requestAnimationFrame(action) | ||
running = true | ||
} | ||
} | ||
var attributeName, attributeValue, isClass, loaded | ||
/** | ||
* Load polyfill | ||
* @param {String} className | ||
* @returns {void} | ||
*/ | ||
export function loadPolyfill(className) { | ||
focusWithinClass = className || 'focus-within' | ||
if (!validClassName(focusWithinClass)) { | ||
console.warn('focus-within-polyfill: cannot load. ' + focusWithinClass + ' is not a valid class name') | ||
return | ||
} | ||
selector = selector || '[focus-within]' | ||
isClass = selector.indexOf('.') === 0 | ||
attributeName = !isClass ? selector.replace(/[[\]']+/g, '') : 'class' | ||
attributeValue = !isClass ? attributeName : selector.replace('.', '') | ||
if (!loaded && !supportsFocusWithin()) { | ||
document.addEventListener('focus', update, true) | ||
document.addEventListener('blur', update, true) | ||
loaded = true | ||
console.info('focus-within-polyfill: loaded.') | ||
/** | ||
* - Remove all applied attributes and | ||
* - Add new attributes based on activeElement | ||
* | ||
* @param {FocusEvent} e | ||
*/ | ||
var handler = function (e) { | ||
var element, running | ||
var _action = function () { | ||
element = document.activeElement | ||
running = false | ||
Array.prototype.slice | ||
.call(document.querySelectorAll(selector)) | ||
.forEach(function (el) { removeAttribute(el, attributeName, attributeValue) }) | ||
if (e.type === 'focus' && element && element !== document.body) { | ||
for (var el = element; el && el.nodeType === 1; el = el.parentNode) { | ||
addAttribute(el, attributeName, attributeValue) | ||
} | ||
} | ||
} | ||
if (!running) { | ||
window.requestAnimationFrame(_action) | ||
running = true | ||
} | ||
} | ||
} | ||
/** | ||
* Unload polyfill | ||
* @returns {void} | ||
*/ | ||
export function unloadPolyfill() { | ||
if (!loaded) { | ||
console.warn('focus-within-polyfill: cannot unload. Polyfill was never loaded.') | ||
return | ||
// kick off polyfill | ||
loaded = !supportsFocusWithin() | ||
if (loaded) { | ||
document.addEventListener('focus', handler, true) | ||
document.addEventListener('blur', handler, true) | ||
} | ||
document.removeEventListener('focus', update, true) | ||
document.removeEventListener('blur', update, true) | ||
loaded = false | ||
console.info('focus-within-polyfill: unloaded.') | ||
return loaded | ||
} | ||
export default { | ||
polyfill: polyfill | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
30912
21
153
69
22
1