- Getting Started
  - Requirements
  - Installation
  - Basic Usage
- Usage & Examples
  - Supported Variations
  - Lightbox Gallery
- Configuration
  - Carousel Options
  - Modal Options
- Methods
  - Lightbox.invoke
  - Lightbox.hasInstance
  - Lightbox.getInstance
  - Lightbox.getOrCreateInstance
  - <lightbox>.dispose
  - <lightbox>.append
  - <lightbox>.toggle
  - <lightbox>.show
  - <lightbox>.hide
  - <lightbox>.cycle
  - <lightbox>.next
  - <lightbox>.prev
  - <lightbox>.to
  - <lightbox>.on
  - <lightbox>.off
- Events

# @rat.md/bs-lightbox

A simple and ease-to-use Lightbox system build on top of Bootstrap's native Carousel and Modal JavaScript components. bs-lightbox is compatible with Bootstrap v4 and Bootstrap v5.

## Getting Started

Our bs-lightbox package depends on the Bootstrap CSS and JS framework, especially the Carousel and Modal components. Since this package does not provide a bundled version you've to ensure yourself that the Bootstrap framework is added to your HTML document and loaded BEFORE the bs-lightbox JavaScript.

bs-lightbox does also not provide any stylings or stylesheets but uses and depends on the Bootstrap native CSS components and utility classes. You don't have to worry, when you're using the already bundled distribution files - provided on getbootstrap.com. Only if you're using the Bootstrap source files, you've to make sure, that the default utility classes as well as the Carousel and Modal components are loaded and included in your bundled stylesheet.

### Requirements

bs-lightbox has been especially designed for Bootstrap v5 and provides a working backward compatibility to Bootstrap v4. Older versions of Bootstrap may work with this plugin, but aren't supported nor tested.

### Installation

You can download and embed the latest bs-lightbox version on the official GitHub Repository. Otherwise you can also use node.js and NPM, to include this package in your bundle / stack.

    npm i @rat.md/bs-lightbox

### Basic Usage

You can use bs-lightbox similar to many other different JavaScript packages. The following example code shows how to load and invoke the UMD bundle in the most basic way.

    <html>
        <head>
            <link href="/bs-lightbox/assets/css/bootstrap.min.css" />
        </head>
        <body>
            <script src="/bs-lightbox/assets/js/bootstrap.bundle.min.js"></script>
            <script src="/bs-lightbox/assets/js/rat.lightbox.min.js"></script>
            <script>
                document.addEventListener('DOMContentLoaded', () => {
                    rat.Lightbox.invoke();
                });
            </script>
        </body>
    </html>

The `rat.Lightbox.invoke()` method will fetch all supported elements, which has either the `data-bs-toggle="lightbox"`, `data-toggle="lightbox"` or `data-rat-lightbox` attribute on it. However, you can also pass your own selector string to the `.invoke` method, or pass your options as second parameter (Read more about the Configurations here).

    document.addEventListener('DOMContentLoaded', () => {

        // Invoke using a custom selector
        rat.Lightbox.invoke('[data-custom-lightbox]');

        // Invoke using custom configuration and the default selector
        rat.Lightbox.invoke(null, {
            carousel: {
                ride: true
            },
            modal: {
                size: 'fullscreen'
            }
        });

    });

bs-lightbox will create a new Lightbox instance for each image, unless the items are grouped using the `data-bs-gallery` or `data-gallery` attribute, as described here. You can also add new images using the `getOrCreateInstance` or the Lightbox `constructor` method itself. However, we recommend using `getOrCreateInstance` to keep the gallery grouping alive and prevent throwing errors on images, which are already included in a Lightbox or Lightbox Set.

    document.addEventListener('DOMContentLoaded', () => {

        let element = document.querySelector('img.some-special-image');

        // Creates a new Lightbox, or throws an Error when the image
        // is already included in another Lightbox.

        let lightbox = new rat.Lightbox(element, /* Custom Configuration */);

        // Create a new Lightbox or returns an existing Lightbox
        // Appends the image on grouped lightbox instances

        let lightbox = rat.Lightbox.getOrCreateInstance(element);

    });

## Usage & Examples

