├── .gitattributes
├── .github
└── FUNDING.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── bower.json
├── build.js
├── demos
├── create.html
├── default.html
├── dom.html
└── events.html
├── dist
├── basicLightbox.min.css
└── basicLightbox.min.js
├── package.json
└── src
├── scripts
└── main.js
└── styles
└── main.scss
/.gitattributes:
--------------------------------------------------------------------------------
1 | dist/**/* binary
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: electerious
2 | custom: ['https://paypal.me/electerious', 'https://www.buymeacoffee.com/electerious']
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | yarn.lock
3 | package-lock.json
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6 |
7 | ## [5.0.4] - 2021-01-17
8 |
9 | ### Changed
10 |
11 | - Updated dependencies
12 |
13 | ## [5.0.3] - 2020-03-20
14 |
15 | ### Changed
16 |
17 | - Updated dependencies
18 |
19 | ## [5.0.2] - 2019-02-23
20 |
21 | ### Changed
22 |
23 | - Replace `gulp` and `basicTasks` with custom build process
24 |
25 | ## [5.0.1] - 2018-09-23
26 |
27 | ### Added
28 |
29 | - Link to CodePen demos
30 |
31 | ## [5.0.0] - 2018-09-23
32 |
33 | ### Added
34 |
35 | - Node elements and templates in `.create()` (#15, #17)
36 | - `onShow` and `onClose` callbacks
37 | - Streamlined API with less options to make basicLightbox easier to use
38 | - More demos
39 |
40 | ### Changed
41 |
42 | - Removed `beforeShow` and `afterShow` callbacks
43 | - Removed `beforeClose` and `afterClose` callbacks
44 | - Removed `beforePlaceholder` and `afterPlaceholder` options
45 |
46 | ## [4.0.3] - 2018-05-18
47 |
48 | ### Fixed
49 |
50 | - Multiple classes issue in className (#13)
51 |
52 | ## [4.0.2] - 2018-04-21
53 |
54 | ### Changed
55 |
56 | - Syntax of JS files
57 | - Placeholder images in demos
58 |
59 | ### Fixed
60 |
61 | - Videos and iframe content not clickable
62 |
63 | ## [4.0.1] - 2018-02-23
64 |
65 | ### Changed
66 |
67 | - Removed unnecessary `requestAnimationFrame` (#12)
68 |
69 | ## [4.0.0] - 2017-12-22
70 |
71 | ### Added
72 |
73 | - Support for `video` tag
74 | - Documentation of SASS variables
75 |
76 | ### Changed
77 |
78 | - Improved responsiveness when used with `iframe` tag
79 | - Syntax of JS and SCSS files
80 |
81 | ## [3.0.4] - 2017-08-08
82 |
83 | ### Changed
84 |
85 | - Ignore `yarn.lock` and `package-lock.json` files
86 |
87 | ## [3.0.3] - 2017-08-08
88 |
89 | ### Added
90 |
91 | - Added a changelog
92 |
93 | ### Fixed
94 |
95 | - `.99` opacity bug (#7)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Tobias Reich
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # basicLightbox
2 |
3 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CYKBESW577YWE)
4 |
5 | The lightest lightbox ever made.
6 |
7 | ## Contents
8 |
9 | - [Demos](#demos)
10 | - [Features](#features)
11 | - [Requirements](#requirements)
12 | - [Setup](#setup)
13 | - [API](#api)
14 | - [Instance API](#instance-api)
15 | - [Options](#options)
16 |
17 | ## Demos
18 |
19 | | Name | Description | Link |
20 | |:-----------|:------------|:------------|
21 | | Default | Includes most features. | [Try it on CodePen](https://codepen.io/electerious/pen/rLBvGz) |
22 | | DOM elements/nodes | Use DOM elements/nodes in basicLightbox. | [Try it on CodePen](https://codepen.io/electerious/pen/pOBLxQ) |
23 | | Create element | Use `.createElement()` with basicLightbox. | [Try it on CodePen](https://codepen.io/electerious/pen/wEZmQy) |
24 | | Events | Multiple ways to handle events. | [Try it on CodePen](https://codepen.io/electerious/pen/pOBLQQ) |
25 |
26 | ## Features
27 |
28 | - Works in all modern browsers and IE11 ([with polyfills](#requirements))
29 | - Supports images, videos, iframes and any kind of HTML
30 | - Creates a lightbox from a string or from a DOM element/node
31 | - Zero dependencies
32 | - CommonJS and AMD support
33 | - Simple JS API
34 |
35 | ## Requirements
36 |
37 | basicLightbox depends on the following browser features and APIs:
38 |
39 | - [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
40 | - [NodeList.prototype.forEach](https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach)
41 | - [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
42 | - [window.requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
43 |
44 | Some of these APIs are capable of being polyfilled in older browsers. Check the linked resources above to determine if you must polyfill to achieve your desired level of browser support.
45 |
46 | ## Setup
47 |
48 | We recommend installing basicLightbox using [npm](https://npmjs.com) or [yarn](https://yarnpkg.com).
49 |
50 | ```sh
51 | npm install basiclightbox
52 | ```
53 |
54 | ```sh
55 | yarn add basiclightbox
56 | ```
57 |
58 | Include the CSS file in the `head` tag and the JS file at the end of your `body` tag…
59 |
60 | ```html
61 |
62 | ```
63 |
64 | ```html
65 |
66 | ```
67 |
68 | …or skip the JS file and use basicLightbox as a module:
69 |
70 | ```js
71 | const basicLightbox = require('basiclightbox')
72 | ```
73 |
74 | ```js
75 | import * as basicLightbox from 'basiclightbox'
76 | ```
77 |
78 | ## API
79 |
80 | ### .create(content, opts)
81 |
82 | Creates a new basicLightbox instance.
83 |
84 | Be sure to assign your instance to a variable. Using your instance, you can…
85 |
86 | * …show and hide the lightbox.
87 | * …check if the the lightbox is visible.
88 | * …modify the content of the lightbox.
89 |
90 | Examples:
91 |
92 | ```js
93 | const instance = basicLightbox.create(`
94 |
Dynamic Content
95 | You can set the content of the lightbox with JS.
96 | `)
97 | ```
98 |
99 | ```js
100 | const instance = basicLightbox.create(`
101 | Not closable
102 | It's not possible to close this lightbox with a click.
103 | `, {
104 | closable: false
105 | })
106 | ```
107 |
108 | ```js
109 | const instance = basicLightbox.create(
110 | document.querySelector('#template')
111 | )
112 | ```
113 |
114 | Parameters:
115 |
116 | - `content` `{Node|String}` Content of the lightbox.
117 | - `opts` `{?Object}` An object of [options](#options).
118 |
119 | Returns:
120 |
121 | - `{Object}` The created instance.
122 |
123 | ### .visible()
124 |
125 | Returns `true` when a lightbox is visible. Also returns `true` when a lightbox is currently in the process of showing/hiding and not fully visible/hidden, yet.
126 |
127 | Example:
128 |
129 | ```js
130 | const visible = basicLightbox.visible()
131 | ```
132 |
133 | Returns:
134 |
135 | - `{Boolean}` Visibility of any lightbox.
136 |
137 | ## Instance API
138 |
139 | Each basicLightbox instance has a handful of handy functions. Below are all of them along with a short description.
140 |
141 | ### .show(cb)
142 |
143 | Shows a lightbox instance.
144 |
145 | Examples:
146 |
147 | ```js
148 | instance.show()
149 | ```
150 |
151 | ```js
152 | instance.show(() => console.log('lightbox now visible'))
153 | ```
154 |
155 | Parameters:
156 |
157 | - `cb(instance)` `{?Function}` A function that gets executed as soon as the lightbox starts to fade in.
158 |
159 | ### .close(cb)
160 |
161 | Closes a lightbox instance.
162 |
163 | Examples:
164 |
165 | ```js
166 | instance.close()
167 | ```
168 |
169 | ```js
170 | instance.close(() => console.log('lightbox not visible anymore'))
171 | ```
172 |
173 | Parameters:
174 |
175 | - `cb(instance)` `{?Function}` A function that gets executed as soon as the lightbox has been faded out.
176 |
177 | ### .visible()
178 |
179 | Returns `true` when the lightbox instance is visible. Also returns `true` when the lightbox is currently in the process of showing/hiding and not fully visible/hidden, yet.
180 |
181 | Example:
182 |
183 | ```js
184 | const visible = instance.visible()
185 | ```
186 |
187 | Returns:
188 |
189 | - `{Boolean}` Visibility of lightbox.
190 |
191 | ### .element()
192 |
193 | Returns the DOM element/node associated with the instance.
194 |
195 | Example:
196 |
197 | ```js
198 | const elem = instance.element()
199 | ```
200 |
201 | Returns:
202 |
203 | - `{Node}` DOM element/node associated with the instance.
204 |
205 | ## Options
206 |
207 | The option object can include the following properties:
208 |
209 | ```js
210 | {
211 | /*
212 | * Prevents the lightbox from closing when clicking its background.
213 | */
214 | closable: true,
215 | /*
216 | * One or more space separated classes to be added to the basicLightbox element.
217 | */
218 | className: '',
219 | /*
220 | * Function that gets executed before the lightbox will be shown.
221 | * Returning false will prevent the lightbox from showing.
222 | */
223 | onShow: (instance) => {},
224 | /*
225 | * Function that gets executed before the lightbox closes.
226 | * Returning false will prevent the lightbox from closing.
227 | */
228 | onClose: (instance) => {}
229 | }
230 | ```
231 |
232 | Import `src/styles/main.scss` directly to customize the look of basicLightbox:
233 |
234 | ```scss
235 | $basicLightbox__background: rgba(0, 0, 0, .8); // Background color
236 | $basicLightbox__zIndex: 1000; // Stack order
237 | $basicLightbox__duration: .4s; // Transition duration
238 | $basicLightbox__timing: ease; // Transition timing
239 |
240 | @import 'src/styles/main';
241 | ```
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "basicLightbox",
3 | "authors": [
4 | "Tobias Reich "
5 | ],
6 | "description": "The lightest lightbox ever made",
7 | "main": [
8 | "dist/basicLightbox.min.css",
9 | "dist/basicLightbox.min.js"
10 | ],
11 | "keywords": [
12 | "lightbox",
13 | "popup",
14 | "modal",
15 | "window",
16 | "dialog",
17 | "gallery",
18 | "photo",
19 | "responsive",
20 | "mobile"
21 | ],
22 | "ignore": [
23 | "**/.*",
24 | "demos",
25 | "build.js",
26 | "package.json"
27 | ],
28 | "license": "MIT",
29 | "homepage": "https://basiclightbox.electerious.com",
30 | "repository": {
31 | "type": "git",
32 | "url": "https://github.com/electerious/basicLightbox.git"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { writeFile } = require('fs').promises
4 | const js = require('rosid-handler-js')
5 | const sass = require('rosid-handler-sass')
6 |
7 | sass('src/styles/main.scss', {
8 |
9 | optimize: true
10 |
11 | }).then((data) => {
12 |
13 | return writeFile('dist/basicLightbox.min.css', data)
14 |
15 | })
16 |
17 | js('src/scripts/main.js', {
18 |
19 | optimize: true,
20 | browserify: {
21 | standalone: 'basicLightbox'
22 | }
23 |
24 | }).then((data) => {
25 |
26 | return writeFile('dist/basicLightbox.min.js', data)
27 |
28 | })
--------------------------------------------------------------------------------
/demos/create.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | basicLightbox Demo
6 |
7 |
8 |
9 |
10 |
11 |
46 |
47 |
48 |
49 |
50 |
51 |
69 |
70 |
--------------------------------------------------------------------------------
/demos/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | basicLightbox Demo
6 |
7 |
8 |
9 |
10 |
11 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
188 |
189 |
--------------------------------------------------------------------------------
/demos/dom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | basicLightbox Demo
6 |
7 |
8 |
9 |
10 |
11 |
46 |
47 |
48 |
DOM element/node
49 |
DOM element/node has been moved into the lightbox.
50 |
51 |
52 |
53 |

54 |
55 |
56 |
57 |
Persistant
58 |
The value and state of this lightbox persists as long as you use the same instance.
Create a new instance when you don't want to keep the state.
59 |
60 |
61 |
62 |
63 | HTML <template> Tag
64 | The template element holds HTML code without displaying it.
Doesn't work in older browsers.
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
87 |
88 |
--------------------------------------------------------------------------------
/demos/events.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | basicLightbox Demo
6 |
7 |
8 |
9 |
10 |
11 |
46 |
47 |
48 |
Existing event
49 |
The event of this button has been attached to the DOM element/node and basicLightbox keeps it.
50 |
51 |
52 |
53 |
54 |
New events
55 |
The event of this button has been added via JS in the `.onShow` callback of basicLightbox.
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
108 |
109 |
--------------------------------------------------------------------------------
/dist/basicLightbox.min.css:
--------------------------------------------------------------------------------
1 | .basicLightbox{position:fixed;display:flex;justify-content:center;align-items:center;top:0;left:0;width:100%;height:100vh;background:rgba(0,0,0,.8);opacity:.01;transition:opacity .4s ease;z-index:1000;will-change:opacity}.basicLightbox--visible{opacity:1}.basicLightbox__placeholder{max-width:100%;transform:scale(.9);transition:transform .4s ease;z-index:1;will-change:transform}.basicLightbox__placeholder>iframe:first-child:last-child,.basicLightbox__placeholder>img:first-child:last-child,.basicLightbox__placeholder>video:first-child:last-child{display:block;position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;max-width:95%;max-height:95%}.basicLightbox__placeholder>iframe:first-child:last-child,.basicLightbox__placeholder>video:first-child:last-child{pointer-events:auto}.basicLightbox__placeholder>img:first-child:last-child,.basicLightbox__placeholder>video:first-child:last-child{width:auto;height:auto}.basicLightbox--iframe .basicLightbox__placeholder,.basicLightbox--img .basicLightbox__placeholder,.basicLightbox--video .basicLightbox__placeholder{width:100%;height:100%;pointer-events:none}.basicLightbox--visible .basicLightbox__placeholder{transform:scale(1)}
--------------------------------------------------------------------------------
/dist/basicLightbox.min.js:
--------------------------------------------------------------------------------
1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).basicLightbox=e()}}((function(){return function e(n,t,o){function r(c,u){if(!t[c]){if(!n[c]){var s="function"==typeof require&&require;if(!u&&s)return s(c,!0);if(i)return i(c,!0);var a=new Error("Cannot find module '"+c+"'");throw a.code="MODULE_NOT_FOUND",a}var l=t[c]={exports:{}};n[c][0].call(l.exports,(function(e){return r(n[c][1][e]||e)}),l,l.exports,e,n,t,o)}return t[c].exports}for(var i="function"==typeof require&&require,c=0;c1&&void 0!==arguments[1]&&arguments[1],t=document.createElement("div");return t.innerHTML=e.trim(),!0===n?t.children:t.firstChild},r=function(e,n){var t=e.children;return 1===t.length&&t[0].tagName===n},i=function(e){return null!=(e=e||document.querySelector(".basicLightbox"))&&!0===e.ownerDocument.body.contains(e)};t.visible=i;t.create=function(e,n){var t=function(e,n){var t=o('\n\t\t\n\t')),i=t.querySelector(".basicLightbox__placeholder");e.forEach((function(e){return i.appendChild(e)}));var c=r(i,"IMG"),u=r(i,"VIDEO"),s=r(i,"IFRAME");return!0===c&&t.classList.add("basicLightbox--img"),!0===u&&t.classList.add("basicLightbox--video"),!0===s&&t.classList.add("basicLightbox--iframe"),t}(e=function(e){var n="string"==typeof e,t=e instanceof HTMLElement==1;if(!1===n&&!1===t)throw new Error("Content must be a DOM element/node or string");return!0===n?Array.from(o(e,!0)):"TEMPLATE"===e.tagName?[e.content.cloneNode(!0)]:Array.from(e.children)}(e),n=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(null==(e=Object.assign({},e)).closable&&(e.closable=!0),null==e.className&&(e.className=""),null==e.onShow&&(e.onShow=function(){}),null==e.onClose&&(e.onClose=function(){}),"boolean"!=typeof e.closable)throw new Error("Property `closable` must be a boolean");if("string"!=typeof e.className)throw new Error("Property `className` must be a string");if("function"!=typeof e.onShow)throw new Error("Property `onShow` must be a function");if("function"!=typeof e.onClose)throw new Error("Property `onClose` must be a function");return e}(n)),c=function(e){return!1!==n.onClose(u)&&function(e,n){return e.classList.remove("basicLightbox--visible"),setTimeout((function(){return!1===i(e)||e.parentElement.removeChild(e),n()}),410),!0}(t,(function(){if("function"==typeof e)return e(u)}))};!0===n.closable&&t.addEventListener("click",(function(e){e.target===t&&c()}));var u={element:function(){return t},visible:function(){return i(t)},show:function(e){return!1!==n.onShow(u)&&function(e,n){return document.body.appendChild(e),setTimeout((function(){requestAnimationFrame((function(){return e.classList.add("basicLightbox--visible"),n()}))}),10),!0}(t,(function(){if("function"==typeof e)return e(u)}))},close:c};return u}},{}]},{},[1])(1)}));
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "basiclightbox",
3 | "version": "5.0.4",
4 | "authors": [
5 | "Tobias Reich "
6 | ],
7 | "description": "The lightest lightbox ever made",
8 | "main": "dist/basicLightbox.min.js",
9 | "keywords": [
10 | "lightbox",
11 | "popup",
12 | "modal",
13 | "window",
14 | "dialog",
15 | "gallery",
16 | "photo",
17 | "responsive",
18 | "mobile"
19 | ],
20 | "scripts": {
21 | "build": "node build.js"
22 | },
23 | "license": "MIT",
24 | "homepage": "https://basiclightbox.electerious.com",
25 | "repository": {
26 | "type": "git",
27 | "url": "https://github.com/electerious/basicLightbox.git"
28 | },
29 | "files": [
30 | "dist",
31 | "src"
32 | ],
33 | "devDependencies": {
34 | "rosid-handler-js": "^13.0.2",
35 | "rosid-handler-sass": "^8.0.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/scripts/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creates an element from a HTML string.
3 | * @param {String} html
4 | * @param {?Boolean} children - Return all children instead of the first one.
5 | * @returns {Node}
6 | */
7 | const toElement = function(html, children = false) {
8 |
9 | const elem = document.createElement('div')
10 |
11 | elem.innerHTML = html.trim()
12 |
13 | return children === true ? elem.children : elem.firstChild
14 |
15 | }
16 |
17 | /**
18 | * Validates and converts content.
19 | * @param {Node|String} content
20 | * @returns {Array} content - Validated content.
21 | */
22 | const validateContent = function(content) {
23 |
24 | const isString = typeof content === 'string'
25 | const isHTMLElement = content instanceof HTMLElement === true
26 |
27 | if (isString === false && isHTMLElement === false) {
28 |
29 | throw new Error('Content must be a DOM element/node or string')
30 |
31 | }
32 |
33 | if (isString === true) {
34 |
35 | // String
36 | return Array.from(toElement(content, true))
37 |
38 | } else if (content.tagName === 'TEMPLATE') {
39 |
40 | // Template
41 | return [ content.content.cloneNode(true) ]
42 |
43 | } else {
44 |
45 | // HTMLElement
46 | return Array.from(content.children)
47 |
48 | }
49 |
50 | }
51 |
52 | /**
53 | * Validates options and sets defaults for undefined properties.
54 | * @param {?Object} opts
55 | * @returns {Object} opts - Validated options.
56 | */
57 | const validateOptions = function(opts = {}) {
58 |
59 | opts = Object.assign({}, opts)
60 |
61 | if (opts.closable == null) opts.closable = true
62 | if (opts.className == null) opts.className = ''
63 | if (opts.onShow == null) opts.onShow = () => {}
64 | if (opts.onClose == null) opts.onClose = () => {}
65 |
66 | if (typeof opts.closable !== 'boolean') throw new Error('Property `closable` must be a boolean')
67 | if (typeof opts.className !== 'string') throw new Error('Property `className` must be a string')
68 | if (typeof opts.onShow !== 'function') throw new Error('Property `onShow` must be a function')
69 | if (typeof opts.onClose !== 'function') throw new Error('Property `onClose` must be a function')
70 |
71 | return opts
72 |
73 | }
74 |
75 | /**
76 | * Checks if an element's first child has a specific tag.
77 | * @param {Node} elem
78 | * @param {String} tag
79 | * @returns {Boolean} containsTag
80 | */
81 | const containsTag = function(elem, tag) {
82 |
83 | const children = elem.children
84 |
85 | return (children.length === 1 && children[0].tagName === tag)
86 |
87 | }
88 |
89 | /**
90 | * Checks if a given or any lightbox is visible.
91 | * @param {?Node} elem
92 | * @returns {Boolean} visible
93 | */
94 | export const visible = function(elem) {
95 |
96 | elem = elem || document.querySelector('.basicLightbox')
97 |
98 | return (elem != null && elem.ownerDocument.body.contains(elem) === true)
99 |
100 | }
101 |
102 | /**
103 | * Creates a lightbox element.
104 | * @param {Array} content
105 | * @param {Object} opts
106 | * @returns {Node} elem
107 | */
108 | const render = function(content, opts) {
109 |
110 | const elem = toElement(`
111 |
114 | `)
115 |
116 | const placeholder = elem.querySelector('.basicLightbox__placeholder')
117 |
118 | // Move content into lightbox placeholder
119 | content.forEach((child) => placeholder.appendChild(child))
120 |
121 | // Check if placeholder contains a tag that requires a special treatment
122 | const img = containsTag(placeholder, 'IMG')
123 | const video = containsTag(placeholder, 'VIDEO')
124 | const iframe = containsTag(placeholder, 'IFRAME')
125 |
126 | // Add special treatment class when it only contains an image, a video or iframe.
127 | // This class is necessary to center the image, video or iframe.
128 | if (img === true) elem.classList.add('basicLightbox--img')
129 | if (video === true) elem.classList.add('basicLightbox--video')
130 | if (iframe === true) elem.classList.add('basicLightbox--iframe')
131 |
132 | return elem
133 |
134 | }
135 |
136 | /**
137 | * Shows a lightbox by appending an element to the DOM.
138 | * @param {Node} elem
139 | * @param {Function} next - The callback that gets executed when the lightbox starts to show up.
140 | * @returns {Boolean} success
141 | */
142 | const show = function(elem, next) {
143 |
144 | document.body.appendChild(elem)
145 |
146 | // Wait a while to ensure that the class change triggers the animation
147 | setTimeout(() => {
148 | requestAnimationFrame(() => {
149 |
150 | elem.classList.add('basicLightbox--visible')
151 |
152 | return next()
153 |
154 | })
155 | }, 10)
156 |
157 | return true
158 |
159 | }
160 |
161 | /**
162 | * Closes a lightbox by fading the element out and by removing the element from the DOM.
163 | * @param {Node} elem
164 | * @param {Function} next - The callback that gets executed when the lightbox is fully closed.
165 | * @returns {Boolean} success
166 | */
167 | const close = function(elem, next) {
168 |
169 | elem.classList.remove('basicLightbox--visible')
170 |
171 | setTimeout(() => {
172 |
173 | // Don't continue to remove lightbox when element missing
174 | if (visible(elem) === false) return next()
175 |
176 | elem.parentElement.removeChild(elem)
177 |
178 | return next()
179 |
180 | }, 410)
181 |
182 | return true
183 |
184 | }
185 |
186 | /**
187 | * Creats a new instance.
188 | * @param {Node|String} content
189 | * @param {?Object} opts
190 | * @returns {Object} instance
191 | */
192 | export const create = function(content, opts) {
193 |
194 | content = validateContent(content)
195 | opts = validateOptions(opts)
196 |
197 | // Render the lightbox element
198 | const elem = render(content, opts)
199 |
200 | // Returns the lightbox element
201 | const _element = () => {
202 |
203 | return elem
204 |
205 | }
206 |
207 | // Check if the lightbox is attached to the DOM
208 | const _visible = () => {
209 |
210 | return visible(elem)
211 |
212 | }
213 |
214 | // Show the lightbox
215 | const _show = (next) => {
216 |
217 | // Run onShow callback and stop execution when function returns false
218 | if (opts.onShow(instance) === false) return false
219 |
220 | // Show the lightbox
221 | return show(elem, () => {
222 |
223 | // Continue with the callback when available
224 | if (typeof next === 'function') return next(instance)
225 |
226 | })
227 |
228 | }
229 |
230 | // Hide the lightbox
231 | const _close = (next) => {
232 |
233 | // Run onClose callback and stop execution when function returns false
234 | if (opts.onClose(instance) === false) return false
235 |
236 | return close(elem, () => {
237 |
238 | // Continue with the callback when available
239 | if (typeof next === 'function') return next(instance)
240 |
241 | })
242 |
243 | }
244 |
245 | // Close lightbox when clicking the background
246 | if (opts.closable === true) elem.addEventListener('click', (e) => {
247 |
248 | // If e.target is not the same element as elem,
249 | // then the user clicked a descendant of the element.
250 | if (e.target !== elem) return
251 |
252 | // Close lightbox with the instance function
253 | _close()
254 |
255 | })
256 |
257 | // Assign instance to a variable so the instance can be used
258 | // elsewhere in the current function.
259 | const instance = {
260 | element: _element,
261 | visible: _visible,
262 | show: _show,
263 | close: _close
264 | }
265 |
266 | return instance
267 |
268 | }
--------------------------------------------------------------------------------
/src/styles/main.scss:
--------------------------------------------------------------------------------
1 | // Vars ---------------------------------------------------------------- //
2 | $basicLightbox__background: rgba(0, 0, 0, .8) !default;
3 | $basicLightbox__zIndex: 1000 !default;
4 | $basicLightbox__duration: .4s !default;
5 | $basicLightbox__timing: ease !default;
6 |
7 | // basicLightbox ------------------------------------------------------- //
8 | .basicLightbox {
9 |
10 | position: fixed;
11 | display: flex;
12 | justify-content: center;
13 | align-items: center;
14 | top: 0;
15 | left: 0;
16 | width: 100%;
17 | height: 100vh;
18 | background: $basicLightbox__background;
19 | opacity: .01; // Start with .01 to avoid the repaint that happens from 0 to .01
20 | transition: opacity $basicLightbox__duration $basicLightbox__timing;
21 | z-index: $basicLightbox__zIndex;
22 | will-change: opacity;
23 |
24 | &--visible {
25 | opacity: 1;
26 | }
27 |
28 | &__placeholder {
29 | max-width: 100%;
30 | transform: scale(.9);
31 | transition: transform $basicLightbox__duration $basicLightbox__timing;
32 | z-index: 1;
33 | will-change: transform;
34 |
35 | > img:first-child:last-child,
36 | > video:first-child:last-child,
37 | > iframe:first-child:last-child {
38 | display: block;
39 | position: absolute;
40 | top: 0;
41 | right: 0;
42 | bottom: 0;
43 | left: 0;
44 | margin: auto;
45 | max-width: 95%;
46 | max-height: 95%;
47 | }
48 |
49 | > video:first-child:last-child,
50 | > iframe:first-child:last-child {
51 | pointer-events: auto;
52 | }
53 |
54 | > img:first-child:last-child,
55 | > video:first-child:last-child {
56 | width: auto;
57 | height: auto;
58 | }
59 | }
60 |
61 | &--img &__placeholder,
62 | &--video &__placeholder,
63 | &--iframe &__placeholder {
64 | width: 100%;
65 | height: 100%;
66 | pointer-events: none;
67 | }
68 |
69 | &--visible &__placeholder {
70 | transform: scale(1);
71 | }
72 |
73 | }
--------------------------------------------------------------------------------