@dkvz/img-lightbox 0.2.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,6 +9,8 @@ I quickly made this in regard to a blog article I was writing, it could be impro
9
9
 
10
10
  Uncompressed minified size: 8.5Kb including the loading spinner image.
11
11
 
12
+ **Note**: we no longer minify the build - It seems to be standard practice for libraries nowadays.
13
+
12
14
  ## Using the component from npm
13
15
  To use it in a project with a module bundler, install the dependency first:
14
16
  ```
@@ -44,6 +46,22 @@ img-lightbox:active, img-lightbox:focus {
44
46
  }
45
47
  ```
46
48
 
49
+ You also may have strange spacing issues if the a and img elements have their default "inline" display mode. Which could be changed like so:
50
+ ```css
51
+ img-lightbox a, img-lightbox img {
52
+ display: block;
53
+ }
54
+ ```
55
+
56
+ This is also where you should set any max-width or max-height. Or you could set it on img-lightbox itself but then you need to set width and height to 100% as in:
57
+ ```css
58
+ img-lightbox a, img-lightbox img {
59
+ display: block;
60
+ width: 100%;
61
+ height: 100%;
62
+ }
63
+ ```
64
+
47
65
  ## Building the component
48
66
 
49
67
  ### Build requirements
@@ -62,11 +80,6 @@ Build using either:
62
80
  ```
63
81
  npm run build
64
82
  ```
65
- For the shadow DOM (default) version and:
66
- ```
67
- npm run build-no-shadow
68
- ```
69
- For the version that does not use the shadow DOM API at all.
70
83
 
71
84
  You'll find the build script in the `dist` folder.
72
85
 
@@ -77,8 +90,20 @@ To manually use it in some page, you could do something like this:
77
90
  customElements.define('img-lightbox', ImgLightbox.default);
78
91
  </script>
