From cb29d5cf68d4d6b52e491e467ed7a6a11a65019a Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Wed, 13 Oct 2021 09:58:39 +0200 Subject: [PATCH 01/12] Initial --- .babelrc | 8 +-- index.html | 11 +++- src/lazyframe.js | 164 ++++++++++++++--------------------------------- 3 files changed, 58 insertions(+), 125 deletions(-) diff --git a/.babelrc b/.babelrc index b4c0c62..aba07e3 100644 --- a/.babelrc +++ b/.babelrc @@ -1,14 +1,12 @@ { "presets": [ [ - "@babel/env", + "@babel/preset-env", { "modules": false, - "forceAllTransforms": true + "forceAllTransforms": true, + "targets": "> 0.005%" } ] - ], - "plugins": [ - "@babel/plugin-transform-object-assign" ] } diff --git a/index.html b/index.html index cb6279d..34bce60 100644 --- a/index.html +++ b/index.html @@ -53,7 +53,7 @@

Youtube video with thumbnail and title from API

-
+

Youtube video with custom thumbnail and title

@@ -82,9 +82,14 @@ data-title="Something completely different" data-initinview="true">
- + diff --git a/src/lazyframe.js b/src/lazyframe.js index 3967dc9..7d33bd0 100644 --- a/src/lazyframe.js +++ b/src/lazyframe.js @@ -2,6 +2,8 @@ import './scss/lazyframe.scss' const Lazyframe = () => { + const findVendorIdAndQuery = new RegExp(/^(?:https?:\/\/)?(?:www\.)?(youtube-nocookie|youtube|vimeo)(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([\w-_]+)(?:\&|\?|\/\?)?(.+)?$/); + let settings; const elements = []; @@ -23,41 +25,8 @@ const Lazyframe = () => { onThumbnailLoad: (img) => {} }; - const constants = { - regex: { - youtube_nocookie: /(?:youtube-nocookie\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=)))([a-zA-Z0-9_-]{6,11})/, - youtube: /(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})/, - vimeo: /vimeo\.com\/(?:video\/)?([0-9]*)(?:\?|)/, - }, - condition: { - youtube: (m) => (m && m[1].length == 11 ? m[1] : false), - youtube_nocookie: (m) => (m && m[1].length == 11 ? m[1] : false), - vimeo: (m) => - (m && m[1].length === 9) || m[1].length === 8 ? m[1] : false, - }, - src: { - youtube: (s) => - `https://www.youtube.com/embed/${s.id}/?autoplay=${ - s.autoplay ? "1" : "0" - }&${s.query}`, - youtube_nocookie: (s) => - `https://www.youtube-nocookie.com/embed/${s.id}/?autoplay=${ - s.autoplay ? "1" : "0" - }&${s.query}`, - vimeo: (s) => - `https://player.vimeo.com/video/${s.id}/?autoplay=${ - s.autoplay ? "1" : "0" - }&${s.query}`, - }, - endpoint: (s) => `https://noembed.com/embed?url=${s.src}`, - response: { - title: (r) => r.title, - thumbnail: (r) => r.thumbnail_url, - }, - }; - function init(elements, ...args) { - settings = Object.assign({}, defaults, args[0]); + settings = {...defaults, ...args[0]}; if (typeof elements === 'string') { @@ -87,8 +56,9 @@ const Lazyframe = () => { function loop(el) { - if(el instanceof HTMLElement === false || - el.classList.contains('lazyframe--loaded')) return; + if (el instanceof HTMLElement === false || el.classList.contains('lazyframe--loaded')) { + return; + } const lazyframe = { el: el, @@ -97,109 +67,67 @@ const Lazyframe = () => { lazyframe.el.addEventListener('click', () => { lazyframe.el.appendChild(lazyframe.iframe); - - const iframe = el.querySelectorAll('iframe'); - lazyframe.settings.onAppend.call(this, iframe[0]); + lazyframe.settings.onAppend.call(this, el.querySelector('iframe')); }); if (settings.lazyload) { - build(lazyframe); + build(lazyframe, false); } else { - api(lazyframe, !!lazyframe.settings.thumbnail); + api(lazyframe); } } function setup(el) { - const attr = Array.prototype.slice.apply(el.attributes) + const attributes = Array.from(el.attributes) .filter(att => att.value !== '') - .reduce((obj, curr) => { - let name = curr.name.indexOf('data-') === 0 ? curr.name.split('data-')[1] : curr.name; - obj[name] = curr.value; + .filter(att => att.name.startsWith('data-')) + .reduce((obj, { name, value }) => { + const key = name.split('data-')[1]; + obj[key] = value; return obj; }, {}); - const options = Object.assign({}, - settings, - attr, - { + if (!attributes.src) { + throw new Error('You must supply a data-src on the DOM Node'); + } + + const [,vendor, id, query = ''] = attributes.src.match(findVendorIdAndQuery) || []; + return { + ...settings, + ...attributes, + ...{ y: el.offsetTop, - originalSrc: attr.src, - query: getQuery(attr.src) + id, + vendor, + query: `${query}${query ? '&' : ''}autoplay=${settings.autoplay ? '1' : '0'}` } - ); - - if (options.vendor) { - const match = options.src.match(constants.regex[options.vendor]); - options.id = constants.condition[options.vendor](match); - } - - return options; - - } - - function getQuery(src) { - const query = src.split('?'); - return query[1] ? query[1] : null - } + }; - function useApi(settings) { - if (!settings.vendor) return false; - return !settings.title || !settings.thumbnail; } function api(lazyframe) { - - if (useApi(lazyframe.settings)) { - send(lazyframe, (err, data) => { - if (err) return; - - const response = data[0]; - const _l = data[1]; - - if (!_l.settings.title) { - _l.settings.title = constants.response.title(response); - } - if (!_l.settings.thumbnail) { - const url = constants.response.thumbnail(response); - _l.settings.thumbnail = url; - lazyframe.settings.onThumbnailLoad.call(this, url); - } - build(_l, true); - - }); - + if (lazyframe.settings.vendor) { + fetch(`https://noembed.com/embed?url=${lazyframe.settings.src}`) + .then(res => res.json()) + .then(json => { + if (!lazyframe.settings.title) { + lazyframe.settings.title = json.title + } + if (!lazyframe.settings.thumbnail) { + lazyframe.settings.thumbnail = json.thumbnail_url; + lazyframe.settings.onThumbnailLoad.call(this, json.thumbnail_url); + } + + build(lazyframe, true); + }) }else{ build(lazyframe, true); } } - function send(lazyframe, cb) { - - const endpoint = constants.endpoint(lazyframe.settings); - const request = new XMLHttpRequest(); - - request.open('GET', endpoint, true); - - request.onload = function() { - if (request.status >= 200 && request.status < 400) { - const data = JSON.parse(request.responseText); - cb(null, [data, lazyframe]); - } else { - cb(true); - } - }; - - request.onerror = function() { - cb(true); - }; - - request.send(); - - } - function scroll() { const height = window.innerHeight; @@ -269,8 +197,8 @@ const Lazyframe = () => { } if (lazyframe.settings.title && lazyframe.el.children.length === 0) { - const docfrag = document.createDocumentFragment(), - titleNode = document.createElement('span'); + const docfrag = document.createDocumentFragment(); + const titleNode = document.createElement('span'); titleNode.className = 'lazyframe__title'; titleNode.innerHTML = lazyframe.settings.title; @@ -296,8 +224,10 @@ const Lazyframe = () => { const docfrag = document.createDocumentFragment(); const iframeNode = document.createElement('iframe'); - if (settings.vendor) { - settings.src = constants.src[settings.vendor](settings); + if (settings.vendor === 'youtube' || settings.vendor === 'youtube-nocookie') { + settings.src = `https://www.${settings.vendor}.com/embed/${settings.id}/?${settings.query}`; + } else if (settings.vimeo) { + settings.src = `https://player.vimeo.com/video/${s.id}/?${settings.query}` } iframeNode.setAttribute('id', `lazyframe-${settings.id}`); From 6d2c5e1175f1344e7c62434c25d16c859d41da66 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Thu, 14 Oct 2021 14:33:07 +0200 Subject: [PATCH 02/12] more fixes --- src/lazyframe.js | 325 +++++++++++++++++++++++------------------------ 1 file changed, 156 insertions(+), 169 deletions(-) diff --git a/src/lazyframe.js b/src/lazyframe.js index b648a7c..af59bb4 100644 --- a/src/lazyframe.js +++ b/src/lazyframe.js @@ -1,12 +1,11 @@ import './scss/lazyframe.scss' const Lazyframe = () => { + const findVendorIdAndQuery = new RegExp( + /^(?:https?:\/\/)?(?:www\.)?(youtube-nocookie|youtube|vimeo)(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([\w-_]+)(?:\&|\?|\/\?)?(.+)?$/ + ) - const findVendorIdAndQuery = new RegExp(/^(?:https?:\/\/)?(?:www\.)?(youtube-nocookie|youtube|vimeo)(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([\w-_]+)(?:\&|\?|\/\?)?(.+)?$/); - - let settings; - - const elements = []; + const nodes = [] const defaults = { vendor: undefined, @@ -14,234 +13,222 @@ const Lazyframe = () => { src: undefined, thumbnail: undefined, title: undefined, - initialized: false, - y: undefined, debounce: 250, lazyload: true, autoplay: true, initinview: false, - onLoad: (l) => {}, - onAppend: (l) => {}, - onThumbnailLoad: (img) => {} - }; + onLoad: () => {}, + onAppend: () => {}, + onThumbnailLoad: () => {}, + } - function init(elements, ...args) { - settings = {...defaults, ...args[0]}; + function init(initializer, globalConfig) { + const settings = { ...defaults, ...globalConfig } - if (typeof elements === 'string') { + const selection = + typeof initializer === 'string' + ? document.querySelectorAll(initializer) + : typeof initializer.length === 'undefined' + ? [initializer] + : initializer - const selector = document.querySelectorAll(elements); - for (let i = 0; i < selector.length; i++) { - loop(selector[i]); - } - } else if (typeof elements.length === 'undefined'){ - loop(elements); - } else { - for (let i = 0; i < elements.length; i++) { - loop(elements[i]); + for (const node of selection) { + if (node instanceof HTMLElement) { + loop(node, settings) } } if (settings.lazyload) { - scroll(); + scroll(settings.debounce) } - } - function loop(el) { - - if (el instanceof HTMLElement === false || el.classList.contains('lazyframe--loaded')) { - return; + function loop(node, settings) { + if (node.classList.contains('lazyframe--loaded')) { + return } const lazyframe = { - el: el, - settings: setup(el), - }; + ...settings, + ...setup(node, settings), + node, + initialized: false, + } - lazyframe.el.addEventListener('click', () => { - lazyframe.el.appendChild(lazyframe.iframe); - lazyframe.settings.onAppend.call(this, el.querySelector('iframe')); - }); + lazyframe.node.addEventListener('click', () => { + lazyframe.node.appendChild(lazyframe.iframe) + lazyframe.onAppend.call(this, node.querySelector('iframe')) + }) if (settings.lazyload) { - build(lazyframe, false); + build(lazyframe, false) } else { - api(lazyframe); + api(lazyframe) } - } - function setup(el) { - - const attributes = Array.from(el.attributes) - .filter(att => att.value !== '') - .filter(att => att.name.startsWith('data-')) - .reduce((obj, { name, value }) => { - const key = name.split('data-')[1]; - obj[key] = value; - return obj; - }, {}); - - if (!attributes.src) { - throw new Error('You must supply a data-src on the DOM Node'); - } - - const [,vendor, id, query = ''] = attributes.src.match(findVendorIdAndQuery) || []; - return { - ...settings, - ...attributes, - ...{ - y: el.offsetTop, - id, - vendor, - query: `${query}${query ? '&' : ''}autoplay=${settings.autoplay ? '1' : '0'}` - } - }; + function setup(node, settings) { + const src = node.getAttribute('data-src') + const title = node.getAttribute('data-title') + const thumbnail = node.getAttribute('data-thumbnail') + const initinview = node.getAttribute('data-initinview') + if (!src) { + throw new Error('You must supply a data-src on the node') + } + + const [, vendor, id, params] = src.match(findVendorIdAndQuery) || [] + const autoplay = settings.autoplay ? 1 : 0 + const query = params ? '&' + params : '' + return { + src, + title, + thumbnail, + initinview, + id, + vendor, + useApi: vendor && (!title || !thumbnail), + query: `autoplay=${autoplay}${query}`, + } } function api(lazyframe) { - if (lazyframe.settings.vendor) { - fetch(`https://noembed.com/embed?url=${lazyframe.settings.src}`) - .then(res => res.json()) - .then(json => { - if (!lazyframe.settings.title) { - lazyframe.settings.title = json.title + if (lazyframe.useApi) { + const xhr = new XMLHttpRequest() + xhr.open('GET', `https://noembed.com/embed?url=${lazyframe.src}`) + xhr.onload = function () { + if (this.status === 200) { + const json = JSON.parse(xhr.response) + console.log(json) + if (!lazyframe.title) { + lazyframe.title = json.title } - if (!lazyframe.settings.thumbnail) { - lazyframe.settings.thumbnail = json.thumbnail_url; - lazyframe.settings.onThumbnailLoad.call(this, json.thumbnail_url); + if (!lazyframe.thumbnail) { + lazyframe.thumbnail = json.thumbnail_url + lazyframe.onThumbnailLoad.call(this, json.thumbnail_url) } - - build(lazyframe, true); - }) - }else{ - build(lazyframe, true); + build(lazyframe, true) + } + } + xhr.send() + } else { + build(lazyframe, true) } - } - function scroll() { - - const height = window.innerHeight; - let count = elements.length; - const initElement = (el, i) => { - el.settings.initialized = true; - el.el.classList.add('lazyframe--loaded'); - count--; - api(el); - - if (el.settings.initinview) { - el.el.click(); - } + function onLoad(lazyframe) { + lazyframe.node.classList.add('lazyframe--loaded') + if (lazyframe.initinview) { + lazyframe.node.click() + } + lazyframe.onLoad.call(this, lazyframe) + } - el.settings.onLoad.call(this, el); + function scroll(debounceMs) { + const initElement = (lazyframe) => { + lazyframe.initialized = true + api(lazyframe) + onLoad(lazyframe) } - elements - .filter(el => el.settings.y < height) - .forEach(initElement); + nodes + .filter((lf) => lf.node.offsetTop < window.innerHeight) + .forEach(initElement) - const onScroll = debounce(() => { + let lastY = 0 - up = lastY < window.pageYOffset; - lastY = window.pageYOffset; - - if (up) { - elements - .filter(el => el.settings.y < (height + lastY) && el.settings.initialized === false) - .forEach(initElement); + const onScroll = debounce(() => { + const scrollDown = lastY < window.pageYOffset + lastY = window.pageYOffset + + if (scrollDown) { + nodes + .filter((lf) => lf.initialized === false) + .filter((lf) => lf.node.offsetTop < window.innerHeight + lastY) + .forEach(initElement) } - if (count === 0) { - window.removeEventListener('scroll', onScroll, false); + if (nodes.filter((lf) => !lf.initialized).length < 1) { + window.removeEventListener('scroll', onScroll, false) } + }, debounceMs) - }, settings.debounce); - - let lastY = 0; - let up = false; - - window.addEventListener('scroll', onScroll, false); - - function debounce(func, wait, immediate) { - let timeout; - return function() { - let context = this, args = arguments; - let later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - let callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; - }; + window.addEventListener('scroll', onScroll, false) + } + function debounce(func, wait) { + let timeout + return function () { + let later = () => { + timeout = null + func.apply(this) + } + let callNow = !timeout + clearTimeout(timeout) + timeout = setTimeout(later, wait) + if (callNow) func.apply(this) + } } function build(lazyframe, loadImage) { + lazyframe.iframe = getIframe(lazyframe) - lazyframe.iframe = getIframe(lazyframe.settings); - - if (lazyframe.settings.thumbnail && loadImage) { - lazyframe.el.style.backgroundImage = `url(${lazyframe.settings.thumbnail})`; + if (lazyframe.thumbnail && loadImage) { + lazyframe.node.style.backgroundImage = `url(${lazyframe.thumbnail})` } - if (lazyframe.settings.title && lazyframe.el.children.length === 0) { - const docfrag = document.createDocumentFragment(); - const titleNode = document.createElement('span'); + if (lazyframe.title && lazyframe.node.children.length === 0) { + const docfrag = document.createDocumentFragment() + const titleNode = document.createElement('span') - titleNode.className = 'lazyframe__title'; - titleNode.innerHTML = lazyframe.settings.title; - docfrag.appendChild(titleNode); + titleNode.className = 'lazyframe__title' + titleNode.innerHTML = lazyframe.title + docfrag.appendChild(titleNode) - lazyframe.el.appendChild(docfrag); + lazyframe.node.appendChild(docfrag) } - if (!settings.lazyload) { - lazyframe.el.classList.add('lazyframe--loaded'); - lazyframe.settings.onLoad.call(this, lazyframe); - elements.push(lazyframe); + if (!lazyframe.lazyload) { + lazyframe.node.classList.add('lazyframe--loaded') + lazyframe.onLoad.call(this, lazyframe) + nodes.push(lazyframe) } - if (!lazyframe.settings.initialized) { - elements.push(lazyframe); + if (!lazyframe.initialized) { + nodes.push(lazyframe) } - } - function getIframe(settings) { - - const docfrag = document.createDocumentFragment(); - const iframeNode = document.createElement('iframe'); - - if (settings.vendor === 'youtube' || settings.vendor === 'youtube-nocookie') { - settings.src = `https://www.${settings.vendor}.com/embed/${settings.id}/?${settings.query}`; - } else if (settings.vimeo) { - settings.src = `https://player.vimeo.com/video/${s.id}/?${settings.query}` + function getIframe(lazyframe) { + const docfrag = document.createDocumentFragment() + const iframeNode = document.createElement('iframe') + + if ( + lazyframe.vendor === 'youtube' || + lazyframe.vendor === 'youtube-nocookie' + ) { + lazyframe.src = `https://www.${lazyframe.vendor}.com/embed/${lazyframe.id}/?${lazyframe.query}` + } else if (lazyframe.vimeo) { + lazyframe.src = `https://player.vimeo.com/video/${s.id}/?${lazyframe.query}` } - iframeNode.setAttribute('id', `lazyframe-${settings.id}`); - iframeNode.setAttribute('src', settings.src); - iframeNode.setAttribute('frameborder', 0); - iframeNode.setAttribute('allowfullscreen', ''); - - if (settings.autoplay) { - iframeNode.allow = 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture'; - } + iframeNode.setAttribute('id', `lazyframe-${lazyframe.id}`) + iframeNode.setAttribute('src', lazyframe.src) + iframeNode.setAttribute('frameborder', 0) + iframeNode.setAttribute('allowfullscreen', '') - docfrag.appendChild(iframeNode); - return docfrag; + if (lazyframe.autoplay) { + iframeNode.allow = + 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture' + } + docfrag.appendChild(iframeNode) + return docfrag } - return init; - + return init } -const lf = Lazyframe(); +const lf = Lazyframe() -export default lf; +export default lf From baae84112923a8fdfc862cc35d4cd6fa603d5f3e Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Thu, 14 Oct 2021 21:59:30 +0200 Subject: [PATCH 03/12] final --- index.html | 19 ++--- package-lock.json | 6 ++ package.json | 1 + src/lazyframe.js | 185 +++++++++++++++++++++++-------------------- test/browser.js | 198 ++++++++++++++++++++++++++++++---------------- 5 files changed, 242 insertions(+), 167 deletions(-) diff --git a/index.html b/index.html index 34bce60..95f1de5 100644 --- a/index.html +++ b/index.html @@ -53,20 +53,20 @@

Youtube video with thumbnail and title from API

-
+

Youtube video with custom thumbnail and title

-
+

Vimeo video with thumbnail and title from API

-
+

Vimeo video with custom thumbnail and title

-
@@ -78,18 +78,13 @@

Google maps iframe with custom thumbnail and title that gets executed when in view

diff --git a/package-lock.json b/package-lock.json index 911f29e..6390399 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3196,6 +3196,12 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "mock-xmlhttprequest": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/mock-xmlhttprequest/-/mock-xmlhttprequest-7.0.4.tgz", + "integrity": "sha512-hA0fIHy/74p5DE0rdmrpU0sV1U+gnWTcgShWequGRLy0L1eT+zY0ozFukawpLaxMwIA+orRcqFRElYwT+5p81A==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 1ed121b..73a110a 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@rollup/plugin-babel": "^5.3.0", "ava": "^3.15.0", "jsdom": "15", + "mock-xmlhttprequest": "^7.0.4", "rollup": "^2.39.0", "rollup-plugin-scss": "^3.0.0", "rollup-plugin-terser": "^7.0.2", diff --git a/src/lazyframe.js b/src/lazyframe.js index af59bb4..f24e48f 100644 --- a/src/lazyframe.js +++ b/src/lazyframe.js @@ -5,25 +5,24 @@ const Lazyframe = () => { /^(?:https?:\/\/)?(?:www\.)?(youtube-nocookie|youtube|vimeo)(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([\w-_]+)(?:\&|\?|\/\?)?(.+)?$/ ) + const classNames = { + loaded: 'lazyframe--loaded', + title: 'lazyframe__title', + } + const nodes = [] - const defaults = { - vendor: undefined, - id: undefined, - src: undefined, - thumbnail: undefined, - title: undefined, + let settings = { debounce: 250, lazyload: true, autoplay: true, - initinview: false, onLoad: () => {}, onAppend: () => {}, onThumbnailLoad: () => {}, } - function init(initializer, globalConfig) { - const settings = { ...defaults, ...globalConfig } + function init(initializer, config) { + settings = { ...settings, ...config } const selection = typeof initializer === 'string' @@ -34,40 +33,62 @@ const Lazyframe = () => { for (const node of selection) { if (node instanceof HTMLElement) { - loop(node, settings) + create(node) } } if (settings.lazyload) { - scroll(settings.debounce) + scroll() } + + return nodes } - function loop(node, settings) { - if (node.classList.contains('lazyframe--loaded')) { + function create(node) { + if (node.classList.contains(classNames.loaded)) { return } const lazyframe = { - ...settings, - ...setup(node, settings), + ...getSettingsFromNode(node), node, - initialized: false, } - lazyframe.node.addEventListener('click', () => { - lazyframe.node.appendChild(lazyframe.iframe) - lazyframe.onAppend.call(this, node.querySelector('iframe')) - }) + const titleNode = createTitleNode(lazyframe) + lazyframe.node.appendChild(titleNode) + + lazyframe.iframeNode = createIframeNode(lazyframe) + + lazyframe.node.addEventListener('click', onClick, { once: true }) + function onClick() { + lazyframe.node.appendChild(lazyframe.iframeNode) + settings.onAppend.call(this, node.querySelector('iframe')) + } + + nodes.push(lazyframe) if (settings.lazyload) { - build(lazyframe, false) + return } else { - api(lazyframe) + createPlaceholder(lazyframe) } } - function setup(node, settings) { + function createTitleNode(lazyframe) { + const fragment = document.createDocumentFragment() + const titleNode = document.createElement('span') + + titleNode.className = classNames.title + fragment.appendChild(titleNode) + + if (lazyframe.title) { + titleNode.innerHTML = lazyframe.title + } + lazyframe.node.appendChild(fragment) + return fragment + } + + function getSettingsFromNode(node) { const src = node.getAttribute('data-src') const title = node.getAttribute('data-title') const thumbnail = node.getAttribute('data-thumbnail') @@ -78,6 +99,10 @@ const Lazyframe = () => { } const [, vendor, id, params] = src.match(findVendorIdAndQuery) || [] + if (vendor) { + node.setAttribute('data-vendor', vendor) + } + const autoplay = settings.autoplay ? 1 : 0 const query = params ? '&' + params : '' return { @@ -89,51 +114,65 @@ const Lazyframe = () => { vendor, useApi: vendor && (!title || !thumbnail), query: `autoplay=${autoplay}${query}`, + initialized: false, } } - function api(lazyframe) { - if (lazyframe.useApi) { + function fetchFromApi(lazyframe) { + return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open('GET', `https://noembed.com/embed?url=${lazyframe.src}`) xhr.onload = function () { if (this.status === 200) { const json = JSON.parse(xhr.response) - console.log(json) - if (!lazyframe.title) { + if (json.title) { lazyframe.title = json.title } - if (!lazyframe.thumbnail) { + if (json.thumbnail_url) { lazyframe.thumbnail = json.thumbnail_url - lazyframe.onThumbnailLoad.call(this, json.thumbnail_url) } - build(lazyframe, true) + resolve(lazyframe) + } else { + reject() } } xhr.send() + }) + } + + function createPlaceholder(lazyframe) { + if (lazyframe.useApi) { + fetchFromApi(lazyframe).then(populatePlaceholder) } else { - build(lazyframe, true) + populatePlaceholder(lazyframe) + } + } + + function populatePlaceholder(lazyframe) { + const titleNode = lazyframe.node.querySelector('.lazyframe__title') + + if (lazyframe.title && titleNode.innerHTML === '') { + titleNode.innerHTML = lazyframe.title } + if (lazyframe.thumbnail) { + lazyframe.node.style.backgroundImage = `url(${lazyframe.thumbnail})` + } + onLoad(lazyframe) } function onLoad(lazyframe) { - lazyframe.node.classList.add('lazyframe--loaded') + lazyframe.node.classList.add(classNames.loaded) + lazyframe.initialized = true if (lazyframe.initinview) { lazyframe.node.click() } - lazyframe.onLoad.call(this, lazyframe) + settings.onLoad.call(this, lazyframe.node) } - function scroll(debounceMs) { - const initElement = (lazyframe) => { - lazyframe.initialized = true - api(lazyframe) - onLoad(lazyframe) - } - + function scroll() { nodes - .filter((lf) => lf.node.offsetTop < window.innerHeight) - .forEach(initElement) + .filter(({ node }) => node.offsetTop < window.innerHeight) + .forEach(createPlaceholder) let lastY = 0 @@ -143,15 +182,15 @@ const Lazyframe = () => { if (scrollDown) { nodes - .filter((lf) => lf.initialized === false) - .filter((lf) => lf.node.offsetTop < window.innerHeight + lastY) - .forEach(initElement) + .filter(({ initialized }) => initialized === false) + .filter(({ node }) => node.offsetTop < window.innerHeight + lastY) + .forEach(createPlaceholder) } - if (nodes.filter((lf) => !lf.initialized).length < 1) { + if (nodes.filter(({ initialized }) => initialized === false).length < 1) { window.removeEventListener('scroll', onScroll, false) } - }, debounceMs) + }, settings.debounce) window.addEventListener('scroll', onScroll, false) } @@ -170,50 +209,24 @@ const Lazyframe = () => { } } - function build(lazyframe, loadImage) { - lazyframe.iframe = getIframe(lazyframe) - - if (lazyframe.thumbnail && loadImage) { - lazyframe.node.style.backgroundImage = `url(${lazyframe.thumbnail})` - } - - if (lazyframe.title && lazyframe.node.children.length === 0) { - const docfrag = document.createDocumentFragment() - const titleNode = document.createElement('span') - - titleNode.className = 'lazyframe__title' - titleNode.innerHTML = lazyframe.title - docfrag.appendChild(titleNode) - - lazyframe.node.appendChild(docfrag) - } - - if (!lazyframe.lazyload) { - lazyframe.node.classList.add('lazyframe--loaded') - lazyframe.onLoad.call(this, lazyframe) - nodes.push(lazyframe) - } - - if (!lazyframe.initialized) { - nodes.push(lazyframe) - } - } - - function getIframe(lazyframe) { + function createIframeNode(lazyframe) { const docfrag = document.createDocumentFragment() const iframeNode = document.createElement('iframe') - if ( - lazyframe.vendor === 'youtube' || - lazyframe.vendor === 'youtube-nocookie' - ) { - lazyframe.src = `https://www.${lazyframe.vendor}.com/embed/${lazyframe.id}/?${lazyframe.query}` - } else if (lazyframe.vimeo) { - lazyframe.src = `https://player.vimeo.com/video/${s.id}/?${lazyframe.query}` + const vendor = lazyframe.vendor || '' + + if (vendor.indexOf('youtube') > -1) { + lazyframe.embed = `https://www.${vendor}.com/embed/${lazyframe.id}/?${lazyframe.query}` + } else if (vendor === 'vimeo') { + lazyframe.embed = `https://player.vimeo.com/video/${lazyframe.id}/?${lazyframe.query}` + } else { + lazyframe.embed = lazyframe.src } - iframeNode.setAttribute('id', `lazyframe-${lazyframe.id}`) - iframeNode.setAttribute('src', lazyframe.src) + if (lazyframe.id) { + iframeNode.setAttribute('id', `lazyframe-${lazyframe.id}`) + } + iframeNode.setAttribute('src', lazyframe.embed) iframeNode.setAttribute('frameborder', 0) iframeNode.setAttribute('allowfullscreen', '') diff --git a/test/browser.js b/test/browser.js index 8d1faff..b181ed5 100644 --- a/test/browser.js +++ b/test/browser.js @@ -1,119 +1,179 @@ -const path = require('path'); -const { readFileSync } = require('fs'); -const { Script } = require('vm'); +const path = require('path') +const { readFileSync } = require('fs') +const { Script } = require('vm') -const test = require('ava'); -const { JSDOM, VirtualConsole } = require('jsdom'); +const test = require('ava') +const { JSDOM, VirtualConsole } = require('jsdom') -const virtualConsole = new VirtualConsole(); -virtualConsole.sendTo(console); +const MockXMLHttpRequest = require('mock-xmlhttprequest') +const MockXhr = MockXMLHttpRequest.newMockXhr() + +MockXhr.onSend = (xhr) => { + const responseHeaders = { 'Content-Type': 'application/json' } + const response = + '{ "title": "mock title", "thumbnail_url": "mock thumbnail url" }' + xhr.respond(200, responseHeaders, response) +} + +const virtualConsole = new VirtualConsole() +virtualConsole.sendTo(console) const script = new Script( readFileSync(path.join(__dirname, '..', 'dist', 'lazyframe.min.js')) -); +) -test.beforeEach(t => { +test.beforeEach(() => { const dom = new JSDOM(``, { includeNodeLocations: true, resources: 'usable', runScripts: 'dangerously', - virtualConsole - }); + virtualConsole, + }) - dom.runVMScript(script); - global.document = dom.window.document; - global.window = dom.window; + dom.runVMScript(script) + global.document = dom.window.document + dom.window.XMLHttpRequest = MockXhr + global.window = dom.window }) const createDomNode = (params = {}) => { - const node = document.createElement('div'); - node.classList.add('lazyframe'); - for (const [ key, value ] of Object.entries(params)) { + const node = document.createElement('div') + node.classList.add('lazyframe') + for (const [key, value] of Object.entries(params)) { node.setAttribute(`data-${key}`, value) } - document.body.appendChild(node); - return node; + document.body.appendChild(node) + return node } -test('should expose lazyframe()', (t) => { - t.true(typeof window.lazyframe === 'function'); -}); +const lazyframe = (initializer = '.lazyframe', config = {}) => { + return new Promise((resolve) => { + let i = 0 + const nodes = window.lazyframe(initializer, { + ...config, + onLoad: () => { + i++ + if (i === nodes.length) { + resolve() + } + }, + }) + }) +} -test('should initialize one node with a string selector', (t) => { - createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); - window.lazyframe('.lazyframe'); - t.is(document.querySelectorAll('.lazyframe--loaded').length, 1); +test('should expose lazyframe()', async (t) => { + t.true(typeof window.lazyframe === 'function') }) -test('should initialize mulitple nodes with a string selector', (t) => { - createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); - createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); +test('should initialize one node with a string selector', async (t) => { + createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) + await lazyframe() + t.is(document.querySelectorAll('.lazyframe--loaded').length, 1) +}) - window.lazyframe('.lazyframe'); - t.is(document.querySelectorAll('.lazyframe--loaded').length, 2); +test('should initialize mulitple nodes with a string selector', async (t) => { + createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) + createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) + + await lazyframe() + t.is(document.querySelectorAll('.lazyframe--loaded').length, 2) }) -test('should initialize with a single node', (t) => { - const node = createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); +test('should initialize with a single node', async (t) => { + const node = createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) - window.lazyframe(node); - t.is(document.querySelectorAll('.lazyframe--loaded').length, 1); + await lazyframe(node) + t.is(document.querySelectorAll('.lazyframe--loaded').length, 1) }) -test('should initialize with a nodelist', (t) => { - createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDB/?rel=0' }); - createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDC/?rel=0' }); +test('should initialize with a nodelist', async (t) => { + createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDB/?rel=0', + }) + createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDC/?rel=0', + }) const nodes = document.querySelectorAll('.lazyframe') - window.lazyframe(nodes); - t.is(document.querySelectorAll('.lazyframe--loaded').length, 2); + await lazyframe(nodes) + t.is(document.querySelectorAll('.lazyframe--loaded').length, 2) }) -test('should append an iframe on click', (t) => { - const node = createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); +test('should append an iframe on click', async (t) => { + const node = createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) + + await lazyframe() + node.click() - window.lazyframe('.lazyframe'); - node.click(); - t.assert(node.querySelector('iframe')) }) -test('should call onAppend callback function', (t) => { - let i = 0; - const node1 = createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); - const node2 = createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0' }); - - window.lazyframe('.lazyframe', { +test('should call onAppend callback function', async (t) => { + let i = 0 + const node1 = createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) + const node2 = createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + }) + + await lazyframe('.lazyframe', { onAppend() { - i++; - } - }); - node1.click(); - node2.click(); - + i++ + }, + }) + node1.click() + node2.click() + t.is(i, 2) }) -test('should use data-title', (t) => { +test('should use data-title', async (t) => { const title = 'custom title' - const node = createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', title }); + const node = createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', + title, + }) - window.lazyframe('.lazyframe'); + await lazyframe() node.click() t.is(document.querySelector('.lazyframe__title').textContent, title) }) -test('should append optional query params from data-src', (t) => { +test('should append optional query params from data-src', async (t) => { const query = 'rel=0&p=1' - const node = createDomNode({ vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?' + query }); - - window.lazyframe('.lazyframe'); + const node = createDomNode({ + vendor: 'youtube', + src: 'http://www.youtube.com/embed/iwGFalTRHDA/?' + query, + }) + + await lazyframe() node.click() - const iframe = node.querySelector('iframe'); - const src = iframe.getAttribute('src'); - const [,iframQuery] = src.split('?autoplay=1&') + const iframe = node.querySelector('iframe') + const src = iframe.getAttribute('src') + const [, iframQuery] = src.split('?autoplay=1&') - t.is(iframQuery, query); -}) \ No newline at end of file + t.is(iframQuery, query) +}) From acc4a7e3203e1767f446adb63b6b00879eaf9a9e Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Fri, 15 Oct 2021 13:22:25 +0200 Subject: [PATCH 04/12] Added typescript --- .babelrc | 12 --- index.html | 3 +- package-lock.json | 70 +++++++++++++ package.json | 15 ++- rollup.config.js | 54 +++++----- src/lazyframe.css | 156 +++++++++++++++++++++++++++++ src/{lazyframe.js => lazyframe.ts} | 133 +++++++++++++++--------- src/scss/_base.scss | 51 ---------- src/scss/lazyframe.scss | 3 - src/scss/themes/_vimeo.scss | 41 -------- src/scss/themes/_youtube.scss | 64 ------------ test/server.js | 10 +- tsconfig.json | 106 ++++++++++++++++++++ 13 files changed, 463 insertions(+), 255 deletions(-) delete mode 100644 .babelrc create mode 100644 src/lazyframe.css rename src/{lazyframe.js => lazyframe.ts} (60%) delete mode 100644 src/scss/_base.scss delete mode 100644 src/scss/lazyframe.scss delete mode 100644 src/scss/themes/_vimeo.scss delete mode 100644 src/scss/themes/_youtube.scss create mode 100644 tsconfig.json diff --git a/.babelrc b/.babelrc deleted file mode 100644 index aba07e3..0000000 --- a/.babelrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "modules": false, - "forceAllTransforms": true, - "targets": "> 0.005%" - } - ] - ] -} diff --git a/index.html b/index.html index 95f1de5..07b817a 100644 --- a/index.html +++ b/index.html @@ -84,7 +84,8 @@
diff --git a/package-lock.json b/package-lock.json index 6390399..9be4241 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1077,6 +1077,16 @@ "@rollup/pluginutils": "^3.1.0" } }, + "@rollup/plugin-typescript": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz", + "integrity": "sha512-QL/LvDol/PAGB2O0S7/+q2HpSUNodpw7z6nGn9BfoVCPOZ0r4EALrojFU29Bkoi2Hr2jgTocTejJ5GGWZfOxbQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0", + "resolve": "^1.17.0" + } + }, "@rollup/pluginutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", @@ -3941,6 +3951,60 @@ "fsevents": "~2.3.1" } }, + "rollup-plugin-css-only": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz", + "integrity": "sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "4" + }, + "dependencies": { + "@rollup/pluginutils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", + "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", + "dev": true, + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + } + } + }, + "rollup-plugin-import-css": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-import-css/-/rollup-plugin-import-css-3.0.2.tgz", + "integrity": "sha512-4Y/U5EMQHomMlYSF0OBOo/XJSgfou+iHMfBOqneaX5Cp5BCyQn1YrUtXC6KYEPHPxTadC+oXhrTCr9yzRN2DyA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^4.1.1" + }, + "dependencies": { + "@rollup/pluginutils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", + "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", + "dev": true, + "requires": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + } + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + } + } + }, "rollup-plugin-scss": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-scss/-/rollup-plugin-scss-3.0.0.tgz", @@ -4409,6 +4473,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", + "dev": true + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", diff --git a/package.json b/package.json index 73a110a..896351c 100644 --- a/package.json +++ b/package.json @@ -7,20 +7,17 @@ "url": "https://github.com/vb/lazyframe/issues" }, "devDependencies": { - "@babel/core": "^7.12.17", - "@babel/plugin-transform-object-assign": "^7.12.13", - "@babel/preset-env": "^7.12.17", - "@rollup/plugin-babel": "^5.3.0", + "@rollup/plugin-typescript": "^8.2.5", "ava": "^3.15.0", "jsdom": "15", "mock-xmlhttprequest": "^7.0.4", "rollup": "^2.39.0", - "rollup-plugin-scss": "^3.0.0", + "rollup-plugin-import-css": "^3.0.2", "rollup-plugin-terser": "^7.0.2", - "sass": "^1.42.1" + "typescript": "^4.4.4" }, "homepage": "https://vb.github.io/lazyframe", - "jsnext:main": "src/lazyframe.js", + "jsnext:main": "dist/lazyframe.module.js", "keywords": [ "embed", "iframe", @@ -39,8 +36,8 @@ "url": "git+https://github.com/vb/lazyframe.git" }, "scripts": { - "build": "./node_modules/.bin/rollup -c", - "dev": "./node_modules/.bin/rollup -c -w", + "build": "rollup -c", + "dev": "rollup -c -w", "test": "npm run build && ava -s", "test:watch": "npm run build && ava -s -w" }, diff --git a/rollup.config.js b/rollup.config.js index 8e4339d..4661a8d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,25 +1,33 @@ -import { babel } from "@rollup/plugin-babel"; -import { terser } from "rollup-plugin-terser"; -import scss from "rollup-plugin-scss"; +import { terser } from 'rollup-plugin-terser' +import typescript from '@rollup/plugin-typescript' +import css from 'rollup-plugin-import-css' -export default { - input: "src/lazyframe.js", - output: { - file: "dist/lazyframe.min.js", - format: "umd", - exports: "default", - name: "lazyframe", - sourcemap: true, +export default [ + { + input: 'src/lazyframe.ts', + output: { + file: 'dist/lazyframe.min.js', + format: 'umd', + exports: 'default', + name: 'lazyframe', + sourcemap: true, + }, + plugins: [ + typescript({ tsconfig: './tsconfig.json' }), + css({ output: 'lazyframe.css', minify: true }), + terser(), + ], }, - plugins: [ - babel({ - exclude: "node_modules/**", - babelHelpers: "bundled", - }), - terser(), - scss({ - output: "dist/lazyframe.css", - outputStyle: "compressed", - }), - ], -}; + { + input: 'src/lazyframe.ts', + output: { + file: 'dist/lazyframe.module.js', + format: 'cjs', + exports: 'default', + }, + plugins: [ + typescript({ tsconfig: './tsconfig.json' }), + css({ output: 'lazyframe.css', minify: true }), + ], + }, +] diff --git a/src/lazyframe.css b/src/lazyframe.css new file mode 100644 index 0000000..c26218f --- /dev/null +++ b/src/lazyframe.css @@ -0,0 +1,156 @@ +.lazyframe { + position: relative; + background-color: currentColor; + background-repeat: no-repeat; + background-size: cover; + background-position: center; +} + +.lazyframe__title { + position: absolute; + top: 0; + right: 0; + left: 0; + padding: 15px 17px; + z-index: 3; +} + +.lazyframe__title::after { + z-index: -1; +} + +.lazyframe:hover { + cursor: pointer; +} + +.lazyframe::before { + display: block; + content: ''; + width: 100%; + padding-top: 100%; +} + +.lazyframe[data-ratio='16:9']::before { + padding-top: 56.25%; +} + +.lazyframe[data-ratio='4:3']::before { + padding-top: 75%; +} + +.lazyframe[data-ratio='1:1']::before { + padding-top: 100%; +} + +.lazyframe iframe { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 5; + width: 100%; + height: 100%; +} + +.lazyframe[data-vendor='youtube'] { + background-color: #e52d27; + font-family: Roboto, Arial, Helvetica, sans-serif; +} + +.lazyframe[data-vendor='youtube'] .lazyframe__title { + color: #eeeeee; + font-family: Roboto, Arial, Helvetica, sans-serif; + font-size: 18px; + text-shadow: rgba(0, 0, 0, 0.498039) 0 0 2px; + -webkit-font-smoothing: antialiased; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + transition: color 0.1s cubic-bezier(0.4, 0, 1, 1); +} + +.lazyframe[data-vendor='youtube'] .lazyframe__title:hover { + color: #fff; +} + +.lazyframe[data-vendor='youtube'] .lazyframe__title::before { + content: ''; + display: block; + background: linear-gradient(rgba(0, 0, 0, 0.2), transparent); + height: 98px; + width: 100%; + pointer-events: none; + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: -1; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.lazyframe[data-vendor='youtube']::before { + padding-top: 56.25%; +} + +.lazyframe[data-vendor='youtube']::after { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: 68px; + height: 48px; + margin-left: -34px; + margin-top: -24px; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%231F1F1F' d='M255.7 446.3c-53.3.3-106.6-.4-159.8-3.3-17.4-1-34.7-2.5-50.4-11C35 426.3 27 418.4 22 407.2 13.2 388.6 10.5 369 9 349c-3.4-41.3-3.6-82.6-1.8-123.8 1-22 1.6-44 6.8-65.5 2-8.4 5-16.6 8.8-24.4C32 117 48 108 67.3 104c16.2-3 32.8-3 49.3-3.7 56-2.3 112-3.5 168-3 43 .6 86.2 1.7 129.3 4 13.2.6 26.6.8 39.3 5.5 17.2 6.4 30 17.2 37 34.7 6.6 16.8 9.2 34.2 10.6 52 3.8 48.7 4 97.3.7 146-1 16.3-2.2 32.7-6.5 48.8-9.7 37-32.8 51.5-66.7 53.8-36.2 2.5-72.5 3.8-108.8 4.3-21.3.2-42.7 0-64 0zM203.2 344L348 264.7l-144.8-79.3V344z'/%3E%3Cpath fill='%23FEFDFD' d='M203.2 344V185.5L348 264.8 203.2 344z'/%3E%3C/svg%3E"); + background-position: center center; + background-size: 100%; + background-repeat: no-repeat; + opacity: 0.81; + border: none; + z-index: 4; +} + +.lazyframe[data-vendor='youtube']:hover::after { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23DD2C28' d='M255.7 446.3c-53.3.3-106.6-.4-159.8-3.3-17.4-1-34.7-2.5-50.4-11C35 426.3 27 418.4 22 407.2 13.2 388.6 10.5 369 9 349c-3.4-41.3-3.6-82.6-1.8-123.8 1-22 1.6-44 6.8-65.5 2-8.4 5-16.6 8.8-24.4C32 117 48 108 67.3 104c16.2-3 32.8-3 49.3-3.7 56-2.3 112-3.5 168-3 43 .6 86.2 1.7 129.3 4 13.2.6 26.6.8 39.3 5.5 17.2 6.4 30 17.2 37 34.7 6.6 16.8 9.2 34.2 10.6 52 3.8 48.7 4 97.3.7 146-1 16.3-2.2 32.7-6.5 48.8-9.7 37-32.8 51.5-66.7 53.8-36.2 2.5-72.5 3.8-108.8 4.3-21.3.2-42.7 0-64 0zM203.2 344L348 264.7l-144.8-79.3V344z'/%3E%3Cpath fill='%23FEFDFD' d='M203.2 344V185.5L348 264.8 203.2 344z'/%3E%3C/svg%3E"); + opacity: 1; +} + +.lazyframe[data-vendor='vimeo'] { + background-color: #00adef; +} + +.lazyframe[data-vendor='vimeo'] .lazyframe__title { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + color: #00adef; + font-size: 20px; + font-weight: 700; + text-rendering: optimizeLegibility; + user-select: none; + -webkit-font-smoothing: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + background-color: rgba(0, 0, 0, 0.5); +} + +.lazyframe[data-vendor='vimeo']::before { + padding-top: 48.25%; +} + +.lazyframe[data-vendor='vimeo']::after { + content: ''; + height: 40px; + width: 65px; + display: block; + bottom: 10px; + left: 10px; + z-index: 3; + background-color: rgba(0, 0, 0, 0.5); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' baseProfile='tiny' viewBox='0 0 24 24'%3E%3Cpath fill='%23FFF' d='M7.765 16.89l8.47-4.89-8.47-4.89'/%3E%3C/svg%3E"); + background-position: center center; + background-size: 100% 100%; + background-repeat: no-repeat; + border-radius: 5px; + position: relative; +} + +.lazyframe[data-vendor='vimeo']:hover::after { + background-color: #00adef; +} diff --git a/src/lazyframe.js b/src/lazyframe.ts similarity index 60% rename from src/lazyframe.js rename to src/lazyframe.ts index f24e48f..0fba3d7 100644 --- a/src/lazyframe.js +++ b/src/lazyframe.ts @@ -1,4 +1,31 @@ -import './scss/lazyframe.scss' +import './lazyframe.css' + +interface LazyframeObject extends LazyframeSettings { + node: HTMLElement +} + +interface LazyframeSettings { + src: string + embed: string + title: string | null + thumbnail: string | null + initinview: boolean | null + id: string | null + vendor: 'youtube' | 'youtube-nocookie' | 'vimeo' | null + useApi: boolean + query: string + initialized: boolean + iframeNode: DocumentFragment +} + +interface LazyframeOptions { + debounce: number + lazyload: boolean + autoplay: boolean + onLoad: (node: HTMLElement) => void + onAppend: (node: HTMLElement | null) => void + onThumbnailLoad: (url: string) => void +} const Lazyframe = () => { const findVendorIdAndQuery = new RegExp( @@ -10,10 +37,10 @@ const Lazyframe = () => { title: 'lazyframe__title', } - const nodes = [] + const nodes: LazyframeObject[] = [] - let settings = { - debounce: 250, + let settings: LazyframeOptions = { + debounce: 100, lazyload: true, autoplay: true, onLoad: () => {}, @@ -21,15 +48,18 @@ const Lazyframe = () => { onThumbnailLoad: () => {}, } - function init(initializer, config) { + function init( + initializer: string | HTMLElement | NodeList, + config: Partial + ) { settings = { ...settings, ...config } const selection = typeof initializer === 'string' ? document.querySelectorAll(initializer) - : typeof initializer.length === 'undefined' - ? [initializer] - : initializer + : initializer instanceof NodeList + ? initializer + : [initializer] for (const node of selection) { if (node instanceof HTMLElement) { @@ -44,12 +74,12 @@ const Lazyframe = () => { return nodes } - function create(node) { + function create(node: HTMLElement) { if (node.classList.contains(classNames.loaded)) { return } - const lazyframe = { + const lazyframe: LazyframeObject = { ...getSettingsFromNode(node), node, } @@ -57,12 +87,10 @@ const Lazyframe = () => { const titleNode = createTitleNode(lazyframe) lazyframe.node.appendChild(titleNode) - lazyframe.iframeNode = createIframeNode(lazyframe) - lazyframe.node.addEventListener('click', onClick, { once: true }) function onClick() { lazyframe.node.appendChild(lazyframe.iframeNode) - settings.onAppend.call(this, node.querySelector('iframe')) + settings.onAppend.call(null, node.querySelector('iframe')) } nodes.push(lazyframe) @@ -74,7 +102,7 @@ const Lazyframe = () => { } } - function createTitleNode(lazyframe) { + function createTitleNode(lazyframe: LazyframeObject) { const fragment = document.createDocumentFragment() const titleNode = document.createElement('span') @@ -88,23 +116,30 @@ const Lazyframe = () => { return fragment } - function getSettingsFromNode(node) { + function getSettingsFromNode(node: HTMLElement): LazyframeSettings { const src = node.getAttribute('data-src') const title = node.getAttribute('data-title') const thumbnail = node.getAttribute('data-thumbnail') - const initinview = node.getAttribute('data-initinview') + const initinview = node.getAttribute('data-initinview') === 'true' if (!src) { throw new Error('You must supply a data-src on the node') } - const [, vendor, id, params] = src.match(findVendorIdAndQuery) || [] + const [, vendorObj, id, params] = src.match(findVendorIdAndQuery) || [] + const vendor = vendorObj ? (vendorObj as LazyframeSettings['vendor']) : null if (vendor) { - node.setAttribute('data-vendor', vendor) + if (vendor === 'youtube-nocookie') { + node.setAttribute('data-vendor', 'youtube') + } else { + node.setAttribute('data-vendor', vendor) + } } - const autoplay = settings.autoplay ? 1 : 0 - const query = params ? '&' + params : '' + const query = `autoplay=${settings.autoplay ? 1 : 0}${ + params ? '&' + params : '' + }` + return { src, title, @@ -112,13 +147,15 @@ const Lazyframe = () => { initinview, id, vendor, - useApi: vendor && (!title || !thumbnail), - query: `autoplay=${autoplay}${query}`, + embed: src, + useApi: !!vendor && (!title || !thumbnail), + query, initialized: false, + iframeNode: createIframeNode(vendor, query, src, id), } } - function fetchFromApi(lazyframe) { + function fetchFromApi(lazyframe: LazyframeObject): Promise { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest() xhr.open('GET', `https://noembed.com/embed?url=${lazyframe.src}`) @@ -140,7 +177,7 @@ const Lazyframe = () => { }) } - function createPlaceholder(lazyframe) { + function createPlaceholder(lazyframe: LazyframeObject) { if (lazyframe.useApi) { fetchFromApi(lazyframe).then(populatePlaceholder) } else { @@ -148,10 +185,10 @@ const Lazyframe = () => { } } - function populatePlaceholder(lazyframe) { + function populatePlaceholder(lazyframe: LazyframeObject) { const titleNode = lazyframe.node.querySelector('.lazyframe__title') - if (lazyframe.title && titleNode.innerHTML === '') { + if (lazyframe.title && titleNode && titleNode.innerHTML === '') { titleNode.innerHTML = lazyframe.title } if (lazyframe.thumbnail) { @@ -160,13 +197,13 @@ const Lazyframe = () => { onLoad(lazyframe) } - function onLoad(lazyframe) { + function onLoad(lazyframe: LazyframeObject) { lazyframe.node.classList.add(classNames.loaded) lazyframe.initialized = true if (lazyframe.initinview) { lazyframe.node.click() } - settings.onLoad.call(this, lazyframe.node) + settings.onLoad.call(null, lazyframe.node) } function scroll() { @@ -195,42 +232,46 @@ const Lazyframe = () => { window.addEventListener('scroll', onScroll, false) } - function debounce(func, wait) { - let timeout + function debounce(func: () => void, wait: number) { + let timeout: null | NodeJS.Timeout return function () { let later = () => { timeout = null - func.apply(this) + func.apply(null) } let callNow = !timeout - clearTimeout(timeout) + if (timeout) { + clearTimeout(timeout) + } timeout = setTimeout(later, wait) - if (callNow) func.apply(this) + if (callNow) func.apply(null) } } - function createIframeNode(lazyframe) { + function createIframeNode( + vendor: LazyframeObject['vendor'] | '' = '', + query: string, + src: string, + id: string + ) { const docfrag = document.createDocumentFragment() const iframeNode = document.createElement('iframe') - const vendor = lazyframe.vendor || '' - - if (vendor.indexOf('youtube') > -1) { - lazyframe.embed = `https://www.${vendor}.com/embed/${lazyframe.id}/?${lazyframe.query}` + let embed = src + if (vendor && vendor.indexOf('youtube') > -1) { + embed = `https://www.${vendor}.com/embed/${id}/?${query}` } else if (vendor === 'vimeo') { - lazyframe.embed = `https://player.vimeo.com/video/${lazyframe.id}/?${lazyframe.query}` - } else { - lazyframe.embed = lazyframe.src + embed = `https://player.vimeo.com/video/${id}/?${query}` } - if (lazyframe.id) { - iframeNode.setAttribute('id', `lazyframe-${lazyframe.id}`) + if (id) { + iframeNode.setAttribute('id', `lazyframe-${id}`) } - iframeNode.setAttribute('src', lazyframe.embed) - iframeNode.setAttribute('frameborder', 0) + iframeNode.setAttribute('src', embed) + iframeNode.setAttribute('frameborder', '0') iframeNode.setAttribute('allowfullscreen', '') - if (lazyframe.autoplay) { + if (settings.autoplay) { iframeNode.allow = 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture' } diff --git a/src/scss/_base.scss b/src/scss/_base.scss deleted file mode 100644 index 3f223e3..0000000 --- a/src/scss/_base.scss +++ /dev/null @@ -1,51 +0,0 @@ -.lazyframe { - position: relative; - - background-color: currentColor; - background-repeat: no-repeat; - background-size: cover; - background-position: center; - - &__title { - position: absolute; - top: 0; - right: 0; - left: 0; - padding: 15px 17px; - z-index: 3; - - &::after { - z-index: -1; - } - - } - - &:hover { - cursor: pointer; - } - - &::before { - display: block; - content: ""; - width: 100%; - padding-top: 100%; - } - - &[data-ratio="16:9"]::before { padding-top: 56.25%; } - - &[data-ratio="4:3"]::before { padding-top: 75%; } - - &[data-ratio="1:1"]::before { padding-top: 100%; } - - iframe { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 5; - width: 100%; - height: 100%; - } - -} diff --git a/src/scss/lazyframe.scss b/src/scss/lazyframe.scss deleted file mode 100644 index 112a307..0000000 --- a/src/scss/lazyframe.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import "base"; -@import "themes/youtube"; -@import "themes/vimeo"; diff --git a/src/scss/themes/_vimeo.scss b/src/scss/themes/_vimeo.scss deleted file mode 100644 index dcab1df..0000000 --- a/src/scss/themes/_vimeo.scss +++ /dev/null @@ -1,41 +0,0 @@ -.lazyframe[data-vendor="vimeo"] { - background-color: #00adef; - - .lazyframe__title { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - color: #00adef; - font-size: 20px; - font-weight: 700; - text-rendering: optimizeLegibility; - user-select: none; - -webkit-font-smoothing: auto; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - background-color: rgba(0, 0, 0, .5); - } - - &::before { - padding-top: 48.25%; - } - - &::after { - content: ""; - height: 40px; - width: 65px; - display: block; - bottom: 10px; - left: 10px; - z-index: 3; - background-color: rgba(0, 0, 0, .5); - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' baseProfile='tiny' viewBox='0 0 24 24'%3E%3Cpath fill='%23FFF' d='M7.765 16.89l8.47-4.89-8.47-4.89'/%3E%3C/svg%3E"); - background-position: center center; - background-size: 100% 100%; - background-repeat: no-repeat; - border-radius: 5px; - position: relative; - } - - &:hover::after { - background-color: #00adef; - } - -} diff --git a/src/scss/themes/_youtube.scss b/src/scss/themes/_youtube.scss deleted file mode 100644 index 55175a7..0000000 --- a/src/scss/themes/_youtube.scss +++ /dev/null @@ -1,64 +0,0 @@ -.lazyframe[data-vendor="youtube"], -.lazyframe[data-vendor="youtube_nocookie"] { - background-color: #e52d27; - font-family: Roboto, Arial, Helvetica, sans-serif; - - .lazyframe__title { - color: rgb(238, 238, 238); - font-family: Roboto, Arial, Helvetica, sans-serif; - font-size: 18px; - text-shadow: rgba(0, 0, 0, .498039) 0 0 2px; - -webkit-font-smoothing: antialiased; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - transition: color .1s cubic-bezier(.4, 0, 1, 1); - - &:hover { - color: #fff; - } - - &::before { - content: ""; - display: block; - background: linear-gradient(rgba(0, 0, 0, .2), transparent); - height: 98px; - width: 100%; - pointer-events: none; - position: absolute; - top: 0; - left: 0; - right: 0; - z-index: -1; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); - } - - } - - &::before { - padding-top: 56.25%; - } - - &::after { - content: ""; - position: absolute; - left: 50%; - top: 50%; - width: 68px; - height: 48px; - margin-left: -34px; - margin-top: -24px; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%231F1F1F' d='M255.7 446.3c-53.3.3-106.6-.4-159.8-3.3-17.4-1-34.7-2.5-50.4-11C35 426.3 27 418.4 22 407.2 13.2 388.6 10.5 369 9 349c-3.4-41.3-3.6-82.6-1.8-123.8 1-22 1.6-44 6.8-65.5 2-8.4 5-16.6 8.8-24.4C32 117 48 108 67.3 104c16.2-3 32.8-3 49.3-3.7 56-2.3 112-3.5 168-3 43 .6 86.2 1.7 129.3 4 13.2.6 26.6.8 39.3 5.5 17.2 6.4 30 17.2 37 34.7 6.6 16.8 9.2 34.2 10.6 52 3.8 48.7 4 97.3.7 146-1 16.3-2.2 32.7-6.5 48.8-9.7 37-32.8 51.5-66.7 53.8-36.2 2.5-72.5 3.8-108.8 4.3-21.3.2-42.7 0-64 0zM203.2 344L348 264.7l-144.8-79.3V344z'/%3E%3Cpath fill='%23FEFDFD' d='M203.2 344V185.5L348 264.8 203.2 344z'/%3E%3C/svg%3E"); - background-position: center center; - background-size: 100%; - background-repeat: no-repeat; - opacity: .81; - - border: none; - z-index: 4; - } - - &:hover::after { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23DD2C28' d='M255.7 446.3c-53.3.3-106.6-.4-159.8-3.3-17.4-1-34.7-2.5-50.4-11C35 426.3 27 418.4 22 407.2 13.2 388.6 10.5 369 9 349c-3.4-41.3-3.6-82.6-1.8-123.8 1-22 1.6-44 6.8-65.5 2-8.4 5-16.6 8.8-24.4C32 117 48 108 67.3 104c16.2-3 32.8-3 49.3-3.7 56-2.3 112-3.5 168-3 43 .6 86.2 1.7 129.3 4 13.2.6 26.6.8 39.3 5.5 17.2 6.4 30 17.2 37 34.7 6.6 16.8 9.2 34.2 10.6 52 3.8 48.7 4 97.3.7 146-1 16.3-2.2 32.7-6.5 48.8-9.7 37-32.8 51.5-66.7 53.8-36.2 2.5-72.5 3.8-108.8 4.3-21.3.2-42.7 0-64 0zM203.2 344L348 264.7l-144.8-79.3V344z'/%3E%3Cpath fill='%23FEFDFD' d='M203.2 344V185.5L348 264.8 203.2 344z'/%3E%3C/svg%3E"); - opacity: 1; - } - -} diff --git a/test/server.js b/test/server.js index 0225d8d..cccfa05 100644 --- a/test/server.js +++ b/test/server.js @@ -1,9 +1,9 @@ -const path = require('path'); +const path = require('path') -const test = require('ava'); +const test = require('ava') -const lazyframe = require('..'); +const lazyframe = require('../dist/lazyframe.module') test('should expose lazyframe()', (t) => { - t.true(typeof lazyframe === 'function'); -}); + t.true(typeof lazyframe === 'function') +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e81ceea --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,106 @@ +{ + "include": [ + "src/lazyframe.ts" + ], + "exclude": [ + "dist" + ], + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "esnext", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "dist", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + "declarationDir": ".", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From 48cb315adb5b9d0417111f3726f6329bc1f26588 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Fri, 15 Oct 2021 14:42:22 +0200 Subject: [PATCH 05/12] More --- package.json | 10 ++++------ src/lazyframe.ts | 1 + test/browser.js | 27 +++++++++++---------------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 896351c..734bccf 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "typescript": "^4.4.4" }, "homepage": "https://vb.github.io/lazyframe", - "jsnext:main": "dist/lazyframe.module.js", + "main": "dist/lazyframe.module.js", "keywords": [ "embed", "iframe", @@ -30,7 +30,7 @@ "youtube" ], "license": "MIT", - "main": "dist/lazyframe.min.js", + "browser": "dist/lazyframe.min.js", "repository": { "type": "git", "url": "git+https://github.com/vb/lazyframe.git" @@ -42,8 +42,6 @@ "test:watch": "npm run build && ava -s -w" }, "files": [ - "dist", - "src" - ], - "dependencies": {} + "dist" + ] } diff --git a/src/lazyframe.ts b/src/lazyframe.ts index 0fba3d7..a636485 100644 --- a/src/lazyframe.ts +++ b/src/lazyframe.ts @@ -193,6 +193,7 @@ const Lazyframe = () => { } if (lazyframe.thumbnail) { lazyframe.node.style.backgroundImage = `url(${lazyframe.thumbnail})` + settings.onThumbnailLoad.call(null, lazyframe.thumbnail) } onLoad(lazyframe) } diff --git a/test/browser.js b/test/browser.js index b181ed5..0227a7c 100644 --- a/test/browser.js +++ b/test/browser.js @@ -46,15 +46,21 @@ const createDomNode = (params = {}) => { return node } -const lazyframe = (initializer = '.lazyframe', config = {}) => { +const lazyframe = (initializer = '.lazyframe', config = {}, cb = 'onLoad') => { return new Promise((resolve) => { let i = 0 const nodes = window.lazyframe(initializer, { ...config, - onLoad: () => { - i++ - if (i === nodes.length) { - resolve() + lazyload: false, + onLoad: (e) => { + if (!nodes) { + resolve(e) + } else { + i++ + + if (i === nodes.length) { + resolve(e) + } } }, }) @@ -67,7 +73,6 @@ test('should expose lazyframe()', async (t) => { test('should initialize one node with a string selector', async (t) => { createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) await lazyframe() @@ -76,11 +81,9 @@ test('should initialize one node with a string selector', async (t) => { test('should initialize mulitple nodes with a string selector', async (t) => { createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) @@ -90,7 +93,6 @@ test('should initialize mulitple nodes with a string selector', async (t) => { test('should initialize with a single node', async (t) => { const node = createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) @@ -100,11 +102,9 @@ test('should initialize with a single node', async (t) => { test('should initialize with a nodelist', async (t) => { createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDB/?rel=0', }) createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDC/?rel=0', }) @@ -115,7 +115,6 @@ test('should initialize with a nodelist', async (t) => { test('should append an iframe on click', async (t) => { const node = createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) @@ -128,11 +127,9 @@ test('should append an iframe on click', async (t) => { test('should call onAppend callback function', async (t) => { let i = 0 const node1 = createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) const node2 = createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', }) @@ -150,7 +147,6 @@ test('should call onAppend callback function', async (t) => { test('should use data-title', async (t) => { const title = 'custom title' const node = createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?rel=0', title, }) @@ -164,7 +160,6 @@ test('should use data-title', async (t) => { test('should append optional query params from data-src', async (t) => { const query = 'rel=0&p=1' const node = createDomNode({ - vendor: 'youtube', src: 'http://www.youtube.com/embed/iwGFalTRHDA/?' + query, }) From 86ccd0346609b2bcaa8e7e0e6e98df76ecb059f7 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Fri, 15 Oct 2021 14:43:14 +0200 Subject: [PATCH 06/12] 2.3.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9be4241..3a979ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "lazyframe", - "version": "2.2.5", + "version": "2.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 734bccf..905ffa7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "lazyframe", "description": "Dependency-free library for lazyloading iframes", - "version": "2.2.5", + "version": "2.3.0", "author": "Viktor Bergehall", "bugs": { "url": "https://github.com/vb/lazyframe/issues" From b2f1e49eb4e38ad65de932626bfd7454f5127597 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Fri, 15 Oct 2021 14:51:05 +0200 Subject: [PATCH 07/12] added tslib devdependency --- package-lock.json | 1382 +-------------------------------------------- package.json | 1 + 2 files changed, 18 insertions(+), 1365 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3a979ac..9db6a1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,1015 +13,21 @@ "@babel/highlight": "^7.12.13" } }, - "@babel/compat-data": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", - "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==", - "dev": true - }, - "@babel/core": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.16.tgz", - "integrity": "sha512-sXHpixBiWWFti0AV2Zq7avpTasr6sIAu7Y396c608541qAU2ui4a193m0KSQmfPSKFZLnQ3cvlKDOm3XkuXm3Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.16", - "@babel/helper-compilation-targets": "^7.13.16", - "@babel/helper-module-transforms": "^7.13.14", - "@babel/helpers": "^7.13.16", - "@babel/parser": "^7.13.16", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.15", - "@babel/types": "^7.13.16", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - } - }, - "@babel/generator": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.16.tgz", - "integrity": "sha512-grBBR75UnKOcUWMp8WoDxNsWCFl//XCK6HWTrBQKTr5SV9f5g0pNOjdyzi/DTBv12S9GnYPInIXQBTky7OXEMg==", - "dev": true, - "requires": { - "@babel/types": "^7.13.16", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", - "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", - "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz", - "integrity": "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.15", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.13.11", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz", - "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", - "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "regexpu-core": "^4.7.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.0.tgz", - "integrity": "sha512-JT8tHuFjKBo8NnaUbblz7mIu1nnvUDiHVjXXkulZULyidvo/7P6TY7+YqpV37IfF+KUFxmlK04elKtGKXaiVgw==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", - "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.0" - } - }, - "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz", - "integrity": "sha512-1eMtTrXtrwscjcAeO4BVK+vvkxaLJSPFz1w1KLawz6HLNi9bPFGBNwwDyVfiu1Tv/vRRFYfoGaKhmAQPGPn5Wg==", - "dev": true, - "requires": { - "@babel/traverse": "^7.13.15", - "@babel/types": "^7.13.16" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-module-transforms": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", - "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", - "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-wrap-function": "^7.13.0", - "@babel/types": "^7.13.0" - } - }, - "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", - "dev": true, - "requires": { - "@babel/types": "^7.13.12" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.1" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", - "dev": true, - "requires": { - "@babel/types": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", - "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" - } - }, - "@babel/helpers": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.17.tgz", - "integrity": "sha512-Eal4Gce4kGijo1/TGJdqp3WuhllaMLSrW6XcL0ulyUAQOuxHcCafZE8KHg9857gcTehsm/v7RcOx2+jp0Ryjsg==", - "dev": true, - "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.17", - "@babel/types": "^7.13.17" - } - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.16.tgz", - "integrity": "sha512-6bAg36mCwuqLO0hbR+z7PHuqWiCeP7Dzg73OpQwsAB1Eb8HnGEz5xYBzCfbu+YjoaJsJs+qheDxVAuqbt3ILEw==", - "dev": true - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz", - "integrity": "sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.13.12" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz", - "integrity": "sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", - "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", - "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", - "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", - "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", - "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", - "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", - "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", - "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", - "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz", - "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", - "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", - "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", - "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", - "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", - "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", - "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.13.16", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.13.16.tgz", - "integrity": "sha512-ad3PHUxGnfWF4Efd3qFuznEtZKoBp0spS+DgqzVzRPV7urEBvPLue3y2j80w4Jf2YLzZHj8TOv/Lmvdmh3b2xg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", - "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", - "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.17.tgz", - "integrity": "sha512-UAUqiLv+uRLO+xuBKKMEpC+t7YRNVRqBsWWq1yKXbBZBje/t3IXCiSinZhjn/DC3qzBfICeYd2EFGEbHsh5RLA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", - "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", - "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", - "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", - "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", - "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", - "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", - "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", - "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", - "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", - "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.13.0", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-identifier": "^7.12.11", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", - "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", - "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", - "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-object-assign": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.12.13.tgz", - "integrity": "sha512-4QxDMc0lAOkIBSfCrnSGbAJ+4epDBF2XXwcLXuBcG1xl9u7LrktNVD4+LwhL47XuKVPQ7R25e/WdcV+h97HyZA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", - "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/helper-replace-supers": "^7.12.13" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", - "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", - "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz", - "integrity": "sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", - "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", - "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", - "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", - "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", - "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.13.0" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", - "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", - "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", - "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/preset-env": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.15.tgz", - "integrity": "sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.15", - "@babel/helper-compilation-targets": "^7.13.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-option": "^7.12.17", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.13.12", - "@babel/plugin-proposal-async-generator-functions": "^7.13.15", - "@babel/plugin-proposal-class-properties": "^7.13.0", - "@babel/plugin-proposal-dynamic-import": "^7.13.8", - "@babel/plugin-proposal-export-namespace-from": "^7.12.13", - "@babel/plugin-proposal-json-strings": "^7.13.8", - "@babel/plugin-proposal-logical-assignment-operators": "^7.13.8", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", - "@babel/plugin-proposal-numeric-separator": "^7.12.13", - "@babel/plugin-proposal-object-rest-spread": "^7.13.8", - "@babel/plugin-proposal-optional-catch-binding": "^7.13.8", - "@babel/plugin-proposal-optional-chaining": "^7.13.12", - "@babel/plugin-proposal-private-methods": "^7.13.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.13", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.12.13", - "@babel/plugin-transform-arrow-functions": "^7.13.0", - "@babel/plugin-transform-async-to-generator": "^7.13.0", - "@babel/plugin-transform-block-scoped-functions": "^7.12.13", - "@babel/plugin-transform-block-scoping": "^7.12.13", - "@babel/plugin-transform-classes": "^7.13.0", - "@babel/plugin-transform-computed-properties": "^7.13.0", - "@babel/plugin-transform-destructuring": "^7.13.0", - "@babel/plugin-transform-dotall-regex": "^7.12.13", - "@babel/plugin-transform-duplicate-keys": "^7.12.13", - "@babel/plugin-transform-exponentiation-operator": "^7.12.13", - "@babel/plugin-transform-for-of": "^7.13.0", - "@babel/plugin-transform-function-name": "^7.12.13", - "@babel/plugin-transform-literals": "^7.12.13", - "@babel/plugin-transform-member-expression-literals": "^7.12.13", - "@babel/plugin-transform-modules-amd": "^7.13.0", - "@babel/plugin-transform-modules-commonjs": "^7.13.8", - "@babel/plugin-transform-modules-systemjs": "^7.13.8", - "@babel/plugin-transform-modules-umd": "^7.13.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13", - "@babel/plugin-transform-new-target": "^7.12.13", - "@babel/plugin-transform-object-super": "^7.12.13", - "@babel/plugin-transform-parameters": "^7.13.0", - "@babel/plugin-transform-property-literals": "^7.12.13", - "@babel/plugin-transform-regenerator": "^7.13.15", - "@babel/plugin-transform-reserved-words": "^7.12.13", - "@babel/plugin-transform-shorthand-properties": "^7.12.13", - "@babel/plugin-transform-spread": "^7.13.0", - "@babel/plugin-transform-sticky-regex": "^7.12.13", - "@babel/plugin-transform-template-literals": "^7.13.0", - "@babel/plugin-transform-typeof-symbol": "^7.12.13", - "@babel/plugin-transform-unicode-escapes": "^7.12.13", - "@babel/plugin-transform-unicode-regex": "^7.12.13", - "@babel/preset-modules": "^0.1.4", - "@babel/types": "^7.13.14", - "babel-plugin-polyfill-corejs2": "^0.2.0", - "babel-plugin-polyfill-corejs3": "^0.2.0", - "babel-plugin-polyfill-regenerator": "^0.2.0", - "core-js-compat": "^3.9.0", - "semver": "^6.3.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", - "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/runtime": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.17.tgz", - "integrity": "sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - } - }, - "@babel/traverse": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.17.tgz", - "integrity": "sha512-BMnZn0R+X6ayqm3C3To7o1j7Q020gWdqdyP50KEoVqaCO2c/Im7sYZSmVgvefp8TTMQ+9CtwuBp0Z1CZ8V3Pvg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.16", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.16", - "@babel/types": "^7.13.17", - "debug": "^4.1.0", - "globals": "^11.1.0" - } + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true }, - "@babel/types": { - "version": "7.13.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.17.tgz", - "integrity": "sha512-RawydLgxbOPDlTLJNtoIypwdmAy//uQIzlKt2+iBiJaRlVuI6QLUxVAyWGNfOzp8Yu4L4lLIacoCyTNtpb4wiA==", + "@babel/highlight": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", + "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", - "to-fast-properties": "^2.0.0" + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" } }, "@concordance/react": { @@ -1067,16 +73,6 @@ "fastq": "^1.6.0" } }, - "@rollup/plugin-babel": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", - "integrity": "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - } - }, "@rollup/plugin-typescript": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz", @@ -1406,45 +402,6 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.0.tgz", - "integrity": "sha512-9bNwiR0dS881c5SHnzCmmGlMkJLl0OUZvxrxHo9w/iNoRuqaPjqlvBf4HrovXtQs/au5yKkpcdgfT1cC5PAZwg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.0", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.0.tgz", - "integrity": "sha512-zZyi7p3BCUyzNxLx8KV61zTINkkV65zVkDAFNZmrTCRVhjo1jAS+YLvDJ9Jgd/w2tsAviCwFHReYfxO3Iql8Yg==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.0", - "core-js-compat": "^3.9.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.0.tgz", - "integrity": "sha512-J7vKbCuD2Xi/eEHxquHN14bXAW9CXtecwuLrOIDJtcZzTaPzV1VdEfoUf9AzcRBMolKUQKM9/GVojeh0hFiqMg==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.0" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1585,19 +542,6 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "browserslist": { - "version": "4.16.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.5.tgz", - "integrity": "sha512-C2HAjrM1AI/djrpAUU/tr4pml1DqLIzJKSLDBXBrNErl9ZCCTXdhwxdJjYc16953+mBWf7Lw+uUJgpgb8cN71A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001214", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.719", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - } - }, "buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -1646,16 +590,6 @@ } } }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1668,12 +602,6 @@ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true }, - "caniuse-lite": { - "version": "1.0.30001214", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001214.tgz", - "integrity": "sha512-O2/SCpuaU3eASWVaesQirZv1MSjUNOvmugaD8zNSJqw6Vv5SGwoOpA9LJs3pNPfM745nxqPvfZY3MQKY4AKHYg==", - "dev": true - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1838,12 +766,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1942,24 +864,6 @@ "integrity": "sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=", "dev": true }, - "core-js-compat": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.11.0.tgz", - "integrity": "sha512-3wsN9YZJohOSDCjVB0GequOyHax8zFiogSX3XWLE28M1Ew7dTU57tgHjIylSBKSIouwmLBp3g61sKMz/q3xEGA==", - "dev": true, - "requires": { - "browserslist": "^4.16.4", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2094,15 +998,6 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, "del": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", @@ -2168,12 +1063,6 @@ "safer-buffer": "^2.1.0" } }, - "electron-to-chromium": { - "version": "1.3.719", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.719.tgz", - "integrity": "sha512-heM78GKSqrIzO9Oz0/y22nTBN7bqSP1Pla2SyU9DiSnQD+Ea9SyyN5RWWlgqsqeBLNDkSlE9J9EHFmdMPzxB/g==", - "dev": true - }, "emittery": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", @@ -2396,29 +1285,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -2477,12 +1349,6 @@ } } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, "globby": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", @@ -2553,12 +1419,6 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -2898,12 +1758,6 @@ } } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, "json-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", @@ -2940,15 +1794,6 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -3024,12 +1869,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -3218,12 +2057,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", - "dev": true - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -3268,24 +2101,6 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3720,50 +2535,6 @@ "picomatch": "^2.2.1" } }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", - "dev": true, - "requires": { - "regenerate": "^1.4.0" - } - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", - "dev": true, - "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" - } - }, "registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -3782,29 +2553,6 @@ "rc": "^1.2.8" } }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", - "dev": true - }, - "regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -3951,33 +2699,6 @@ "fsevents": "~2.3.1" } }, - "rollup-plugin-css-only": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz", - "integrity": "sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA==", - "dev": true, - "requires": { - "@rollup/pluginutils": "4" - }, - "dependencies": { - "@rollup/pluginutils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz", - "integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==", - "dev": true, - "requires": { - "estree-walker": "^2.0.1", - "picomatch": "^2.2.2" - } - }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - } - } - }, "rollup-plugin-import-css": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rollup-plugin-import-css/-/rollup-plugin-import-css-3.0.2.tgz", @@ -4005,15 +2726,6 @@ } } }, - "rollup-plugin-scss": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-scss/-/rollup-plugin-scss-3.0.0.tgz", - "integrity": "sha512-UldNaNHEon2a5IusHvj/Nnwc7q13YDvbFxz5pfNbHBNStxGoUNyM+0XwAA/UafJ1u8XRPGdBMrhWFthrrGZdWQ==", - "dev": true, - "requires": { - "rollup-pluginutils": "^2.3.3" - } - }, "rollup-plugin-terser": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", @@ -4063,23 +2775,6 @@ } } }, - "rollup-pluginutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", - "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", - "dev": true, - "requires": { - "estree-walker": "^0.6.1" - }, - "dependencies": { - "estree-walker": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", - "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", - "dev": true - } - } - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4101,15 +2796,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sass": { - "version": "1.42.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.42.1.tgz", - "integrity": "sha512-/zvGoN8B7dspKc5mC6HlaygyCBRvnyzzgD5khiaCfglWztY99cYoiTUksVx11NlnemrcfH5CEaCpsUKoW0cQqg==", - "dev": true, - "requires": { - "chokidar": ">=3.0.0 <4.0.0" - } - }, "saxes": { "version": "3.1.11", "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz", @@ -4185,12 +2871,6 @@ } } }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, "source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", @@ -4387,12 +3067,6 @@ "integrity": "sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=", "dev": true }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, "to-readable-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", @@ -4434,6 +3108,12 @@ "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", "dev": true }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -4479,34 +3159,6 @@ "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", "dev": true }, - "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", - "dev": true - }, "unique-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", diff --git a/package.json b/package.json index 905ffa7..3742479 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "rollup": "^2.39.0", "rollup-plugin-import-css": "^3.0.2", "rollup-plugin-terser": "^7.0.2", + "tslib": "^2.3.1", "typescript": "^4.4.4" }, "homepage": "https://vb.github.io/lazyframe", From 432106d12dc2efa73c2b9f8d3ca6a3e16706580c Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Fri, 15 Oct 2021 16:13:38 +0200 Subject: [PATCH 08/12] Added fetch --- README.md | 26 +++++++++++++------------- package-lock.json | 6 ------ package.json | 1 - src/lazyframe.ts | 28 ++++++++++------------------ test/browser.js | 21 ++++++++++++--------- 5 files changed, 35 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index d417782..1eea92d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Lazyframe + [![Node.js Package](https://github.com/vb/lazyframe/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/vb/lazyframe/actions/workflows/npm-publish.yml) [![npm version](https://badge.fury.io/js/lazyframe.svg)](https://badge.fury.io/js/lazyframe) @@ -40,19 +41,19 @@ $ bower install lazyframe JavaScript ES6 imports ```js -import lazyframe from "lazyframe"; +import lazyframe from 'lazyframe' ``` -Include JavaScript in html +Include JavaScript and css in html ```html ``` -Sass import +CSS import -```sass -@import 'src/scss/lazyframe' +```css +@import 'src/lazyframe.css'; ``` Include css in html @@ -65,15 +66,15 @@ Include css in html ```js // Passing a selector -lazyframe(".lazyframe"); +lazyframe('.lazyframe') // Passing a nodelist -let elements = document.querySelectorAll(".lazyframe"); -lazyframe(elements); +let elements = document.querySelectorAll('.lazyframe') +lazyframe(elements) // Passing a jQuery object -let elements = $(".lazyframe"); -lazyframe(elements); +let elements = $('.lazyframe') +lazyframe(elements) ``` ## Options @@ -84,7 +85,7 @@ General options and corresponding defaults ```js lazyframe(elements, { - debounce: 250, + debounce: 100, lazyload: true, autoplay: true, @@ -92,7 +93,7 @@ lazyframe(elements, { onLoad: (lazyframe) => console.log(lazyframe), onAppend: (iframe) => console.log(iframe), onThumbnailLoad: (img) => console.log(img), -}); +}) ``` ### `debounce` @@ -130,7 +131,6 @@ Callback function with the thumbnail URL data-src="" data-ratio="1:1" data-initinview="false" - data-autoplay="false" >
``` diff --git a/package-lock.json b/package-lock.json index 9db6a1c..fc51f8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2045,12 +2045,6 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "mock-xmlhttprequest": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/mock-xmlhttprequest/-/mock-xmlhttprequest-7.0.4.tgz", - "integrity": "sha512-hA0fIHy/74p5DE0rdmrpU0sV1U+gnWTcgShWequGRLy0L1eT+zY0ozFukawpLaxMwIA+orRcqFRElYwT+5p81A==", - "dev": true - }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index 3742479..234ae17 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "@rollup/plugin-typescript": "^8.2.5", "ava": "^3.15.0", "jsdom": "15", - "mock-xmlhttprequest": "^7.0.4", "rollup": "^2.39.0", "rollup-plugin-import-css": "^3.0.2", "rollup-plugin-terser": "^7.0.2", diff --git a/src/lazyframe.ts b/src/lazyframe.ts index a636485..2c4960f 100644 --- a/src/lazyframe.ts +++ b/src/lazyframe.ts @@ -156,25 +156,17 @@ const Lazyframe = () => { } function fetchFromApi(lazyframe: LazyframeObject): Promise { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - xhr.open('GET', `https://noembed.com/embed?url=${lazyframe.src}`) - xhr.onload = function () { - if (this.status === 200) { - const json = JSON.parse(xhr.response) - if (json.title) { - lazyframe.title = json.title - } - if (json.thumbnail_url) { - lazyframe.thumbnail = json.thumbnail_url - } - resolve(lazyframe) - } else { - reject() + return fetch(`https://noembed.com/embed?url=${lazyframe.src}`) + .then((res) => res.json()) + .then((json) => { + if (json.title) { + lazyframe.title = json.title } - } - xhr.send() - }) + if (json.thumbnail_url) { + lazyframe.thumbnail = json.thumbnail_url + } + return lazyframe + }) } function createPlaceholder(lazyframe: LazyframeObject) { diff --git a/test/browser.js b/test/browser.js index 0227a7c..20b13b0 100644 --- a/test/browser.js +++ b/test/browser.js @@ -5,14 +5,17 @@ const { Script } = require('vm') const test = require('ava') const { JSDOM, VirtualConsole } = require('jsdom') -const MockXMLHttpRequest = require('mock-xmlhttprequest') -const MockXhr = MockXMLHttpRequest.newMockXhr() - -MockXhr.onSend = (xhr) => { - const responseHeaders = { 'Content-Type': 'application/json' } - const response = - '{ "title": "mock title", "thumbnail_url": "mock thumbnail url" }' - xhr.respond(200, responseHeaders, response) +const mockData = { + title: 'mock title', + thumbnail_url: 'mock thumbnail url', +} + +const mockFetch = () => { + const mockResponse = { + json: () => Promise.resolve(mockResponse), + ...mockData, + } + return Promise.resolve(mockResponse) } const virtualConsole = new VirtualConsole() @@ -32,7 +35,7 @@ test.beforeEach(() => { dom.runVMScript(script) global.document = dom.window.document - dom.window.XMLHttpRequest = MockXhr + dom.window.fetch = mockFetch global.window = dom.window }) From 9875b760c306df1a250d960adfcaa40e563eced5 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Fri, 15 Oct 2021 16:33:13 +0200 Subject: [PATCH 09/12] Trying to resolve tslib issue --- rollup.config.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 4661a8d..45b7e77 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -13,7 +13,10 @@ export default [ sourcemap: true, }, plugins: [ - typescript({ tsconfig: './tsconfig.json' }), + typescript({ + tsconfig: './tsconfig.json', + tslib: require.resolve('tslib'), + }), css({ output: 'lazyframe.css', minify: true }), terser(), ], @@ -26,7 +29,10 @@ export default [ exports: 'default', }, plugins: [ - typescript({ tsconfig: './tsconfig.json' }), + typescript({ + tsconfig: './tsconfig.json', + tslib: require.resolve('tslib'), + }), css({ output: 'lazyframe.css', minify: true }), ], }, From 04ccbb1dcadbc028d23f6424eeb09b264766c276 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Sat, 16 Oct 2021 14:40:33 +0200 Subject: [PATCH 10/12] Updated workflow --- .github/workflows/npm-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 265e41e..03f41e1 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -5,7 +5,7 @@ name: Node.js Package on: release: - types: [created] + types: [created, edited] jobs: build: From e47237cb515df1850662796fe59fa42caefc5510 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Sun, 17 Oct 2021 12:42:30 +0200 Subject: [PATCH 11/12] 2.3.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7fce711..aab93ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "lazyframe", - "version": "2.3.0", + "version": "2.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 234ae17..36f916d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "lazyframe", "description": "Dependency-free library for lazyloading iframes", - "version": "2.3.0", + "version": "2.3.1", "author": "Viktor Bergehall", "bugs": { "url": "https://github.com/vb/lazyframe/issues" From dfd82ab25f659d2136a30bab00f3ff6a7380c635 Mon Sep 17 00:00:00 2001 From: Viktor Bergehall Date: Tue, 19 Oct 2021 11:44:39 +0200 Subject: [PATCH 12/12] Added settings for youtube thumbnails --- README.md | 21 ++++++++++- src/lazyframe.ts | 94 +++++++++++++++++++++++++++++++++++++----------- test/browser.js | 4 +-- 3 files changed, 96 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1eea92d..64558d0 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,8 @@ lazyframe(elements, { debounce: 100, lazyload: true, autoplay: true, - + youtubeThumbnailQuality: 'hq', + youtubeThumbnailImage: 'default', // Callbacks onLoad: (lazyframe) => console.log(lazyframe), onAppend: (iframe) => console.log(iframe), @@ -108,6 +109,14 @@ Set this to `false` if you want all API calls and local images to be loaded on p Set this to `false` to remove autoplay from the `allow` attribute on the iframe tag i.e if set this to `false` if you want don't want your Youtube video to automatically start playing once the user clicks on the play icon. +### youtubeThumbnailQuality + +Defines the thumbnail quality to use from Youtubes thumbnail service. Possible values are '', 'sd', 'mq', 'hq' and 'maxres' + +### youtubeThumbnailImage + +Defines the thumbnail image to use from Youtubes thumbnail service. Possible values are 'default', '1', '2' and '3' + ### `onLoad` Callback function for when a element is initialized. @@ -131,6 +140,8 @@ Callback function with the thumbnail URL data-src="" data-ratio="1:1" data-initinview="false" + data-youtube-thumbnail-image="default" + data-youtube-thumbnail-quality="hq" >
``` @@ -158,6 +169,14 @@ The ratio of the lazyframe. Possible values: 16:9, 4:3, 1:1 Set this to true if you want the resource to execute (for example video to play) when the element is in view. +### data-youtube-thumbnail-image + +Defines the thumbnail image to use from Youtubes thumbnail service. Possible values are 'default', '1', '2' and '3'. + +### data-youtube-thumbnail-quality + +Defines the thumbnail quality to use from Youtubes thumbnail service. Possible values are '', 'sd', 'mq', 'hq' and 'maxres' + ## License [MIT](https://opensource.org/licenses/MIT). © 2016 Viktor Bergehall diff --git a/src/lazyframe.ts b/src/lazyframe.ts index 2c4960f..19ca16c 100644 --- a/src/lazyframe.ts +++ b/src/lazyframe.ts @@ -4,7 +4,22 @@ interface LazyframeObject extends LazyframeSettings { node: HTMLElement } -interface LazyframeSettings { +interface LazyframeOptions { + debounce: number + lazyload: boolean + autoplay: boolean + youtubeThumbnailQuality: '' | 'sd' | 'mq' | 'hq' | 'maxres' + youtubeThumbnailImage: 'default' | '1' | '2' | '3' + onLoad: (node: HTMLElement) => void + onAppend: (node: HTMLElement | null) => void + onThumbnailLoad: (url: string) => void +} + +type OverrideAbleSettings = Pick< + LazyframeOptions, + 'youtubeThumbnailImage' | 'youtubeThumbnailQuality' +> +interface LazyframeSettings extends OverrideAbleSettings { src: string embed: string title: string | null @@ -18,23 +33,27 @@ interface LazyframeSettings { iframeNode: DocumentFragment } -interface LazyframeOptions { - debounce: number - lazyload: boolean - autoplay: boolean - onLoad: (node: HTMLElement) => void - onAppend: (node: HTMLElement | null) => void - onThumbnailLoad: (url: string) => void -} - const Lazyframe = () => { const findVendorIdAndQuery = new RegExp( /^(?:https?:\/\/)?(?:www\.)?(youtube-nocookie|youtube|vimeo)(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([\w-_]+)(?:\&|\?|\/\?)?(.+)?$/ ) - const classNames = { - loaded: 'lazyframe--loaded', - title: 'lazyframe__title', + const youtube = { + quality: { + values: ['', 'sd', 'mq', 'hq', 'maxres'], + default: 'hq' as LazyframeSettings['youtubeThumbnailQuality'], + }, + image: { + values: ['default', '1', '2', '3'], + default: 'default' as LazyframeSettings['youtubeThumbnailImage'], + }, + isYoutube: (vendor: LazyframeSettings['vendor']) => + vendor && vendor.indexOf('youtube') > -1, + } + + enum Classes { + LOADED = 'lazyframe--loaded', + TITLE = 'lazyframe__title', } const nodes: LazyframeObject[] = [] @@ -43,6 +62,8 @@ const Lazyframe = () => { debounce: 100, lazyload: true, autoplay: true, + youtubeThumbnailQuality: youtube.quality.default, + youtubeThumbnailImage: youtube.image.default, onLoad: () => {}, onAppend: () => {}, onThumbnailLoad: () => {}, @@ -75,7 +96,7 @@ const Lazyframe = () => { } function create(node: HTMLElement) { - if (node.classList.contains(classNames.loaded)) { + if (node.classList.contains(Classes.LOADED)) { return } @@ -106,7 +127,7 @@ const Lazyframe = () => { const fragment = document.createDocumentFragment() const titleNode = document.createElement('span') - titleNode.className = classNames.title + titleNode.className = Classes.TITLE fragment.appendChild(titleNode) if (lazyframe.title) { @@ -122,6 +143,8 @@ const Lazyframe = () => { const thumbnail = node.getAttribute('data-thumbnail') const initinview = node.getAttribute('data-initinview') === 'true' + const youtube = getYoutubeSettings(node) + if (!src) { throw new Error('You must supply a data-src on the node') } @@ -152,6 +175,23 @@ const Lazyframe = () => { query, initialized: false, iframeNode: createIframeNode(vendor, query, src, id), + youtubeThumbnailQuality: youtube.quality, + youtubeThumbnailImage: youtube.image, + } + } + + function getYoutubeSettings(node: HTMLElement) { + let quality = node.getAttribute('data-youtube-thumbnail-quality') + if (!quality || !youtube.quality.values.includes(quality)) { + quality = settings.youtubeThumbnailQuality + } + let image = node.getAttribute('data-youtube-thumbnail-image') + if (!image || !youtube.image.values.includes(image)) { + image = settings.youtubeThumbnailImage + } + return { + image: image as LazyframeSettings['youtubeThumbnailImage'], + quality: quality as LazyframeSettings['youtubeThumbnailQuality'], } } @@ -163,7 +203,21 @@ const Lazyframe = () => { lazyframe.title = json.title } if (json.thumbnail_url) { - lazyframe.thumbnail = json.thumbnail_url + if (youtube.isYoutube(lazyframe.vendor)) { + if ( + lazyframe.youtubeThumbnailImage === youtube.image.default && + lazyframe.youtubeThumbnailQuality === youtube.quality.default + ) { + lazyframe.thumbnail = json.thumbnail_url + } + lazyframe.thumbnail = json.thumbnail_url.replace( + new RegExp(youtube.quality.default + youtube.image.default), + lazyframe.youtubeThumbnailQuality + + lazyframe.youtubeThumbnailImage + ) + } else { + lazyframe.thumbnail = json.thumbnail_url + } } return lazyframe }) @@ -178,7 +232,7 @@ const Lazyframe = () => { } function populatePlaceholder(lazyframe: LazyframeObject) { - const titleNode = lazyframe.node.querySelector('.lazyframe__title') + const titleNode = lazyframe.node.querySelector(`.${Classes.TITLE}`) if (lazyframe.title && titleNode && titleNode.innerHTML === '') { titleNode.innerHTML = lazyframe.title @@ -191,7 +245,7 @@ const Lazyframe = () => { } function onLoad(lazyframe: LazyframeObject) { - lazyframe.node.classList.add(classNames.loaded) + lazyframe.node.classList.add(Classes.LOADED) lazyframe.initialized = true if (lazyframe.initinview) { lazyframe.node.click() @@ -242,7 +296,7 @@ const Lazyframe = () => { } function createIframeNode( - vendor: LazyframeObject['vendor'] | '' = '', + vendor: LazyframeSettings['vendor'], query: string, src: string, id: string @@ -251,7 +305,7 @@ const Lazyframe = () => { const iframeNode = document.createElement('iframe') let embed = src - if (vendor && vendor.indexOf('youtube') > -1) { + if (youtube.isYoutube(vendor)) { embed = `https://www.${vendor}.com/embed/${id}/?${query}` } else if (vendor === 'vimeo') { embed = `https://player.vimeo.com/video/${id}/?${query}` diff --git a/test/browser.js b/test/browser.js index 20b13b0..f4a5d46 100644 --- a/test/browser.js +++ b/test/browser.js @@ -171,7 +171,7 @@ test('should append optional query params from data-src', async (t) => { node.click() const iframe = node.querySelector('iframe') const src = iframe.getAttribute('src') - const [, iframQuery] = src.split('?autoplay=1&') + const [, iframeQuery] = src.split('?autoplay=1&') - t.is(iframQuery, query) + t.is(iframeQuery, query) })