New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

focus-within-polyfill

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

focus-within-polyfill - npm Package Compare versions

Comparing version 4.0.0 to 4.1.0

7

CHANGELOG.md

@@ -0,1 +1,8 @@

# [4.1.0](https://github.com/matteobad/focus-within-polyfill/compare/v4.0.0...v4.1.0) (2019-05-02)
### Features
* add support for shadow dom ([01707bf](https://github.com/matteobad/focus-within-polyfill/commit/01707bf))
# [4.0.0](https://github.com/matteobad/focus-within-polyfill/compare/v3.1.0...v4.0.0) (2019-05-01)

@@ -2,0 +9,0 @@

2

dist/focus-within-polyfill.js

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

!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}}});
!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";return{polyfill:function(e){var t,r,o,n;if(e){if("string"!=typeof e)throw new TypeError('Failed to execute "polyfill" on "focusWithin":parameter 1 ("selector") is not a string.');if("."!==e.charAt(0)&&"["!==e.charAt(0)&&"]"!==e.charAt(e.length-1))throw new TypeError('Failed to execute "polyfill" on "focusWithin":parameter 1 ("selector") is not a valid selector.');try{document.querySelector(e)}catch(e){throw new TypeError('Failed to execute "polyfill" on "focusWithin":parameter 1 ("selector") is not a valid selector.')}}function i(e){for(var t=[];e&&(1===e.nodeType||11===e.nodeType);)11!==e.nodeType?(t.push(e),e=e.parentNode):e=e.host;return t}function c(e){var c;o=function(){for(var e=document.activeElement;e&&e.shadowRoot&&e.shadowRoot.activeElement;)e=e.shadowRoot.activeElement;return e}(),c||(window.requestAnimationFrame(function(){var a,u;c=!1,Array.prototype.slice.call(i(n)).forEach((a=t,u=r,function(e){var t=e.getAttribute(a)||"";if(-1!==t.indexOf(u)){var r=t.replace(u,"").trim();""===r?e.removeAttribute(a):e.setAttribute(a,r)}})),n=o,"focus"===e.type&&o&&Array.prototype.slice.call(i(o)).forEach(function(e,t){return function(r){var o=r.getAttribute(e)||"";if(-1===o.indexOf(t)){var n=(o+" "+t).trim();r.setAttribute(e,n)}}}(t,r))}),c=!0)}e=0!==(e=e||"[focus-within]").indexOf(".")?t=r=e.replace(/[[\]']+/g,""):(t="class",r=e.replace(".",""));try{return document.querySelector(":focus-within"),!0}catch(e){return document.addEventListener("focus",c,!0),document.addEventListener("blur",c,!0),!1}}}});
//# sourceMappingURL=focus-within-polyfill.js.map
{
"name": "focus-within-polyfill",
"version": "4.0.0",
"version": "4.1.0",
"description": "focus-within pseudo selector polyfill",

@@ -21,9 +21,4 @@ "main": "dist/focus-within-polyfill.js",

"homepage": "https://github.com/matteobad/focus-within-polyfill#readme",
"repository": {
"type": "git",
"url": "https://github.com/matteobad/focus-within-polyfill"
},
"bugs": {
"url": "https://github.com/matteobad/focus-within-polyfill/issues"
},
"repository": "https://github.com/matteobad/focus-within-polyfill",
"bugs": "https://github.com/matteobad/focus-within-polyfill/issues",
"keywords": [

@@ -37,3 +32,5 @@ "polyfill",

"vanilla",
"vanilla-js"
"vanilla-js",
"webcomponents",
"shadowRoot"
],

@@ -67,5 +64,2 @@ "author": "Matteo Badini",

},
"browserslist": [
"defaults"
],
"config": {

@@ -72,0 +66,0 @@ "commitizen": {

@@ -7,12 +7,11 @@ # `:focus-within` Pseudo-Class Polyfill

* [How to use](#hot-to-use)
* [Notes](#notes)
* [How it works](#how-it-works)
* [Features](#features)
* [Browser support](#browser-support)
* [`:focus-within`](#focus-within)
* [Demo](#demo)
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*.
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`. (This includes descendants in shadow trees.)
## `:focus-within`
This selector is useful, to take a common example, for highlighting an entire `<form>` container when the user focuses on one of its `<input>` fields.
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.
More information on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within).

@@ -58,13 +57,24 @@

## Notes
## How it works
This polyfill does not support shadow DOM. The goal is to polyfill a feature that is missing in IE and EDGE and since shadow DOM is another feature that [needs polyfilling](https://caniuse.com/#feat=shadowdomv1) in this browser I won't implement such feature, but any PR is well accepted.
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 `getAttribute`, `setAttribute` and `removeAttribute` methods are used to set both attributes and classes. Then `requestAnimationFrame` is used to apply the modification to the DOM.
This polyfill is compatible with native [Shadow DOM](https://developers.google.com/web/fundamentals/web-components/shadowdom#what) and with the [webcomponents polyfill](https://www.webcomponents.org/polyfills/). This means that even on IE11 and EDGE you will be able to use the `:focus-within` pseudo-class to style elements even outside a shadowRoot.
## Features
* _Custom attribute/class_ value to apply the polyfill
* _Shady CSS/DOM_ support even with the [webcomponents polyfill](https://www.webcomponents.org/polyfills/)
* _Non standard Element_ support, like SVG Element with link inside
## Browser Support
* _Natively supported in Chrome_
* _Natively supported in Firefox_
* _Natively supported in Safari_
* _Natively supported in Opera_
* IE 10+
* Edge
| Polyfill | Edge | IE9+ | Chrome | Firefox | Safari |
| --------------- |:----:|:----:|:------:|:-------:|:------:|
| `:focus-within` | ✓ | ✓ | ✓ | ✓ | ✓ |
\* This polyfill maybe work on older versions of the browsers.
## Demo
You can try a working demo [here](https://matteobad.github.io/focus-within-polyfill).

@@ -1,5 +0,1 @@

import supportsFocusWithin from './utils/supportsFocusWithin'
import addAttribute from './utils/addAttribute'
import removeAttribute from './utils/removeAttribute'
/**

@@ -13,6 +9,11 @@ * Load polyfill and return loading state boolean

function polyfill (selector) {
var attrName, attrValue, activeElement, lastActiveElement
// Sanity check
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.')`)
throw new TypeError(
'Failed to execute "polyfill" on "focusWithin":' +
'parameter 1 ("selector") is not a string.')
}

@@ -22,5 +23,6 @@

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.')`)
throw new TypeError(
'Failed to execute "polyfill" on "focusWithin":' +
'parameter 1 ("selector") is not a valid selector.')
}
// check if valid selector

@@ -30,39 +32,109 @@ try {

} catch (error) {
throw new TypeError(`Failed to execute '${this.name}' on 'FocusWithin': parameter 1 ('selector') is not a valid selector.')`)
throw new TypeError(
'Failed to execute "polyfill" on "focusWithin":' +
'parameter 1 ("selector") is not a valid selector.')
}
}
var attributeName, attributeValue, isClass, loaded
// Variables initialization
selector = selector || '[focus-within]'
isClass = selector.indexOf('.') === 0
attributeName = !isClass ? selector.replace(/[[\]']+/g, '') : 'class'
attributeValue = !isClass ? attributeName : selector.replace('.', '')
selector = (selector.indexOf('.') !== 0)
? (attrName = attrValue = selector.replace(/[[\]']+/g, ''))
: (attrName = 'class', attrValue = selector.replace('.', ''))
/**
* - Remove all applied attributes and
* - Add new attributes based on activeElement
* Find and return the current Element with focus.
* This will loop through shadow DOM.
*
* @returns {Element}
*/
function findActiveElement () {
var activeEl = document.activeElement
while (activeEl && activeEl.shadowRoot && activeEl.shadowRoot.activeElement) {
activeEl = activeEl.shadowRoot.activeElement
}
return activeEl
}
/**
* Create and return the event path from root to element.
* The computed path includes element inside a shadowRoot.
*
* @param {Element} el
* @returns {Array}
*/
function computeEventPath (el) {
var path = []
while (el && (el.nodeType === 1 || el.nodeType === 11)) {
if (el.nodeType !== 11) {
path.push(el)
el = el.parentNode
} else {
el = el.host
}
}
return path
}
/**
* Add user defined attribute to element retaining any previously applied attributes.
* Attribute can be the 'class' attribute for compatibility reasons.
*
* @param {String} name
* @param {String} value
*/
function addAttribute (name, value) {
return function (el) {
var attributes = el.getAttribute(name) || ''
if (attributes.indexOf(value) === -1) {
var newAttributes = (attributes + ' ' + value).trim()
el.setAttribute(name, newAttributes)
}
}
}
/**
* Remove user defined attribute value or entire attribute if last one.
* Attribute can be the 'class' attribute for compatibility reasons.
*
* @param {String} name
* @param {String} value
*/
function removeAttribute (name, value) {
return function (el) {
var attributes = el.getAttribute(name) || ''
if (attributes.indexOf(value) !== -1) {
var newAttributes = attributes.replace(value, '').trim()
if (newAttributes === '') el.removeAttribute(name)
else el.setAttribute(name, newAttributes)
}
}
}
/**
* Use rAF to remove and apply custom attribute on FocusEvent.
*
* @param {FocusEvent} e
*/
var handler = function (e) {
var element, running
function handler (e) {
var running
activeElement = findActiveElement()
var _action = function () {
element = document.activeElement
function action () {
running = false
Array.prototype.slice
.call(document.querySelectorAll(selector))
.forEach(function (el) { removeAttribute(el, attributeName, attributeValue) })
.call(computeEventPath(lastActiveElement))
.forEach(removeAttribute(attrName, attrValue))
if (e.type === 'focus' && element && element !== document.body) {
for (var el = element; el && el.nodeType === 1; el = el.parentNode) {
addAttribute(el, attributeName, attributeValue)
}
}
lastActiveElement = activeElement
if (e.type !== 'focus' || !activeElement) return
Array.prototype.slice
.call(computeEventPath(activeElement))
.forEach(addAttribute(attrName, attrValue))
}
if (!running) {
window.requestAnimationFrame(_action)
window.requestAnimationFrame(action)
running = true

@@ -72,10 +144,10 @@ }

// kick off polyfill
loaded = !supportsFocusWithin()
if (loaded) {
try {
document.querySelector(':focus-within')
return true
} catch (error) {
document.addEventListener('focus', handler, true)
document.addEventListener('blur', handler, true)
return false
}
return loaded
}

@@ -82,0 +154,0 @@

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

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