79
92
  ```
93
+ **Update 2025**: There is a .mjs file built as well and it might be a good idea to use that one (with `type="module" in the script tag`).
94
+
80
95
  The loading icon SVG file is normally not necessary but since I change my mind all the time about it you might want to copy it along anyway.
81
96
 
97
+ ## Build without shadow DOM
98
+ In the past I had a way to build the component without using the shadow DOM at all, which has a few consequences but I think the main idea was to support some old browsers.
99
+
100
+ Anyway, after upgrading Parcel to v2 I didn't take time to fix the build command for the no-shadow DOM version.
101
+
102
+ It used to be:
103
+ ```
104
+ npm run build-no-shadow
105
+ ```
106
+
82
107
  The no-shadow DOM version also requires extra styles to work. See `src/no-shadow/index.pug`.
83
108
 
84
109
  ## Remarks
@@ -127,7 +152,6 @@ if (event.altKey)
127
152
  - [ ] Write tests - Probably going to need jsdom
128
153
  - [x] Don't forget to register the keyboard events
129
154
  - [x] Use template tags, they say it's better (here)[https://github.com/GoogleChromeLabs/howto-components/blob/master/elements/howto-checkbox/howto-checkbox.js]
130
- - [ ] Document how to check for web component browser support
131
155
  - [x] Disable overflow on the fullscreen overlay
132
156
  - [x] Make a shadow DOM version
133
157
  - [x] To maximize accessibility we need some kind of focus outline
@@ -1,6 +1,204 @@
1
- parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c<t.length;c++)try{f(t[c])}catch(e){i||(i=e)}if(t.length){var l=f(t[t.length-1]);"object"==typeof exports&&"undefined"!=typeof module?module.exports=l:"function"==typeof define&&define.amd?define(function(){return l}):n&&(this[n]=l)}if(parcelRequire=f,i)throw i;return f}({"q71P":[function(require,module,exports) {
2
- module.exports="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2NCA2NCIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgNjQgNjQiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPjxtZXRhZGF0YT48cmRmOlJERj48Y2M6V29yayByZGY6YWJvdXQ9IiI+PGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+PGRjOnR5cGUgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIvPjxkYzp0aXRsZS8+PC9jYzpXb3JrPjwvcmRmOlJERj48L21ldGFkYXRhPgo8Zz4KCQk8Y2lyY2xlIGNsYXNzPSJzdDAiIGN4PSIzMiIgY3k9IjMyIiByPSIzMiIvPgoJPC9nPjxnIGNsYXNzPSJzdDEiIG9wYWNpdHk9Ii4yIj4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJtNDYgNTBoLTJ2LTRjMC00LjUtMy03LjQtMy03LjRzLTMtMi44LTMuOS0zLjcgMC0xLjggMC0xLjggMS4zLTEuMyA0LjItNGMyLjgtMi43IDIuNy02LjcgMi43LTYuN3YtNS4xbC0xMi0xLTEyIDF2NS4xcy0wLjEgMy45IDIuNyA2LjdjMi44IDIuNyA0LjIgNCA0LjIgNHMwLjkgMC45IDAgMS44LTMuOSAzLjctMy45IDMuNy0zIDIuOC0zIDcuNHY0aC0yYy0xLjEgMC0yIDAuOS0yIDJzMC45IDIgMiAyaDI4YzEuMSAwIDItMC45IDItMnMtMC45LTItMi0yeiIgZmlsbD0iIzIzMWYyMCIvPgoJPC9nPgoJCTxwYXRoIGNsYXNzPSJzdDMiIGQ9Im00MSAzNi42cy0zLTIuOC0zLjktMy43IDAtMS44IDAtMS44IDEuMy0xLjMgNC4yLTRjMi44LTIuNyAyLjctNi43IDIuNy02Ljd2LTUuMWwtMTItMS0xMiAxdjUuMXMtMC4xIDMuOSAyLjcgNi43YzIuOCAyLjcgNC4yIDQgNC4yIDRzMC45IDAuOSAwIDEuOC0zLjkgMy43LTMuOSAzLjctMyAyLjgtMyA3LjR2NS4xaDI0di01LjFjMC00LjUtMy03LjQtMy03LjR6IiBmaWxsPSIjZmZmIi8+CgkKCQk8cGF0aCBjbGFzcz0ic3Q0IiBkPSJtMzEgNDN2LTExYzAtMi4xLTEtMy40LTEuMy0zLjdsLTQuMi00Yy0xLjUtMS40LTEuNS0zLjctMS41LTMuN2gxNnMwIDIuMy0xLjUgMy43bC00LjIgNGMtMC40IDAuMy0xLjMgMS42LTEuMyAzLjd2MTF6Ii8+Cgk8ZyBjbGFzcz0ic3Q1IiBvcGFjaXR5PSIuMyI+CgkJPHBhdGggY2xhc3M9InN0MiIgZD0ibTQ4IDE2YzAgMS4xLTAuOSAyLTIgMmgtMjhjLTEuMSAwLTItMC45LTItMnMwLjktMiAyLTJoMjhjMS4xIDAgMiAwLjkgMiAyeiIgZmlsbD0iIzIzMWYyMCIvPgoJPC9nPjxnIGZpbGw9IiNmZmYiPgoJCTxwYXRoIGNsYXNzPSJzdDYiIGQ9Im00OCAxNGMwIDEuMS0wLjkgMi0yIDJoLTI4Yy0xLjEgMC0yLTAuOS0yLTJzMC45LTIgMi0yaDI4YzEuMSAwIDIgMC45IDIgMnoiIGZpbGw9IiNmZmYiLz4KCTwvZz48ZyBmaWxsPSIjZmZmIj4KCQk8cGF0aCBjbGFzcz0ic3Q2IiBkPSJtNDggNTBjMCAxLjEtMC45IDItMiAyaC0yOGMtMS4xIDAtMi0wLjktMi0yczAuOS0yIDItMmgyOGMxLjEgMCAyIDAuOSAyIDJ6IiBmaWxsPSIjZmZmIi8+Cgk8L2c+PGc+CgkJPHBvbHlnb24gY2xhc3M9InN0NCIgcG9pbnRzPSIyMyA0OCAyMyA0OCAzMiA0MCA0MSA0OCIvPgoJPC9nPgoKPC9zdmc+Cg==";
3
- },{}],"wPYj":[function(require,module,exports) {
4
- "use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function o(t,e,o){return e&&n(t.prototype,e),o&&n(t,o),t}function r(e,n){return!n||"object"!==t(n)&&"function"!=typeof n?i(e):n}function i(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&f(t,e)}function l(t){var e="function"==typeof Map?new Map:void 0;return(l=function(t){if(null===t||!c(t))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,n)}function n(){return u(t,arguments,h(this).constructor)}return n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,t)})(t)}function s(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}function u(t,e,n){return(u=s()?Reflect.construct:function(t,e,n){var o=[null];o.push.apply(o,e);var r=new(Function.bind.apply(t,o));return n&&f(r,n.prototype),r}).apply(null,arguments)}function c(t){return-1!==Function.toString.call(t).indexOf("[native code]")}function f(t,e){return(f=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(t){return(h=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var d=require("../../assets/hourglass.svg"),y=function(t){function n(){var t;return e(this,n),(t=r(this,h(n).call(this))).loading=!1,t.attachShadow({mode:"open"}),t}return a(n,l(HTMLElement)),o(n,[{key:"connectedCallback",value:function(){this.shadowRoot.appendChild(this.template.content.cloneNode(!0)),this.overlay=this.shadowRoot.querySelector("#overlay"),this.loadingOverlay=this.shadowRoot.querySelector("#loader"),this.tabIndex=0;var t=this.querySelector("a"),e=this.querySelector("img");t?(this.fullImage=t.getAttribute("href"),t.tabIndex=-1):e&&(this.fullImage=e.getAttribute("src")),this.fullImage&&this._addListeners()}},{key:"_addListeners",value:function(){var t=this;this.addEventListener("click",this.showLightbox.bind(this),!0),this.addEventListener("keydown",function(e){if(!e.altKey)switch(e.keyCode){case 13:case 32:t.showLightbox(e);default:return}},!0)}},{key:"showLightbox",value:function(t){var e=this;t.preventDefault(),this.loading||(this.loading=!0,this._showOverlay(this.loadingOverlay),this.img?this.showImage():(this.img=document.createElement("img"),this.img.addEventListener("load",function(){return e.showImage()}),this.img.src=this.fullImage,this.img.tabIndex=1,["click","keydown"].forEach(function(t){return e.overlay.addEventListener(t,function(t){return e._hideOverlay(t.currentTarget)})}),this.overlay.appendChild(this.img)))}},{key:"showImage",value:function(){this.img.style.transform="scale(0.1)",this._hideOverlay(this.loadingOverlay),this._showOverlay(this.overlay),this.overlay.focus(),this.img.style.transform="scale(1)",this.loading=!1}},{key:"_showOverlay",value:function(t){t.style.display="flex"}},{key:"_hideOverlay",value:function(t){t.style.display=""}}]),n}(),p=document.createElement("template");p.innerHTML='\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host(:focus), :host(:active) {\n outline: 2px solid #77b;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader img {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id="overlay" tabindex="0"></div>\n<div id="loader">\n <img src="'.concat(d,'">\n</div>\n'),y.prototype.template=p;var g=y;exports.default=g;
5
- },{"../../assets/hourglass.svg":"q71P"}]},{},["wPYj"], "ImgLightbox")
6
- //# sourceMappingURL=img-lightbox.js.map
1
+
2
+ function $parcel$interopDefault(a) {
3
+ return a && a.__esModule ? a.default : a;
4
+ }
5
+
6
+ function $parcel$defineInteropFlag(a) {
7
+ Object.defineProperty(a, '__esModule', {value: true, configurable: true});
8
+ }
9
+
10
+ function $parcel$export(e, n, v, s) {
11
+ Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
12
+ }
13
+
14
+ $parcel$defineInteropFlag(module.exports);
15
+
16
+ $parcel$export(module.exports, "default", () => $a6ba83244539002c$export$2e2bcd8739ae039);
17
+ // const loaderSvgUrl = require('../../assets/hourglass.svg');
18
+ var $735957c3b581425f$exports = {};
19
+ $735957c3b581425f$exports = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" enable-background=\"new 0 0 64 64\" version=\"1.1\" viewBox=\"0 0 64 64\" xml:space=\"preserve\"><metadata><rdf:RDF><cc:Work rdf:about=\"\"><dc:format>image/svg+xml</dc:format><dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/><dc:title/></cc:Work></rdf:RDF></metadata>\n<g>\n\t\t<circle class=\"st0\" cx=\"32\" cy=\"32\" r=\"32\"/>\n\t</g><g class=\"st1\" opacity=\".2\">\n\t\t<path class=\"st2\" d=\"m46 50h-2v-4c0-4.5-3-7.4-3-7.4s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v4h-2c-1.1 0-2 0.9-2 2s0.9 2 2 2h28c1.1 0 2-0.9 2-2s-0.9-2-2-2z\" fill=\"#231f20\"/>\n\t</g>\n\t\t<path class=\"st3\" d=\"m41 36.6s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v5.1h24v-5.1c0-4.5-3-7.4-3-7.4z\" fill=\"#fff\"/>\n\t\n\t\t<path class=\"st4\" d=\"m31 43v-11c0-2.1-1-3.4-1.3-3.7l-4.2-4c-1.5-1.4-1.5-3.7-1.5-3.7h16s0 2.3-1.5 3.7l-4.2 4c-0.4 0.3-1.3 1.6-1.3 3.7v11z\"/>\n\t<g class=\"st5\" opacity=\".3\">\n\t\t<path class=\"st2\" d=\"m48 16c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#231f20\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 14c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 50c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g>\n\t\t<polygon class=\"st4\" points=\"23 48 23 48 32 40 41 48\"/>\n\t</g>\n\n</svg>";
20
+
21
+
22
+ class $a6ba83244539002c$var$ImgLightbox extends HTMLElement {
23
+ constructor(){
24
+ super();
25
+ this.loading = false;
26
+ this.attachShadow({
27
+ mode: 'open'
28
+ });
29
+ }
30
+ connectedCallback() {
31
+ // Template is added to prototype below the
32
+ // class definition.
33
+ // It's from a template tag because it's
34
+ // supposed to be faster this way.
35
+ this.shadowRoot.appendChild(this.template.content.cloneNode(true));
36
+ // Get some element references from shadow DOM:
37
+ this.overlay = this.shadowRoot.querySelector('#overlay');
38
+ this.loadingOverlay = this.shadowRoot.querySelector('#loader');
39
+ // Add the loading SVG to that element:
40
+ this.loadingOverlay.innerHTML = (0, (/*@__PURE__*/$parcel$interopDefault($735957c3b581425f$exports)));
41
+ // Component needs a tabIndex to be focusable.
42
+ this.tabIndex = 0;
43
+ // The slotted elements are actually not in
44
+ // the shadow DOM so we can get them like so:
45
+ const link = this.querySelector('a');
46
+ const img = this.querySelector('img');
47
+ if (link !== null) {
48
+ // Store the URL as the full image URL:
49
+ this.fullImage = link.getAttribute('href');
50
+ // Register a click event that has to
51
+ // prevent default:
52
+ //this._addListeners(link);
53
+ // Prevent ability to focus the link:
54
+ link.tabIndex = -1;
55
+ } else if (img !== null) this.fullImage = img.getAttribute('src');
56
+ this.fullImage && this._addListeners();
57
+ }
58
+ _addListeners() {
59
+ this.addEventListener('click', this.showLightbox.bind(this), true);
60
+ this.addEventListener('keydown', (e)=>{
61
+ // It's common to ignore anything with alt
62
+ // modifiers. I've copied this from Google
63
+ // people.
64
+ if (e.altKey) return;
65
+ // Catch enter and space:
66
+ switch(e.keyCode){
67
+ case 13:
68
+ case 32:
69
+ this.showLightbox(e);
70
+ default:
71
+ return;
72
+ }
73
+ }, true);
74
+ }
75
+ showLightbox(e) {
76
+ // This is required so that the link element does not get
77
+ // followed:
78
+ e.preventDefault();
79
+ // Implement some kind of lock:
80
+ if (!this.loading) {
81
+ this.loading = true;
82
+ // Preload the full image.
83
+ // Show the spinner overlay:
84
+ this._showOverlay(this.loadingOverlay);
85
+ if (!this.img) {
86
+ this.img = document.createElement('img');
87
+ // For the moment we just do nothing on error with
88
+ // the link target.
89
+ this.img.addEventListener('error', ()=>{
90
+ this._hideOverlay(this.loadingOverlay);
91
+ this.loading = false;
92
+ });
93
+ this.img.addEventListener('load', ()=>this.showImage());
94
+ this.img.src = this.fullImage;
95
+ this.img.tabIndex = 1;
96
+ // Prepare the events to close the overlay.
97
+ // I'm doing this here to light up what's
98
+ // happening in connectedCallback.
99
+ // I'm not doing a check for which key was
100
+ // called on purpose, but maybe I should do
101
+ // that alt key check?
102
+ [
103
+ 'click',
104
+ 'keydown'
105
+ ].forEach((type)=>this.overlay.addEventListener(type, (e)=>this._hideOverlay(e.currentTarget)));
106
+ this.overlay.appendChild(this.img);
107
+ } else this.showImage();
108
+ }
109
+ }
110
+ showImage() {
111
+ this.img.style.transform = 'scale(0.1)';
112
+ // Hide the loading overlay:
113
+ this._hideOverlay(this.loadingOverlay);
114
+ this._showOverlay(this.overlay);
115
+ // Focus the overlay (requires it to have a tabIndex):
116
+ this.overlay.focus();
117
+ // Start the CSS transition:
118
+ this.img.style.transform = 'scale(1)';
119
+ // Don't forget to unlock the click event:
120
+ this.loading = false;
121
+ }
122
+ _showOverlay(overlay) {
123
+ overlay.style.display = 'flex';
124
+ }
125
+ _hideOverlay(overlay) {
126
+ overlay.style.display = '';
127
+ }
128
+ }
129
+ // I'm using a true template tag because the Chrome
130
+ // team says it's faster. The template tag has
131
+ // better browser support than web components anyway.
132
+ // The strange comment here is needed for syntax
133
+ // highlighting with a VS Code extension I'm using.
134
+ const $a6ba83244539002c$var$tpl = document.createElement('template');
135
+ $a6ba83244539002c$var$tpl.innerHTML = /*template*/ `
136
+ <style>
137
+ :host {
138
+ display: inline-block;
139
+ cursor: pointer;
140
+ position: relative;
141
+ }
142
+
143
+ :host([hidden]) {
144
+ display: none;
145
+ }
146
+
147
+ :host(:focus), :host(:active) {
148
+ outline: 2px solid #77b;
149
+ }
150
+
151
+ #loader {
152
+ position: absolute;
153
+ z-index: 1;
154
+ top: 0;
155
+ left: 0;
156
+ width: 100%;
157
+ height: 100%;
158
+ background-color: rgba(0,0,0,.2);
159
+ display: none;
160
+ align-items: center;
161
+ justify-content: center;
162
+ }
163
+
164
+ #overlay {
165
+ position: fixed;
166
+ top: 0;
167
+ left: 0;
168
+ bottom: 0;
169
+ right: 0;
170
+ overflow: hidden;
171
+ z-index: 999;
172
+ background-color: rgba(0,0,0,.5);
173
+ display: none;
174
+ align-items: center;
175
+ justify-content: center;
176
+ }
177
+
178
+ #loader svg {
179
+ width: 50%;
180
+ opacity: 0.6;
181
+ animation: lightbox-loader 2s infinite;
182
+ }
183
+
184
+ #overlay img {
185
+ max-width: 100%;
186
+ max-height: 100%;
187
+ transition: transform 0.8s;
188
+ }
189
+
190
+ @keyframes lightbox-loader {
191
+ 0% {transform: rotate(0deg);}
192
+ 100% {transform: rotate(360deg);}
193
+ }
194
+ </style>
195
+ <slot></slot>
196
+ <div id="overlay" tabindex="0"></div>
197
+ <div id="loader">
198
+ </div>
199
+ `;
200
+ $a6ba83244539002c$var$ImgLightbox.prototype.template = $a6ba83244539002c$var$tpl;
201
+ var $a6ba83244539002c$export$2e2bcd8739ae039 = $a6ba83244539002c$var$ImgLightbox;
202
+
203
+
204
+ //# sourceMappingURL=img-lightbox.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["img-lightbox.js"],"names":["ImgLightbox","loaderSvgUrl","require","loading","attachShadow","mode","HTMLElement","shadowRoot","appendChild","template","content","cloneNode","overlay","querySelector","loadingOverlay","tabIndex","link","img","fullImage","getAttribute","_addListeners","addEventListener","showLightbox","bind","e","altKey","keyCode","preventDefault","_showOverlay","showImage","document","createElement","src","forEach","type","_hideOverlay","currentTarget","style","transform","focus","display","tpl","innerHTML","prototype"],"mappings":"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","file":"img-lightbox.js","sourceRoot":"../src/shadow","sourcesContent":["const loaderSvgUrl = require('../../assets/hourglass.svg');\n\nclass ImgLightbox extends HTMLElement {\n\n constructor() {\n super();\n this.loading = false;\n this.attachShadow({mode: 'open'});\n }\n\n connectedCallback() {\n // Template is added to prototype below the \n // class definition.\n // It's from a template tag because it's \n // supposed to be faster this way.\n this.shadowRoot.appendChild(\n this.template.content.cloneNode(true)\n );\n // Get some element references from shadow DOM:\n this.overlay = this.shadowRoot.querySelector('#overlay');\n this.loadingOverlay = this.shadowRoot.querySelector('#loader');\n // Component needs a tabIndex to be focusable.\n this.tabIndex = 0;\n // The slotted elements are actually not in \n // the shadow DOM so we can get them like so:\n const link = this.querySelector('a');\n const img = this.querySelector('img');\n if (link) {\n // Store the URL as the full image URL:\n this.fullImage = link.getAttribute('href');\n // Register a click event that has to \n // prevent default:\n //this._addListeners(link);\n // Prevent ability to focus the link:\n link.tabIndex = -1;\n } else if (img) {\n this.fullImage = img.getAttribute('src');\n // Nothing wrong with giving the same tabIndex\n // to things, they're ordered by position.\n // I think.\n //img.tabIndex = 0;\n //this._addListeners(img);\n }\n this.fullImage && this._addListeners();\n }\n\n _addListeners() {\n this.addEventListener('click', this.showLightbox.bind(this), true);\n this.addEventListener('keydown', (e) => {\n // It's common to ignore anything with alt\n // modifiers. I've copied this from Google\n // people.\n if (e.altKey) return;\n // Catch enter and space:\n switch (e.keyCode) {\n case 13:\n case 32:\n this.showLightbox(e);\n default:\n return;\n }\n }, true);\n }\n\n showLightbox(e) {\n // This is required so that the link element does not get \n // followed:\n e.preventDefault();\n\n // Implement some kind of lock:\n if (!this.loading) {\n this.loading = true;\n // Preload the full image.\n // Show the spinner overlay:\n this._showOverlay(this.loadingOverlay);\n if (!this.img) {\n this.img = document.createElement('img');\n this.img.addEventListener('load', () => this.showImage());\n this.img.src = this.fullImage;\n this.img.tabIndex = 1;\n // Prepare the events to close the overlay.\n // I'm doing this here to light up what's\n // happening in connectedCallback.\n // I'm not doing a check for which key was\n // called on purpose, but maybe I should do\n // that alt key check?\n ['click', 'keydown'].forEach(\n (type) => \n this.overlay.addEventListener(\n type, \n (e) => this._hideOverlay(e.currentTarget)\n )\n );\n this.overlay.appendChild(this.img);\n } else {\n this.showImage();\n }\n }\n }\n\n showImage() {\n this.img.style.transform = 'scale(0.1)';\n // Hide the loading overlay:\n this._hideOverlay(this.loadingOverlay);\n this._showOverlay(this.overlay);\n // Focus the overlay (requires it to have a tabIndex):\n this.overlay.focus();\n // Start the CSS transition:\n this.img.style.transform = 'scale(1)';\n // Don't forget to unlock the click event:\n this.loading = false;\n }\n\n _showOverlay(overlay) {\n overlay.style.display = 'flex';\n }\n\n _hideOverlay(overlay) {\n overlay.style.display = '';\n }\n\n}\n\n// I'm using a true template tag because the Chrome\n// team says it's faster. The template tag has \n// better browser support than web components anyway.\n// The strange comment here is needed for syntax\n// highlighting with a VS Code extension I'm using.\nconst tpl = document.createElement('template');\ntpl.innerHTML = /*template*/`\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host(:focus), :host(:active) {\n outline: 2px solid #77b;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader img {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id=\"overlay\" tabindex=\"0\"></div>\n<div id=\"loader\">\n <img src=\"${loaderSvgUrl}\">\n</div>\n`;\nImgLightbox.prototype.template = tpl;\n\nexport default ImgLightbox;"]}
1
+ {"mappings":"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","sources":["src/shadow/img-lightbox.js","node_modules/@parcel/runtime-js/lib/bundles/runtime-4f432e39aae9d60a.js"],"sourcesContent":["// const loaderSvgUrl = require('../../assets/hourglass.svg');\nimport loaderSvg from 'bundle-text:../../assets/hourglass.svg';\n\nclass ImgLightbox extends HTMLElement {\n\n constructor() {\n super();\n this.loading = false;\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n // Template is added to prototype below the \n // class definition.\n // It's from a template tag because it's \n // supposed to be faster this way.\n this.shadowRoot.appendChild(\n this.template.content.cloneNode(true)\n );\n // Get some element references from shadow DOM:\n this.overlay = this.shadowRoot.querySelector('#overlay');\n this.loadingOverlay = this.shadowRoot.querySelector('#loader');\n // Add the loading SVG to that element:\n this.loadingOverlay.innerHTML = loaderSvg;\n // Component needs a tabIndex to be focusable.\n this.tabIndex = 0;\n // The slotted elements are actually not in \n // the shadow DOM so we can get them like so:\n const link = this.querySelector('a');\n const img = this.querySelector('img');\n if (link !== null) {\n // Store the URL as the full image URL:\n this.fullImage = link.getAttribute('href');\n // Register a click event that has to \n // prevent default:\n //this._addListeners(link);\n // Prevent ability to focus the link:\n link.tabIndex = -1;\n } else if (img !== null) {\n this.fullImage = img.getAttribute('src');\n // Nothing wrong with giving the same tabIndex\n // to things, they're ordered by position.\n // I think.\n //img.tabIndex = 0;\n //this._addListeners(img);\n }\n this.fullImage && this._addListeners();\n }\n\n _addListeners() {\n this.addEventListener('click', this.showLightbox.bind(this), true);\n this.addEventListener('keydown', (e) => {\n // It's common to ignore anything with alt\n // modifiers. I've copied this from Google\n // people.\n if (e.altKey) return;\n // Catch enter and space:\n switch (e.keyCode) {\n case 13:\n case 32:\n this.showLightbox(e);\n default:\n return;\n }\n }, true);\n }\n\n showLightbox(e) {\n // This is required so that the link element does not get \n // followed:\n e.preventDefault();\n\n // Implement some kind of lock:\n if (!this.loading) {\n this.loading = true;\n // Preload the full image.\n // Show the spinner overlay:\n this._showOverlay(this.loadingOverlay);\n if (!this.img) {\n this.img = document.createElement('img');\n // For the moment we just do nothing on error with\n // the link target.\n this.img.addEventListener('error', () => {\n this._hideOverlay(this.loadingOverlay);\n this.loading = false;\n });\n this.img.addEventListener('load', () => this.showImage());\n this.img.src = this.fullImage;\n this.img.tabIndex = 1;\n // Prepare the events to close the overlay.\n // I'm doing this here to light up what's\n // happening in connectedCallback.\n // I'm not doing a check for which key was\n // called on purpose, but maybe I should do\n // that alt key check?\n ['click', 'keydown'].forEach(\n (type) =>\n this.overlay.addEventListener(\n type,\n (e) => this._hideOverlay(e.currentTarget)\n )\n );\n this.overlay.appendChild(this.img);\n } else {\n this.showImage();\n }\n }\n }\n\n showImage() {\n this.img.style.transform = 'scale(0.1)';\n // Hide the loading overlay:\n this._hideOverlay(this.loadingOverlay);\n this._showOverlay(this.overlay);\n // Focus the overlay (requires it to have a tabIndex):\n this.overlay.focus();\n // Start the CSS transition:\n this.img.style.transform = 'scale(1)';\n // Don't forget to unlock the click event:\n this.loading = false;\n }\n\n _showOverlay(overlay) {\n overlay.style.display = 'flex';\n }\n\n _hideOverlay(overlay) {\n overlay.style.display = '';\n }\n\n}\n\n// I'm using a true template tag because the Chrome\n// team says it's faster. The template tag has \n// better browser support than web components anyway.\n// The strange comment here is needed for syntax\n// highlighting with a VS Code extension I'm using.\nconst tpl = document.createElement('template');\ntpl.innerHTML = /*template*/`\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host(:focus), :host(:active) {\n outline: 2px solid #77b;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader svg {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id=\"overlay\" tabindex=\"0\"></div>\n<div id=\"loader\">\n</div>\n`;\nImgLightbox.prototype.template = tpl;\n\nexport default ImgLightbox;\n","module.exports = \"1f3d06fcd1df419a\";"],"names":[],"version":3,"file":"img-lightbox.js.map"}
@@ -0,0 +1,193 @@
1
+
2
+ function $parcel$interopDefault(a) {
3
+ return a && a.__esModule ? a.default : a;
4
+ }
5
+ // const loaderSvgUrl = require('../../assets/hourglass.svg');
6
+ var $6ba1613a1599b26d$exports = {};
7
+ $6ba1613a1599b26d$exports = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" enable-background=\"new 0 0 64 64\" version=\"1.1\" viewBox=\"0 0 64 64\" xml:space=\"preserve\"><metadata><rdf:RDF><cc:Work rdf:about=\"\"><dc:format>image/svg+xml</dc:format><dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/><dc:title/></cc:Work></rdf:RDF></metadata>\n<g>\n\t\t<circle class=\"st0\" cx=\"32\" cy=\"32\" r=\"32\"/>\n\t</g><g class=\"st1\" opacity=\".2\">\n\t\t<path class=\"st2\" d=\"m46 50h-2v-4c0-4.5-3-7.4-3-7.4s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v4h-2c-1.1 0-2 0.9-2 2s0.9 2 2 2h28c1.1 0 2-0.9 2-2s-0.9-2-2-2z\" fill=\"#231f20\"/>\n\t</g>\n\t\t<path class=\"st3\" d=\"m41 36.6s-3-2.8-3.9-3.7 0-1.8 0-1.8 1.3-1.3 4.2-4c2.8-2.7 2.7-6.7 2.7-6.7v-5.1l-12-1-12 1v5.1s-0.1 3.9 2.7 6.7c2.8 2.7 4.2 4 4.2 4s0.9 0.9 0 1.8-3.9 3.7-3.9 3.7-3 2.8-3 7.4v5.1h24v-5.1c0-4.5-3-7.4-3-7.4z\" fill=\"#fff\"/>\n\t\n\t\t<path class=\"st4\" d=\"m31 43v-11c0-2.1-1-3.4-1.3-3.7l-4.2-4c-1.5-1.4-1.5-3.7-1.5-3.7h16s0 2.3-1.5 3.7l-4.2 4c-0.4 0.3-1.3 1.6-1.3 3.7v11z\"/>\n\t<g class=\"st5\" opacity=\".3\">\n\t\t<path class=\"st2\" d=\"m48 16c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#231f20\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 14c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g fill=\"#fff\">\n\t\t<path class=\"st6\" d=\"m48 50c0 1.1-0.9 2-2 2h-28c-1.1 0-2-0.9-2-2s0.9-2 2-2h28c1.1 0 2 0.9 2 2z\" fill=\"#fff\"/>\n\t</g><g>\n\t\t<polygon class=\"st4\" points=\"23 48 23 48 32 40 41 48\"/>\n\t</g>\n\n</svg>";
8
+
9
+
10
+ class $ef17987508a11d23$var$ImgLightbox extends HTMLElement {
11
+ constructor(){
12
+ super();
13
+ this.loading = false;
14
+ this.attachShadow({
15
+ mode: 'open'
16
+ });
17
+ }
18
+ connectedCallback() {
19
+ // Template is added to prototype below the
20
+ // class definition.
21
+ // It's from a template tag because it's
22
+ // supposed to be faster this way.
23
+ this.shadowRoot.appendChild(this.template.content.cloneNode(true));
24
+ // Get some element references from shadow DOM:
25
+ this.overlay = this.shadowRoot.querySelector('#overlay');
26
+ this.loadingOverlay = this.shadowRoot.querySelector('#loader');
27
+ // Add the loading SVG to that element:
28
+ this.loadingOverlay.innerHTML = (0, (/*@__PURE__*/$parcel$interopDefault($6ba1613a1599b26d$exports)));
29
+ // Component needs a tabIndex to be focusable.
30
+ this.tabIndex = 0;
31
+ // The slotted elements are actually not in
32
+ // the shadow DOM so we can get them like so:
33
+ const link = this.querySelector('a');
34
+ const img = this.querySelector('img');
35
+ if (link !== null) {
36
+ // Store the URL as the full image URL:
37
+ this.fullImage = link.getAttribute('href');
38
+ // Register a click event that has to
39
+ // prevent default:
40
+ //this._addListeners(link);
41
+ // Prevent ability to focus the link:
42
+ link.tabIndex = -1;
43
+ } else if (img !== null) this.fullImage = img.getAttribute('src');
44
+ this.fullImage && this._addListeners();
45
+ }
46
+ _addListeners() {
47
+ this.addEventListener('click', this.showLightbox.bind(this), true);
48
+ this.addEventListener('keydown', (e)=>{
49
+ // It's common to ignore anything with alt
50
+ // modifiers. I've copied this from Google
51
+ // people.
52
+ if (e.altKey) return;
53
+ // Catch enter and space:
54
+ switch(e.keyCode){
55
+ case 13:
56
+ case 32:
57
+ this.showLightbox(e);
58
+ default:
59
+ return;
60
+ }
61
+ }, true);
62
+ }
63
+ showLightbox(e) {
64
+ // This is required so that the link element does not get
65
+ // followed:
66
+ e.preventDefault();
67
+ // Implement some kind of lock:
68
+ if (!this.loading) {
69
+ this.loading = true;
70
+ // Preload the full image.
71
+ // Show the spinner overlay:
72
+ this._showOverlay(this.loadingOverlay);
73
+ if (!this.img) {
74
+ this.img = document.createElement('img');
75
+ // For the moment we just do nothing on error with
76
+ // the link target.
77
+ this.img.addEventListener('error', ()=>{
78
+ this._hideOverlay(this.loadingOverlay);
79
+ this.loading = false;
80
+ });
81
+ this.img.addEventListener('load', ()=>this.showImage());
82
+ this.img.src = this.fullImage;
83
+ this.img.tabIndex = 1;
84
+ // Prepare the events to close the overlay.
85
+ // I'm doing this here to light up what's
86
+ // happening in connectedCallback.
87
+ // I'm not doing a check for which key was
88
+ // called on purpose, but maybe I should do
89
+ // that alt key check?
90
+ [
91
+ 'click',
92
+ 'keydown'
93
+ ].forEach((type)=>this.overlay.addEventListener(type, (e)=>this._hideOverlay(e.currentTarget)));
94
+ this.overlay.appendChild(this.img);
95
+ } else this.showImage();
96
+ }
97
+ }
98
+ showImage() {
99
+ this.img.style.transform = 'scale(0.1)';
100
+ // Hide the loading overlay:
101
+ this._hideOverlay(this.loadingOverlay);
102
+ this._showOverlay(this.overlay);
103
+ // Focus the overlay (requires it to have a tabIndex):
104
+ this.overlay.focus();
105
+ // Start the CSS transition:
106
+ this.img.style.transform = 'scale(1)';
107
+ // Don't forget to unlock the click event:
108
+ this.loading = false;
109
+ }
110
+ _showOverlay(overlay) {
111
+ overlay.style.display = 'flex';
112
+ }
113
+ _hideOverlay(overlay) {
114
+ overlay.style.display = '';
115
+ }
116
+ }
117
+ // I'm using a true template tag because the Chrome
118
+ // team says it's faster. The template tag has
119
+ // better browser support than web components anyway.
120
+ // The strange comment here is needed for syntax
121
+ // highlighting with a VS Code extension I'm using.
122
+ const $ef17987508a11d23$var$tpl = document.createElement('template');
123
+ $ef17987508a11d23$var$tpl.innerHTML = /*template*/ `
124
+ <style>
125
+ :host {
126
+ display: inline-block;
127
+ cursor: pointer;
128
+ position: relative;
129
+ }
130
+
131
+ :host([hidden]) {
132
+ display: none;
133
+ }
134
+
135
+ :host(:focus), :host(:active) {
136
+ outline: 2px solid #77b;
137
+ }
138
+
139
+ #loader {
140
+ position: absolute;
141
+ z-index: 1;
142
+ top: 0;
143
+ left: 0;
144
+ width: 100%;
145
+ height: 100%;
146
+ background-color: rgba(0,0,0,.2);
147
+ display: none;
148
+ align-items: center;
149
+ justify-content: center;
150
+ }
151
+
152
+ #overlay {
153
+ position: fixed;
154
+ top: 0;
155
+ left: 0;
156
+ bottom: 0;
157
+ right: 0;
158
+ overflow: hidden;
159
+ z-index: 999;
160
+ background-color: rgba(0,0,0,.5);
161
+ display: none;
162
+ align-items: center;
163
+ justify-content: center;
164
+ }
165
+
166
+ #loader svg {
167
+ width: 50%;
168
+ opacity: 0.6;
169
+ animation: lightbox-loader 2s infinite;
170
+ }
171
+
172
+ #overlay img {
173
+ max-width: 100%;
174
+ max-height: 100%;
175
+ transition: transform 0.8s;
176
+ }
177
+
178
+ @keyframes lightbox-loader {
179
+ 0% {transform: rotate(0deg);}
180
+ 100% {transform: rotate(360deg);}
181
+ }
182
+ </style>
183
+ <slot></slot>
184
+ <div id="overlay" tabindex="0"></div>
185
+ <div id="loader">
186
+ </div>
187
+ `;
188
+ $ef17987508a11d23$var$ImgLightbox.prototype.template = $ef17987508a11d23$var$tpl;
189
+ var $ef17987508a11d23$export$2e2bcd8739ae039 = $ef17987508a11d23$var$ImgLightbox;
190
+
191
+
192
+ export {$ef17987508a11d23$export$2e2bcd8739ae039 as default};
193
+ //# sourceMappingURL=img-lightbox.mjs.map
@@ -0,0 +1 @@
1
+ {"mappings":"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","sources":["src/shadow/img-lightbox.js","node_modules/@parcel/runtime-js/lib/bundles/runtime-7833d3a46095a7f4.js"],"sourcesContent":["// const loaderSvgUrl = require('../../assets/hourglass.svg');\nimport loaderSvg from 'bundle-text:../../assets/hourglass.svg';\n\nclass ImgLightbox extends HTMLElement {\n\n constructor() {\n super();\n this.loading = false;\n this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n // Template is added to prototype below the \n // class definition.\n // It's from a template tag because it's \n // supposed to be faster this way.\n this.shadowRoot.appendChild(\n this.template.content.cloneNode(true)\n );\n // Get some element references from shadow DOM:\n this.overlay = this.shadowRoot.querySelector('#overlay');\n this.loadingOverlay = this.shadowRoot.querySelector('#loader');\n // Add the loading SVG to that element:\n this.loadingOverlay.innerHTML = loaderSvg;\n // Component needs a tabIndex to be focusable.\n this.tabIndex = 0;\n // The slotted elements are actually not in \n // the shadow DOM so we can get them like so:\n const link = this.querySelector('a');\n const img = this.querySelector('img');\n if (link !== null) {\n // Store the URL as the full image URL:\n this.fullImage = link.getAttribute('href');\n // Register a click event that has to \n // prevent default:\n //this._addListeners(link);\n // Prevent ability to focus the link:\n link.tabIndex = -1;\n } else if (img !== null) {\n this.fullImage = img.getAttribute('src');\n // Nothing wrong with giving the same tabIndex\n // to things, they're ordered by position.\n // I think.\n //img.tabIndex = 0;\n //this._addListeners(img);\n }\n this.fullImage && this._addListeners();\n }\n\n _addListeners() {\n this.addEventListener('click', this.showLightbox.bind(this), true);\n this.addEventListener('keydown', (e) => {\n // It's common to ignore anything with alt\n // modifiers. I've copied this from Google\n // people.\n if (e.altKey) return;\n // Catch enter and space:\n switch (e.keyCode) {\n case 13:\n case 32:\n this.showLightbox(e);\n default:\n return;\n }\n }, true);\n }\n\n showLightbox(e) {\n // This is required so that the link element does not get \n // followed:\n e.preventDefault();\n\n // Implement some kind of lock:\n if (!this.loading) {\n this.loading = true;\n // Preload the full image.\n // Show the spinner overlay:\n this._showOverlay(this.loadingOverlay);\n if (!this.img) {\n this.img = document.createElement('img');\n // For the moment we just do nothing on error with\n // the link target.\n this.img.addEventListener('error', () => {\n this._hideOverlay(this.loadingOverlay);\n this.loading = false;\n });\n this.img.addEventListener('load', () => this.showImage());\n this.img.src = this.fullImage;\n this.img.tabIndex = 1;\n // Prepare the events to close the overlay.\n // I'm doing this here to light up what's\n // happening in connectedCallback.\n // I'm not doing a check for which key was\n // called on purpose, but maybe I should do\n // that alt key check?\n ['click', 'keydown'].forEach(\n (type) =>\n this.overlay.addEventListener(\n type,\n (e) => this._hideOverlay(e.currentTarget)\n )\n );\n this.overlay.appendChild(this.img);\n } else {\n this.showImage();\n }\n }\n }\n\n showImage() {\n this.img.style.transform = 'scale(0.1)';\n // Hide the loading overlay:\n this._hideOverlay(this.loadingOverlay);\n this._showOverlay(this.overlay);\n // Focus the overlay (requires it to have a tabIndex):\n this.overlay.focus();\n // Start the CSS transition:\n this.img.style.transform = 'scale(1)';\n // Don't forget to unlock the click event:\n this.loading = false;\n }\n\n _showOverlay(overlay) {\n overlay.style.display = 'flex';\n }\n\n _hideOverlay(overlay) {\n overlay.style.display = '';\n }\n\n}\n\n// I'm using a true template tag because the Chrome\n// team says it's faster. The template tag has \n// better browser support than web components anyway.\n// The strange comment here is needed for syntax\n// highlighting with a VS Code extension I'm using.\nconst tpl = document.createElement('template');\ntpl.innerHTML = /*template*/`\n<style>\n :host {\n display: inline-block;\n cursor: pointer;\n position: relative;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n :host(:focus), :host(:active) {\n outline: 2px solid #77b;\n }\n\n #loader {\n position: absolute;\n z-index: 1;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,.2);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #overlay {\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n overflow: hidden;\n z-index: 999;\n background-color: rgba(0,0,0,.5);\n display: none;\n align-items: center;\n justify-content: center;\n }\n\n #loader svg {\n width: 50%;\n opacity: 0.6;\n animation: lightbox-loader 2s infinite;\n }\n\n #overlay img {\n max-width: 100%;\n max-height: 100%;\n transition: transform 0.8s;\n }\n\n @keyframes lightbox-loader {\n 0% {transform: rotate(0deg);}\n 100% {transform: rotate(360deg);}\n }\n</style>\n<slot></slot>\n<div id=\"overlay\" tabindex=\"0\"></div>\n<div id=\"loader\">\n</div>\n`;\nImgLightbox.prototype.template = tpl;\n\nexport default ImgLightbox;\n","module.exports = \"0470ae78683fa4f4\";"],"names":[],"version":3,"file":"img-lightbox.mjs.map"}
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@dkvz/img-lightbox",
3
- "version": "0.2.0",
3
+ "version": "1.1.0",
4
4
  "description": "Web component to add a lightbox effect to img elements",
5
5
  "main": "dist/img-lightbox.js",
6
+ "module": "dist/img-lightbox.mjs",
7
+ "source": "src/shadow/img-lightbox.js",
6
8
  "scripts": {
7
9
  "start": "parcel src/shadow/index.pug",
8
- "build": "parcel build src/shadow/img-lightbox.js --public-url ./ --global ImgLightbox",
10
+ "build": "rimraf dist && parcel build",
9
11
  "start-no-shadow": "parcel src/no-shadow/index.pug",
10
- "build-no-shadow": "parcel build src/no-shadow/img-lightbox.js --public-url ./ --global ImgLightbox"
12
+ "build-no-shadow": "parcel build src/no-shadow/img-lightbox.js --public-url ./"
11
13
  },
12
14
  "repository": {
13
15
  "type": "git",
@@ -16,9 +18,10 @@
16
18
  "author": "dkvz",
17
19
  "license": "MIT",
18
20
  "devDependencies": {
19
- "parcel-bundler": "^1.12.4",
20
- "parcel-plugin-clean-dist": "0.0.6",
21
- "parcel-plugin-url-loader": "^1.3.1",
22
- "pug": "^2.0.4"
21
+ "@parcel/transformer-inline-string": "^2.15.4",
22
+ "@parcel/transformer-pug": "^2.15.4",
23
+ "parcel": "^2.15.4",
24
+ "pug": "^2.0.4",
25
+ "rimraf": "^6.0.1"
23
26
  }
24
27
  }
@@ -1,11 +1,12 @@
1
- const loaderSvgUrl = require('../../assets/hourglass.svg');
1
+ // const loaderSvgUrl = require('../../assets/hourglass.svg');
2
+ import loaderSvg from 'bundle-text:../../assets/hourglass.svg';
2
3
 
3
4
  class ImgLightbox extends HTMLElement {
4
5
 
5
6
  constructor() {
6
7
  super();
7
8
  this.loading = false;
8
- this.attachShadow({mode: 'open'});
9
+ this.attachShadow({ mode: 'open' });
9
10
  }
10
11
 
11
12
  connectedCallback() {
@@ -19,13 +20,15 @@ class ImgLightbox extends HTMLElement {
19
20
  // Get some element references from shadow DOM:
20
21
  this.overlay = this.shadowRoot.querySelector('#overlay');
21
22
  this.loadingOverlay = this.shadowRoot.querySelector('#loader');
23
+ // Add the loading SVG to that element:
24
+ this.loadingOverlay.innerHTML = loaderSvg;
22
25
  // Component needs a tabIndex to be focusable.
23
26
  this.tabIndex = 0;
24
27
  // The slotted elements are actually not in
25
28
  // the shadow DOM so we can get them like so:
26
29
  const link = this.querySelector('a');
27
30
  const img = this.querySelector('img');
28
- if (link) {
31
+ if (link !== null) {
29
32
  // Store the URL as the full image URL:
30
33
  this.fullImage = link.getAttribute('href');
31
34
  // Register a click event that has to
@@ -33,7 +36,7 @@ class ImgLightbox extends HTMLElement {
33
36
  //this._addListeners(link);
34
37
  // Prevent ability to focus the link:
35
38
  link.tabIndex = -1;
36
- } else if (img) {
39
+ } else if (img !== null) {
37
40
  this.fullImage = img.getAttribute('src');
38
41
  // Nothing wrong with giving the same tabIndex
39
42
  // to things, they're ordered by position.
@@ -75,6 +78,12 @@ class ImgLightbox extends HTMLElement {
75
78
  this._showOverlay(this.loadingOverlay);
76
79
  if (!this.img) {
77
80
  this.img = document.createElement('img');
81
+ // For the moment we just do nothing on error with
82
+ // the link target.
83
+ this.img.addEventListener('error', () => {
84
+ this._hideOverlay(this.loadingOverlay);
85
+ this.loading = false;
86
+ });
78
87
  this.img.addEventListener('load', () => this.showImage());
79
88
  this.img.src = this.fullImage;
80
89
  this.img.tabIndex = 1;
@@ -85,9 +94,9 @@ class ImgLightbox extends HTMLElement {
85
94
  // called on purpose, but maybe I should do
86
95
  // that alt key check?
87
96
  ['click', 'keydown'].forEach(
88
- (type) =>
97
+ (type) =>
89
98
  this.overlay.addEventListener(
90
- type,
99
+ type,
91
100
  (e) => this._hideOverlay(e.currentTarget)
92
101
  )
93
102
  );
@@ -170,7 +179,7 @@ tpl.innerHTML = /*template*/`
170
179
  justify-content: center;
171
180
  }
172
181
 
173
- #loader img {
182
+ #loader svg {
174
183
  width: 50%;
175
184
  opacity: 0.6;
176
185
  animation: lightbox-loader 2s infinite;
@@ -190,9 +199,8 @@ tpl.innerHTML = /*template*/`
190
199
  <slot></slot>
191
200
  <div id="overlay" tabindex="0"></div>
192
201
  <div id="loader">
193
- <img src="${loaderSvgUrl}">
194
202
  </div>
195
203
  `;
196
204
  ImgLightbox.prototype.template = tpl;
197
205
 
198
- export default ImgLightbox;
206
+ export default ImgLightbox;
@@ -18,6 +18,13 @@ html
18
18
  display: inline-block;
19
19
  border: 1px solid #333;
20
20
  box-shadow: 0px 0px 4px rgba(0,0,0,0.6);
21
+ background-color: #333;
22
+ }
23
+
24
+ /* Both slotted elements should be display: block */
25
+ img-lightbox a, img-lightbox img {
26
+ display: block;
27
+ max-width: 200px;
21
28
  }
22
29
 
23
30
  img-lightbox:active, img-lightbox:focus {
@@ -2,9 +2,9 @@
2
2
  <p>The image should still show and link to the full version with JS disabled.</p>
3
3
 
4
4
  <img-lightbox>
5
- <a href="../../assets/example.png" target="_blank" rel="noopener noreferrer">
6
- <img src="../../assets/example_preview.png"
7
- alt="Rabbit with a trumpet mute on its head">
5
+ <a href="../../assets/example.jpg" target="_blank" rel="noopener noreferrer">
6
+ <img src="../../assets/example_preview.jpg"
7
+ alt="Some cute cat">
8
8
  </a>
9
9
  </img-lightbox>
10
10
 
@@ -14,4 +14,4 @@
14
14
 
15
15
  </div>
16
16
 
17
- <script src="./example.js"></script>
17
+ <script type="module" src="./example.js"></script>