bs-lightbox uses the `data-bs-toggle="lightbox"` (alternatively also `data-toggle="lightbox"` or `data-rat-lightbox`) attribute to find the nearest `<picture />` or `<img />` element (which must either the linked one or one of it's children). Thus, the most basic way to add a lightbox to your image is by following the syntax below. However, bs-lightbox does also support sightly different variations, as described in the chapter below.

When a `<picture />` or `<img />` Element has been found, bs-lightbox will deep-clone the whole node and remove the class names on the main element ... and only on the main element. So, if you've a picture > img construct, you should style your `<picture />` element and set the height / width of the child `<img />` node to 100%.

Even if the pictures above aren't linked, you're still able to click on them to open the Lightbox.

    <div class="mb-3 d-flex justify-content-center">
        <img src="/bs-lightbox/assets/imgs/demo-4.jpg" data-bs-toggle="lightbox" class="w-25 d-block" />
    </div>

    <div class="mb-3 d-flex justify-content-center">
        <picture data-bs-toggle="lightbox" class="w-25 d-block">
            <img src="/bs-lightbox/assets/imgs/demo-5.jpg" class="w-100" />
        </picture>
    </div>

    <p class="text-muted mt-5">
        ...
    </p>

### Supported Variations

bs-lightbox also supports different formatting variations, which allows to change the image shown on the modal-carousel and also to add an optional title or caption.

#### Simple Link

Using a link as parent element allows to change the URL on an `<img />` element, for example to provide a higher resolution version of the same (or a different) image. This does NOT work when using a `<picture />` element - in this case you should rely on the HTML native <source> element.

Both links above point to the opposite picture, however just the first one works due to the <img /> element.

    <a href="/bs-lightbox/assets/imgs/demo-5.jpg" class="mb-3 d-flex justify-content-center" data-bs-toggle="lightbox">
        <img src="/bs-lightbox/assets/imgs/demo-4.jpg" class="w-25 d-block" />
    </a>

    <a href="/bs-lightbox/assets/imgs/demo-4.jpg" class="mb-3 d-flex justify-content-center" data-bs-toggle="lightbox">
        <picture class="w-25 d-block">
            <img src="/bs-lightbox/assets/imgs/demo-5.jpg" class="w-100" />
        </picture>
    </a>

    <p class="text-muted mt-5">
        ...
    </p>

#### Title & Caption

Since bs-lightbox using the official Bootstrap Carousel component, you can also add an own title and caption to the respective image. Just add the `data-bs-title` / `data-bs-caption` attributes or their alternative version `data-title` / `data-caption` on the desired picture.

The attributes can either be set on the same element or on the <picture> / <img /> one.

    <a href="/bs-lightbox/assets/imgs/demo-5.jpg" class="mb-3 d-flex justify-content-center"
        data-bs-toggle="lightbox" data-bs-title="Title" data-bs-caption="Caption">
        <img src="/bs-lightbox/assets/imgs/demo-4.jpg" class="w-25 d-block" />
    </a>

    <a href="/bs-lightbox/assets/imgs/demo-4.jpg" class="mb-3 d-flex justify-content-center" data-bs-toggle="lightbox">
        <picture class="w-25 d-block" data-title="Title" data-caption="Caption">
            <img src="/bs-lightbox/assets/imgs/demo-5.jpg" class="w-100" />
        </picture>
    </a>

    <p class="text-muted mt-5">
        ...
    </p>

#### Figure & Figcaption

Alternatively to the data-attributes above, you can also use the `<figure>` and `<figcaption>` elements, which allows to show the caption outside the Lightbox as well.

Caption
Caption

    <figure class="figure" data-bs-toggle="lightbox" data-bs-title="Title">
        <img src="/bs-lightbox/assets/imgs/demo-4.jpg" class="w-25 d-block figure-img" />
        <figcaption>Caption</figcaption>
    </figure>

    <figure class="figure" data-bs-toggle="lightbox" data-title="Title">
        <picture class="w-25 d-block figure-img">
            <img src="/bs-lightbox/assets/imgs/demo-5.jpg" class="w-100" />
        </picture>
        <figcaption>Caption</figcaption>
    </figure>

### Lightbox Gallery

A Lightbox / Carousel without the possibility to collect and slide through a bunch of pictures is absolutely useless. Thus, bs-lightbox provides the `data-bs-gallery` (or alternatively `data-gallery`) attribute, which allows to group different pictures all over the whole document and shows them all together.

    <div class="row">
        <div class="col-4 p-2">
            <a href="/bs-lightbox/assets/imgs/demo-1.png" data-bs-toggle="lightbox" data-bs-gallery="example" class="d-block">
                <img src="/bs-lightbox/assets/imgs/demo-1.png" class="w-100 rounded-2" />
            </a>
        </div>

        <div class="col-4 p-2">
            <a href="/bs-lightbox/assets/imgs/demo-2.png" data-bs-toggle="lightbox" data-bs-gallery="example" class="d-block">
                <img src="/bs-lightbox/assets/imgs/demo-2.png" class="w-100 rounded-2" />
            </a>
        </div>

        <div class="col-4 p-2">
            <a href="/bs-lightbox/assets/imgs/demo-3.png" data-bs-toggle="lightbox" data-bs-gallery="example" class="d-block">
                <img src="/bs-lightbox/assets/imgs/demo-3.png" class="w-100 rounded-2" />
            </a>
        </div>
    </div>

## Configuration

bs-lightbox gives you the full control over the used Carousel and Modal instances, just pass the desired options as second parameter on the Lightbox `constructor`, the recommended `getOrCreateInstance` or the general `invoke` method.

    rat.Lightbox.invoke(
        null,       // Use default selector string
        {
            carousel: {
                id: null,
                controls: true,
                indicators: false,
                interval: 5000,
                keyboard: false,
                pause: 'hover',
                ride: false,
                touch: true,
                wrap: true
            },
            modal: {
                id: null,
                backdrop: true,
                focus: true,
                keyboard: true,
                size: 'xl'
            }
        }
    );

### Carousel Options

You may recognize a few of the available Carousel options from the official Bootstrap documentation.

Option | Type | Default | Description
--- | --- | --- | ---
id | `string` | `"lightboxCarousel"` | Set a custom id value for the carousel element.
controls | `boolean` | `true` | Whether the carousel control action buttons, for sliding to the next or previous item, should be shown or not. When only one slide is available, the control buttons will be hidden regardless of this value.
indicators | `boolean` | `false` | Whether the carousel indicator buttons should be shown or not. When only one slide is available, the indicator buttons will be hidden regardless of this value.
interval | `number` | `5000` | The amount of time in milliseconds to delay between automatically cycling an item.
keyboard | `boolean` | `true` | Whether the carousel should react to keyboard events or not (left / right button).
pause | `boolean` `"hover"` | `"hover"` | Whether the carousel should pause on mouse and touch-events or not.
ride | `boolean` `"carousel"` | `false` | Whether the carousel should autoplay or not. `"carousel"` starts the autoplay of the carousel automatically, using `true` will autoplay after the user manually cycles the first item, `false` disables the autoplay completely.
touch | `boolean` | `true` | Whether the carousel should support left/right swipe interactions on touchscreen devices.
wrap | `boolean` | `true` | Whether the carousel should cycle continuously or have hard stops

### Modal Options

You may recognize a few of the available Modal options from the official Bootstrap documentation.

Option | Type | Default | Description
--- | --- | --- | ---
id | `string` | `"lightboxModal"` | Set a custom id value for the lightbox modal.
backdrop | `boolean` `"static"` | `true` | Includes a modal-backdrop element. Alternatively, specify `static` for a backdrop which doesn't close the modal when clicked.
focus | `boolean` | `true` | Puts the focus on the modal when initialized.
keyboard | `boolean` | `true` | Closes the modal when escape key is pressed.
size | `string` | `"xl"` | Sets the size of the modal, supports the following sizes: `"sm"`, `"md"`, `"lg"`, `"xl"` and `"fullscreen"`

## Methods

The current version of bs-lightbox provides the following Methods.

### Lightbox.invoke()

Signature

    rat.Lightbox.invoke(selector: null|string = null, config: object = {}): Lightbox[]

Invokes the Lightbox instances on all capable elements within the current DOM. This method supports 2 optional parameters: `selector` allows to change the default selector string used to find valid Lightbox candidates, `config` allows to override the default set of options to configure each single Lightbox instance.

### Lightbox.hasInstance()

Signature

    rat.Lightbox.hasInstance(data: HTMLElement|string): boolean

Checks if the passed HTMLElement or gallery string identifier has already been invoked within a Lightbox instance. Attention: This method does NOT verify if the passed HTMLElement is or could be a valid Lightbox candidate, it just checks if an instance has been assigned with it.

### Lightbox.getInstance()

Signature

    rat.Lightbox.getInstance(data: HTMLElement|string): Lightbox|null

Receive an already invoked Lightbox instance using the respective HTMLElement or a gallery string identifier. This method returns `null` if the passed argument is not assigned with a Lightbox instance. Attention: This method does NOT verify if the passed HTMLElement is or could be a valid Lightbox candidate, it just checks if an instance has been assigned with it.

### Lightbox.getOrCreateInstance()

Signature

    rat.Lightbox.getOrCreateInstance(element: HTMLElement, config: object: = {}): Lightbox

Receive or create a new Lightbox instance, based on the desired HTMLElement. The second parameter `config` is only used when this method invokes a new Lightbox instance, the options of existing Lightbox instances stay the same. When the element has a gallery string identifier - which has already been invoked - the element will be appended to this instance.

### Lightbox.constructor()

Signature

    rat.Lightbox.constructor(element: HTMLElement, config: object: = {}): Lightbox

Create a new Lightbox instance. This method will throw an `Error`, when the passed element is already be part of an Lightbox instance. We recommend using `getOrCreateInstance` to prevent this.

### `<lightbox>`.dispose()

Signature

    rat.Lightbox.dispose(): Lightbox

Destroys the Carousel and Modal bootstrap instances - by calling their own `dispose` method, and will clear the core Lightbox element. The Lightbox instance itself stays available, with all configurations and native event listeners. This method is used internally, when an open Lightbox closes.

### `<lightbox>`.append()

Signature

    rat.Lightbox.append(source: HTMLElement): Lightbox

Appends a new image to the same Lightbox instance. This method checks if the passed HTMLElement is a valid Lightbox candidate, if not it throws an error. Using `append` allows to create Lightbox galleries, and is used internally by the `getOrCreateInstance` method.

### `<lightbox>`.toggle()

Signature

    rat.Lightbox.toggle(): Lightbox

Calls the `.show()` or `.hide()` method, depending if the Lightbox is currently shown or not.

### `<lightbox>`.show()

Signature

    rat.Lightbox.show(): Lightbox

Creates the Lightbox modal HTML structure, applies the Modal and Carousel instances, binds all native as well as custom events, adds this whole construct to the DOM and starts the modal itself. This method does nothing, when the Lightbox Modal is already available.

### `<lightbox>`.hide()

Signature

    rat.Lightbox.hide(): Lightbox

Simple hides the Lightbox modal, when available, otherwise does nothing.

### `<lightbox>`.cycle()

Signature

    rat.Lightbox.cycle(): Lightbox

Calls the `.cycle()` method on the Carousel instance, when available.

### `<lightbox>`.next()

Signature

    rat.Lightbox.next(): Lightbox

Calls the `.next()` method on the Carousel instance, when available.

### `<lightbox>`.prev()

Signature

    rat.Lightbox.prev(): Lightbox

Calls the `.prev()` method on the Carousel instance, when available.

### `<lightbox>`.to()

Signature

    rat.Lightbox.to(direction: number|string): Lightbox

Allows to slide to a specific position within the Carousel instance. `direction` can either be an exact slide number (starting from 0) or one of the following strings: "next", "prev" or "previous".

### `<lightbox>`.on()

Signature

    rat.Lightbox.on(event: string, caller: Function): Lightbox

Attach an event listener to the modal or carousel. Currently supported events are: "slid.bs.carousel", "slide.bs.carousel", "hide.bs.modal", "hidden.bs.modal", "show.bs.modal" and "shown.bs.modal". The event listener is stored internally and attached every time, when then Lightbox' `.show()` method is called.

### `<lightbox>`.off()

Signature

    rat.Lightbox.off(event: string, caller: Function): Lightbox

Removes an event listener (as attached by the own `.on()` method) and detach it from the Carousel or Modal instance when the Lightbox is currently shown.

## Events

The current version of bs-lightbox does not provide own events, however using the `.on()` method allows you to attach all available, Bootstrap-native Carousel and Modal events as described below.

Event | Description
--- | ---
`slid.bs.carousel` | Fired when the carousel has completed its slide transition.
`slide.bs.carousel` | Fires immediately when the Carousel `slide` instance method is invoked.
`hide.bs.modal` | This event is fired immediately when the `hide` instance method has been called.
`hidden.bs.modal` | This event is fired when the modal has finished being hidden from the user (will wait for CSS transitions to complete).
`hidePrevented.bs.modal` | This event is fired when the modal is shown, its backdrop is `static` and a click outside of the modal is performed. The event is also fired when the escape key is pressed and the `keyboard` option is set to `false`.
`show.bs.modal` | This event fires immediately when the `show` instance method is called. If caused by a click, the clicked element is available as the `relatedTarget` property of the event.
`shown.bs.modal` | This event is fired when the modal has been made visible to the user (will wait for CSS transitions to complete). If caused by a click, the clicked element is available as the `relatedTarget` property of the event.