UNPKG

@ks89/angular-modal-gallery

Version:
5,686 lines 391 kB
import * as i0 from '@angular/core';
import { Component, ChangeDetectionStrategy, Injectable, EventEmitter, Directive, Input, Output, HostListener, HostBinding, PLATFORM_ID, Inject, InjectionToken, SecurityContext, ViewChild, Injector, APP_INITIALIZER, NgModule } from '@angular/core';
import * as i2$1 from '@angular/common';
import { isPlatformBrowser, CommonModule } from '@angular/common';
import * as i1 from '@angular/cdk/overlay';
import { OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
import { Subject, timer } from 'rxjs';
import { map, filter, switchMap, takeUntil } from 'rxjs/operators';
import * as i1$1 from '@angular/cdk/layout';
import { Breakpoints } from '@angular/cdk/layout';
import * as i2 from '@angular/platform-browser';
import { ComponentPortal } from '@angular/cdk/portal';

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Key of the keyboard's key `enter`
 */
const ENTER_KEY = 'Enter';
/**
 * Code of the keyboard's key `enter`
 */
const ENTER_CODE = 'Enter';
/**
 * Key of the keyboard's key `esc`
 */
const ESC_KEY = 'Escape';
/**
 * Code of the keyboard's key `esc`
 */
const ESC_CODE = 'Escape';
/**
 * Key of the keyboard's key 'right arrow'
 */
const RIGHT_ARROW_KEY = 'ArrowRight';
/**
 * Code of the keyboard's key 'right arrow'
 */
const RIGHT_ARROW_CODE = 'ArrowRight';
/**
 * Key of the keyboard's key 'left arrow'
 */
const LEFT_ARROW_KEY = 'ArrowLeft';
/**
 * Code of the keyboard's key 'left arrow'
 */
const LEFT_ARROW_CODE = 'ArrowLeft';
/**
 * Key of the keyboard's key 'left arrow'
 */
const UP_ARROW_KEY = 'ArrowUp';
/**
 * Code of the keyboard's key 'left arrow'
 */
const UP_ARROW_CODE = 'ArrowUp';
/**
 * Key of the keyboard's key 'left arrow'
 */
const DOWN_ARROW_KEY = 'ArrowDown';
/**
 * Code of the keyboard's key 'left arrow'
 */
const DOWN_ARROW_CODE = 'ArrowDown';
/**
 * Key of the keyboard's key `space`
 */
const SPACE_KEY = '';
/**
 * Code of the keyboard's key `space`
 */
const SPACE_CODE = 'Space';
/**
 * Const to represent the right direction
 */
const DIRECTION_RIGHT = 'right';
/**
 * Const to represent the left direction
 */
const DIRECTION_LEFT = 'left';
/**
 * Keycode of the main mouse button
 */
const MOUSE_MAIN_BUTTON_CLICK = 0;
/**
 * Const NEXT
 */
const NEXT = 1;
/**
 * Const PREV
 */
const PREV = -1;
/**
 * Const NOTHING to represents a situation when it isn't both NEXT and PREV
 */
const NOTHING = 0;

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Provides some useful methods to add accessibility features to subclasses.
 * In particular, it exposes a method to handle navigation event with both Keyboard and Mouse
 * and another with also the direction (right or left).
 */
class AccessibleComponent {
    constructor() { }
    /**
     * Method to handle navigation events with both Keyboard and Mouse.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent | MouseEvent event payload
     * @returns number -1 for PREV, 1 for NEXT and 0 for NOTHING
     */
    handleNavigationEvent(direction, event) {
        if (!event) {
            return NOTHING;
        }
        if (event instanceof KeyboardEvent) {
            return this.handleKeyboardNavigationEvent(direction, event);
        }
        else if (event instanceof MouseEvent) {
            return this.handleMouseNavigationEvent(direction, event);
        }
        return NOTHING;
    }
    /**
     * Method to handle events over an image, for instance a keypress with the Keyboard or a Mouse click.
     * @param event KeyboardEvent | MouseEvent payload
     * @returns number 1 for NEXT and 0 for NOTHING
     */
    handleImageEvent(event) {
        if (!event) {
            return NOTHING;
        }
        if (event instanceof KeyboardEvent) {
            return this.handleImageKeyboardEvent(event);
        }
        else if (event instanceof MouseEvent) {
            return this.handleImageMouseEvent(event);
        }
        return NOTHING;
    }
    /**
     * Private method to handle keyboard events over an image.
     * @param event KeyboardEvent payload
     * @returns number 1 for NEXT and 0 for NOTHING
     */
    handleImageKeyboardEvent(event) {
        const key = event.code;
        if (key === SPACE_CODE || key === ENTER_CODE) {
            return NEXT;
        }
        return NOTHING;
    }
    /**
     * Private method to handle mouse events over an image.
     * @param MouseEvent event payload
     * @returns number 1 for NEXT and 0 for NOTHING
     */
    handleImageMouseEvent(event) {
        const mouseBtn = event.button;
        if (mouseBtn === MOUSE_MAIN_BUTTON_CLICK) {
            return NEXT;
        }
        return NOTHING;
    }
    /**
     * Method to handle events over an image, for instance a keypress with the Keyboard or a Mouse click.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent event payload
     * @returns number -1 for PREV, 1 for NEXT and 0 for NOTHING
     */
    handleKeyboardNavigationEvent(direction, event) {
        const key = event.code;
        if (key === SPACE_CODE || key === ENTER_CODE) {
            return direction === DIRECTION_RIGHT ? NEXT : PREV;
        }
        return NOTHING;
    }
    /**
     * Method to handle events over an image, for instance a keypress with the Keyboard or a Mouse click.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param MouseEvent event payload
     * @returns number -1 for PREV, 1 for NEXT and 0 for NOTHING
     */
    handleMouseNavigationEvent(direction, event) {
        const mouseBtn = event.button;
        if (mouseBtn === MOUSE_MAIN_BUTTON_CLICK) {
            return direction === DIRECTION_RIGHT ? NEXT : PREV;
        }
        return NOTHING;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: AccessibleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: AccessibleComponent, isStandalone: false, selector: "ks-accessible", ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: AccessibleComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ks-accessible',
                    template: ``,
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    standalone: false
                }]
        }], ctorParameters: () => [] });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Class `Image` that represents an image with both `modal` and `plain` configurations.
 * Both image `id` and `modal` are mandatory, instead `plain` is optional.
 */
class Image {
    constructor(id, modal, plain, loading = 'lazy', fetchpriority = 'auto') {
        this.id = id;
        this.modal = modal;
        this.plain = plain;
        this.loading = loading;
        this.fetchpriority = fetchpriority;
    }
}
/**
 * Class `ImageEvent` that represents the event payload with the result and the triggered action.
 * It also contains the source id of the gallery that emitted this event
 */
class ImageEvent {
    constructor(galleryId, action, result) {
        this.galleryId = galleryId;
        this.action = action;
        this.result = result;
    }
}
/**
 * Class `ImageModalEvent` that represents the event payload with galleryId, result and the triggered action.
 */
class ImageModalEvent extends ImageEvent {
    constructor(galleryId, action, result) {
        super(galleryId, action, result);
    }
}

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Enum `Action` with a list of possible actions, based on the source of the action.
 */
var Action;
(function (Action) {
    Action[Action["NORMAL"] = 0] = "NORMAL";
    Action[Action["CLICK"] = 1] = "CLICK";
    Action[Action["KEYBOARD"] = 2] = "KEYBOARD";
    Action[Action["SWIPE"] = 3] = "SWIPE";
    Action[Action["LOAD"] = 4] = "LOAD";
    Action[Action["AUTOPLAY"] = 5] = "AUTOPLAY";
})(Action || (Action = {}));

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Utility function to get the index of the input `image` from `arrayOfImages`
 * @param image Image to get the index. The image 'id' must be a number >= 0
 * @param arrayOfImages Image[] to search the image within it
 * @returns number the index of the image. -1 if not found.
 * @throws an Error if either image or arrayOfImages are not valid,
 *  or if the input image doesn't contain an 'id', or the 'id' is < 0
 */
function getIndex(image, arrayOfImages) {
    if (!image) {
        throw new Error('image must be a valid Image object');
    }
    if (!arrayOfImages) {
        throw new Error('arrayOfImages must be a valid Image[]');
    }
    if (!image.id && image.id !== 0) {
        // id = 0 is admitted
        throw new Error(`A numeric Image 'id' is mandatory`);
    }
    if (image.id < 0) {
        throw new Error(`Image 'id' must be >= 0`);
    }
    return arrayOfImages.findIndex((val) => val.id === image.id);
}

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Enum `DescriptionStrategy` with keys and their relative key codes.
 */
var DescriptionStrategy;
(function (DescriptionStrategy) {
    DescriptionStrategy[DescriptionStrategy["ALWAYS_HIDDEN"] = 1] = "ALWAYS_HIDDEN";
    DescriptionStrategy[DescriptionStrategy["ALWAYS_VISIBLE"] = 2] = "ALWAYS_VISIBLE";
    DescriptionStrategy[DescriptionStrategy["HIDE_IF_EMPTY"] = 3] = "HIDE_IF_EMPTY";
})(DescriptionStrategy || (DescriptionStrategy = {}));

/**
 * Default accessibility configuration.
 */
const KS_DEFAULT_ACCESSIBILITY_CONFIG = {
    backgroundAriaLabel: 'Modal gallery full screen background',
    backgroundTitle: '',
    plainGalleryContentAriaLabel: 'Plain gallery content',
    plainGalleryContentTitle: '',
    modalGalleryContentAriaLabel: 'Modal gallery content',
    modalGalleryContentTitle: '',
    loadingSpinnerAriaLabel: 'The current image is loading. Please be patient.',
    loadingSpinnerTitle: 'The current image is loading. Please be patient.',
    mainContainerAriaLabel: 'Current image and navigation',
    mainContainerTitle: '',
    mainPrevImageAriaLabel: 'Previous image',
    mainPrevImageTitle: 'Previous image',
    mainNextImageAriaLabel: 'Next image',
    mainNextImageTitle: 'Next image',
    dotsContainerAriaLabel: 'Image navigation dots',
    dotsContainerTitle: '',
    dotAriaLabel: 'Navigate to image number',
    previewsContainerAriaLabel: 'Image previews',
    previewsContainerTitle: '',
    previewScrollPrevAriaLabel: 'Scroll previous previews',
    previewScrollPrevTitle: 'Scroll previous previews',
    previewScrollNextAriaLabel: 'Scroll next previews',
    previewScrollNextTitle: 'Scroll next previews',
    carouselContainerAriaLabel: 'Current image and navigation',
    carouselContainerTitle: '',
    carouselPrevImageAriaLabel: 'Previous image',
    carouselPrevImageTitle: 'Previous image',
    carouselNextImageAriaLabel: 'Next image',
    carouselNextImageTitle: 'Next image',
    carouselPreviewsContainerAriaLabel: 'Image previews',
    carouselPreviewsContainerTitle: '',
    carouselPreviewScrollPrevAriaLabel: 'Scroll previous previews',
    carouselPreviewScrollPrevTitle: 'Scroll previous previews',
    carouselPreviewScrollNextAriaLabel: 'Scroll next previews',
    carouselPreviewScrollNextTitle: 'Scroll next previews'
};

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Enum `ButtonsStrategy` to configure the logic of a button.
 */
var ButtonsStrategy;
(function (ButtonsStrategy) {
    // don't use 0 here
    // the first index is 1 and all of the following members are auto-incremented from that point on
    ButtonsStrategy[ButtonsStrategy["DEFAULT"] = 1] = "DEFAULT";
    ButtonsStrategy[ButtonsStrategy["SIMPLE"] = 2] = "SIMPLE";
    ButtonsStrategy[ButtonsStrategy["ADVANCED"] = 3] = "ADVANCED";
    ButtonsStrategy[ButtonsStrategy["FULL"] = 4] = "FULL";
    ButtonsStrategy[ButtonsStrategy["CUSTOM"] = 5] = "CUSTOM";
})(ButtonsStrategy || (ButtonsStrategy = {}));
/**
 * Enum `ButtonType` is the type of a button.
 */
var ButtonType;
(function (ButtonType) {
    // don't use 0 here
    // the first index is 1 and all of the following members are auto-incremented from that point on
    ButtonType[ButtonType["DELETE"] = 1] = "DELETE";
    ButtonType[ButtonType["EXTURL"] = 2] = "EXTURL";
    ButtonType[ButtonType["DOWNLOAD"] = 3] = "DOWNLOAD";
    ButtonType[ButtonType["CLOSE"] = 4] = "CLOSE";
    ButtonType[ButtonType["CUSTOM"] = 5] = "CUSTOM";
    ButtonType[ButtonType["FULLSCREEN"] = 6] = "FULLSCREEN";
})(ButtonType || (ButtonType = {}));
/**
 * Array of admitted types of buttons.
 */
const WHITELIST_BUTTON_TYPES = [
    ButtonType.FULLSCREEN,
    ButtonType.DELETE,
    ButtonType.EXTURL,
    ButtonType.DOWNLOAD,
    ButtonType.CLOSE,
    ButtonType.CUSTOM
];

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Class `LineLayout` to configure a linear plain gallery.
 */
class LineLayout {
    constructor(size, breakConfig, justify) {
        this.size = size;
        this.breakConfig = breakConfig;
        this.justify = justify;
    }
}
/**
 * Class `GridLayout` to configure a grid plain gallery.
 */
class GridLayout {
    constructor(size, breakConfig) {
        this.size = size;
        this.breakConfig = breakConfig;
    }
}
/**
 * Enum `PlainGalleryStrategy` to choose the behaviour of the plain gallery.
 */
var PlainGalleryStrategy;
(function (PlainGalleryStrategy) {
    // don't use 0 here
    // the first index is 1 and all of the following members are auto-incremented from that point on
    PlainGalleryStrategy[PlainGalleryStrategy["ROW"] = 1] = "ROW";
    PlainGalleryStrategy[PlainGalleryStrategy["COLUMN"] = 2] = "COLUMN";
    PlainGalleryStrategy[PlainGalleryStrategy["GRID"] = 3] = "GRID";
    PlainGalleryStrategy[PlainGalleryStrategy["CUSTOM"] = 4] = "CUSTOM"; // full custom strategy
})(PlainGalleryStrategy || (PlainGalleryStrategy = {}));

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Enum `LoadingType` with a list of possible types.
 */
var LoadingType;
(function (LoadingType) {
    LoadingType[LoadingType["STANDARD"] = 1] = "STANDARD";
    LoadingType[LoadingType["CIRCULAR"] = 2] = "CIRCULAR";
    LoadingType[LoadingType["BARS"] = 3] = "BARS";
    LoadingType[LoadingType["DOTS"] = 4] = "DOTS";
    LoadingType[LoadingType["CUBE_FLIPPING"] = 5] = "CUBE_FLIPPING";
    LoadingType[LoadingType["CIRCLES"] = 6] = "CIRCLES";
    LoadingType[LoadingType["EXPLOSING_SQUARES"] = 7] = "EXPLOSING_SQUARES";
})(LoadingType || (LoadingType = {}));

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
const DEFAULT_PREVIEW_SIZE = { height: '50px', width: 'auto' };
const DEFAULT_LAYOUT = new LineLayout(DEFAULT_PREVIEW_SIZE, { length: -1, wrap: false }, 'flex-start');
const DEFAULT_PLAIN_CONFIG = {
    strategy: PlainGalleryStrategy.ROW,
    layout: DEFAULT_LAYOUT,
    advanced: { aTags: false, additionalBackground: '50% 50%/cover' }
};
const DEFAULT_LOADING = { enable: true, type: LoadingType.STANDARD };
const DEFAULT_DESCRIPTION_STYLE = {
    bgColor: 'rgba(0, 0, 0, .5)',
    textColor: 'white',
    marginTop: '0px',
    marginBottom: '0px',
    marginLeft: '0px',
    marginRight: '0px'
};
const DEFAULT_DESCRIPTION = {
    strategy: DescriptionStrategy.ALWAYS_VISIBLE,
    imageText: 'Image ',
    numberSeparator: '/',
    beforeTextDescription: ' - ',
    style: DEFAULT_DESCRIPTION_STYLE
};
const DEFAULT_CAROUSEL_DESCRIPTION = {
    strategy: DescriptionStrategy.ALWAYS_HIDDEN,
    imageText: 'Image ',
    numberSeparator: '/',
    beforeTextDescription: ' - ',
    style: DEFAULT_DESCRIPTION_STYLE
};
const DEFAULT_CURRENT_IMAGE_CONFIG = {
    navigateOnClick: true,
    loadingConfig: DEFAULT_LOADING,
    description: DEFAULT_DESCRIPTION,
    downloadable: false,
    invertSwipe: false
};
const DEFAULT_CAROUSEL_IMAGE_CONFIG = {
    description: DEFAULT_CAROUSEL_DESCRIPTION,
    invertSwipe: false
};
const DEFAULT_CURRENT_CAROUSEL_CONFIG = {
    maxWidth: '100%',
    maxHeight: '400px',
    showArrows: true,
    objectFit: 'cover',
    keyboardEnable: true,
    modalGalleryEnable: false
};
const DEFAULT_CURRENT_CAROUSEL_PLAY = {
    autoPlay: true,
    interval: 5000,
    pauseOnHover: true
};
const DEFAULT_CAROUSEL_BREAKPOINTS = { xSmall: 100, small: 100, medium: 150, large: 200, xLarge: 200 };
const DEFAULT_CAROUSEL_PREVIEWS_CONFIG = {
    visible: true,
    number: 4,
    arrows: true,
    clickable: true,
    width: 100 / 4 + '%',
    maxHeight: '200px',
    breakpoints: DEFAULT_CAROUSEL_BREAKPOINTS
};
const DEFAULT_SLIDE_CONFIG = {
    infinite: false,
    playConfig: { autoPlay: false, interval: 5000, pauseOnHover: true },
    sidePreviews: { show: true, size: { width: '100px', height: 'auto' } }
};
const DEFAULT_PREVIEW_CONFIG = {
    visible: true,
    number: 3,
    arrows: true,
    clickable: true,
    size: DEFAULT_PREVIEW_SIZE
};
const DEFAULT_CONFIG = Object.freeze({
    slideConfig: DEFAULT_SLIDE_CONFIG,
    accessibilityConfig: KS_DEFAULT_ACCESSIBILITY_CONFIG,
    previewConfig: DEFAULT_PREVIEW_CONFIG,
    buttonsConfig: { visible: true, strategy: ButtonsStrategy.DEFAULT },
    dotsConfig: { visible: true },
    plainGalleryConfig: DEFAULT_PLAIN_CONFIG,
    currentImageConfig: DEFAULT_CURRENT_IMAGE_CONFIG,
    keyboardConfig: undefined, // by default nothing, because the library uses default buttons automatically
    carouselConfig: DEFAULT_CURRENT_CAROUSEL_CONFIG,
    carouselImageConfig: DEFAULT_CAROUSEL_IMAGE_CONFIG,
    carouselPreviewsConfig: DEFAULT_CAROUSEL_PREVIEWS_CONFIG,
    carouselPlayConfig: DEFAULT_CURRENT_CAROUSEL_PLAY,
    carouselDotsConfig: { visible: true },
    carouselSlideInfinite: true,
    enableCloseOutside: true
});
/**
 * Service to handle library configuration in a unique place
 */
class ConfigService {
    constructor() {
        this.configMap = new Map();
    }
    getConfig(id) {
        this.initIfNotExists(id);
        return this.configMap.get(id);
    }
    setConfig(id, obj) {
        this.initIfNotExists(id);
        if (!obj) {
            return;
        }
        if (!DEFAULT_CONFIG ||
            !DEFAULT_CONFIG.slideConfig ||
            !DEFAULT_CONFIG.slideConfig.sidePreviews ||
            !DEFAULT_CONFIG.previewConfig ||
            !DEFAULT_CONFIG.previewConfig.size ||
            !DEFAULT_CONFIG.previewConfig.number ||
            !DEFAULT_CONFIG.plainGalleryConfig ||
            !DEFAULT_CONFIG.currentImageConfig ||
            !DEFAULT_CONFIG.currentImageConfig ||
            !DEFAULT_CONFIG.currentImageConfig.description ||
            !DEFAULT_CONFIG.carouselImageConfig ||
            !DEFAULT_CONFIG.carouselImageConfig.description ||
            !DEFAULT_CONFIG.carouselPreviewsConfig ||
            !DEFAULT_CONFIG.carouselPreviewsConfig.breakpoints ||
            !DEFAULT_CAROUSEL_PREVIEWS_CONFIG.number) {
            throw new Error('Internal library error - DEFAULT_CONFIG must be fully initialized!!!');
        }
        const newConfig = Object.assign({}, this.configMap.get(id));
        if (obj.slideConfig) {
            let playConfig;
            let sidePreviews;
            let size;
            if (obj.slideConfig.playConfig) {
                playConfig = Object.assign({}, DEFAULT_CONFIG.slideConfig.playConfig, obj.slideConfig.playConfig);
            }
            else {
                playConfig = DEFAULT_CONFIG.slideConfig.playConfig;
            }
            if (obj.slideConfig.sidePreviews) {
                if (obj.slideConfig.sidePreviews.size) {
                    size = Object.assign({}, DEFAULT_CONFIG.slideConfig.sidePreviews.size, obj.slideConfig.sidePreviews.size);
                }
                else {
                    size = DEFAULT_CONFIG.slideConfig.sidePreviews.size;
                }
                sidePreviews = Object.assign({}, DEFAULT_CONFIG.slideConfig.sidePreviews, obj.slideConfig.sidePreviews);
            }
            else {
                sidePreviews = DEFAULT_CONFIG.slideConfig.sidePreviews;
                size = DEFAULT_CONFIG.slideConfig.sidePreviews.size;
            }
            const newSlideConfig = Object.assign({}, DEFAULT_CONFIG.slideConfig, obj.slideConfig);
            newSlideConfig.playConfig = playConfig;
            newSlideConfig.sidePreviews = sidePreviews;
            newSlideConfig.sidePreviews.size = size;
            newConfig.slideConfig = newSlideConfig;
        }
        if (obj.accessibilityConfig) {
            newConfig.accessibilityConfig = Object.assign({}, DEFAULT_CONFIG.accessibilityConfig, obj.accessibilityConfig);
        }
        if (obj.previewConfig) {
            let size;
            let num;
            if (obj.previewConfig.size) {
                size = Object.assign({}, DEFAULT_CONFIG.previewConfig.size, obj.previewConfig.size);
            }
            else {
                size = DEFAULT_CONFIG.previewConfig.size;
            }
            if (obj.previewConfig.number) {
                if (obj.previewConfig.number <= 0) {
                    // if number is <= 0 reset to default
                    num = DEFAULT_CONFIG.previewConfig.number;
                }
                else {
                    num = obj.previewConfig.number;
                }
            }
            else {
                num = DEFAULT_CONFIG.previewConfig.number;
            }
            const newPreviewConfig = Object.assign({}, DEFAULT_CONFIG.previewConfig, obj.previewConfig);
            newPreviewConfig.size = size;
            newPreviewConfig.number = num;
            newConfig.previewConfig = newPreviewConfig;
        }
        if (obj.buttonsConfig) {
            newConfig.buttonsConfig = Object.assign({}, DEFAULT_CONFIG.buttonsConfig, obj.buttonsConfig);
        }
        if (obj.dotsConfig) {
            newConfig.dotsConfig = Object.assign({}, DEFAULT_CONFIG.dotsConfig, obj.dotsConfig);
        }
        if (obj.plainGalleryConfig) {
            let advanced;
            let layout;
            if (obj.plainGalleryConfig.advanced) {
                advanced = Object.assign({}, DEFAULT_CONFIG.plainGalleryConfig.advanced, obj.plainGalleryConfig.advanced);
            }
            else {
                advanced = DEFAULT_CONFIG.plainGalleryConfig.advanced;
            }
            if (obj.plainGalleryConfig.layout) {
                // it isn't mandatory to use assign, because obj.plainGalleryConfig.layout is an instance of class (LineaLayout, GridLayout)
                layout = obj.plainGalleryConfig.layout;
            }
            else {
                layout = DEFAULT_CONFIG.plainGalleryConfig.layout;
            }
            const newPlainGalleryConfig = Object.assign({}, DEFAULT_CONFIG.plainGalleryConfig, obj.plainGalleryConfig);
            newPlainGalleryConfig.layout = layout;
            newPlainGalleryConfig.advanced = advanced;
            newConfig.plainGalleryConfig = initPlainGalleryConfig(newPlainGalleryConfig);
        }
        if (obj.currentImageConfig) {
            let loading;
            let description;
            let descriptionStyle;
            if (obj.currentImageConfig.loadingConfig) {
                loading = Object.assign({}, DEFAULT_CONFIG.currentImageConfig.loadingConfig, obj.currentImageConfig.loadingConfig);
            }
            else {
                loading = DEFAULT_CONFIG.currentImageConfig.loadingConfig;
            }
            if (obj.currentImageConfig.description) {
                description = Object.assign({}, DEFAULT_CONFIG.currentImageConfig.description, obj.currentImageConfig.description);
                if (obj.currentImageConfig.description.style) {
                    descriptionStyle = Object.assign({}, DEFAULT_CONFIG.currentImageConfig.description.style, obj.currentImageConfig.description.style);
                }
                else {
                    descriptionStyle = DEFAULT_CONFIG.currentImageConfig.description.style;
                }
            }
            else {
                description = DEFAULT_CONFIG.currentImageConfig.description;
                descriptionStyle = DEFAULT_CONFIG.currentImageConfig.description.style;
            }
            const newCurrentImageConfig = Object.assign({}, DEFAULT_CONFIG.currentImageConfig, obj.currentImageConfig);
            newCurrentImageConfig.loadingConfig = loading;
            newCurrentImageConfig.description = description;
            newCurrentImageConfig.description.style = descriptionStyle;
            newConfig.currentImageConfig = newCurrentImageConfig;
        }
        if (obj.keyboardConfig) {
            newConfig.keyboardConfig = Object.assign({}, DEFAULT_CONFIG.keyboardConfig, obj.keyboardConfig);
        }
        // carousel
        if (obj.carouselConfig) {
            newConfig.carouselConfig = Object.assign({}, DEFAULT_CONFIG.carouselConfig, obj.carouselConfig);
        }
        if (obj.carouselImageConfig) {
            let description;
            let descriptionStyle;
            if (obj.carouselImageConfig.description) {
                description = Object.assign({}, DEFAULT_CONFIG.carouselImageConfig.description, obj.carouselImageConfig.description);
                if (obj.carouselImageConfig.description.style) {
                    descriptionStyle = Object.assign({}, DEFAULT_CONFIG.carouselImageConfig.description.style, obj.carouselImageConfig.description.style);
                }
                else {
                    descriptionStyle = DEFAULT_CONFIG.carouselImageConfig.description.style;
                }
            }
            else {
                description = DEFAULT_CONFIG.carouselImageConfig.description;
                descriptionStyle = DEFAULT_CONFIG.carouselImageConfig.description.style;
            }
            const newCarouselImageConfig = Object.assign({}, DEFAULT_CONFIG.carouselImageConfig, obj.carouselImageConfig);
            newCarouselImageConfig.description = description;
            newCarouselImageConfig.description.style = descriptionStyle;
            newConfig.carouselImageConfig = newCarouselImageConfig;
        }
        if (obj.carouselPlayConfig) {
            // check values
            if (obj.carouselPlayConfig.interval <= 0) {
                throw new Error(`Carousel's interval must be a number >= 0`);
            }
            newConfig.carouselPlayConfig = Object.assign({}, DEFAULT_CONFIG.carouselPlayConfig, obj.carouselPlayConfig);
        }
        if (obj.carouselPreviewsConfig) {
            // check values
            let num;
            let breakpoints;
            if (!obj.carouselPreviewsConfig.number || obj.carouselPreviewsConfig.number <= 0) {
                num = DEFAULT_CAROUSEL_PREVIEWS_CONFIG.number;
            }
            else {
                num = obj.carouselPreviewsConfig.number;
            }
            if (obj.carouselPreviewsConfig.breakpoints) {
                breakpoints = Object.assign({}, DEFAULT_CONFIG.carouselPreviewsConfig.breakpoints, obj.carouselPreviewsConfig.breakpoints);
            }
            else {
                breakpoints = DEFAULT_CONFIG.carouselPreviewsConfig.breakpoints;
            }
            newConfig.carouselPreviewsConfig = Object.assign({}, DEFAULT_CONFIG.carouselPreviewsConfig, obj.carouselPreviewsConfig);
            newConfig.carouselPreviewsConfig.number = num;
            newConfig.carouselPreviewsConfig.breakpoints = breakpoints;
            // Init preview image width based on the number of previews in PreviewConfig
            // Don't move this line above, because I need to be sure that both configPreview.number
            // and configPreview.size are initialized
            newConfig.carouselPreviewsConfig.width = 100 / newConfig.carouselPreviewsConfig.number + '%';
        }
        if (obj.carouselDotsConfig) {
            newConfig.carouselDotsConfig = Object.assign({}, DEFAULT_CONFIG.carouselDotsConfig, obj.carouselDotsConfig);
        }
        if (obj.carouselSlideInfinite === undefined) {
            newConfig.carouselSlideInfinite = DEFAULT_CONFIG.carouselSlideInfinite;
        }
        else {
            newConfig.carouselSlideInfinite = obj.carouselSlideInfinite;
        }
        if (obj.enableCloseOutside === undefined) {
            newConfig.enableCloseOutside = DEFAULT_CONFIG.enableCloseOutside;
        }
        else {
            newConfig.enableCloseOutside = obj.enableCloseOutside;
        }
        this.configMap.set(id, newConfig);
    }
    initIfNotExists(id) {
        if (!this.configMap.has(id)) {
            this.configMap.set(id, DEFAULT_CONFIG);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ConfigService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ConfigService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });
/**
 * Function to build and return a `PlainGalleryConfig` object, proving also default values and validating the input object.
 * @param plainGalleryConfig object with the config requested by user
 * @returns PlainGalleryConfig the plain gallery configuration
 * @throws an Error if layout and strategy aren't compatible
 */
function initPlainGalleryConfig(plainGalleryConfig) {
    const newPlayGalleryConfig = Object.assign({}, DEFAULT_CONFIG.plainGalleryConfig, plainGalleryConfig);
    if (newPlayGalleryConfig.layout instanceof LineLayout) {
        if (newPlayGalleryConfig.strategy !== PlainGalleryStrategy.ROW && newPlayGalleryConfig.strategy !== PlainGalleryStrategy.COLUMN) {
            throw new Error('LineLayout requires either ROW or COLUMN strategy');
        }
        if (!newPlayGalleryConfig.layout || !newPlayGalleryConfig.layout.breakConfig) {
            throw new Error('Both layout and breakConfig must be valid');
        }
    }
    if (newPlayGalleryConfig.layout instanceof GridLayout) {
        if (newPlayGalleryConfig.strategy !== PlainGalleryStrategy.GRID) {
            throw new Error('GridLayout requires GRID strategy');
        }
        if (!newPlayGalleryConfig.layout || !newPlayGalleryConfig.layout.breakConfig) {
            throw new Error('Both layout and breakConfig must be valid');
        }
        // force wrap for grid layout
        newPlayGalleryConfig.layout.breakConfig.wrap = true;
    }
    return newPlayGalleryConfig;
}

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Class that represents the modal dialog instance.
 * It is returned by the open method.
 */
class ModalGalleryRef {
    constructor(overlayRef) {
        this.overlayRef = overlayRef;
        this.close = new Subject();
        this.close$ = this.close.asObservable();
        this.show = new Subject();
        this.show$ = this.show.asObservable();
        this.firstImage = new Subject();
        this.firstImage$ = this.firstImage.asObservable();
        this.lastImage = new Subject();
        this.lastImage$ = this.lastImage.asObservable();
        this.hasData = new Subject();
        this.hasData$ = this.hasData.asObservable();
        this.buttonBeforeHook = new Subject();
        this.buttonBeforeHook$ = this.buttonBeforeHook.asObservable();
        this.buttonAfterHook = new Subject();
        this.buttonAfterHook$ = this.buttonAfterHook.asObservable();
    }
    /**
     * Close modal dialog, disposing the Overlay.
     */
    closeModal() {
        this.overlayRef.dispose();
    }
    /**
     * Method to emit close event.
     * @param event ImageModalEvent event payload
     */
    emitClose(event) {
        this.close.next(event);
    }
    /**
     * Method to emit show event.
     * @param event ImageModalEvent event payload
     */
    emitShow(event) {
        this.show.next(event);
    }
    /**
     * Method to emit firstImage event.
     * @param event ImageModalEvent event payload
     */
    emitFirstImage(event) {
        this.firstImage.next(event);
    }
    /**
     * Method to emit lastImage event.
     * @param event ImageModalEvent event payload
     */
    emitLastImage(event) {
        this.lastImage.next(event);
    }
    /**
     * Method to emit hasData event.
     * @param event ImageModalEvent event payload
     */
    emitHasData(event) {
        this.hasData.next(event);
    }
    /**
     * Method to emit buttonBeforeHook event.
     * @param event ImageModalEvent event payload
     */
    emitButtonBeforeHook(event) {
        this.buttonBeforeHook.next(event);
    }
    /**
     * Method to emit buttonAfterHook event.
     * @param event ImageModalEvent event payload
     */
    emitButtonAfterHook(event) {
        this.buttonAfterHook.next(event);
    }
}

const DEFAULT_DIALOG_CONFIG = {
    hasBackdrop: true,
    backdropClass: 'ks-modal-gallery-backdrop',
    panelClass: 'ks-modal-gallery-panel'
};
class ModalGalleryService {
    constructor(overlay, configService) {
        this.overlay = overlay;
        this.configService = configService;
        this.updateImages = new Subject();
        this.updateImages$ = this.updateImages.asObservable();
        this.triggerAttachToOverlay = new EventEmitter();
    }
    /**
     * Method to open modal gallery passing the configuration
     * @param config ModalGalleryConfig that contains: id, array of images, current image and optionally the configuration object
     * @return ModalGalleryRef | undefined is the object used to listen for events.
     */
    open(config) {
        // Returns an OverlayRef which is a PortalHost
        const overlayRef = this.createOverlay();
        // Instantiate a reference to the dialog
        this.dialogRef = new ModalGalleryRef(overlayRef);
        // Attach dialog container
        this.triggerAttachToOverlay.emit({
            overlayRef,
            config,
            dialogRef: this.dialogRef
        });
        overlayRef.backdropClick().subscribe(() => {
            if (this.dialogRef) {
                this.dialogRef.closeModal();
            }
        });
        return this.dialogRef;
    }
    /**
     * Method to close a modal gallery previously opened.
     * @param id Unique identifier of the modal gallery
     * @param clickOutside boolean is true if closed clicking on the modal backdrop, false otherwise.
     */
    close(id, clickOutside) {
        const libConfig = this.configService.getConfig(id);
        if (clickOutside) {
            if (this.dialogRef && libConfig && libConfig.enableCloseOutside) {
                this.dialogRef.closeModal();
            }
        }
        else {
            if (this.dialogRef) {
                this.dialogRef.closeModal();
            }
        }
    }
    /**
     * Method to update images array.
     * @param images Image[] updated array of images
     */
    updateModalImages(images) {
        this.updateImages.next(images);
    }
    /**
     * Method to emit close event.
     * @param event ImageModalEvent is the event payload
     */
    emitClose(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitClose(event);
    }
    /**
     * Method to emit show event.
     * @param event ImageModalEvent is the event payload
     */
    emitShow(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitShow(event);
    }
    /**
     * Method to emit firstImage event.
     * @param event ImageModalEvent is the event payload
     */
    emitFirstImage(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitFirstImage(event);
    }
    /**
     * Method to emit lastImage event.
     * @param event ImageModalEvent is the event payload
     */
    emitLastImage(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitLastImage(event);
    }
    /**
     * Method to emit hasData event.
     * @param event ImageModalEvent is the event payload
     */
    emitHasData(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitHasData(event);
    }
    /**
     * Method to emit buttonBeforeHook event.
     * @param event ButtonEvent is the event payload
     */
    emitButtonBeforeHook(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitButtonBeforeHook(event);
    }
    /**
     * Method to emit buttonAfterHook event.
     * @param event ButtonEvent is the event payload
     */
    emitButtonAfterHook(event) {
        if (!this.dialogRef) {
            return;
        }
        this.dialogRef.emitButtonAfterHook(event);
    }
    /**
     * Private method to create an Overlay using Angular CDK APIs
     * @private
     */
    createOverlay() {
        const overlayConfig = this.getOverlayConfig();
        return this.overlay.create(overlayConfig);
    }
    /**
     * Private method to create an OverlayConfig instance
     * @private
     */
    getOverlayConfig() {
        const positionStrategy = this.overlay.position().global().centerHorizontally().centerVertically();
        return new OverlayConfig({
            hasBackdrop: DEFAULT_DIALOG_CONFIG.hasBackdrop,
            backdropClass: DEFAULT_DIALOG_CONFIG.backdropClass,
            panelClass: DEFAULT_DIALOG_CONFIG.panelClass,
            scrollStrategy: this.overlay.scrollStrategies.block(),
            positionStrategy
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ModalGalleryService, deps: [{ token: i1.Overlay }, { token: ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ModalGalleryService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ModalGalleryService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.Overlay }, { type: ConfigService }] });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to change the size of an element.
 */
class SizeDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an Angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an Angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to change both width and height of an element.
     */
    applyStyle() {
        if (!this.sizeConfig) {
            return;
        }
        // apply [style.width]
        if (this.sizeConfig.width) {
            this.renderer.setStyle(this.el.nativeElement, 'width', this.sizeConfig.width);
        }
        if (this.sizeConfig.height) {
            this.renderer.setStyle(this.el.nativeElement, 'height', this.sizeConfig.height);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SizeDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: SizeDirective, isStandalone: false, selector: "[ksSize]", inputs: { sizeConfig: "sizeConfig" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SizeDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksSize]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { sizeConfig: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to add fallback image if the original one is not reachable.
 */
class FallbackImageDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
        this.fallbackApplied = new EventEmitter();
    }
    onError() {
        if (!this.fallbackImg) {
            this.fallbackApplied.emit(false);
            return;
        }
        this.renderer.setAttribute(this.el.nativeElement, 'src', this.fallbackImg.toString());
        this.fallbackApplied.emit(true);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: FallbackImageDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: FallbackImageDirective, isStandalone: false, selector: "[ksFallbackImage]", inputs: { fallbackImg: "fallbackImg" }, outputs: { fallbackApplied: "fallbackApplied" }, host: { listeners: { "error": "onError()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: FallbackImageDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksFallbackImage]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { fallbackImg: [{
                type: Input
            }], fallbackApplied: [{
                type: Output
            }], onError: [{
                type: HostListener,
                args: ['error']
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Default max height of previews.
 */
const DEFAULT_MAX_HEIGHT = '200px';
/**
 * Component with image previews for carousel
 */
class CarouselPreviewsComponent extends AccessibleComponent {
    constructor(ref, breakpointObserver, 
    // sanitizer is used only to sanitize style before add it to background property when legacyIE11Mode is enabled
    sanitizer, configService) {
        super();
        this.ref = ref;
        this.breakpointObserver = breakpointObserver;
        this.sanitizer = sanitizer;
        this.configService = configService;
        /**
         * Variable to change the max-width of the host component
         */
        this.hostMaxWidth = '100%';
        /**
         * Variable to set aria-label of the host component
         */
        this.ariaLabel = `Carousel previews`;
        /**
         * Output to emit the clicked preview. The payload contains the `InternalLibImage` associated to the clicked preview.
         */
        this.clickPreview = new EventEmitter();
        /**
         * Enum of type `Action` that represents a mouse click on a button.
         * Declared here to be used inside the template.
         */
        this.clickAction = Action.CLICK;
        /**
         * Enum of type `Action` that represents a keyboard action.
         * Declared here to be used inside the template.
         */
        this.keyboardAction = Action.KEYBOARD;
        /**
         * Array of `InternalLibImage` exposed to the template. This field is initialized
         * applying transformations, default values and so on to the input of the same type.
         */
        this.previews = [];
        /**
         * Variable with the preview's maxHeight
         */
        this.previewMaxHeight = DEFAULT_MAX_HEIGHT;
        // listen for width changes and update preview heights accordingly
        this.breakpointSubscription = breakpointObserver
            .observe([Breakpoints.XSmall, Breakpoints.Small, Breakpoints.Medium, Breakpoints.Large, Breakpoints.XLarge])
            .subscribe((result) => {
            if (!this.previewConfig || !this.previewConfig.breakpoints) {
                return;
            }
            if (result.breakpoints[Breakpoints.XSmall]) {
                this.updateHeight(this.previewConfig.breakpoints.xSmall);
            }
            else if (result.breakpoints[Breakpoints.Small]) {
                this.updateHeight(this.previewConfig.breakpoints.small);
            }
            else if (result.breakpoints[Breakpoints.Medium]) {
                this.updateHeight(this.previewConfig.breakpoints.medium);
            }
            else if (result.breakpoints[Breakpoints.Large]) {
                this.updateHeight(this.previewConfig.breakpoints.large);
            }
            else if (result.breakpoints[Breakpoints.XLarge]) {
                this.updateHeight(this.previewConfig.breakpoints.xLarge);
            }
        });
    }
    /**
     * Method to update the height of previews, passing the desired height as input.
     * @param configBreakpointHeight is a number that represent the desired height to set.
     */
    updateHeight(configBreakpointHeight) {
        if (this.previewConfig && this.previewConfig.maxHeight) {
            const heightNum = +this.previewConfig.maxHeight.replace('/px/g', '').replace('/%/g', '');
            this.previewMaxHeight = Math.min(configBreakpointHeight, heightNum) + 'px';
        }
        else {
            const heightNum = +DEFAULT_MAX_HEIGHT.replace('/px/g', '').replace('/%/g', '');
            this.previewMaxHeight = Math.min(configBreakpointHeight, heightNum) + 'px';
        }
        this.ref.markForCheck();
    }
    /**
     * Method ´ngOnInit´ to build `configPreview` applying a default value and also to
     * init the `previews` array.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        this.carouselConfig = libConfig.carouselConfig;
        this.previewConfig = libConfig.carouselPreviewsConfig;
        this.accessibilityConfig = libConfig.accessibilityConfig;
        if (!this.previewConfig || !this.previewConfig.maxHeight || !this.previewConfig.breakpoints) {
            throw new Error('Internal library error - previewConfig must be defined');
        }
        // change the max-width of this component if there is a specified width !== 100% in carouselConfig
        if (this.carouselConfig && this.carouselConfig.maxWidth !== '100%') {
            this.hostMaxWidth = this.carouselConfig.maxWidth;
        }
        this.previewMaxHeight = this.previewConfig.maxHeight;
        // init previews based on currentImage and the full array of images
        this.initPreviews(this.currentImage, this.images);
        // apply custom height based on responsive breakpoints
        // This is required, because the breakpointSubscription is not triggered at creation,
        // but only when the width changes
        const isXsmallScreen = this.breakpointObserver.isMatched(Breakpoints.XSmall);
        const isSmallScreen = this.breakpointObserver.isMatched(Breakpoints.Small);
        const isMediumScreen = this.breakpointObserver.isMatched(Breakpoints.Medium);
        const isLargeScreen = this.breakpointObserver.isMatched(Breakpoints.Large);
        const isxLargeScreen = this.breakpointObserver.isMatched(Breakpoints.XLarge);
        if (isXsmallScreen) {
            this.updateHeight(this.previewConfig.breakpoints.xSmall);
        }
        else if (isSmallScreen) {
            this.updateHeight(this.previewConfig.breakpoints.small);
        }
        else if (isMediumScreen) {
            this.updateHeight(this.previewConfig.breakpoints.medium);
        }
        else if (isLargeScreen) {
            this.updateHeight(this.previewConfig.breakpoints.large);
        }
        else if (isxLargeScreen) {
            this.updateHeight(this.previewConfig.breakpoints.xLarge);
        }
    }
    /**
     * Method to check if an image is active (i.e. a preview image).
     * @param InternalLibImage preview is an image to check if it's active or not
     * @returns boolean true if is active, false otherwise
     */
    isActive(preview) {
        if (!preview || !this.currentImage) {
            return false;
        }
        return preview.id === this.currentImage.id;
    }
    /**
     * Method ´ngOnChanges´ to update `previews` array.
     * Also, both `start` and `end` local variables will be updated accordingly.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges(changes) {
        const simpleChange = changes.currentImage;
        if (!simpleChange) {
            return;
        }
        const prev = simpleChange.previousValue;
        const current = simpleChange.currentValue;
        if (current && changes.images && changes.images.previousValue && changes.images.currentValue) {
            // I'm in this if statement, if input images are changed (for instance, because I removed one of them with the 'delete button',
            // or because users changed the images array while modal gallery is still open).
            // In this case, I have to re-init previews, because the input array of images is changed.
            this.initPreviews(current, changes.images.currentValue);
        }
        if (prev && current && prev.id !== current.id) {
            // to manage infinite sliding I have to reset both `start` and `end` at the beginning
            // to show again previews from the first image.
            // This happens when you navigate over the last image to return to the first one
            let prevIndex;
            let currentIndex;
            try {
                prevIndex = getIndex(prev, this.images);
                currentIndex = getIndex(current, this.images);
            }
            catch (err) {
                console.error('Cannot get previous and current image indexes in previews');
                throw err;
            }
            // apply a formula to get a values to be used to decide if go next, return back or stay without doing anything
            const calc = Math.floor((this.end - this.start) / 2) + this.start;
            if (prevIndex === this.images.length - 1 && currentIndex === 0) {
                // first image
                this.setBeginningIndexesPreviews();
                this.previews = this.images.filter((img, i) => i >= this.start && i < this.end);
                return;
            }
            // the same for the opposite case, when you navigate back from the fist image to go to the last one.
            if (prevIndex === 0 && currentIndex === this.images.length - 1) {
                // last image
                this.setEndIndexesPreviews();
                this.previews = this.images.filter((img, i) => i >= this.start && i < this.end);
                return;
            }
            if (this.previewConfig && this.previewConfig.number % 2 === 0) {
                if (calc > currentIndex) {
                    this.previous();
                }
                else {
                    this.next();
                }
            }
            else {
                if (calc > currentIndex) {
                    this.previous();
                }
                if (calc < currentIndex) {
                    this.next();
                }
            }
        }
    }
    /**
     * Method called by events from both keyboard and mouse on a preview.
     * This will trigger the `clickpreview` output with the input preview as its payload.
     * @param InternalLibImage preview that triggered this method
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action that triggered this event (Action.NORMAL by default)
     */
    onImageEvent(preview, event, action = Action.NORMAL) {
        if (!this.previewConfig || !this.previewConfig.clickable) {
            return;
        }
        const clickedImageIndex = this.images.indexOf(preview);
        const result = super.handleImageEvent(event);
        if (result === NEXT) {
            this.clickPreview.emit({ action, result: clickedImageIndex });
        }
        else if (result === PREV) {
            this.clickPreview.emit({ action, result: clickedImageIndex });
        }
    }
    /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent | MouseEvent event payload
     */
    onNavigationEvent(direction, event) {
        const result = super.handleNavigationEvent(direction, event);
        if (result === NEXT) {
            this.next();
        }
        else if (result === PREV) {
            this.previous();
        }
    }
    /**
     * Method to get aria-label text for a preview image.
     * @param Image is the preview
     */
    getAriaLabel(preview) {
        if (!preview.plain) {
            return preview.modal.ariaLabel || '';
        }
        return preview.plain.ariaLabel || preview.modal.ariaLabel || '';
    }
    /**
     * Method to get title text for a preview image.
     * @param Image is the preview
     */
    getTitle(preview) {
        if (!preview.plain) {
            return preview.modal.title || '';
        }
        return preview.plain.title || preview.modal.title || '';
    }
    /**
     * Method to get alt text for a preview image.
     * @param Image is the preview
     */
    getAlt(preview) {
        if (!preview.plain) {
            return preview.modal.alt || '';
        }
        return preview.plain.alt || preview.modal.alt || '';
    }
    /**
     * Method used in the template to track ids in ngFor.
     * @param number index of the array
     * @param Image item of the array
     * @returns number the id of the item
     */
    trackById(index, item) {
        return item.id;
    }
    /**
     * Method used in template to sanitize an url when you need legacyIE11Mode.
     * In this way you can set an url as background of a div.
     * @param unsafeStyle is a string or a SafeResourceUrl that represents the url to sanitize.
     * @param unsafeStyleFallback is a string or a SafeResourceUrl that represents the fallback url to sanitize.
     * @returns a SafeStyle object that can be used in template without problems.
     */
    sanitizeUrlBgStyle(unsafeStyle, unsafeStyleFallback) {
        // Method used only to sanitize background-image style before add it to background property when legacyIE11Mode is enabled
        let bg = 'url(' + unsafeStyle + ')';
        if (!!unsafeStyleFallback) {
            // if a fallback image is defined, append it. In this way, it will be used by the browser as fallback.
            bg += ', ' + 'url(' + unsafeStyleFallback + ')';
        }
        return this.sanitizer.bypassSecurityTrustStyle(bg);
    }
    /**
     * Method to cleanup resources. In fact, it cleans breakpointSubscription.
     * This is an angular lifecycle hook that is called when this component is destroyed.
     */
    ngOnDestroy() {
        if (this.breakpointSubscription) {
            this.breakpointSubscription.unsubscribe();
        }
    }
    /**
     * Private method to init previews based on the currentImage and the full array of images.
     * The current image in mandatory to show always the current preview (as highlighted).
     * @param InternalLibImage currentImage to decide how to show previews, because I always want to see the current image as highlighted
     * @param InternalLibImage[] images is the array of all images.
     */
    initPreviews(currentImage, images) {
        let index;
        try {
            index = getIndex(currentImage, images);
        }
        catch (err) {
            throw err;
        }
        switch (index) {
            case 0:
                // first image
                this.setBeginningIndexesPreviews();
                break;
            case images.length - 1:
                // last image
                this.setEndIndexesPreviews();
                break;
            // default:
            //   // other images
            //   // TODO unused because it starts always at image 0
            //   this.setIndexesPreviews();
            //   break;
        }
        this.previews = images.filter((img, i) => i >= this.start && i < this.end);
    }
    /**
     * Private method to init both `start` and `end` to the beginning.
     */
    setBeginningIndexesPreviews() {
        if (!this.previewConfig || this.previewConfig.number === undefined) {
            throw new Error('Internal library error - previewConfig and number must be defined');
        }
        this.start = 0;
        this.end = Math.min(this.previewConfig.number, this.images.length);
    }
    /**
     * Private method to init both `start` and `end` to the end.
     */
    setEndIndexesPreviews() {
        if (!this.previewConfig || this.previewConfig.number === undefined) {
            throw new Error('Internal library error - previewConfig and number must be defined');
        }
        this.start = this.images.length - 1 - (this.previewConfig.number - 1);
        this.end = this.images.length;
    }
    /**
     * Private method to update the visible previews navigating to the right (next).
     */
    next() {
        // check if nextImage should be blocked
        if (this.isPreventSliding(this.images.length - 1)) {
            return;
        }
        if (this.end === this.images.length) {
            return;
        }
        this.start++;
        this.end = Math.min(this.end + 1, this.images.length);
        this.previews = this.images.filter((img, i) => i >= this.start && i < this.end);
    }
    /**
     * Private method to update the visible previews navigating to the left (previous).
     */
    previous() {
        // check if prevImage should be blocked
        if (this.isPreventSliding(0)) {
            return;
        }
        if (this.start === 0) {
            return;
        }
        this.start = Math.max(this.start - 1, 0);
        this.end = Math.min(this.end - 1, this.images.length);
        this.previews = this.images.filter((img, i) => i >= this.start && i < this.end);
    }
    /**
     * Private method to block/permit sliding between previews.
     * @param number boundaryIndex is the first or the last index of `images` input array
     * @returns boolean if true block sliding, otherwise not
     */
    isPreventSliding(boundaryIndex) {
        return getIndex(this.currentImage, this.images) === boundaryIndex;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CarouselPreviewsComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$1.BreakpointObserver }, { token: i2.DomSanitizer }, { token: ConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: CarouselPreviewsComponent, isStandalone: false, selector: "ks-carousel-previews", inputs: { id: "id", currentImage: "currentImage", images: "images" }, outputs: { clickPreview: "clickPreview" }, host: { properties: { "style.max-width": "this.hostMaxWidth", "attr.aria-label": "this.ariaLabel" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<nav *ngIf=\"previewConfig?.visible\"\n     class=\"previews-container\"\n     [attr.aria-label]=\"accessibilityConfig?.carouselPreviewsContainerAriaLabel\"\n     [title]=\"accessibilityConfig?.carouselPreviewsContainerTitle\">\n\n  <a class=\"nav-left\"\n     [attr.aria-label]=\"accessibilityConfig?.carouselPreviewScrollPrevAriaLabel\"\n     [tabIndex]=\"previewConfig?.arrows && start > 0 ? 0 : -1\" role=\"button\"\n     (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n    <div class=\"inside {{previewConfig?.arrows && start > 0 ? 'left-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n         aria-hidden=\"true\"\n         [title]=\"accessibilityConfig?.carouselPreviewScrollPrevTitle\"></div>\n  </a>\n\n  <div class=\"preview-inner-container\">\n    <ng-container *ngFor=\"let preview of previews; trackBy: trackById; let index = index\">\n      <img *ngIf=\"preview?.modal?.img\"\n           [loading]=\"preview.loading\"\n           [attr.fetchpriority]=\"preview.fetchpriority\"\n           class=\"inside preview-image{{isActive(preview) ? ' active' : ''}}{{!previewConfig?.clickable ? ' unclickable' : ''}}\"\n           [src]=\"preview.plain?.img ? preview.plain?.img : preview.modal.img\"\n           ksFallbackImage [fallbackImg]=\"preview.plain?.fallbackImg ? preview.plain?.fallbackImg : preview.modal.fallbackImg\"\n           ksSize [sizeConfig]=\"{width: previewConfig?.width!,\n                                 height: previewMaxHeight}\"\n           [attr.aria-label]=\"getAriaLabel(preview)\"\n           [title]=\"getTitle(preview)\"\n           alt=\"{{getAlt(preview)}}\"\n           [tabIndex]=\"0\" role=\"img\"\n           (click)=\"onImageEvent(preview, $event, clickAction)\" (keyup)=\"onImageEvent(preview, $event, keyboardAction)\"/>\n    </ng-container>\n  </div>\n\n  <a class=\"nav-right\"\n     [attr.aria-label]=\"accessibilityConfig?.carouselPreviewScrollNextAriaLabel\"\n     [tabIndex]=\"previewConfig?.arrows && end < images.length ? 0 : -1\" role=\"button\"\n     (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n    <div class=\"inside {{previewConfig?.arrows && end < images.length ? 'right-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n         aria-hidden=\"true\"\n         [title]=\"accessibilityConfig?.carouselPreviewScrollNextTitle\"></div>\n  </a>\n\n</nav>\n", styles: [":host{position:relative;margin-top:3px;margin-bottom:3px;width:100%}.previews-container{align-items:center;animation:fadein-semi-visible08 .8s;display:flex;flex-direction:row;justify-content:center;margin-bottom:0}.previews-container>.preview-inner-container{display:flex;flex-direction:row;justify-content:center;align-items:center;flex-wrap:nowrap;width:100%}.previews-container>.preview-inner-container>.preview-image{cursor:pointer;object-fit:cover}.previews-container>.preview-inner-container>.preview-image.unclickable{cursor:not-allowed}.previews-container .nav,.previews-container>.nav-right,.previews-container>.nav-left{position:absolute;top:calc(50% - 7px);color:#919191;z-index:1000;cursor:pointer;transition:all .5s}.previews-container .nav:hover,.previews-container>.nav-right:hover,.previews-container>.nav-left:hover{transform:scale(1.1)}.previews-container>.nav-left{margin-right:10px;left:10px}.previews-container>.nav-left>.left-arrow-preview-image{opacity:1}.previews-container>.nav-right{margin-left:10px;right:10px}.previews-container>.nav-right>.right-arrow-preview-image{opacity:1}\n", ".arrow-preview-image,.right-arrow-preview-image,.left-arrow-preview-image,.empty-arrow-preview-image{width:15px;height:15px;opacity:.5}.empty-arrow-preview-image{background:#000;opacity:0}.left-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.left-arrow-preview-image:hover{transform:scale(1.2)}.right-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.right-arrow-preview-image:hover{transform:scale(1.2)}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }, { kind: "directive", type: FallbackImageDirective, selector: "[ksFallbackImage]", inputs: ["fallbackImg"], outputs: ["fallbackApplied"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CarouselPreviewsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-carousel-previews', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<nav *ngIf=\"previewConfig?.visible\"\n     class=\"previews-container\"\n     [attr.aria-label]=\"accessibilityConfig?.carouselPreviewsContainerAriaLabel\"\n     [title]=\"accessibilityConfig?.carouselPreviewsContainerTitle\">\n\n  <a class=\"nav-left\"\n     [attr.aria-label]=\"accessibilityConfig?.carouselPreviewScrollPrevAriaLabel\"\n     [tabIndex]=\"previewConfig?.arrows && start > 0 ? 0 : -1\" role=\"button\"\n     (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n    <div class=\"inside {{previewConfig?.arrows && start > 0 ? 'left-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n         aria-hidden=\"true\"\n         [title]=\"accessibilityConfig?.carouselPreviewScrollPrevTitle\"></div>\n  </a>\n\n  <div class=\"preview-inner-container\">\n    <ng-container *ngFor=\"let preview of previews; trackBy: trackById; let index = index\">\n      <img *ngIf=\"preview?.modal?.img\"\n           [loading]=\"preview.loading\"\n           [attr.fetchpriority]=\"preview.fetchpriority\"\n           class=\"inside preview-image{{isActive(preview) ? ' active' : ''}}{{!previewConfig?.clickable ? ' unclickable' : ''}}\"\n           [src]=\"preview.plain?.img ? preview.plain?.img : preview.modal.img\"\n           ksFallbackImage [fallbackImg]=\"preview.plain?.fallbackImg ? preview.plain?.fallbackImg : preview.modal.fallbackImg\"\n           ksSize [sizeConfig]=\"{width: previewConfig?.width!,\n                                 height: previewMaxHeight}\"\n           [attr.aria-label]=\"getAriaLabel(preview)\"\n           [title]=\"getTitle(preview)\"\n           alt=\"{{getAlt(preview)}}\"\n           [tabIndex]=\"0\" role=\"img\"\n           (click)=\"onImageEvent(preview, $event, clickAction)\" (keyup)=\"onImageEvent(preview, $event, keyboardAction)\"/>\n    </ng-container>\n  </div>\n\n  <a class=\"nav-right\"\n     [attr.aria-label]=\"accessibilityConfig?.carouselPreviewScrollNextAriaLabel\"\n     [tabIndex]=\"previewConfig?.arrows && end < images.length ? 0 : -1\" role=\"button\"\n     (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n    <div class=\"inside {{previewConfig?.arrows && end < images.length ? 'right-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n         aria-hidden=\"true\"\n         [title]=\"accessibilityConfig?.carouselPreviewScrollNextTitle\"></div>\n  </a>\n\n</nav>\n", styles: [":host{position:relative;margin-top:3px;margin-bottom:3px;width:100%}.previews-container{align-items:center;animation:fadein-semi-visible08 .8s;display:flex;flex-direction:row;justify-content:center;margin-bottom:0}.previews-container>.preview-inner-container{display:flex;flex-direction:row;justify-content:center;align-items:center;flex-wrap:nowrap;width:100%}.previews-container>.preview-inner-container>.preview-image{cursor:pointer;object-fit:cover}.previews-container>.preview-inner-container>.preview-image.unclickable{cursor:not-allowed}.previews-container .nav,.previews-container>.nav-right,.previews-container>.nav-left{position:absolute;top:calc(50% - 7px);color:#919191;z-index:1000;cursor:pointer;transition:all .5s}.previews-container .nav:hover,.previews-container>.nav-right:hover,.previews-container>.nav-left:hover{transform:scale(1.1)}.previews-container>.nav-left{margin-right:10px;left:10px}.previews-container>.nav-left>.left-arrow-preview-image{opacity:1}.previews-container>.nav-right{margin-left:10px;right:10px}.previews-container>.nav-right>.right-arrow-preview-image{opacity:1}\n", ".arrow-preview-image,.right-arrow-preview-image,.left-arrow-preview-image,.empty-arrow-preview-image{width:15px;height:15px;opacity:.5}.empty-arrow-preview-image{background:#000;opacity:0}.left-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.left-arrow-preview-image:hover{transform:scale(1.2)}.right-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.right-arrow-preview-image:hover{transform:scale(1.2)}\n"] }]
        }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$1.BreakpointObserver }, { type: i2.DomSanitizer }, { type: ConfigService }], propDecorators: { hostMaxWidth: [{
                type: HostBinding,
                args: ['style.max-width']
            }], ariaLabel: [{
                type: HostBinding,
                args: ['attr.aria-label']
            }], id: [{
                type: Input
            }], currentImage: [{
                type: Input
            }], images: [{
                type: Input
            }], clickPreview: [{
                type: Output
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Component with clickable dots (small circles) to navigate between images inside the modal gallery.
 */
class DotsComponent extends AccessibleComponent {
    constructor(configService) {
        super();
        this.configService = configService;
        /**
         * Output to emit clicks on dots. The payload contains a number that represent
         * the index of the clicked dot.
         */
        this.clickDot = new EventEmitter();
    }
    /**
     * Method ´ngOnInit´ to build `configDots` applying a default value.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        this.accessibilityConfig = libConfig.accessibilityConfig;
        this.configDots = Object.assign({}, this.dotsConfig);
    }
    /**
     * Method ´ngOnChanges´ to change `configDots` if the input dotsConfig is changed.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     */
    ngOnChanges(changes) {
        const dotsConfigChanges = changes.dotsConfig;
        if (dotsConfigChanges && dotsConfigChanges.currentValue !== dotsConfigChanges.previousValue) {
            this.configDots = dotsConfigChanges.currentValue;
        }
    }
    /**
     * Method to check if an image is active (i.e. the current image).
     * It checks currentImage and images to prevent errors.
     * @param number index of the image to check if it's active or not
     * @returns boolean true if is active (and input params are valid), false otherwise
     */
    isActive(index) {
        if (!this.currentImage || !this.images || this.images.length === 0) {
            return false;
        }
        let imageIndex;
        try {
            imageIndex = getIndex(this.currentImage, this.images);
        }
        catch (err) {
            console.error(`Internal error while trying to show the active 'dot'`, err);
            return false;
        }
        return index === imageIndex;
    }
    /**
     * Method called by events from keyboard and mouse.
     * @param number index of the dot
     * @param KeyboardEvent | MouseEvent event payload
     */
    onDotEvent(index, event) {
        const result = super.handleImageEvent(event);
        if (result === NEXT) {
            this.clickDot.emit(index);
        }
    }
    /**
     * Method used in the template to track ids in ngFor.
     * @param number index of the array
     * @param Image item of the array
     * @returns number the id of the item
     */
    trackById(index, item) {
        return item.id;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DotsComponent, deps: [{ token: ConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: DotsComponent, isStandalone: false, selector: "ks-dots", inputs: { id: "id", currentImage: "currentImage", images: "images", dotsConfig: "dotsConfig" }, outputs: { clickDot: "clickDot" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<nav class=\"dots-container\" [attr.aria-label]=\"accessibilityConfig?.dotsContainerAriaLabel\"\n     [title]=\"accessibilityConfig?.dotsContainerTitle\">\n  <ng-container *ngIf=\"!dotsConfig || dotsConfig?.visible\">\n    <div class=\"inside dot\"\n         *ngFor=\"let img of images; trackBy: trackById; let index = index\"\n         [ngClass]=\"{'active': isActive(index)}\"\n         [attr.aria-label]=\"accessibilityConfig?.dotAriaLabel + ' ' + (index + 1)\"\n         [tabIndex]=\"0\" role=\"navigation\"\n         (click)=\"onDotEvent(index, $event)\" (keyup)=\"onDotEvent(index, $event)\"></div>\n  </ng-container>\n</nav>\n", styles: [".dots-container{display:flex;flex-direction:row;justify-content:center;margin-bottom:30px}.dots-container>.dot{background:#fff;border-radius:5px;height:10px;margin-left:4px;margin-right:4px;width:10px;cursor:pointer;opacity:.5}.dots-container>.dot:hover{opacity:.9;transition:all .5s ease;transition-property:opacity}.dots-container>.dot.active{cursor:pointer;opacity:.9}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible09{0%{opacity:0}to{opacity:.9}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DotsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-dots', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<nav class=\"dots-container\" [attr.aria-label]=\"accessibilityConfig?.dotsContainerAriaLabel\"\n     [title]=\"accessibilityConfig?.dotsContainerTitle\">\n  <ng-container *ngIf=\"!dotsConfig || dotsConfig?.visible\">\n    <div class=\"inside dot\"\n         *ngFor=\"let img of images; trackBy: trackById; let index = index\"\n         [ngClass]=\"{'active': isActive(index)}\"\n         [attr.aria-label]=\"accessibilityConfig?.dotAriaLabel + ' ' + (index + 1)\"\n         [tabIndex]=\"0\" role=\"navigation\"\n         (click)=\"onDotEvent(index, $event)\" (keyup)=\"onDotEvent(index, $event)\"></div>\n  </ng-container>\n</nav>\n", styles: [".dots-container{display:flex;flex-direction:row;justify-content:center;margin-bottom:30px}.dots-container>.dot{background:#fff;border-radius:5px;height:10px;margin-left:4px;margin-right:4px;width:10px;cursor:pointer;opacity:.5}.dots-container>.dot:hover{opacity:.9;transition:all .5s ease;transition-property:opacity}.dots-container>.dot.active{cursor:pointer;opacity:.9}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible09{0%{opacity:0}to{opacity:.9}}\n"] }]
        }], ctorParameters: () => [{ type: ConfigService }], propDecorators: { id: [{
                type: Input
            }], currentImage: [{
                type: Input
            }], images: [{
                type: Input
            }], dotsConfig: [{
                type: Input
            }], clickDot: [{
                type: Output
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to customize the description.
 */
class DescriptionDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to change description's style.
     */
    applyStyle() {
        if (!this.description) {
            return;
        }
        if (this.description.style) {
            this.renderer.setStyle(this.el.nativeElement, 'background', this.description.style.bgColor);
            this.renderer.setStyle(this.el.nativeElement, 'color', this.description.style.textColor);
            if (this.description.style.width) {
                this.renderer.setStyle(this.el.nativeElement, 'width', this.description.style.width);
            }
            if (this.description.style.height) {
                this.renderer.setStyle(this.el.nativeElement, 'height', this.description.style.height);
            }
            if (this.description.style.position) {
                this.renderer.setStyle(this.el.nativeElement, 'position', this.description.style.position);
            }
            if (this.description.style.top) {
                this.renderer.setStyle(this.el.nativeElement, 'top', this.description.style.top);
            }
            if (this.description.style.bottom) {
                this.renderer.setStyle(this.el.nativeElement, 'bottom', this.description.style.bottom);
            }
            if (this.description.style.left) {
                this.renderer.setStyle(this.el.nativeElement, 'left', this.description.style.left);
            }
            if (this.description.style.right) {
                this.renderer.setStyle(this.el.nativeElement, 'right', this.description.style.right);
            }
            this.renderer.setStyle(this.el.nativeElement, 'margin-top', this.description.style.marginTop ? this.description.style.marginTop : '0px');
            this.renderer.setStyle(this.el.nativeElement, 'margin-bottom', this.description.style.marginBottom ? this.description.style.marginBottom : '0px');
            this.renderer.setStyle(this.el.nativeElement, 'margin-left', this.description.style.marginLeft ? this.description.style.marginLeft : '0px');
            this.renderer.setStyle(this.el.nativeElement, 'margin-right', this.description.style.marginRight ? this.description.style.marginRight : '0px');
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DescriptionDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: DescriptionDirective, isStandalone: false, selector: "[ksDescription]", inputs: { description: "description" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DescriptionDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksDescription]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { description: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to change the max size of an element.
 */
class MaxSizeDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to change both max-width and max-height of an element.
     */
    applyStyle() {
        if (!this.maxSizeConfig) {
            return;
        }
        if (this.maxSizeConfig.maxWidth) {
            this.renderer.setStyle(this.el.nativeElement, 'max-width', this.maxSizeConfig.maxWidth);
        }
        if (this.maxSizeConfig.maxHeight) {
            this.renderer.setStyle(this.el.nativeElement, 'max-height', this.maxSizeConfig.maxHeight);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MaxSizeDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: MaxSizeDirective, isStandalone: false, selector: "[ksMaxSize]", inputs: { maxSizeConfig: "maxSizeConfig" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MaxSizeDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksMaxSize]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { maxSizeConfig: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
// The idea to create a carousel with two Subjects came from ng-bootstrap
// So a big thank you to the ng-bootstrap team for the interesting implementation that I used here with some customizations.
/**
 * Component with configurable inline/plain carousel.
 */
class CarouselComponent extends AccessibleComponent {
    /**
     * Listener to stop the gallery when the mouse pointer is over the current image.
     */
    onMouseEnter() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        if (!libConfig.carouselPlayConfig || !libConfig.carouselPlayConfig.pauseOnHover) {
            return;
        }
        this.stopCarousel();
    }
    /**
     * Listener to play the gallery when the mouse pointer leave the current image.
     */
    onMouseLeave() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        if (!libConfig.carouselPlayConfig || !libConfig.carouselPlayConfig.pauseOnHover || !libConfig.carouselPlayConfig.autoPlay) {
            return;
        }
        this.playCarousel();
    }
    /**
     * Listener to navigate carousel images with keyboard (left).
     */
    onKeyDownLeft() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        if (!libConfig.carouselConfig || !libConfig.carouselConfig.keyboardEnable) {
            return;
        }
        this.prevImage();
    }
    /**
     * Listener to navigate carousel images with keyboard (right).
     */
    onKeyDownLRight() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        if (!libConfig.carouselConfig || !libConfig.carouselConfig.keyboardEnable) {
            return;
        }
        this.nextImage();
    }
    constructor(
    // tslint:disable-next-line:no-any
    platformId, ngZone, modalGalleryService, configService, ref) {
        super();
        this.platformId = platformId;
        this.ngZone = ngZone;
        this.modalGalleryService = modalGalleryService;
        this.configService = configService;
        this.ref = ref;
        /**
         * Attribute to set ariaLabel of the host component
         */
        this.ariaLabel = `Carousel`;
        /**
         * Array of `InternalLibImage` that represent the model of this library with all images,
         * thumbs and so on.
         */
        this.images = [];
        /**
         * Output to emit an event when an image is clicked.
         */
        this.clickImage = new EventEmitter();
        /**
         * Output to emit an event when current image is changed.
         */
        this.changeImage = new EventEmitter();
        /**
         * Output to emit an event when the current image is the first one.
         */
        this.firstImage = new EventEmitter();
        /**
         * Output to emit an event when the current image is the last one.
         */
        this.lastImage = new EventEmitter();
        /**
         * Enum of type `Action` that represents a mouse click on a button.
         * Declared here to be used inside the template.
         */
        this.clickAction = Action.CLICK;
        /**
         * Enum of type `Action` that represents a keyboard action.
         * Declared here to be used inside the template.
         */
        this.keyboardAction = Action.KEYBOARD;
        /**
         * Boolean that it's true when you are watching the first image (currently visible).
         * False by default
         */
        this.isFirstImage = false;
        /**
         * Boolean that it's true when you are watching the last image (currently visible).
         * False by default
         */
        this.isLastImage = false;
        /**
         * Subject to play the carousel.
         */
        this.start$ = new Subject();
        /**
         * Subject to stop the carousel.
         */
        this.stop$ = new Subject();
    }
    ngOnInit() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        if (!this.images || this.images.length === 0) {
            throw new Error('Internal library error - images array must be defined and with at least an element');
        }
        this.configService.setConfig(this.id, this.config);
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        this.currentImage = this.images[0];
        this.carouselDotsConfig = libConfig.carouselDotsConfig;
        this.accessibilityConfig = libConfig.accessibilityConfig;
        this.carouselSlideInfinite = libConfig.carouselSlideInfinite;
        this.carouselConfig = libConfig.carouselConfig;
        this.carouselImageConfig = libConfig.carouselImageConfig;
        this.manageSlideConfig();
    }
    ngOnChanges(changes) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        // this.configService.setConfig(this.id, this.config);
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        const configChange = changes.config;
        // handle changes of dotsConfig.visible
        if (configChange &&
            !configChange.firstChange &&
            (configChange.previousValue.carouselDotsConfig?.visible !== configChange.currentValue.carouselDotsConfig?.visible || (!configChange.previousValue.carouselDotsConfig && !configChange.currentValue.carouselDotsConfig))) {
            this.configService.setConfig(this.id, {
                carouselDotsConfig: configChange.currentValue?.carouselDotsConfig
            });
            this.carouselDotsConfig = configChange.currentValue?.carouselDotsConfig;
            this.ref.markForCheck();
        }
        // handle changes of carouselConfig.showArrows
        if (configChange &&
            !configChange.firstChange &&
            (configChange.previousValue.carouselConfig?.showArrows !== configChange.currentValue.carouselConfig?.showArrows || (!configChange.previousValue.carouselConfig && !configChange.currentValue.carouselConfig))) {
            this.configService.setConfig(this.id, {
                carouselConfig: configChange.currentValue?.carouselConfig
            });
            this.carouselConfig = configChange.currentValue?.carouselConfig;
            this.ref.markForCheck();
        }
        // handle changes of playConfig starting/stopping the carousel accordingly
        if (configChange &&
            !configChange.firstChange &&
            (configChange.previousValue.carouselPlayConfig?.autoPlay !== configChange.currentValue.carouselPlayConfig?.autoPlay || (!configChange.previousValue.carouselPlayConfig && !configChange.currentValue.carouselPlayConfig))) {
            this.configService.setConfig(this.id, {
                carouselPlayConfig: configChange.currentValue?.carouselPlayConfig
            });
            // this.configPlay = playConfigChange.currentValue;
            // if autoplay is enabled, and this is not the
            // first change (to prevent multiple starts at the beginning)
            if (configChange.currentValue.carouselPlayConfig?.autoPlay && !configChange.firstChange) {
                this.start$.next();
            }
            else {
                this.stopCarousel();
            }
            this.ref.markForCheck();
        }
    }
    ngAfterContentInit() {
        // interval doesn't play well with SSR and protractor,
        // so we should run it in the browser and outside Angular
        if (isPlatformBrowser(this.platformId)) {
            if (this.id === null || this.id === undefined) {
                throw new Error('Internal library error - id must be defined');
            }
            const libConfig = this.configService.getConfig(this.id);
            if (!libConfig || !libConfig.carouselPlayConfig) {
                throw new Error('Internal library error - libConfig and carouselPlayConfig must be defined');
            }
            this.ngZone.runOutsideAngular(() => {
                this.start$
                    .pipe(map(() => libConfig?.carouselPlayConfig?.interval), 
                // tslint:disable-next-line:no-any
                filter((interval) => interval > 0), switchMap(interval => timer(interval).pipe(takeUntil(this.stop$))))
                    .subscribe(() => this.ngZone.run(() => {
                    if (libConfig.carouselPlayConfig?.autoPlay) {
                        this.nextImage();
                    }
                    this.ref.markForCheck();
                }));
                this.start$.next();
            });
        }
    }
    /**
     * Method called when a dot is clicked and used to update the current image.
     * @param number index of the clicked dot
     */
    onClickDot(index) {
        this.changeCurrentImage(this.images[index], Action.NORMAL);
    }
    /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the event or `Action.NORMAL` if not provided
     */
    onNavigationEvent(direction, event, action = Action.NORMAL) {
        const result = super.handleNavigationEvent(direction, event);
        if (result === NEXT) {
            this.nextImage(action);
        }
        else if (result === PREV) {
            this.prevImage(action);
        }
    }
    /**
     * Method triggered when you click on the current image.
     * Also, if modalGalleryEnable is true, you can open the modal-gallery.
     */
    onClickCurrentImage() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.carouselConfig || !this.currentImage) {
            throw new Error('Internal library error - libConfig, carouselConfig and currentImage must be defined');
        }
        if (!libConfig.carouselConfig.modalGalleryEnable) {
            return;
        }
        const index = getIndex(this.currentImage, this.images);
        this.clickImage.emit(index);
    }
    /**
     * Method to get the image description based on input params.
     * If you provide a full description this will be the visible description, otherwise,
     * it will be built using the `Description` object, concatenating its fields.
     * @param Image image to get its description. If not provided it will be the current image
     * @returns String description of the image (or the current image if not provided)
     * @throws an Error if description isn't available
     */
    getDescriptionToDisplay(image = this.currentImage) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        const configCurrentImageCarousel = libConfig.carouselImageConfig;
        if (!configCurrentImageCarousel || !configCurrentImageCarousel.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        if (!image) {
            throw new Error('Internal library error - image must be defined');
        }
        const imageWithoutDescription = !image || !image.modal || !image.modal.description || image.modal.description === '';
        switch (configCurrentImageCarousel.description.strategy) {
            case DescriptionStrategy.HIDE_IF_EMPTY:
                return imageWithoutDescription ? '' : image.modal.description + '';
            case DescriptionStrategy.ALWAYS_HIDDEN:
                return '';
            default:
                // ----------- DescriptionStrategy.ALWAYS_VISIBLE -----------------
                return this.buildTextDescription(image, imageWithoutDescription);
        }
    }
    /**
     * Method used by SwipeDirective to support touch gestures (you can also invert the swipe direction with configCurrentImage.invertSwipe).
     * @param action String that represent the direction of the swipe action. 'swiperight' by default.
     */
    swipe(action = 'swiperight') {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.carouselImageConfig) {
            throw new Error('Internal library error - libConfig and carouselImageConfig must be defined');
        }
        const configCurrentImageCarousel = libConfig.carouselImageConfig;
        switch (action) {
            case 'swiperight':
                if (configCurrentImageCarousel.invertSwipe) {
                    this.prevImage(Action.SWIPE);
                }
                else {
                    this.nextImage(Action.SWIPE);
                }
                break;
            case 'swipeleft':
                if (configCurrentImageCarousel.invertSwipe) {
                    this.nextImage(Action.SWIPE);
                }
                else {
                    this.prevImage(Action.SWIPE);
                }
                break;
            // case this.SWIPE_ACTION.UP:
            //   break;
            // case this.SWIPE_ACTION.DOWN:
            //   break;
        }
    }
    /**
     * Method to go back to the previous image.
     * @param action Enum of type `Action` that represents the source
     *  action that moved back to the previous image. `Action.NORMAL` by default.
     */
    prevImage(action = Action.NORMAL) {
        // check if prevImage should be blocked
        if (this.isPreventSliding(0)) {
            return;
        }
        this.changeCurrentImage(this.getPrevImage(), action);
        this.manageSlideConfig();
        this.start$.next();
    }
    /**
     * Method to go back to the previous image.
     * @param action Enum of type `Action` that represents the source
     *  action that moved to the next image. `Action.NORMAL` by default.
     */
    nextImage(action = Action.NORMAL) {
        // check if nextImage should be blocked
        if (this.isPreventSliding(this.images.length - 1)) {
            return;
        }
        this.changeCurrentImage(this.getNextImage(), action);
        this.manageSlideConfig();
        this.start$.next();
    }
    /**
     * Method used in the template to track ids in ngFor.
     * @param number index of the array
     * @param Image item of the array
     * @returns number the id of the item
     */
    trackById(index, item) {
        return item.id;
    }
    /**
     * Method called when an image preview is clicked and used to update the current image.
     * @param event an ImageEvent object with the relative action and the index of the clicked preview.
     */
    onClickPreview(event) {
        const imageFound = this.images[event.result];
        if (!!imageFound) {
            this.manageSlideConfig();
            this.changeCurrentImage(imageFound, event.action);
        }
    }
    /**
     * Method to play carousel.
     */
    playCarousel() {
        this.start$.next();
    }
    /**
     * Stops the carousel from cycling through items.
     */
    stopCarousel() {
        this.stop$.next();
    }
    // TODO remove this because duplicated
    /**
     * Method to get `alt attribute`.
     * `alt` specifies an alternate text for an image, if the image cannot be displayed.
     * @param Image image to get its alt description. If not provided it will be the current image
     * @returns String alt description of the image (or the current image if not provided)
     */
    getAltDescriptionByImage(image = this.currentImage) {
        if (!image) {
            return '';
        }
        return image.modal && image.modal.description ? image.modal.description : `Image ${getIndex(image, this.images) + 1}`;
    }
    // TODO remove this because duplicated
    /**
     * Method to get the title attributes based on descriptions.
     * This is useful to prevent accessibility issues, because if DescriptionStrategy is ALWAYS_HIDDEN,
     * it prevents an empty string as title.
     * @param Image image to get its description. If not provided it will be the current image
     * @returns String title of the image based on descriptions
     * @throws an Error if description isn't available
     */
    getTitleToDisplay(image = this.currentImage) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.carouselImageConfig) {
            throw new Error('Internal library error - libConfig and carouselImageConfig must be defined');
        }
        const configCurrentImageCarousel = libConfig.carouselImageConfig;
        if (!configCurrentImageCarousel || !configCurrentImageCarousel.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        const imageWithoutDescription = !image || !image.modal || !image.modal.description || image.modal.description === '';
        const description = this.buildTextDescription(image, imageWithoutDescription);
        return description;
    }
    /**
     * Method to reset carousel (force image with index 0 to be the current image and re-init also previews)
     */
    // temporary removed because never tested
    // reset() {
    //   if (this.configPlay && this.configPlay.autoPlay) {
    //     this.stopCarousel();
    //   }
    //   this.currentImage = this.images[0];
    //   this.handleBoundaries(0);
    //   if (this.configPlay && this.configPlay.autoPlay) {
    //     this.playCarousel();
    //   }
    //   this.ref.markForCheck();
    // }
    /**
     * Method to cleanup resources. In fact, this will stop the carousel.
     * This is an angular lifecycle hook that is called when this component is destroyed.
     */
    ngOnDestroy() {
        this.stopCarousel();
    }
    /**
     * Method to change the current image, receiving the new image as input the relative action.
     * @param image an Image object that represents the new image to set as current.
     * @param action Enum of type `Action` that represents the source action that triggered the change.
     */
    changeCurrentImage(image, action) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        this.currentImage = image;
        const index = getIndex(image, this.images);
        // emit first/last event based on newIndex value
        this.emitBoundaryEvent(action, index);
        // emit current visible image index
        this.changeImage.emit(new ImageEvent(this.id, action, index + 1));
    }
    /**
     * Private method to get the next index.
     * This is necessary because at the end, when you call next again, you'll go to the first image.
     * That happens because all modal images are shown like in a circle.
     */
    getNextImage() {
        if (!this.currentImage) {
            throw new Error('Internal library error - currentImage must be defined');
        }
        const currentIndex = getIndex(this.currentImage, this.images);
        let newIndex = 0;
        if (currentIndex >= 0 && currentIndex < this.images.length - 1) {
            newIndex = currentIndex + 1;
        }
        else {
            newIndex = 0; // start from the first index
        }
        return this.images[newIndex];
    }
    /**
     * Private method to get the previous index.
     * This is necessary because at index 0, when you call prev again, you'll go to the last image.
     * That happens because all modal images are shown like in a circle.
     */
    getPrevImage() {
        if (!this.currentImage) {
            throw new Error('Internal library error - currentImage must be defined');
        }
        const currentIndex = getIndex(this.currentImage, this.images);
        let newIndex = 0;
        if (currentIndex > 0 && currentIndex <= this.images.length - 1) {
            newIndex = currentIndex - 1;
        }
        else {
            newIndex = this.images.length - 1; // start from the last index
        }
        return this.images[newIndex];
    }
    /**
     * Private method to build a text description.
     * This is used also to create titles.
     * @param Image image to get its description. If not provided it will be the current image.
     * @param boolean imageWithoutDescription is a boolean that it's true if the image hasn't a 'modal' description.
     * @returns String description built concatenating image fields with a specific logic.
     */
    buildTextDescription(image, imageWithoutDescription) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.carouselImageConfig) {
            throw new Error('Internal library error - libConfig and carouselImageConfig must be defined');
        }
        const configCurrentImageCarousel = libConfig.carouselImageConfig;
        if (!configCurrentImageCarousel || !configCurrentImageCarousel.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        if (!image) {
            throw new Error('Internal library error - image must be defined');
        }
        // If customFullDescription use it, otherwise proceed to build a description
        if (configCurrentImageCarousel.description.customFullDescription && configCurrentImageCarousel.description.customFullDescription !== '') {
            return configCurrentImageCarousel.description.customFullDescription;
        }
        const currentIndex = getIndex(image, this.images);
        // If the current image hasn't a description,
        // prevent to write the ' - ' (or this.description.beforeTextDescription)
        const prevDescription = configCurrentImageCarousel.description.imageText ? configCurrentImageCarousel.description.imageText : '';
        const midSeparator = configCurrentImageCarousel.description.numberSeparator ? configCurrentImageCarousel.description.numberSeparator : '';
        const middleDescription = currentIndex + 1 + midSeparator + this.images.length;
        if (imageWithoutDescription) {
            return prevDescription + middleDescription;
        }
        const currImgDescription = image.modal && image.modal.description ? image.modal.description : '';
        const endDescription = configCurrentImageCarousel.description.beforeTextDescription + currImgDescription;
        return prevDescription + middleDescription + endDescription;
    }
    /**
     * Private method to update both `isFirstImage` and `isLastImage` based on
     * the index of the current image.
     * @param number currentIndex is the index of the current image
     */
    handleBoundaries(currentIndex) {
        if (this.images.length === 1) {
            this.isFirstImage = true;
            this.isLastImage = true;
            return;
        }
        switch (currentIndex) {
            case 0:
                // execute this only if infinite sliding is disabled
                this.isFirstImage = true;
                this.isLastImage = false;
                break;
            case this.images.length - 1:
                // execute this only if infinite sliding is disabled
                this.isFirstImage = false;
                this.isLastImage = true;
                break;
            default:
                this.isFirstImage = false;
                this.isLastImage = false;
                break;
        }
    }
    /**
     * Private method to manage boundary arrows and sliding.
     * This is based on the slideConfig input to enable/disable 'infinite sliding'.
     * @param number index of the visible image
     */
    manageSlideConfig() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        if (!this.currentImage) {
            throw new Error('Internal library error - currentImage must be defined');
        }
        let index;
        try {
            index = getIndex(this.currentImage, this.images);
        }
        catch (err) {
            console.error('Cannot get the current image index in current-image');
            throw err;
        }
        if (libConfig.carouselSlideInfinite === true) {
            // enable infinite sliding
            this.isFirstImage = false;
            this.isLastImage = false;
        }
        else {
            this.handleBoundaries(index);
        }
    }
    /**
     * Private method to emit events when either the last or the first image are visible.
     * @param action Enum of type Action that represents the source of the event that changed the
     *  current image to the first one or the last one.
     * @param indexToCheck is the index number of the image (the first or the last one).
     */
    emitBoundaryEvent(action, indexToCheck) {
        if (this.id === null || this.id === undefined) {
            return;
        }
        // to emit first/last event
        switch (indexToCheck) {
            case 0:
                this.firstImage.emit(new ImageEvent(this.id, action, true));
                break;
            case this.images.length - 1:
                this.lastImage.emit(new ImageEvent(this.id, action, true));
                break;
        }
    }
    /**
     * Private method to check if next/prev actions should be blocked.
     * It checks if carouselSlideInfinite === false and if the image index is equals to the input parameter.
     * If yes, it returns true to say that sliding should be blocked, otherwise not.
     * @param number boundaryIndex that could be either the beginning index (0) or the last index
     *  of images (this.images.length - 1).
     * @returns boolean true if carouselSlideInfinite === false and the current index is
     *  either the first or the last one.
     */
    isPreventSliding(boundaryIndex) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        if (!this.currentImage) {
            throw new Error('Internal library error - currentImage must be defined');
        }
        return !libConfig.carouselSlideInfinite && getIndex(this.currentImage, this.images) === boundaryIndex;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CarouselComponent, deps: [{ token: PLATFORM_ID }, { token: i0.NgZone }, { token: ModalGalleryService }, { token: ConfigService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: CarouselComponent, isStandalone: false, selector: "ks-carousel", inputs: { id: "id", images: "images", config: "config" }, outputs: { clickImage: "clickImage", changeImage: "changeImage", firstImage: "firstImage", lastImage: "lastImage" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "keydown.arrowLeft": "onKeyDownLeft()", "keydown.arrowRight": "onKeyDownLRight()" }, properties: { "attr.aria-label": "this.ariaLabel" } }, providers: [ConfigService], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<main id=\"carousel-container\"\n      [attr.aria-label]=\"accessibilityConfig?.carouselContainerAriaLabel\"\n      [title]=\"accessibilityConfig?.carouselContainerTitle\"\n      ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n                               maxHeight: ''}\">\n\n\n  <!-- Workaround to support 2 ng-content in the same template in 2 ngIf (https://github.com/angular/angular/issues/22972) -->\n  <ng-template #content><ng-content></ng-content></ng-template>\n\n  <figure class=\"current-figure\" *ngIf=\"currentImage && currentImage.modal\"\n          ksSize [sizeConfig]=\"{width: carouselConfig?.maxWidth,\n                                height: ''}\">\n\n    <a class=\"nav-left\" *ngIf=\"carouselConfig?.showArrows\"\n       [attr.aria-label]=\"accessibilityConfig?.carouselPrevImageAriaLabel\"\n       [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\">\n      <div class=\"inside {{(isFirstImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.carouselPrevImageTitle\"></div>\n    </a>\n\n    <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n    <picture class=\"current-image\" ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n      maxHeight: carouselConfig?.maxHeight}\">\n      <ng-container *ngFor=\"let source of currentImage.modal?.sources\">\n        <source [media]=\"source.media\" [srcset]=\"source.srcset\">\n      </ng-container>\n      <img [id]=\"currentImage.id\"\n          [loading]=\"currentImage.loading\"\n          [attr.fetchpriority]=\"currentImage.fetchpriority\"\n          [style.object-fit]=\"carouselConfig?.objectFit\"\n          ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n                                    maxHeight: carouselConfig?.maxHeight}\"\n          [src]=\"currentImage.modal.img\"\n          ksFallbackImage [fallbackImg]=\"currentImage.modal.fallbackImg\"\n          [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n          [title]=\"(currentImage.modal.title || currentImage.modal.title === '') ? currentImage.modal.title : getTitleToDisplay()\"\n          alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n          [tabIndex]=\"0\" role=\"img\"\n          (click)=\"onClickCurrentImage()\"\n          (swipeleft)=\"swipe($event.type)\"\n          (swiperight)=\"swipe($event.type)\"/>\n    </picture>\n    <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n                class=\"description\"\n                ksDescription [description]=\"carouselImageConfig?.description\"\n                [innerHTML]=\"getDescriptionToDisplay()\"></figcaption>\n\n    <a class=\"nav-right\" *ngIf=\"carouselConfig?.showArrows\"\n       [attr.aria-label]=\"accessibilityConfig?.carouselNextImageAriaLabel\"\n       [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\">\n      <div class=\"inside {{(isLastImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.carouselNextImageTitle\"></div>\n    </a>\n\n    <div id=\"dots\">\n      <ks-dots [id]=\"id\"\n               [currentImage]=\"currentImage\"\n               [images]=\"images\"\n               [dotsConfig]=\"carouselDotsConfig\"\n               (clickDot)=\"onClickDot($event)\"></ks-dots>\n    </div>\n\n  </figure>\n\n</main>\n\n<ks-carousel-previews [id]=\"id\"\n                      [images]=\"images\"\n                      [currentImage]=\"currentImage\"\n                      (clickPreview)=\"onClickPreview($event)\"></ks-carousel-previews>\n", styles: [":host{display:flex;flex-direction:column;justify-content:flex-start;align-items:center}#carousel-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between;width:100%}#carousel-container>.current-figure{animation:fadein-visible .8s;text-align:center;margin:0;position:relative}#carousel-container>.current-figure .nav,#carousel-container>.current-figure>.nav-right,#carousel-container>.current-figure>.nav-left{animation:animatezoom 1s;cursor:pointer;transition:all .5s;top:50%;position:absolute}#carousel-container>.current-figure .nav:hover,#carousel-container>.current-figure>.nav-right:hover,#carousel-container>.current-figure>.nav-left:hover{transform:scale(1.1)}#carousel-container>.current-figure>.nav-left{left:5px}#carousel-container>.current-figure>.nav-right{right:5px}#carousel-container>.current-figure>.current-image{display:block}#carousel-container>.current-figure>.current-image>img{width:100%;height:auto;display:block}#carousel-container>.current-figure>figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}#carousel-container>.current-figure>figcaption .description{font-weight:700;text-align:center}#carousel-container>.current-figure>#dots{position:absolute;bottom:20px;width:100%}\n", ".arrow-image,.right-arrow-image,.left-arrow-image,.empty-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:#000;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.left-arrow-image:hover{transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.right-arrow-image:hover{transform:scale(1.2)}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CarouselPreviewsComponent, selector: "ks-carousel-previews", inputs: ["id", "currentImage", "images"], outputs: ["clickPreview"] }, { kind: "component", type: DotsComponent, selector: "ks-dots", inputs: ["id", "currentImage", "images", "dotsConfig"], outputs: ["clickDot"] }, { kind: "directive", type: SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }, { kind: "directive", type: DescriptionDirective, selector: "[ksDescription]", inputs: ["description"] }, { kind: "directive", type: MaxSizeDirective, selector: "[ksMaxSize]", inputs: ["maxSizeConfig"] }, { kind: "directive", type: FallbackImageDirective, selector: "[ksFallbackImage]", inputs: ["fallbackImg"], outputs: ["fallbackApplied"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CarouselComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-carousel', changeDetection: ChangeDetectionStrategy.OnPush, providers: [ConfigService], standalone: false, template: "<main id=\"carousel-container\"\n      [attr.aria-label]=\"accessibilityConfig?.carouselContainerAriaLabel\"\n      [title]=\"accessibilityConfig?.carouselContainerTitle\"\n      ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n                               maxHeight: ''}\">\n\n\n  <!-- Workaround to support 2 ng-content in the same template in 2 ngIf (https://github.com/angular/angular/issues/22972) -->\n  <ng-template #content><ng-content></ng-content></ng-template>\n\n  <figure class=\"current-figure\" *ngIf=\"currentImage && currentImage.modal\"\n          ksSize [sizeConfig]=\"{width: carouselConfig?.maxWidth,\n                                height: ''}\">\n\n    <a class=\"nav-left\" *ngIf=\"carouselConfig?.showArrows\"\n       [attr.aria-label]=\"accessibilityConfig?.carouselPrevImageAriaLabel\"\n       [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\">\n      <div class=\"inside {{(isFirstImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.carouselPrevImageTitle\"></div>\n    </a>\n\n    <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n    <picture class=\"current-image\" ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n      maxHeight: carouselConfig?.maxHeight}\">\n      <ng-container *ngFor=\"let source of currentImage.modal?.sources\">\n        <source [media]=\"source.media\" [srcset]=\"source.srcset\">\n      </ng-container>\n      <img [id]=\"currentImage.id\"\n          [loading]=\"currentImage.loading\"\n          [attr.fetchpriority]=\"currentImage.fetchpriority\"\n          [style.object-fit]=\"carouselConfig?.objectFit\"\n          ksMaxSize [maxSizeConfig]=\"{maxWidth: carouselConfig?.maxWidth,\n                                    maxHeight: carouselConfig?.maxHeight}\"\n          [src]=\"currentImage.modal.img\"\n          ksFallbackImage [fallbackImg]=\"currentImage.modal.fallbackImg\"\n          [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n          [title]=\"(currentImage.modal.title || currentImage.modal.title === '') ? currentImage.modal.title : getTitleToDisplay()\"\n          alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n          [tabIndex]=\"0\" role=\"img\"\n          (click)=\"onClickCurrentImage()\"\n          (swipeleft)=\"swipe($event.type)\"\n          (swiperight)=\"swipe($event.type)\"/>\n    </picture>\n    <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n                class=\"description\"\n                ksDescription [description]=\"carouselImageConfig?.description\"\n                [innerHTML]=\"getDescriptionToDisplay()\"></figcaption>\n\n    <a class=\"nav-right\" *ngIf=\"carouselConfig?.showArrows\"\n       [attr.aria-label]=\"accessibilityConfig?.carouselNextImageAriaLabel\"\n       [tabIndex]=\"isLastImage && !carouselSlideInfinite ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\">\n      <div class=\"inside {{(isLastImage && !carouselSlideInfinite) || !carouselConfig.showArrows ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.carouselNextImageTitle\"></div>\n    </a>\n\n    <div id=\"dots\">\n      <ks-dots [id]=\"id\"\n               [currentImage]=\"currentImage\"\n               [images]=\"images\"\n               [dotsConfig]=\"carouselDotsConfig\"\n               (clickDot)=\"onClickDot($event)\"></ks-dots>\n    </div>\n\n  </figure>\n\n</main>\n\n<ks-carousel-previews [id]=\"id\"\n                      [images]=\"images\"\n                      [currentImage]=\"currentImage\"\n                      (clickPreview)=\"onClickPreview($event)\"></ks-carousel-previews>\n", styles: [":host{display:flex;flex-direction:column;justify-content:flex-start;align-items:center}#carousel-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between;width:100%}#carousel-container>.current-figure{animation:fadein-visible .8s;text-align:center;margin:0;position:relative}#carousel-container>.current-figure .nav,#carousel-container>.current-figure>.nav-right,#carousel-container>.current-figure>.nav-left{animation:animatezoom 1s;cursor:pointer;transition:all .5s;top:50%;position:absolute}#carousel-container>.current-figure .nav:hover,#carousel-container>.current-figure>.nav-right:hover,#carousel-container>.current-figure>.nav-left:hover{transform:scale(1.1)}#carousel-container>.current-figure>.nav-left{left:5px}#carousel-container>.current-figure>.nav-right{right:5px}#carousel-container>.current-figure>.current-image{display:block}#carousel-container>.current-figure>.current-image>img{width:100%;height:auto;display:block}#carousel-container>.current-figure>figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}#carousel-container>.current-figure>figcaption .description{font-weight:700;text-align:center}#carousel-container>.current-figure>#dots{position:absolute;bottom:20px;width:100%}\n", ".arrow-image,.right-arrow-image,.left-arrow-image,.empty-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:#000;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.left-arrow-image:hover{transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.right-arrow-image:hover{transform:scale(1.2)}\n"] }]
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [PLATFORM_ID]
                }] }, { type: i0.NgZone }, { type: ModalGalleryService }, { type: ConfigService }, { type: i0.ChangeDetectorRef }], propDecorators: { ariaLabel: [{
                type: HostBinding,
                args: ['attr.aria-label']
            }], id: [{
                type: Input
            }], images: [{
                type: Input
            }], config: [{
                type: Input
            }], clickImage: [{
                type: Output
            }], changeImage: [{
                type: Output
            }], firstImage: [{
                type: Output
            }], lastImage: [{
                type: Output
            }], onMouseEnter: [{
                type: HostListener,
                args: ['mouseenter']
            }], onMouseLeave: [{
                type: HostListener,
                args: ['mouseleave']
            }], onKeyDownLeft: [{
                type: HostListener,
                args: ['keydown.arrowLeft']
            }], onKeyDownLRight: [{
                type: HostListener,
                args: ['keydown.arrowRight']
            }] } });

/**
 * Default button size object
 */
const KS_DEFAULT_SIZE = { height: 'auto', width: '30px' };
/**
 * Default close button object
 */
const KS_DEFAULT_BTN_CLOSE = {
    className: 'close-image',
    size: KS_DEFAULT_SIZE,
    type: ButtonType.CLOSE,
    title: 'Close this modal image gallery',
    ariaLabel: 'Close this modal image gallery'
};
/**
 * Default download button object
 */
const KS_DEFAULT_BTN_DOWNLOAD = {
    className: 'download-image',
    size: KS_DEFAULT_SIZE,
    type: ButtonType.DOWNLOAD,
    title: 'Download the current image',
    ariaLabel: 'Download the current image'
};
/**
 * Default exturl button object
 */
const KS_DEFAULT_BTN_EXTURL = {
    className: 'ext-url-image',
    size: KS_DEFAULT_SIZE,
    type: ButtonType.EXTURL,
    title: 'Navigate the current image',
    ariaLabel: 'Navigate the current image'
};
// /**
//  * Default refresh button object
//  */
// export const KS_DEFAULT_BTN_REFRESH: ButtonConfig = {
//   className: 'refresh-image',
//   size: KS_DEFAULT_SIZE,
//   type: ButtonType.REFRESH,
//   title: 'Refresh all images',
//   ariaLabel: 'Refresh all images'
// };
/**
 * Default delete button object
 */
const KS_DEFAULT_BTN_DELETE = {
    className: 'delete-image',
    size: KS_DEFAULT_SIZE,
    type: ButtonType.DELETE,
    title: 'Delete the current image',
    ariaLabel: 'Delete the current image'
};
/**
 * Default full-screen button object
 */
const KS_DEFAULT_BTN_FULL_SCREEN = {
    className: 'fullscreen-image',
    size: KS_DEFAULT_SIZE,
    type: ButtonType.FULLSCREEN,
    title: 'Switch to full-screen',
    ariaLabel: 'Switch to full-screen'
};
/**
 * Default rotate button object
 */
// export const KS_DEFAULT_BTN_ROTATE: ButtonConfig = {
//   className: 'rotate-image',
//   size: KS_DEFAULT_SIZE,
//   type: ButtonType.ROTATE,
//   title: 'Rotate clockwise of 90 degrees the current image',
//   ariaLabel: 'Rotate clockwise of 90 degrees the current image'
// };

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Component with all upper buttons.
 * Also it emits click events as outputs.
 */
class UpperButtonsComponent extends AccessibleComponent {
    constructor(configService) {
        super();
        this.configService = configService;
        /**
         * Output to emit clicks on refresh button. The payload contains a `ButtonEvent`.
         */
        this.refresh = new EventEmitter();
        /**
         * Output to emit clicks on delete button. The payload contains a `ButtonEvent`.
         */
        this.delete = new EventEmitter();
        /**
         * Output to emit clicks on navigate button. The payload contains a `ButtonEvent`.
         */
        this.navigate = new EventEmitter();
        /**
         * Output to emit clicks on download button. The payload contains a `ButtonEvent`.
         */
        this.download = new EventEmitter();
        /**
         * Output to emit clicks on close button. The payload contains a `ButtonEvent`.
         */
        this.closeButton = new EventEmitter();
        /**
         * Output to emit clicks on full-screen button. The payload contains a `ButtonEvent`.
         */
        this.fullscreen = new EventEmitter();
        /**
         * Output to emit clicks on all custom buttons. The payload contains a `ButtonEvent`.
         */
        this.customEmit = new EventEmitter();
        /**
         * Default buttons array for standard configuration
         */
        this.defaultButtonsDefault = [KS_DEFAULT_BTN_CLOSE];
        /**
         * Default buttons array for simple configuration
         */
        this.simpleButtonsDefault = [KS_DEFAULT_BTN_DOWNLOAD, ...this.defaultButtonsDefault];
        /**
         * Default buttons array for advanced configuration
         */
        this.advancedButtonsDefault = [KS_DEFAULT_BTN_EXTURL, ...this.simpleButtonsDefault];
        /**
         * Default buttons array for full configuration
         */
        this.fullButtonsDefault = [
            KS_DEFAULT_BTN_FULL_SCREEN,
            KS_DEFAULT_BTN_DELETE,
            ...this.advancedButtonsDefault
        ];
    }
    /**
     * Method ´ngOnInit´ to build `configButtons` applying a default value and also to
     * init the `buttons` array.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.buttonsConfig) {
            throw new Error('Internal library error - libConfig and buttonsConfig must be defined');
        }
        this.buttonsConfig = libConfig.buttonsConfig;
        switch (this.buttonsConfig.strategy) {
            case ButtonsStrategy.SIMPLE:
                this.buttons = this.addButtonIds(this.simpleButtonsDefault);
                break;
            case ButtonsStrategy.ADVANCED:
                this.buttons = this.addButtonIds(this.advancedButtonsDefault);
                break;
            case ButtonsStrategy.FULL:
                this.buttons = this.addButtonIds(this.fullButtonsDefault);
                break;
            case ButtonsStrategy.CUSTOM:
                this.buttons = this.addButtonIds(this.validateCustomButtons(this.buttonsConfig.buttons));
                break;
            case ButtonsStrategy.DEFAULT:
            default:
                this.buttons = this.addButtonIds(this.defaultButtonsDefault);
                break;
        }
    }
    /**
     * Method called by events from both keyboard and mouse on a button.
     * This will call a private method to trigger an output with the right payload.
     * @param InternalButtonConfig button that called this method
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the source event or `Action.CLICK` if not specified
     * @throws an error if the button type is unknown
     */
    onEvent(button, event, action = Action.CLICK) {
        if (!event) {
            return;
        }
        const dataToEmit = {
            button,
            // current image initialized as null
            // (I'll fill this value inside the parent of this component
            image: null,
            action,
            galleryId: this.id
        };
        switch (button.type) {
            case ButtonType.DELETE:
                this.triggerOnMouseAndKeyboard(this.delete, event, dataToEmit);
                break;
            case ButtonType.EXTURL:
                if (!this.currentImage || !this.currentImage.modal || !this.currentImage.modal.extUrl) {
                    return;
                }
                this.triggerOnMouseAndKeyboard(this.navigate, event, dataToEmit);
                break;
            case ButtonType.DOWNLOAD:
                this.triggerOnMouseAndKeyboard(this.download, event, dataToEmit);
                break;
            case ButtonType.CLOSE:
                this.triggerOnMouseAndKeyboard(this.closeButton, event, dataToEmit);
                break;
            case ButtonType.CUSTOM:
                this.triggerOnMouseAndKeyboard(this.customEmit, event, dataToEmit);
                break;
            case ButtonType.FULLSCREEN:
                this.triggerOnMouseAndKeyboard(this.fullscreen, event, dataToEmit);
                break;
            default:
                throw new Error(`Unknown button's type into ButtonConfig`);
        }
    }
    /**
     * Method used in the template to track ids in ngFor.
     * @param number index of the array
     * @param Image item of the array
     * @returns number the id of the item or undefined if the item is not valid
     */
    trackById(index, item) {
        return item ? item.id : undefined;
    }
    /**
     * Private method to emit an event using the specified output as an `EventEmitter`.
     * @param EventEmitter<ButtonEvent> emitter is the output to emit the `ButtonEvent`
     * @param KeyboardEvent | MouseEvent event is the source that triggered this method
     * @param ButtonEvent dataToEmit payload to emit
     */
    triggerOnMouseAndKeyboard(emitter, event, dataToEmit) {
        if (!emitter) {
            throw new Error(`UpperButtonsComponent unknown emitter in triggerOnMouseAndKeyboard`);
        }
        const result = super.handleImageEvent(event);
        if (result === NEXT) {
            emitter.emit(dataToEmit);
        }
    }
    /**
     * Private method to add ids to the array of buttons.
     * It adds ids in a reverse way, to be sure that the last button will always have id = 0.
     * This is really useful in unit testing to be sure that close button always have id = 0, download 1 and so on...
     * It's totally transparent to the user.
     * @param ButtonConfig[] buttons config array
     * @returns ButtonConfig[] the input array with incremental numeric ids
     */
    addButtonIds(buttons) {
        return buttons.map((val, i) => Object.assign(val, { id: buttons.length - 1 - i }));
    }
    /**
     * Private method to validate custom buttons received as input.
     * @param ButtonConfig[] buttons config array. [] by default.
     * @returns ButtonConfig[] the same input buttons config array
     * @throws an error is exists a button with an unknown type
     */
    validateCustomButtons(buttons = []) {
        buttons.forEach((val) => {
            const indexOfButtonType = WHITELIST_BUTTON_TYPES.findIndex((type) => type === val.type);
            if (indexOfButtonType === -1) {
                throw new Error(`Unknown ButtonType. For custom types use ButtonType.CUSTOM`);
            }
        });
        return buttons;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: UpperButtonsComponent, deps: [{ token: ConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: UpperButtonsComponent, isStandalone: false, selector: "ks-upper-buttons", inputs: { id: "id", currentImage: "currentImage" }, outputs: { refresh: "refresh", delete: "delete", navigate: "navigate", download: "download", closeButton: "closeButton", fullscreen: "fullscreen", customEmit: "customEmit" }, usesInheritance: true, ngImport: i0, template: "<header class=\"buttons-container\">\n\n  <ng-container *ngIf=\"!buttonsConfig || buttonsConfig?.visible\">\n    <a *ngFor=\"let btn of buttons; trackBy: trackById; let index = index\"\n       class=\"upper-button\"\n       ksSize [sizeConfig]=\"{width: btn.size?.width!, height: btn.size?.height!}\"\n       [ngStyle]=\"{'font-size': btn.fontSize}\"\n       [attr.aria-label]=\"btn.ariaLabel\"\n       [tabIndex]=\"0\" role=\"button\"\n       (click)=\"onEvent(btn, $event)\" (keyup)=\"onEvent(btn, $event)\">\n      <div class=\"inside {{btn.className}}\" aria-hidden=\"true\" title=\"{{btn.title}}\"></div>\n    </a>\n  </ng-container>\n</header>\n", styles: [".buttons-container{display:flex;flex-direction:row;justify-content:flex-end}.buttons-container>.upper-button{align-self:center;margin-right:30px;margin-top:28px;font-size:50px;text-decoration:none;cursor:pointer;animation:animatezoom .6s;color:#fff}@keyframes animatezoom{0%{transform:scale(0)}to{transform:scale(1)}}.base-btn,.copy,.refresh-image,.close-image,.download-image,.ext-url-image,.delete-image,.fullscreen-image,.rotate-image{width:30px;height:30px;background-size:30px;opacity:.8;transition:all .5s}.base-btn:hover,.copy:hover,.refresh-image:hover,.close-image:hover,.download-image:hover,.ext-url-image:hover,.delete-image:hover,.fullscreen-image:hover,.rotate-image:hover{transform:scale(1.2)}.rotate-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDY0IDY0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA2NCA2NDsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTMzLDJjNy43NDYsMCwxNS4wMjgsMy4wMTcsMjAuNTA1LDguNDk0YzEwLjEzOCwxMC4xMzcsMTEuMzEsMjYuMzk2LDIuNzQsMzcuODQ5TDUyLDUyLjU4OVY0NGgtMnYxMWwxLDFoMTF2LTJoLTguNTgyICAgIGw0LjI5Mi00LjI5M2wwLjA5Mi0wLjEwNmM5LjIxMS0xMi4yNDcsNy45NzItMjkuNjY3LTIuODgzLTQwLjUyMUM0OS4wNjQsMy4yMjUsNDEuMjgsMCwzMywwVjJ6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTcuNzU1LDE1LjY1N0wxMiwxMS40MTFWMjBoMlY5bC0xLTFIMnYyaDguNTgyTDYuMjksMTQuMjkzbC0wLjA5MiwwLjEwNkMtMy4wMTMsMjYuNjQ2LTEuNzczLDQ0LjA2Niw5LjA4MSw1NC45MiAgICBDMTQuOTM2LDYwLjc3NSwyMi43Miw2NCwzMSw2NHYtMmMtNy43NDYsMC0xNS4wMjgtMy4wMTctMjAuNTA1LTguNDk0QzAuMzU3LDQzLjM2OS0wLjgxNCwyNy4xMSw3Ljc1NSwxNS42NTd6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48L3N2Zz4=)}.fullscreen-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTMgNTMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUzIDUzOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNNTIuOTIzLDAuNjE4Yy0wLjEwMS0wLjI0NC0wLjI5Ni0wLjQzOS0wLjU0MS0wLjU0MUM1Mi4yNiwwLjAyNyw1Mi4xMywwLDUyLDBINDBjLTAuNTUyLDAtMSwwLjQ0OC0xLDFzMC40NDgsMSwxLDFoOS41ODYgICBMMzMuMjkzLDE4LjI5M2MtMC4zOTEsMC4zOTEtMC4zOTEsMS4wMjMsMCwxLjQxNEMzMy40ODgsMTkuOTAyLDMzLjc0NCwyMCwzNCwyMHMwLjUxMi0wLjA5OCwwLjcwNy0wLjI5M0w1MSwzLjQxNFYxMyAgIGMwLDAuNTUyLDAuNDQ4LDEsMSwxczEtMC40NDgsMS0xVjFDNTMsMC44Nyw1Mi45NzMsMC43NCw1Mi45MjMsMC42MTh6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTE4LjI5MywzMy4yOTNMMiw0OS41ODZWNDBjMC0wLjU1Mi0wLjQ0OC0xLTEtMXMtMSwwLjQ0OC0xLDF2MTJjMCwwLjEzLDAuMDI3LDAuMjYsMC4wNzcsMC4zODIgICBjMC4xMDEsMC4yNDQsMC4yOTYsMC40MzksMC41NDEsMC41NDFDMC43NCw1Mi45NzMsMC44Nyw1MywxLDUzaDEyYzAuNTUyLDAsMS0wLjQ0OCwxLTFzLTAuNDQ4LTEtMS0xSDMuNDE0bDE2LjI5My0xNi4yOTMgICBjMC4zOTEtMC4zOTEsMC4zOTEtMS4wMjMsMC0xLjQxNFMxOC42ODQsMzIuOTAyLDE4LjI5MywzMy4yOTN6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTEsMTRjMC41NTIsMCwxLTAuNDQ4LDEtMVYzLjQxNGwxNi4yOTIsMTYuMjkyYzAuMTk1LDAuMTk1LDAuNDUxLDAuMjkzLDAuNzA3LDAuMjkzczAuNTEyLTAuMDk4LDAuNzA3LTAuMjkzICAgYzAuMzkxLTAuMzkxLDAuMzkxLTEuMDIzLDAtMS40MTRMMy40MTQsMkgxM2MwLjU1MiwwLDEtMC40NDgsMS0xcy0wLjQ0OC0xLTEtMUgxQzAuODcsMCwwLjc0LDAuMDI3LDAuNjE4LDAuMDc3ICAgQzAuMzczLDAuMTc5LDAuMTc5LDAuMzczLDAuMDc3LDAuNjE4QzAuMDI3LDAuNzQsMCwwLjg3LDAsMXYxMkMwLDEzLjU1MiwwLjQ0OCwxNCwxLDE0eiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik01MiwzOWMtMC41NTIsMC0xLDAuNDQ4LTEsMXY5LjU4NkwzNC43MDcsMzMuMjkyYy0wLjM5MS0wLjM5MS0xLjAyMy0wLjM5MS0xLjQxNCwwcy0wLjM5MSwxLjAyMywwLDEuNDE0TDQ5LjU4Niw1MUg0MCAgIGMtMC41NTIsMC0xLDAuNDQ4LTEsMXMwLjQ0OCwxLDEsMWgxMmMwLjEzLDAsMC4yNi0wLjAyNywwLjM4Mi0wLjA3N2MwLjI0NC0wLjEwMSwwLjQzOS0wLjI5NiwwLjU0MS0wLjU0MSAgIEM1Mi45NzMsNTIuMjYsNTMsNTIuMTMsNTMsNTJWNDBDNTMsMzkuNDQ4LDUyLjU1MiwzOSw1MiwzOXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.delete-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ4Ni40IDQ4Ni40IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0ODYuNCA0ODYuNDsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTQ0Niw3MEgzNDQuOFY1My41YzAtMjkuNS0yNC01My41LTUzLjUtNTMuNWgtOTYuMmMtMjkuNSwwLTUzLjUsMjQtNTMuNSw1My41VjcwSDQwLjRjLTcuNSwwLTEzLjUsNi0xMy41LDEzLjUgICAgUzMyLjksOTcsNDAuNCw5N2gyNC40djMxNy4yYzAsMzkuOCwzMi40LDcyLjIsNzIuMiw3Mi4yaDIxMi40YzM5LjgsMCw3Mi4yLTMyLjQsNzIuMi03Mi4yVjk3SDQ0NmM3LjUsMCwxMy41LTYsMTMuNS0xMy41ICAgIFM0NTMuNSw3MCw0NDYsNzB6IE0xNjguNiw1My41YzAtMTQuNiwxMS45LTI2LjUsMjYuNS0yNi41aDk2LjJjMTQuNiwwLDI2LjUsMTEuOSwyNi41LDI2LjVWNzBIMTY4LjZWNTMuNXogTTM5NC42LDQxNC4yICAgIGMwLDI0LjktMjAuMyw0NS4yLTQ1LjIsNDUuMkgxMzdjLTI0LjksMC00NS4yLTIwLjMtNDUuMi00NS4yVjk3aDMwMi45djMxNy4ySDM5NC42eiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0yNDMuMiw0MTFjNy41LDAsMTMuNS02LDEzLjUtMTMuNVYxNTguOWMwLTcuNS02LTEzLjUtMTMuNS0xMy41cy0xMy41LDYtMTMuNSwxMy41djIzOC41ICAgIEMyMjkuNyw0MDQuOSwyMzUuNyw0MTEsMjQzLjIsNDExeiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0xNTUuMSwzOTYuMWM3LjUsMCwxMy41LTYsMTMuNS0xMy41VjE3My43YzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MjA4LjkgICAgQzE0MS42LDM5MC4xLDE0Ny43LDM5Ni4xLDE1NS4xLDM5Ni4xeiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0zMzEuMywzOTYuMWM3LjUsMCwxMy41LTYsMTMuNS0xMy41VjE3My43YzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MjA4LjkgICAgQzMxNy44LDM5MC4xLDMyMy44LDM5Ni4xLDMzMS4zLDM5Ni4xeiIgZmlsbD0iI0ZGRkZGRiIvPjwvZz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.ext-url-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iNTEycHgiIGhlaWdodD0iNTEycHgiPjxnPjxnPjxnPjxwYXRoIGQ9Ik00ODAsMjg4djExMmMwLDQ0LjE4My0zNS44MTcsODAtODAsODBIMTEyYy00NC4xODMsMC04MC0zNS44MTctODAtODBWMTEyYzAtNDQuMTgzLDM1LjgxNy04MCw4MC04MGg5NlYwaC05NiAgICAgQzUwLjE0NCwwLDAsNTAuMTQ0LDAsMTEydjI4OGMwLDYxLjg1Niw1MC4xNDQsMTEyLDExMiwxMTJoMjg4YzYxLjg1NiwwLDExMi01MC4xNDQsMTEyLTExMlYyODhINDgweiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0xNzYsNDE2aDMyVjI4OGMwLTEyNS43NiwxMDcuNTItMTI4LDExMi0xMjhoMTA1LjQ0bC04NC42NCw4NC42NGwyMi41NiwyMi41NmwxMTItMTEyYzYuMjA0LTYuMjQxLDYuMjA0LTE2LjMxOSwwLTIyLjU2ICAgICBsLTExMi0xMTJsLTIyLjcyLDIyLjcybDg0LjgsODQuNjRIMzIwYy0xLjQ0LDAtMTQ0LDEuNzYtMTQ0LDE2MFY0MTZ6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.download-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3MS4yIDQ3MS4yIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NzEuMiA0NzEuMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTQ1Ny43LDIzMC4xNWMtNy41LDAtMTMuNSw2LTEzLjUsMTMuNXYxMjIuOGMwLDMzLjQtMjcuMiw2MC41LTYwLjUsNjAuNUg4Ny41Yy0zMy40LDAtNjAuNS0yNy4yLTYwLjUtNjAuNXYtMTI0LjggICAgYzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MTI0LjhjMCw0OC4zLDM5LjMsODcuNSw4Ny41LDg3LjVoMjk2LjJjNDguMywwLDg3LjUtMzkuMyw4Ny41LTg3LjV2LTEyMi44ICAgIEM0NzEuMiwyMzYuMjUsNDY1LjIsMjMwLjE1LDQ1Ny43LDIzMC4xNXoiIGZpbGw9IiNGRkZGRkYiLz48cGF0aCBkPSJNMjI2LjEsMzQ2Ljc1YzIuNiwyLjYsNi4xLDQsOS41LDRzNi45LTEuMyw5LjUtNGw4NS44LTg1LjhjNS4zLTUuMyw1LjMtMTMuOCwwLTE5LjFjLTUuMy01LjMtMTMuOC01LjMtMTkuMSwwbC02Mi43LDYyLjggICAgVjMwLjc1YzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MjczLjlsLTYyLjgtNjIuOGMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xICAgIEwyMjYuMSwzNDYuNzV6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48L3N2Zz4=)}.close-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3NS4yIDQ3NS4yIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NzUuMiA0NzUuMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTQwNS42LDY5LjZDMzYwLjcsMjQuNywzMDEuMSwwLDIzNy42LDBzLTEyMy4xLDI0LjctMTY4LDY5LjZTMCwxNzQuMSwwLDIzNy42czI0LjcsMTIzLjEsNjkuNiwxNjhzMTA0LjUsNjkuNiwxNjgsNjkuNiAgICBzMTIzLjEtMjQuNywxNjgtNjkuNnM2OS42LTEwNC41LDY5LjYtMTY4UzQ1MC41LDExNC41LDQwNS42LDY5LjZ6IE0zODYuNSwzODYuNWMtMzkuOCwzOS44LTkyLjcsNjEuNy0xNDguOSw2MS43ICAgIHMtMTA5LjEtMjEuOS0xNDguOS02MS43Yy04Mi4xLTgyLjEtODIuMS0yMTUuNywwLTI5Ny44QzEyOC41LDQ4LjksMTgxLjQsMjcsMjM3LjYsMjdzMTA5LjEsMjEuOSwxNDguOSw2MS43ICAgIEM0NjguNiwxNzAuOCw0NjguNiwzMDQuNCwzODYuNSwzODYuNXoiIGZpbGw9IiNGRkZGRkYiLz48cGF0aCBkPSJNMzQyLjMsMTMyLjljLTUuMy01LjMtMTMuOC01LjMtMTkuMSwwbC04NS42LDg1LjZMMTUyLDEzMi45Yy01LjMtNS4zLTEzLjgtNS4zLTE5LjEsMGMtNS4zLDUuMy01LjMsMTMuOCwwLDE5LjEgICAgbDg1LjYsODUuNmwtODUuNiw4NS42Yy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWMyLjYsMi42LDYuMSw0LDkuNSw0czYuOS0xLjMsOS41LTRsODUuNi04NS42bDg1LjYsODUuNmMyLjYsMi42LDYuMSw0LDkuNSw0ICAgIGMzLjUsMCw2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xbC04NS40LTg1LjZsODUuNi04NS42QzM0Ny42LDE0Ni43LDM0Ny42LDEzOC4yLDM0Mi4zLDEzMi45eiIgZmlsbD0iI0ZGRkZGRiIvPjwvZz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.refresh-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ4OS43MTEgNDg5LjcxMSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDg5LjcxMSA0ODkuNzExOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48Zz48cGF0aCBkPSJNMTEyLjE1Niw5Ny4xMTFjNzIuMy02NS40LDE4MC41LTY2LjQsMjUzLjgtNi43bC01OC4xLDIuMmMtNy41LDAuMy0xMy4zLDYuNS0xMywxNGMwLjMsNy4zLDYuMywxMywxMy41LDEzICAgIGMwLjIsMCwwLjMsMCwwLjUsMGw4OS4yLTMuM2M3LjMtMC4zLDEzLTYuMiwxMy0xMy41di0xYzAtMC4yLDAtMC4zLDAtMC41di0wLjFsMCwwbC0zLjMtODguMmMtMC4zLTcuNS02LjYtMTMuMy0xNC0xMyAgICBjLTcuNSwwLjMtMTMuMyw2LjUtMTMsMTRsMi4xLDU1LjNjLTM2LjMtMjkuNy04MS00Ni45LTEyOC44LTQ5LjNjLTU5LjItMy0xMTYuMSwxNy4zLTE2MCw1Ny4xYy02MC40LDU0LjctODYsMTM3LjktNjYuOCwyMTcuMSAgICBjMS41LDYuMiw3LDEwLjMsMTMuMSwxMC4zYzEuMSwwLDIuMS0wLjEsMy4yLTAuNGM3LjItMS44LDExLjctOS4xLDkuOS0xNi4zQzM2LjY1NiwyMTguMjExLDU5LjA1NiwxNDUuMTExLDExMi4xNTYsOTcuMTExeiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik00NjIuNDU2LDE5NS41MTFjLTEuOC03LjItOS4xLTExLjctMTYuMy05LjljLTcuMiwxLjgtMTEuNyw5LjEtOS45LDE2LjNjMTYuOSw2OS42LTUuNiwxNDIuNy01OC43LDE5MC43ICAgIGMtMzcuMywzMy43LTg0LjEsNTAuMy0xMzAuNyw1MC4zYy00NC41LDAtODguOS0xNS4xLTEyNC43LTQ0LjlsNTguOC01LjNjNy40LTAuNywxMi45LTcuMiwxMi4yLTE0LjdzLTcuMi0xMi45LTE0LjctMTIuMmwtODguOSw4ICAgIGMtNy40LDAuNy0xMi45LDcuMi0xMi4yLDE0LjdsOCw4OC45YzAuNiw3LDYuNSwxMi4zLDEzLjQsMTIuM2MwLjQsMCwwLjgsMCwxLjItMC4xYzcuNC0wLjcsMTIuOS03LjIsMTIuMi0xNC43bC00LjgtNTQuMSAgICBjMzYuMywyOS40LDgwLjgsNDYuNSwxMjguMyw0OC45YzMuOCwwLjIsNy42LDAuMywxMS4zLDAuM2M1NS4xLDAsMTA3LjUtMjAuMiwxNDguNy01Ny40ICAgIEM0NTYuMDU2LDM1Ny45MTEsNDgxLjY1NiwyNzQuODExLDQ2Mi40NTYsMTk1LjUxMXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvc3ZnPg==)}.copy{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ4OC4zIDQ4OC4zIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0ODguMyA0ODguMzsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTMxNC4yNSw4NS40aC0yMjdjLTIxLjMsMC0zOC42LDE3LjMtMzguNiwzOC42djMyNS43YzAsMjEuMywxNy4zLDM4LjYsMzguNiwzOC42aDIyN2MyMS4zLDAsMzguNi0xNy4zLDM4LjYtMzguNlYxMjQgICAgQzM1Mi43NSwxMDIuNywzMzUuNDUsODUuNCwzMTQuMjUsODUuNHogTTMyNS43NSw0NDkuNmMwLDYuNC01LjIsMTEuNi0xMS42LDExLjZoLTIyN2MtNi40LDAtMTEuNi01LjItMTEuNi0xMS42VjEyNCAgICBjMC02LjQsNS4yLTExLjYsMTEuNi0xMS42aDIyN2M2LjQsMCwxMS42LDUuMiwxMS42LDExLjZWNDQ5LjZ6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTQwMS4wNSwwaC0yMjdjLTIxLjMsMC0zOC42LDE3LjMtMzguNiwzOC42YzAsNy41LDYsMTMuNSwxMy41LDEzLjVzMTMuNS02LDEzLjUtMTMuNWMwLTYuNCw1LjItMTEuNiwxMS42LTExLjZoMjI3ICAgIGM2LjQsMCwxMS42LDUuMiwxMS42LDExLjZ2MzI1LjdjMCw2LjQtNS4yLDExLjYtMTEuNiwxMS42Yy03LjUsMC0xMy41LDYtMTMuNSwxMy41czYsMTMuNSwxMy41LDEzLjVjMjEuMywwLDM4LjYtMTcuMywzOC42LTM4LjYgICAgVjM4LjZDNDM5LjY1LDE3LjMsNDIyLjM1LDAsNDAxLjA1LDB6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48L3N2Zz4=)}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: UpperButtonsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-upper-buttons', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<header class=\"buttons-container\">\n\n  <ng-container *ngIf=\"!buttonsConfig || buttonsConfig?.visible\">\n    <a *ngFor=\"let btn of buttons; trackBy: trackById; let index = index\"\n       class=\"upper-button\"\n       ksSize [sizeConfig]=\"{width: btn.size?.width!, height: btn.size?.height!}\"\n       [ngStyle]=\"{'font-size': btn.fontSize}\"\n       [attr.aria-label]=\"btn.ariaLabel\"\n       [tabIndex]=\"0\" role=\"button\"\n       (click)=\"onEvent(btn, $event)\" (keyup)=\"onEvent(btn, $event)\">\n      <div class=\"inside {{btn.className}}\" aria-hidden=\"true\" title=\"{{btn.title}}\"></div>\n    </a>\n  </ng-container>\n</header>\n", styles: [".buttons-container{display:flex;flex-direction:row;justify-content:flex-end}.buttons-container>.upper-button{align-self:center;margin-right:30px;margin-top:28px;font-size:50px;text-decoration:none;cursor:pointer;animation:animatezoom .6s;color:#fff}@keyframes animatezoom{0%{transform:scale(0)}to{transform:scale(1)}}.base-btn,.copy,.refresh-image,.close-image,.download-image,.ext-url-image,.delete-image,.fullscreen-image,.rotate-image{width:30px;height:30px;background-size:30px;opacity:.8;transition:all .5s}.base-btn:hover,.copy:hover,.refresh-image:hover,.close-image:hover,.download-image:hover,.ext-url-image:hover,.delete-image:hover,.fullscreen-image:hover,.rotate-image:hover{transform:scale(1.2)}.rotate-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDY0IDY0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA2NCA2NDsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTMzLDJjNy43NDYsMCwxNS4wMjgsMy4wMTcsMjAuNTA1LDguNDk0YzEwLjEzOCwxMC4xMzcsMTEuMzEsMjYuMzk2LDIuNzQsMzcuODQ5TDUyLDUyLjU4OVY0NGgtMnYxMWwxLDFoMTF2LTJoLTguNTgyICAgIGw0LjI5Mi00LjI5M2wwLjA5Mi0wLjEwNmM5LjIxMS0xMi4yNDcsNy45NzItMjkuNjY3LTIuODgzLTQwLjUyMUM0OS4wNjQsMy4yMjUsNDEuMjgsMCwzMywwVjJ6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTcuNzU1LDE1LjY1N0wxMiwxMS40MTFWMjBoMlY5bC0xLTFIMnYyaDguNTgyTDYuMjksMTQuMjkzbC0wLjA5MiwwLjEwNkMtMy4wMTMsMjYuNjQ2LTEuNzczLDQ0LjA2Niw5LjA4MSw1NC45MiAgICBDMTQuOTM2LDYwLjc3NSwyMi43Miw2NCwzMSw2NHYtMmMtNy43NDYsMC0xNS4wMjgtMy4wMTctMjAuNTA1LTguNDk0QzAuMzU3LDQzLjM2OS0wLjgxNCwyNy4xMSw3Ljc1NSwxNS42NTd6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48L3N2Zz4=)}.fullscreen-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTMgNTMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUzIDUzOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNNTIuOTIzLDAuNjE4Yy0wLjEwMS0wLjI0NC0wLjI5Ni0wLjQzOS0wLjU0MS0wLjU0MUM1Mi4yNiwwLjAyNyw1Mi4xMywwLDUyLDBINDBjLTAuNTUyLDAtMSwwLjQ0OC0xLDFzMC40NDgsMSwxLDFoOS41ODYgICBMMzMuMjkzLDE4LjI5M2MtMC4zOTEsMC4zOTEtMC4zOTEsMS4wMjMsMCwxLjQxNEMzMy40ODgsMTkuOTAyLDMzLjc0NCwyMCwzNCwyMHMwLjUxMi0wLjA5OCwwLjcwNy0wLjI5M0w1MSwzLjQxNFYxMyAgIGMwLDAuNTUyLDAuNDQ4LDEsMSwxczEtMC40NDgsMS0xVjFDNTMsMC44Nyw1Mi45NzMsMC43NCw1Mi45MjMsMC42MTh6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTE4LjI5MywzMy4yOTNMMiw0OS41ODZWNDBjMC0wLjU1Mi0wLjQ0OC0xLTEtMXMtMSwwLjQ0OC0xLDF2MTJjMCwwLjEzLDAuMDI3LDAuMjYsMC4wNzcsMC4zODIgICBjMC4xMDEsMC4yNDQsMC4yOTYsMC40MzksMC41NDEsMC41NDFDMC43NCw1Mi45NzMsMC44Nyw1MywxLDUzaDEyYzAuNTUyLDAsMS0wLjQ0OCwxLTFzLTAuNDQ4LTEtMS0xSDMuNDE0bDE2LjI5My0xNi4yOTMgICBjMC4zOTEtMC4zOTEsMC4zOTEtMS4wMjMsMC0xLjQxNFMxOC42ODQsMzIuOTAyLDE4LjI5MywzMy4yOTN6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTEsMTRjMC41NTIsMCwxLTAuNDQ4LDEtMVYzLjQxNGwxNi4yOTIsMTYuMjkyYzAuMTk1LDAuMTk1LDAuNDUxLDAuMjkzLDAuNzA3LDAuMjkzczAuNTEyLTAuMDk4LDAuNzA3LTAuMjkzICAgYzAuMzkxLTAuMzkxLDAuMzkxLTEuMDIzLDAtMS40MTRMMy40MTQsMkgxM2MwLjU1MiwwLDEtMC40NDgsMS0xcy0wLjQ0OC0xLTEtMUgxQzAuODcsMCwwLjc0LDAuMDI3LDAuNjE4LDAuMDc3ICAgQzAuMzczLDAuMTc5LDAuMTc5LDAuMzczLDAuMDc3LDAuNjE4QzAuMDI3LDAuNzQsMCwwLjg3LDAsMXYxMkMwLDEzLjU1MiwwLjQ0OCwxNCwxLDE0eiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik01MiwzOWMtMC41NTIsMC0xLDAuNDQ4LTEsMXY5LjU4NkwzNC43MDcsMzMuMjkyYy0wLjM5MS0wLjM5MS0xLjAyMy0wLjM5MS0xLjQxNCwwcy0wLjM5MSwxLjAyMywwLDEuNDE0TDQ5LjU4Niw1MUg0MCAgIGMtMC41NTIsMC0xLDAuNDQ4LTEsMXMwLjQ0OCwxLDEsMWgxMmMwLjEzLDAsMC4yNi0wLjAyNywwLjM4Mi0wLjA3N2MwLjI0NC0wLjEwMSwwLjQzOS0wLjI5NiwwLjU0MS0wLjU0MSAgIEM1Mi45NzMsNTIuMjYsNTMsNTIuMTMsNTMsNTJWNDBDNTMsMzkuNDQ4LDUyLjU1MiwzOSw1MiwzOXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.delete-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ4Ni40IDQ4Ni40IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0ODYuNCA0ODYuNDsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTQ0Niw3MEgzNDQuOFY1My41YzAtMjkuNS0yNC01My41LTUzLjUtNTMuNWgtOTYuMmMtMjkuNSwwLTUzLjUsMjQtNTMuNSw1My41VjcwSDQwLjRjLTcuNSwwLTEzLjUsNi0xMy41LDEzLjUgICAgUzMyLjksOTcsNDAuNCw5N2gyNC40djMxNy4yYzAsMzkuOCwzMi40LDcyLjIsNzIuMiw3Mi4yaDIxMi40YzM5LjgsMCw3Mi4yLTMyLjQsNzIuMi03Mi4yVjk3SDQ0NmM3LjUsMCwxMy41LTYsMTMuNS0xMy41ICAgIFM0NTMuNSw3MCw0NDYsNzB6IE0xNjguNiw1My41YzAtMTQuNiwxMS45LTI2LjUsMjYuNS0yNi41aDk2LjJjMTQuNiwwLDI2LjUsMTEuOSwyNi41LDI2LjVWNzBIMTY4LjZWNTMuNXogTTM5NC42LDQxNC4yICAgIGMwLDI0LjktMjAuMyw0NS4yLTQ1LjIsNDUuMkgxMzdjLTI0LjksMC00NS4yLTIwLjMtNDUuMi00NS4yVjk3aDMwMi45djMxNy4ySDM5NC42eiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0yNDMuMiw0MTFjNy41LDAsMTMuNS02LDEzLjUtMTMuNVYxNTguOWMwLTcuNS02LTEzLjUtMTMuNS0xMy41cy0xMy41LDYtMTMuNSwxMy41djIzOC41ICAgIEMyMjkuNyw0MDQuOSwyMzUuNyw0MTEsMjQzLjIsNDExeiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0xNTUuMSwzOTYuMWM3LjUsMCwxMy41LTYsMTMuNS0xMy41VjE3My43YzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MjA4LjkgICAgQzE0MS42LDM5MC4xLDE0Ny43LDM5Ni4xLDE1NS4xLDM5Ni4xeiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0zMzEuMywzOTYuMWM3LjUsMCwxMy41LTYsMTMuNS0xMy41VjE3My43YzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MjA4LjkgICAgQzMxNy44LDM5MC4xLDMyMy44LDM5Ni4xLDMzMS4zLDM5Ni4xeiIgZmlsbD0iI0ZGRkZGRiIvPjwvZz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.ext-url-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIiB3aWR0aD0iNTEycHgiIGhlaWdodD0iNTEycHgiPjxnPjxnPjxnPjxwYXRoIGQ9Ik00ODAsMjg4djExMmMwLDQ0LjE4My0zNS44MTcsODAtODAsODBIMTEyYy00NC4xODMsMC04MC0zNS44MTctODAtODBWMTEyYzAtNDQuMTgzLDM1LjgxNy04MCw4MC04MGg5NlYwaC05NiAgICAgQzUwLjE0NCwwLDAsNTAuMTQ0LDAsMTEydjI4OGMwLDYxLjg1Niw1MC4xNDQsMTEyLDExMiwxMTJoMjg4YzYxLjg1NiwwLDExMi01MC4xNDQsMTEyLTExMlYyODhINDgweiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik0xNzYsNDE2aDMyVjI4OGMwLTEyNS43NiwxMDcuNTItMTI4LDExMi0xMjhoMTA1LjQ0bC04NC42NCw4NC42NGwyMi41NiwyMi41NmwxMTItMTEyYzYuMjA0LTYuMjQxLDYuMjA0LTE2LjMxOSwwLTIyLjU2ICAgICBsLTExMi0xMTJsLTIyLjcyLDIyLjcybDg0LjgsODQuNjRIMzIwYy0xLjQ0LDAtMTQ0LDEuNzYtMTQ0LDE2MFY0MTZ6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.download-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3MS4yIDQ3MS4yIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NzEuMiA0NzEuMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTQ1Ny43LDIzMC4xNWMtNy41LDAtMTMuNSw2LTEzLjUsMTMuNXYxMjIuOGMwLDMzLjQtMjcuMiw2MC41LTYwLjUsNjAuNUg4Ny41Yy0zMy40LDAtNjAuNS0yNy4yLTYwLjUtNjAuNXYtMTI0LjggICAgYzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MTI0LjhjMCw0OC4zLDM5LjMsODcuNSw4Ny41LDg3LjVoMjk2LjJjNDguMywwLDg3LjUtMzkuMyw4Ny41LTg3LjV2LTEyMi44ICAgIEM0NzEuMiwyMzYuMjUsNDY1LjIsMjMwLjE1LDQ1Ny43LDIzMC4xNXoiIGZpbGw9IiNGRkZGRkYiLz48cGF0aCBkPSJNMjI2LjEsMzQ2Ljc1YzIuNiwyLjYsNi4xLDQsOS41LDRzNi45LTEuMyw5LjUtNGw4NS44LTg1LjhjNS4zLTUuMyw1LjMtMTMuOCwwLTE5LjFjLTUuMy01LjMtMTMuOC01LjMtMTkuMSwwbC02Mi43LDYyLjggICAgVjMwLjc1YzAtNy41LTYtMTMuNS0xMy41LTEzLjVzLTEzLjUsNi0xMy41LDEzLjV2MjczLjlsLTYyLjgtNjIuOGMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xICAgIEwyMjYuMSwzNDYuNzV6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48L3N2Zz4=)}.close-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3NS4yIDQ3NS4yIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NzUuMiA0NzUuMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTQwNS42LDY5LjZDMzYwLjcsMjQuNywzMDEuMSwwLDIzNy42LDBzLTEyMy4xLDI0LjctMTY4LDY5LjZTMCwxNzQuMSwwLDIzNy42czI0LjcsMTIzLjEsNjkuNiwxNjhzMTA0LjUsNjkuNiwxNjgsNjkuNiAgICBzMTIzLjEtMjQuNywxNjgtNjkuNnM2OS42LTEwNC41LDY5LjYtMTY4UzQ1MC41LDExNC41LDQwNS42LDY5LjZ6IE0zODYuNSwzODYuNWMtMzkuOCwzOS44LTkyLjcsNjEuNy0xNDguOSw2MS43ICAgIHMtMTA5LjEtMjEuOS0xNDguOS02MS43Yy04Mi4xLTgyLjEtODIuMS0yMTUuNywwLTI5Ny44QzEyOC41LDQ4LjksMTgxLjQsMjcsMjM3LjYsMjdzMTA5LjEsMjEuOSwxNDguOSw2MS43ICAgIEM0NjguNiwxNzAuOCw0NjguNiwzMDQuNCwzODYuNSwzODYuNXoiIGZpbGw9IiNGRkZGRkYiLz48cGF0aCBkPSJNMzQyLjMsMTMyLjljLTUuMy01LjMtMTMuOC01LjMtMTkuMSwwbC04NS42LDg1LjZMMTUyLDEzMi45Yy01LjMtNS4zLTEzLjgtNS4zLTE5LjEsMGMtNS4zLDUuMy01LjMsMTMuOCwwLDE5LjEgICAgbDg1LjYsODUuNmwtODUuNiw4NS42Yy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWMyLjYsMi42LDYuMSw0LDkuNSw0czYuOS0xLjMsOS41LTRsODUuNi04NS42bDg1LjYsODUuNmMyLjYsMi42LDYuMSw0LDkuNSw0ICAgIGMzLjUsMCw2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xbC04NS40LTg1LjZsODUuNi04NS42QzM0Ny42LDE0Ni43LDM0Ny42LDEzOC4yLDM0Mi4zLDEzMi45eiIgZmlsbD0iI0ZGRkZGRiIvPjwvZz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+)}.refresh-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ4OS43MTEgNDg5LjcxMSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDg5LjcxMSA0ODkuNzExOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48Zz48cGF0aCBkPSJNMTEyLjE1Niw5Ny4xMTFjNzIuMy02NS40LDE4MC41LTY2LjQsMjUzLjgtNi43bC01OC4xLDIuMmMtNy41LDAuMy0xMy4zLDYuNS0xMywxNGMwLjMsNy4zLDYuMywxMywxMy41LDEzICAgIGMwLjIsMCwwLjMsMCwwLjUsMGw4OS4yLTMuM2M3LjMtMC4zLDEzLTYuMiwxMy0xMy41di0xYzAtMC4yLDAtMC4zLDAtMC41di0wLjFsMCwwbC0zLjMtODguMmMtMC4zLTcuNS02LjYtMTMuMy0xNC0xMyAgICBjLTcuNSwwLjMtMTMuMyw2LjUtMTMsMTRsMi4xLDU1LjNjLTM2LjMtMjkuNy04MS00Ni45LTEyOC44LTQ5LjNjLTU5LjItMy0xMTYuMSwxNy4zLTE2MCw1Ny4xYy02MC40LDU0LjctODYsMTM3LjktNjYuOCwyMTcuMSAgICBjMS41LDYuMiw3LDEwLjMsMTMuMSwxMC4zYzEuMSwwLDIuMS0wLjEsMy4yLTAuNGM3LjItMS44LDExLjctOS4xLDkuOS0xNi4zQzM2LjY1NiwyMTguMjExLDU5LjA1NiwxNDUuMTExLDExMi4xNTYsOTcuMTExeiIgZmlsbD0iI0ZGRkZGRiIvPjxwYXRoIGQ9Ik00NjIuNDU2LDE5NS41MTFjLTEuOC03LjItOS4xLTExLjctMTYuMy05LjljLTcuMiwxLjgtMTEuNyw5LjEtOS45LDE2LjNjMTYuOSw2OS42LTUuNiwxNDIuNy01OC43LDE5MC43ICAgIGMtMzcuMywzMy43LTg0LjEsNTAuMy0xMzAuNyw1MC4zYy00NC41LDAtODguOS0xNS4xLTEyNC43LTQ0LjlsNTguOC01LjNjNy40LTAuNywxMi45LTcuMiwxMi4yLTE0LjdzLTcuMi0xMi45LTE0LjctMTIuMmwtODguOSw4ICAgIGMtNy40LDAuNy0xMi45LDcuMi0xMi4yLDE0LjdsOCw4OC45YzAuNiw3LDYuNSwxMi4zLDEzLjQsMTIuM2MwLjQsMCwwLjgsMCwxLjItMC4xYzcuNC0wLjcsMTIuOS03LjIsMTIuMi0xNC43bC00LjgtNTQuMSAgICBjMzYuMywyOS40LDgwLjgsNDYuNSwxMjguMyw0OC45YzMuOCwwLjIsNy42LDAuMywxMS4zLDAuM2M1NS4xLDAsMTA3LjUtMjAuMiwxNDguNy01Ny40ICAgIEM0NTYuMDU2LDM1Ny45MTEsNDgxLjY1NiwyNzQuODExLDQ2Mi40NTYsMTk1LjUxMXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvc3ZnPg==)}.copy{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ4OC4zIDQ4OC4zIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0ODguMyA0ODguMzsiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI1MTJweCIgaGVpZ2h0PSI1MTJweCI+PGc+PGc+PHBhdGggZD0iTTMxNC4yNSw4NS40aC0yMjdjLTIxLjMsMC0zOC42LDE3LjMtMzguNiwzOC42djMyNS43YzAsMjEuMywxNy4zLDM4LjYsMzguNiwzOC42aDIyN2MyMS4zLDAsMzguNi0xNy4zLDM4LjYtMzguNlYxMjQgICAgQzM1Mi43NSwxMDIuNywzMzUuNDUsODUuNCwzMTQuMjUsODUuNHogTTMyNS43NSw0NDkuNmMwLDYuNC01LjIsMTEuNi0xMS42LDExLjZoLTIyN2MtNi40LDAtMTEuNi01LjItMTEuNi0xMS42VjEyNCAgICBjMC02LjQsNS4yLTExLjYsMTEuNi0xMS42aDIyN2M2LjQsMCwxMS42LDUuMiwxMS42LDExLjZWNDQ5LjZ6IiBmaWxsPSIjRkZGRkZGIi8+PHBhdGggZD0iTTQwMS4wNSwwaC0yMjdjLTIxLjMsMC0zOC42LDE3LjMtMzguNiwzOC42YzAsNy41LDYsMTMuNSwxMy41LDEzLjVzMTMuNS02LDEzLjUtMTMuNWMwLTYuNCw1LjItMTEuNiwxMS42LTExLjZoMjI3ICAgIGM2LjQsMCwxMS42LDUuMiwxMS42LDExLjZ2MzI1LjdjMCw2LjQtNS4yLDExLjYtMTEuNiwxMS42Yy03LjUsMC0xMy41LDYtMTMuNSwxMy41czYsMTMuNSwxMy41LDEzLjVjMjEuMywwLDM4LjYtMTcuMywzOC42LTM4LjYgICAgVjM4LjZDNDM5LjY1LDE3LjMsNDIyLjM1LDAsNDAxLjA1LDB6IiBmaWxsPSIjRkZGRkZGIi8+PC9nPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48L3N2Zz4=)}\n"] }]
        }], ctorParameters: () => [{ type: ConfigService }], propDecorators: { id: [{
                type: Input
            }], currentImage: [{
                type: Input
            }], refresh: [{
                type: Output
            }], delete: [{
                type: Output
            }], navigate: [{
                type: Output
            }], download: [{
                type: Output
            }], closeButton: [{
                type: Output
            }], fullscreen: [{
                type: Output
            }], customEmit: [{
                type: Output
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Component with image previews
 */
class PreviewsComponent extends AccessibleComponent {
    constructor(configService) {
        super();
        this.configService = configService;
        /**
         * Output to emit the clicked preview. The payload contains the `ImageEvent` associated to the clicked preview.
         */
        this.clickPreview = new EventEmitter();
        /**
         * Enum of type `Action` that represents a mouse click on a button.
         * Declared here to be used inside the template.
         */
        this.clickAction = Action.CLICK;
        /**
         * Enum of type `Action` that represents a keyboard action.
         * Declared here to be used inside the template.
         */
        this.keyboardAction = Action.KEYBOARD;
        /**
         * Array of `InternalLibImage` exposed to the template. This field is initialized
         * applying transformations, default values and so on to the input of the same type.
         */
        this.previews = [];
        this.defaultPreviewSize = DEFAULT_PREVIEW_SIZE;
    }
    /**
     * Method ´ngOnInit´ to build `configPreview` applying a default value and also to
     * init the `previews` array.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        this.accessibilityConfig = libConfig.accessibilityConfig;
        this.slideConfig = libConfig.slideConfig;
        this.previewConfig = libConfig.previewConfig;
        this.initPreviews(this.currentImage, this.images);
    }
    /**
     * Method to check if an image is active (i.e. a preview image).
     * @param InternalLibImage preview is an image to check if it's active or not
     * @returns boolean true if is active, false otherwise
     */
    isActive(preview) {
        if (!preview) {
            return false;
        }
        return preview.id === this.currentImage.id;
    }
    /**
     * Method ´ngOnChanges´ to update `previews` array.
     * Also, both `start` and `end` local variables will be updated accordingly.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges(changes) {
        let currentImage = changes.currentImage?.currentValue ?? this.currentImage;
        let images = changes.images?.currentValue ?? this.images;
        if (this.previewConfig && currentImage && images) {
            this.initPreviews(currentImage, images);
        }
    }
    /**
     * Method called by events from both keyboard and mouse on a preview.
     * This will trigger the `clickpreview` output with the input preview as its payload.
     * @param InternalLibImage preview that triggered this method
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the source event or `Action.NORMAL` if not specified
     */
    onImageEvent(preview, event, action = Action.NORMAL) {
        // It's suggested to stop propagation of the event, so the
        // Cdk background will not catch a click and close the modal (like it does on Windows Chrome/FF).
        event?.stopPropagation();
        if (!this.previewConfig || !this.previewConfig.clickable) {
            return;
        }
        const result = super.handleImageEvent(event);
        if (result === NEXT || result === PREV) {
            this.clickPreview.emit(new ImageModalEvent(this.id, action, getIndex(preview, this.images)));
        }
    }
    /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * It also emits an event to specify which arrow.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the source event or `Action.NORMAL` if not specified
     */
    onNavigationEvent(direction, event, action = Action.NORMAL) {
        const result = super.handleNavigationEvent(direction, event);
        if (result === NEXT) {
            this.next();
        }
        else if (result === PREV) {
            this.previous();
        }
    }
    /**
     * Method used in the template to track ids in ngFor.
     * @param number index of the array
     * @param Image item of the array
     * @returns number the id of the item
     */
    trackById(index, item) {
        return item.id;
    }
    /**
     * Indicates if the previews 'left arrow' should be displayed or not.
     * @returns
     */
    displayLeftPreviewsArrow() {
        // Don't show arrows if requested previews number equals or is greated than total number of imgaes
        if (this.previewConfig?.number !== undefined && this.images && this.previewConfig?.number >= this.images?.length) {
            return false;
        }
        return (this.previewConfig?.arrows && this.start > 0) || !!this.slideConfig?.infinite;
    }
    /**
     * Indicates if the previews 'right arrow' should be displayed or not.
     * @returns
     */
    displayRightPreviewsArrow() {
        // Don't show arrows if requested previews number equals or is greated than total number of imgaes
        if (this.previewConfig?.number !== undefined && this.images && this.previewConfig?.number >= this.images?.length) {
            return false;
        }
        return (this.previewConfig?.arrows && this.images && this.end < this.images.length) || !!this.slideConfig?.infinite;
    }
    /**
     * Private method to init previews based on the currentImage and the full array of images.
     * The current image in mandatory to show always the current preview (as highlighted).
     * @param InternalLibImage currentImage to decide how to show previews, because I always want to see the current image as highlighted
     * @param InternalLibImage[] images is the array of all images.
     */
    initPreviews(currentImage, images) {
        this.setIndexesPreviews(currentImage, images);
        this.previews = images.filter((img, i) => i >= this.start && i < this.end);
    }
    /**
     * Private method to update both `start` and `end` based on the currentImage.
     */
    setIndexesPreviews(currentImage, images) {
        if (!this.previewConfig || !images || !currentImage) {
            throw new Error('Internal library error - previewConfig, currentImage and images must be defined');
        }
        const previewsNumber = this.previewConfig.number;
        let start = getIndex(currentImage, images) - Math.floor(previewsNumber / 2);
        // start is, at a minimum, the first index
        if (start < 0)
            start = 0;
        // end index
        let end = start + previewsNumber;
        // end is, at a maximum, the last index
        if (end > images.length) {
            start -= end - images.length;
            if (start < 0)
                start = 0; // start is, at a minimum, the first index
            end = images.length;
        }
        this.start = start;
        this.end = end;
    }
    /**
     * Private method to update the visible previews navigating to the right (next).
     */
    next() {
        if (!this.previewConfig) {
            throw new Error('Internal library error - previewConfig must be defined');
        }
        if (this.end >= this.images.length) {
            // check if nextImage should be blocked
            const preventSliding = !!this.slideConfig && this.slideConfig.infinite === false;
            if (preventSliding) {
                return;
            }
            this.start = 0;
        }
        else {
            this.start++;
        }
        this.end = this.start + Math.min(this.previewConfig.number, this.images.length);
        this.previews = this.images.filter((img, i) => i >= this.start && i < this.end);
    }
    /**
     * Private method to update the visible previews navigating to the left (previous).
     */
    previous() {
        if (!this.previewConfig) {
            throw new Error('Internal library error - previewConfig must be defined');
        }
        if (this.start <= 0) {
            // check if prevImage should be blocked
            const preventSliding = !!this.slideConfig && this.slideConfig.infinite === false;
            if (preventSliding) {
                return;
            }
            this.end = this.images.length;
        }
        else {
            this.end--;
        }
        this.start = this.end - Math.min(this.previewConfig.number, this.images.length);
        this.previews = this.images.filter((img, i) => i >= this.start && i < this.end);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: PreviewsComponent, deps: [{ token: ConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: PreviewsComponent, isStandalone: false, selector: "ks-previews", inputs: { id: "id", currentImage: "currentImage", images: "images", customTemplate: "customTemplate" }, outputs: { clickPreview: "clickPreview" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<nav class=\"previews-container\"\n     [class.mobile-visible]=\"previewConfig?.mobileVisible\"\n     [attr.aria-label]=\"accessibilityConfig?.previewsContainerAriaLabel\"\n     [title]=\"accessibilityConfig?.previewsContainerTitle\">\n\n  <ng-container *ngIf=\"previewConfig?.visible\">\n    <a class=\"nav-left\"\n       [attr.aria-label]=\"accessibilityConfig?.previewScrollPrevAriaLabel\"\n       [tabIndex]=\"displayLeftPreviewsArrow() ? 0 : -1\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n      <div class=\"inside {{ displayLeftPreviewsArrow() ? 'left-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.previewScrollPrevTitle\"></div>\n    </a>\n\n    <ng-container *ngFor=\"let preview of previews; trackBy: trackById; let index = index\">\n\n      <div class=\"preview-container {{!previewConfig?.clickable ? ' unclickable' : ''}}\"\n        (click)=\"onImageEvent(preview, $event, clickAction)\"\n        (keyup)=\"onImageEvent(preview, $event, keyboardAction)\"\n      >\n        <ng-container \n          *ngTemplateOutlet=\"!customTemplate ? defaultTemplate : customTemplate ; context:{preview, defaultTemplate}\">\n        </ng-container>\n        <ng-template #defaultTemplate>\n          <img *ngIf=\"preview?.modal?.img\"\n              class=\"inside preview-image {{isActive(preview) ? 'active' : ''}}\"\n              [loading]=\"preview.loading\"\n              [attr.fetchpriority]=\"preview.fetchpriority\"\n              [src]=\"preview.plain?.img ? preview.plain?.img! : preview.modal.img\"\n              ksFallbackImage [fallbackImg]=\"preview.plain?.fallbackImg ? preview.plain?.fallbackImg : preview.modal.fallbackImg\"\n              ksSize [sizeConfig]=\"{width: previewConfig?.size ? previewConfig?.size?.width! : defaultPreviewSize.width,\n                                    height: previewConfig?.size ? previewConfig?.size?.height! : defaultPreviewSize.height}\"\n              [attr.aria-label]=\"preview.modal.ariaLabel ? preview.modal.ariaLabel : ''\"\n              [title]=\"(preview.modal.title || preview.modal.title === '') ? preview.modal.title : ''\"\n              alt=\"{{preview.modal.alt ? preview.modal.alt : ''}}\"\n              [tabIndex]=\"0\" role=\"img\"\n          />\n        </ng-template>\n      </div>\n\n    </ng-container>\n\n\n    <a class=\"nav-right\"\n       [attr.aria-label]=\"accessibilityConfig?.previewScrollNextAriaLabel\"\n       [tabIndex]=\"displayRightPreviewsArrow() ? 0 : -1\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n      <div class=\"inside {{ displayRightPreviewsArrow() ? 'right-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.previewScrollNextTitle\"></div>\n    </a>\n  </ng-container>\n\n</nav>\n", styles: ["@media only screen and (max-width: 767px),only screen and (max-device-width: 767px){.previews-container{display:none}.previews-container>.preview-image{display:none}.previews-container>.nav-left{display:none}.previews-container>.nav-right{display:none}.previews-container.mobile-visible{align-items:center;animation:fadein-semi-visible08 .8s;display:flex;flex-direction:row;justify-content:center;margin-bottom:15px}.previews-container.mobile-visible>.nav-left{display:flex}.previews-container.mobile-visible>.nav-right{display:flex}.previews-container.mobile-visible>.preview-image{cursor:pointer;display:flex;margin-left:2px;margin-right:2px;opacity:.7;height:50px}.previews-container.mobile-visible>.preview-image.active{opacity:1}.previews-container.mobile-visible>.preview-image.unclickable{cursor:not-allowed}.previews-container.mobile-visible>.preview-image:hover{opacity:1;transition:all .5s ease;transition-property:opacity}}@media only screen and (min-device-width: 768px){.previews-container{align-items:center;animation:fadein-semi-visible08 .8s;display:flex;flex-direction:row;justify-content:center;margin-bottom:15px}.previews-container .preview-container{margin-left:2px;margin-right:2px;cursor:pointer}.previews-container .preview-container.unclickable{cursor:not-allowed}.previews-container .preview-container .preview-image{opacity:.7;height:50px}.previews-container .preview-container .preview-image.active{opacity:1}.previews-container .preview-container .preview-image:hover{opacity:1;transition:all .5s ease;transition-property:opacity}.previews-container .nav,.previews-container>.nav-right,.previews-container>.nav-left{color:#919191;cursor:pointer;transition:all .5s}.previews-container .nav:hover,.previews-container>.nav-right:hover,.previews-container>.nav-left:hover{transform:scale(1.1)}.previews-container>.nav-left{margin-right:10px}.previews-container>.nav-right{margin-left:10px}}@keyframes fadein-visible{0%{opacity:0}to{opacity:1}}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible08{0%{opacity:0}to{opacity:.8}}@keyframes fadein-semi-visible09{0%{opacity:0}to{opacity:.9}}\n", ".arrow-preview-image,.right-arrow-preview-image,.left-arrow-preview-image,.empty-arrow-preview-image{width:15px;height:15px;opacity:.5}.empty-arrow-preview-image{background:#000;opacity:0}.left-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.left-arrow-preview-image:hover{transform:scale(1.2)}.right-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.right-arrow-preview-image:hover{transform:scale(1.2)}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }, { kind: "directive", type: FallbackImageDirective, selector: "[ksFallbackImage]", inputs: ["fallbackImg"], outputs: ["fallbackApplied"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: PreviewsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-previews', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<nav class=\"previews-container\"\n     [class.mobile-visible]=\"previewConfig?.mobileVisible\"\n     [attr.aria-label]=\"accessibilityConfig?.previewsContainerAriaLabel\"\n     [title]=\"accessibilityConfig?.previewsContainerTitle\">\n\n  <ng-container *ngIf=\"previewConfig?.visible\">\n    <a class=\"nav-left\"\n       [attr.aria-label]=\"accessibilityConfig?.previewScrollPrevAriaLabel\"\n       [tabIndex]=\"displayLeftPreviewsArrow() ? 0 : -1\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n      <div class=\"inside {{ displayLeftPreviewsArrow() ? 'left-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.previewScrollPrevTitle\"></div>\n    </a>\n\n    <ng-container *ngFor=\"let preview of previews; trackBy: trackById; let index = index\">\n\n      <div class=\"preview-container {{!previewConfig?.clickable ? ' unclickable' : ''}}\"\n        (click)=\"onImageEvent(preview, $event, clickAction)\"\n        (keyup)=\"onImageEvent(preview, $event, keyboardAction)\"\n      >\n        <ng-container \n          *ngTemplateOutlet=\"!customTemplate ? defaultTemplate : customTemplate ; context:{preview, defaultTemplate}\">\n        </ng-container>\n        <ng-template #defaultTemplate>\n          <img *ngIf=\"preview?.modal?.img\"\n              class=\"inside preview-image {{isActive(preview) ? 'active' : ''}}\"\n              [loading]=\"preview.loading\"\n              [attr.fetchpriority]=\"preview.fetchpriority\"\n              [src]=\"preview.plain?.img ? preview.plain?.img! : preview.modal.img\"\n              ksFallbackImage [fallbackImg]=\"preview.plain?.fallbackImg ? preview.plain?.fallbackImg : preview.modal.fallbackImg\"\n              ksSize [sizeConfig]=\"{width: previewConfig?.size ? previewConfig?.size?.width! : defaultPreviewSize.width,\n                                    height: previewConfig?.size ? previewConfig?.size?.height! : defaultPreviewSize.height}\"\n              [attr.aria-label]=\"preview.modal.ariaLabel ? preview.modal.ariaLabel : ''\"\n              [title]=\"(preview.modal.title || preview.modal.title === '') ? preview.modal.title : ''\"\n              alt=\"{{preview.modal.alt ? preview.modal.alt : ''}}\"\n              [tabIndex]=\"0\" role=\"img\"\n          />\n        </ng-template>\n      </div>\n\n    </ng-container>\n\n\n    <a class=\"nav-right\"\n       [attr.aria-label]=\"accessibilityConfig?.previewScrollNextAriaLabel\"\n       [tabIndex]=\"displayRightPreviewsArrow() ? 0 : -1\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n      <div class=\"inside {{ displayRightPreviewsArrow() ? 'right-arrow-preview-image' : 'empty-arrow-preview-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig?.previewScrollNextTitle\"></div>\n    </a>\n  </ng-container>\n\n</nav>\n", styles: ["@media only screen and (max-width: 767px),only screen and (max-device-width: 767px){.previews-container{display:none}.previews-container>.preview-image{display:none}.previews-container>.nav-left{display:none}.previews-container>.nav-right{display:none}.previews-container.mobile-visible{align-items:center;animation:fadein-semi-visible08 .8s;display:flex;flex-direction:row;justify-content:center;margin-bottom:15px}.previews-container.mobile-visible>.nav-left{display:flex}.previews-container.mobile-visible>.nav-right{display:flex}.previews-container.mobile-visible>.preview-image{cursor:pointer;display:flex;margin-left:2px;margin-right:2px;opacity:.7;height:50px}.previews-container.mobile-visible>.preview-image.active{opacity:1}.previews-container.mobile-visible>.preview-image.unclickable{cursor:not-allowed}.previews-container.mobile-visible>.preview-image:hover{opacity:1;transition:all .5s ease;transition-property:opacity}}@media only screen and (min-device-width: 768px){.previews-container{align-items:center;animation:fadein-semi-visible08 .8s;display:flex;flex-direction:row;justify-content:center;margin-bottom:15px}.previews-container .preview-container{margin-left:2px;margin-right:2px;cursor:pointer}.previews-container .preview-container.unclickable{cursor:not-allowed}.previews-container .preview-container .preview-image{opacity:.7;height:50px}.previews-container .preview-container .preview-image.active{opacity:1}.previews-container .preview-container .preview-image:hover{opacity:1;transition:all .5s ease;transition-property:opacity}.previews-container .nav,.previews-container>.nav-right,.previews-container>.nav-left{color:#919191;cursor:pointer;transition:all .5s}.previews-container .nav:hover,.previews-container>.nav-right:hover,.previews-container>.nav-left:hover{transform:scale(1.1)}.previews-container>.nav-left{margin-right:10px}.previews-container>.nav-right{margin-left:10px}}@keyframes fadein-visible{0%{opacity:0}to{opacity:1}}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible08{0%{opacity:0}to{opacity:.8}}@keyframes fadein-semi-visible09{0%{opacity:0}to{opacity:.9}}\n", ".arrow-preview-image,.right-arrow-preview-image,.left-arrow-preview-image,.empty-arrow-preview-image{width:15px;height:15px;opacity:.5}.empty-arrow-preview-image{background:#000;opacity:0}.left-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.left-arrow-preview-image:hover{transform:scale(1.2)}.right-arrow-preview-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);background-size:15px;transition:all .5s}.right-arrow-preview-image:hover{transform:scale(1.2)}\n"] }]
        }], ctorParameters: () => [{ type: ConfigService }], propDecorators: { id: [{
                type: Input
            }], currentImage: [{
                type: Input
            }], images: [{
                type: Input
            }], customTemplate: [{
                type: Input
            }], clickPreview: [{
                type: Output
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Enum `Keyboard` with keys and their relative codes.
 */
const Keyboard = {
    ESC: ESC_CODE,
    LEFT_ARROW: LEFT_ARROW_CODE,
    RIGHT_ARROW: RIGHT_ARROW_CODE,
    UP_ARROW: UP_ARROW_CODE,
    DOWN_ARROW: DOWN_ARROW_CODE
};

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Component with the loading spinner
 */
class LoadingSpinnerComponent {
    constructor() {
        /**
         * Enum of type `LoadingType` to choose the standard loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingStandard = LoadingType.STANDARD;
        /**
         * Enum of type `LoadingType` to choose the bars loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingBars = LoadingType.BARS;
        /**
         * Enum of type `LoadingType` to choose the circular loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingCircular = LoadingType.CIRCULAR;
        /**
         * Enum of type `LoadingType` to choose the dots loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingDots = LoadingType.DOTS;
        /**
         * Enum of type `LoadingType` to choose the cube flipping loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingCubeFlipping = LoadingType.CUBE_FLIPPING;
        /**
         * Enum of type `LoadingType` to choose the circles loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingCircles = LoadingType.CIRCLES;
        /**
         * Enum of type `LoadingType` to choose the explosing squares loading spinner.
         * Declared here to be used inside the template.
         */
        this.loadingExplosingSquares = LoadingType.EXPLOSING_SQUARES;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LoadingSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: LoadingSpinnerComponent, isStandalone: false, selector: "ks-loading-spinner", inputs: { loadingConfig: "loadingConfig", accessibilityConfig: "accessibilityConfig" }, ngImport: i0, template: "<div [attr.aria-label]=\"accessibilityConfig?.loadingSpinnerAriaLabel\"\n     [title]=\"accessibilityConfig?.loadingSpinnerTitle\">\n\n  <ng-container [ngSwitch]=\"loadingConfig?.type\">\n    <ng-container *ngSwitchCase=\"loadingStandard\">\n      <div class=\"cssload-loader\">\n        <div class=\"cssload-inner cssload-one\"></div>\n        <div class=\"cssload-inner cssload-two\"></div>\n        <div class=\"cssload-inner cssload-three\"></div>\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingBars\">\n      <div class=\"loader-bars\">\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingCircular\">\n      <div class=\"loader-circular\">\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingDots\">\n      <div class=\"loader-dots\">\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingCubeFlipping\">\n      <div class=\"cube-wrapper\">\n        <div class=\"cube-folding\">\n          <span class=\"leaf1\"></span>\n          <span class=\"leaf2\"></span>\n          <span class=\"leaf3\"></span>\n          <span class=\"leaf4\"></span>\n        </div>\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingCircles\">\n      <div id=\"preloader\">\n        <div id=\"loader\"></div>\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingExplosingSquares\">\n      <div class=\"loader\">\n        <span></span>\n        <span></span>\n        <span></span>\n        <span></span>\n      </div>\n    </ng-container>\n  </ng-container>\n</div>\n", styles: [".cssload-loader{position:absolute;inset:0;margin:auto;width:64px;height:64px;border-radius:50%;-o-border-radius:50%;-ms-border-radius:50%;-webkit-border-radius:50%;-moz-border-radius:50%;perspective:800px}.cssload-inner{position:absolute;width:100%;height:100%;box-sizing:border-box;-o-box-sizing:border-box;-ms-box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;border-radius:50%;-o-border-radius:50%;-ms-border-radius:50%;-webkit-border-radius:50%;-moz-border-radius:50%}.cssload-inner.cssload-one{left:0%;top:0%;animation:cssload-rotate-one .6s linear infinite;-o-animation:cssload-rotate-one .6s linear infinite;-ms-animation:cssload-rotate-one .6s linear infinite;-webkit-animation:cssload-rotate-one .6s linear infinite;-moz-animation:cssload-rotate-one .6s linear infinite;border-bottom:3px solid rgba(255,255,255,.99)}.cssload-inner.cssload-two{right:0%;top:0%;animation:cssload-rotate-two .6s linear infinite;-o-animation:cssload-rotate-two .6s linear infinite;-ms-animation:cssload-rotate-two .6s linear infinite;-webkit-animation:cssload-rotate-two .6s linear infinite;-moz-animation:cssload-rotate-two .6s linear infinite;border-right:3px solid rgb(255,255,255)}.cssload-inner.cssload-three{right:0%;bottom:0%;animation:cssload-rotate-three .6s linear infinite;-o-animation:cssload-rotate-three .6s linear infinite;-ms-animation:cssload-rotate-three .6s linear infinite;-webkit-animation:cssload-rotate-three .6s linear infinite;-moz-animation:cssload-rotate-three .6s linear infinite;border-top:3px solid rgb(255,255,255)}@keyframes cssload-rotate-one{0%{transform:rotateX(35deg) rotateY(-45deg) rotate(0)}to{transform:rotateX(35deg) rotateY(-45deg) rotate(360deg)}}@-o-keyframes cssload-rotate-one{0%{-o-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-o-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@-ms-keyframes cssload-rotate-one{0%{-ms-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-ms-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@-webkit-keyframes cssload-rotate-one{0%{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@-moz-keyframes cssload-rotate-one{0%{-moz-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-moz-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@keyframes cssload-rotate-two{0%{transform:rotateX(50deg) rotateY(10deg) rotate(0)}to{transform:rotateX(50deg) rotateY(10deg) rotate(360deg)}}@-o-keyframes cssload-rotate-two{0%{-o-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-o-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@-ms-keyframes cssload-rotate-two{0%{-ms-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-ms-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@-webkit-keyframes cssload-rotate-two{0%{-webkit-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-webkit-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@-moz-keyframes cssload-rotate-two{0%{-moz-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-moz-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@keyframes cssload-rotate-three{0%{transform:rotateX(35deg) rotateY(55deg) rotate(0)}to{transform:rotateX(35deg) rotateY(55deg) rotate(360deg)}}@-o-keyframes cssload-rotate-three{0%{-o-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-o-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}@-ms-keyframes cssload-rotate-three{0%{-ms-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-ms-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}@-webkit-keyframes cssload-rotate-three{0%{-webkit-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}@-moz-keyframes cssload-rotate-three{0%{-moz-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-moz-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}\n", ".loader-dots{position:absolute;inset:0;color:#fefcff;font-size:10px;margin:auto;width:1em;height:1em;border-radius:50%;text-indent:-9999em;-webkit-animation:load4 1.3s infinite linear;animation:load4 1.3s infinite linear;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}@-webkit-keyframes load4{0%,to{box-shadow:0 -3em 0 .2em,2em -2em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em}12.5%{box-shadow:0 -3em,2em -2em 0 .2em,3em 0,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}25%{box-shadow:0 -3em 0 -.5em,2em -2em,3em 0 0 .2em,2em 2em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}37.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0,2em 2em 0 .2em,0 3em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}50%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em,0 3em 0 .2em,-2em 2em,-3em 0 0 -1em,-2em -2em 0 -1em}62.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em,-2em 2em 0 .2em,-3em 0,-2em -2em 0 -1em}75%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0 0 .2em,-2em -2em}87.5%{box-shadow:0 -3em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0,-2em -2em 0 .2em}}@keyframes load4{0%,to{box-shadow:0 -3em 0 .2em,2em -2em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em}12.5%{box-shadow:0 -3em,2em -2em 0 .2em,3em 0,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}25%{box-shadow:0 -3em 0 -.5em,2em -2em,3em 0 0 .2em,2em 2em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}37.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0,2em 2em 0 .2em,0 3em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}50%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em,0 3em 0 .2em,-2em 2em,-3em 0 0 -1em,-2em -2em 0 -1em}62.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em,-2em 2em 0 .2em,-3em 0,-2em -2em 0 -1em}75%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0 0 .2em,-2em -2em}87.5%{box-shadow:0 -3em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0,-2em -2em 0 .2em}}\n", ".loader-bars,.loader-bars:before,.loader-bars:after{background:#fefcff;-webkit-animation:load1 1s infinite ease-in-out;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader-bars{position:absolute;inset:0;color:#fefcff;text-indent:-9999em;margin:auto;font-size:11px;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation-delay:-.16s;animation-delay:-.16s}.loader-bars:before,.loader-bars:after{position:absolute;top:0;content:\"\"}.loader-bars:before{left:-1.5em;-webkit-animation-delay:-.32s;animation-delay:-.32s}.loader-bars:after{left:1.5em}@-webkit-keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}@keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}\n", ".loader-circular,.loader-circular:after{border-radius:50%;width:10em;height:10em}.loader-circular{position:absolute;inset:0;margin:auto;font-size:10px;text-indent:-9999em;border-top:1.1em solid rgba(255,255,255,.2);border-right:1.1em solid rgba(255,255,255,.2);border-bottom:1.1em solid rgba(255,255,255,.2);border-left:1.1em solid #ffffff;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}\n", ".cube-folding{width:50px;height:50px;display:inline-block;-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);font-size:0}.cube-folding span{position:relative;width:25px;height:25px;-moz-transform:scale(1.1);-ms-transform:scale(1.1);-webkit-transform:scale(1.1);transform:scale(1.1);display:inline-block}.cube-folding span:before{content:\"\";background-color:#fff;position:absolute;left:0;top:0;display:block;width:25px;height:25px;-moz-transform-origin:100% 100%;-ms-transform-origin:100% 100%;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-moz-animation:folding 2.5s infinite linear both;-webkit-animation:folding 2.5s infinite linear both;animation:folding 2.5s infinite linear both}.cube-folding .leaf2{-moz-transform:rotateZ(90deg) scale(1.1);-ms-transform:rotateZ(90deg) scale(1.1);-webkit-transform:rotateZ(90deg) scale(1.1);transform:rotate(90deg) scale(1.1)}.cube-folding .leaf2:before{-moz-animation-delay:.3s;-webkit-animation-delay:.3s;animation-delay:.3s;background-color:#f2f2f2}.cube-folding .leaf3{-moz-transform:rotateZ(270deg) scale(1.1);-ms-transform:rotateZ(270deg) scale(1.1);-webkit-transform:rotateZ(270deg) scale(1.1);transform:rotate(270deg) scale(1.1)}.cube-folding .leaf3:before{-moz-animation-delay:.9s;-webkit-animation-delay:.9s;animation-delay:.9s;background-color:#f2f2f2}.cube-folding .leaf4{-moz-transform:rotateZ(180deg) scale(1.1);-ms-transform:rotateZ(180deg) scale(1.1);-webkit-transform:rotateZ(180deg) scale(1.1);transform:rotate(180deg) scale(1.1)}.cube-folding .leaf4:before{-moz-animation-delay:.6s;-webkit-animation-delay:.6s;animation-delay:.6s;background-color:#e6e6e6}@-moz-keyframes folding{0%,10%{-moz-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-moz-transform:perspective(140px) rotateX(0deg);transform:perspective(140px) rotateX(0);opacity:1}90%,to{-moz-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}@-webkit-keyframes folding{0%,10%{-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-webkit-transform:perspective(140px) rotateX(0deg);transform:perspective(140px) rotateX(0);opacity:1}90%,to{-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}@keyframes folding{0%,10%{-moz-transform:perspective(140px) rotateX(-180deg);-ms-transform:perspective(140px) rotateX(-180deg);-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-moz-transform:perspective(140px) rotateX(0deg);-ms-transform:perspective(140px) rotateX(0deg);-webkit-transform:perspective(140px) rotateX(0deg);transform:perspective(140px) rotateX(0);opacity:1}90%,to{-moz-transform:perspective(140px) rotateY(180deg);-ms-transform:perspective(140px) rotateY(180deg);-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}.cube-wrapper{position:fixed;left:50%;top:50%;margin-top:-50px;margin-left:-50px;width:100px;height:100px;text-align:center}@-moz-keyframes text{to{top:35px}}@-webkit-keyframes text{to{top:35px}}@keyframes text{to{top:35px}}@-moz-keyframes shadow{to{bottom:-18px;width:100px}}@-webkit-keyframes shadow{to{bottom:-18px;width:100px}}@keyframes shadow{to{bottom:-18px;width:100px}}\n", "#preloader{position:fixed;top:0;left:0;width:100%;height:100%}#loader{display:block;position:relative;left:50%;top:50%;width:100px;height:100px;margin:-75px 0 0 -75px;border-radius:50%;border:3px solid transparent;border-top-color:#b4b4b4;-webkit-animation:spin 2s linear infinite;animation:spin 2s linear infinite}#loader:before{content:\"\";position:absolute;inset:5px;border-radius:50%;border:3px solid transparent;border-top-color:#d9d9d9;-webkit-animation:spin 3s linear infinite;animation:spin 3s linear infinite}#loader:after{content:\"\";position:absolute;inset:15px;border-radius:50%;border:3px solid transparent;border-top-color:#fff;-webkit-animation:spin 1.5s linear infinite;animation:spin 1.5s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}\n", "@keyframes loader{0%,10%,to{width:60px;height:60px}65%{width:150px;height:150px}}@keyframes loaderBlock{0%,30%{transform:rotate(0)}55%{background-color:#b4b4b4}to{transform:rotate(90deg)}}@keyframes loaderBlockInverse{0%,20%{transform:rotate(0)}55%{background-color:#d9d9d9}to{transform:rotate(-90deg)}}.loader{position:absolute;top:50%;left:50%;width:60px;height:60px;transform:translate(-50%,-50%) rotate(45deg) translateZ(0);animation:loader 1.2s infinite ease-in-out}.loader span{position:absolute;display:block;width:40px;height:40px;background-color:#fff;animation:loaderBlock 1.2s infinite ease-in-out both}.loader span:nth-child(1){top:0;left:0}.loader span:nth-child(2){top:0;right:0;animation:loaderBlockInverse 1.2s infinite ease-in-out both}.loader span:nth-child(3){bottom:0;left:0;animation:loaderBlockInverse 1.2s infinite ease-in-out both}.loader span:nth-child(4){bottom:0;right:0}\n"], dependencies: [{ kind: "directive", type: i2$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LoadingSpinnerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-loading-spinner', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div [attr.aria-label]=\"accessibilityConfig?.loadingSpinnerAriaLabel\"\n     [title]=\"accessibilityConfig?.loadingSpinnerTitle\">\n\n  <ng-container [ngSwitch]=\"loadingConfig?.type\">\n    <ng-container *ngSwitchCase=\"loadingStandard\">\n      <div class=\"cssload-loader\">\n        <div class=\"cssload-inner cssload-one\"></div>\n        <div class=\"cssload-inner cssload-two\"></div>\n        <div class=\"cssload-inner cssload-three\"></div>\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingBars\">\n      <div class=\"loader-bars\">\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingCircular\">\n      <div class=\"loader-circular\">\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingDots\">\n      <div class=\"loader-dots\">\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingCubeFlipping\">\n      <div class=\"cube-wrapper\">\n        <div class=\"cube-folding\">\n          <span class=\"leaf1\"></span>\n          <span class=\"leaf2\"></span>\n          <span class=\"leaf3\"></span>\n          <span class=\"leaf4\"></span>\n        </div>\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingCircles\">\n      <div id=\"preloader\">\n        <div id=\"loader\"></div>\n      </div>\n    </ng-container>\n    <ng-container *ngSwitchCase=\"loadingExplosingSquares\">\n      <div class=\"loader\">\n        <span></span>\n        <span></span>\n        <span></span>\n        <span></span>\n      </div>\n    </ng-container>\n  </ng-container>\n</div>\n", styles: [".cssload-loader{position:absolute;inset:0;margin:auto;width:64px;height:64px;border-radius:50%;-o-border-radius:50%;-ms-border-radius:50%;-webkit-border-radius:50%;-moz-border-radius:50%;perspective:800px}.cssload-inner{position:absolute;width:100%;height:100%;box-sizing:border-box;-o-box-sizing:border-box;-ms-box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;border-radius:50%;-o-border-radius:50%;-ms-border-radius:50%;-webkit-border-radius:50%;-moz-border-radius:50%}.cssload-inner.cssload-one{left:0%;top:0%;animation:cssload-rotate-one .6s linear infinite;-o-animation:cssload-rotate-one .6s linear infinite;-ms-animation:cssload-rotate-one .6s linear infinite;-webkit-animation:cssload-rotate-one .6s linear infinite;-moz-animation:cssload-rotate-one .6s linear infinite;border-bottom:3px solid rgba(255,255,255,.99)}.cssload-inner.cssload-two{right:0%;top:0%;animation:cssload-rotate-two .6s linear infinite;-o-animation:cssload-rotate-two .6s linear infinite;-ms-animation:cssload-rotate-two .6s linear infinite;-webkit-animation:cssload-rotate-two .6s linear infinite;-moz-animation:cssload-rotate-two .6s linear infinite;border-right:3px solid rgb(255,255,255)}.cssload-inner.cssload-three{right:0%;bottom:0%;animation:cssload-rotate-three .6s linear infinite;-o-animation:cssload-rotate-three .6s linear infinite;-ms-animation:cssload-rotate-three .6s linear infinite;-webkit-animation:cssload-rotate-three .6s linear infinite;-moz-animation:cssload-rotate-three .6s linear infinite;border-top:3px solid rgb(255,255,255)}@keyframes cssload-rotate-one{0%{transform:rotateX(35deg) rotateY(-45deg) rotate(0)}to{transform:rotateX(35deg) rotateY(-45deg) rotate(360deg)}}@-o-keyframes cssload-rotate-one{0%{-o-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-o-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@-ms-keyframes cssload-rotate-one{0%{-ms-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-ms-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@-webkit-keyframes cssload-rotate-one{0%{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@-moz-keyframes cssload-rotate-one{0%{-moz-transform:rotateX(35deg) rotateY(-45deg) rotateZ(0deg)}to{-moz-transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@keyframes cssload-rotate-two{0%{transform:rotateX(50deg) rotateY(10deg) rotate(0)}to{transform:rotateX(50deg) rotateY(10deg) rotate(360deg)}}@-o-keyframes cssload-rotate-two{0%{-o-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-o-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@-ms-keyframes cssload-rotate-two{0%{-ms-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-ms-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@-webkit-keyframes cssload-rotate-two{0%{-webkit-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-webkit-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@-moz-keyframes cssload-rotate-two{0%{-moz-transform:rotateX(50deg) rotateY(10deg) rotateZ(0deg)}to{-moz-transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@keyframes cssload-rotate-three{0%{transform:rotateX(35deg) rotateY(55deg) rotate(0)}to{transform:rotateX(35deg) rotateY(55deg) rotate(360deg)}}@-o-keyframes cssload-rotate-three{0%{-o-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-o-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}@-ms-keyframes cssload-rotate-three{0%{-ms-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-ms-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}@-webkit-keyframes cssload-rotate-three{0%{-webkit-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-webkit-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}@-moz-keyframes cssload-rotate-three{0%{-moz-transform:rotateX(35deg) rotateY(55deg) rotateZ(0deg)}to{-moz-transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}\n", ".loader-dots{position:absolute;inset:0;color:#fefcff;font-size:10px;margin:auto;width:1em;height:1em;border-radius:50%;text-indent:-9999em;-webkit-animation:load4 1.3s infinite linear;animation:load4 1.3s infinite linear;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)}@-webkit-keyframes load4{0%,to{box-shadow:0 -3em 0 .2em,2em -2em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em}12.5%{box-shadow:0 -3em,2em -2em 0 .2em,3em 0,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}25%{box-shadow:0 -3em 0 -.5em,2em -2em,3em 0 0 .2em,2em 2em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}37.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0,2em 2em 0 .2em,0 3em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}50%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em,0 3em 0 .2em,-2em 2em,-3em 0 0 -1em,-2em -2em 0 -1em}62.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em,-2em 2em 0 .2em,-3em 0,-2em -2em 0 -1em}75%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0 0 .2em,-2em -2em}87.5%{box-shadow:0 -3em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0,-2em -2em 0 .2em}}@keyframes load4{0%,to{box-shadow:0 -3em 0 .2em,2em -2em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em}12.5%{box-shadow:0 -3em,2em -2em 0 .2em,3em 0,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}25%{box-shadow:0 -3em 0 -.5em,2em -2em,3em 0 0 .2em,2em 2em,0 3em 0 -1em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}37.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0,2em 2em 0 .2em,0 3em,-2em 2em 0 -1em,-3em 0 0 -1em,-2em -2em 0 -1em}50%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em,0 3em 0 .2em,-2em 2em,-3em 0 0 -1em,-2em -2em 0 -1em}62.5%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em,-2em 2em 0 .2em,-3em 0,-2em -2em 0 -1em}75%{box-shadow:0 -3em 0 -1em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0 0 .2em,-2em -2em}87.5%{box-shadow:0 -3em,2em -2em 0 -1em,3em 0 0 -1em,2em 2em 0 -1em,0 3em 0 -1em,-2em 2em,-3em 0,-2em -2em 0 .2em}}\n", ".loader-bars,.loader-bars:before,.loader-bars:after{background:#fefcff;-webkit-animation:load1 1s infinite ease-in-out;animation:load1 1s infinite ease-in-out;width:1em;height:4em}.loader-bars{position:absolute;inset:0;color:#fefcff;text-indent:-9999em;margin:auto;font-size:11px;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation-delay:-.16s;animation-delay:-.16s}.loader-bars:before,.loader-bars:after{position:absolute;top:0;content:\"\"}.loader-bars:before{left:-1.5em;-webkit-animation-delay:-.32s;animation-delay:-.32s}.loader-bars:after{left:1.5em}@-webkit-keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}@keyframes load1{0%,80%,to{box-shadow:0 0;height:4em}40%{box-shadow:0 -2em;height:5em}}\n", ".loader-circular,.loader-circular:after{border-radius:50%;width:10em;height:10em}.loader-circular{position:absolute;inset:0;margin:auto;font-size:10px;text-indent:-9999em;border-top:1.1em solid rgba(255,255,255,.2);border-right:1.1em solid rgba(255,255,255,.2);border-bottom:1.1em solid rgba(255,255,255,.2);border-left:1.1em solid #ffffff;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}\n", ".cube-folding{width:50px;height:50px;display:inline-block;-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);transform:rotate(45deg);font-size:0}.cube-folding span{position:relative;width:25px;height:25px;-moz-transform:scale(1.1);-ms-transform:scale(1.1);-webkit-transform:scale(1.1);transform:scale(1.1);display:inline-block}.cube-folding span:before{content:\"\";background-color:#fff;position:absolute;left:0;top:0;display:block;width:25px;height:25px;-moz-transform-origin:100% 100%;-ms-transform-origin:100% 100%;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-moz-animation:folding 2.5s infinite linear both;-webkit-animation:folding 2.5s infinite linear both;animation:folding 2.5s infinite linear both}.cube-folding .leaf2{-moz-transform:rotateZ(90deg) scale(1.1);-ms-transform:rotateZ(90deg) scale(1.1);-webkit-transform:rotateZ(90deg) scale(1.1);transform:rotate(90deg) scale(1.1)}.cube-folding .leaf2:before{-moz-animation-delay:.3s;-webkit-animation-delay:.3s;animation-delay:.3s;background-color:#f2f2f2}.cube-folding .leaf3{-moz-transform:rotateZ(270deg) scale(1.1);-ms-transform:rotateZ(270deg) scale(1.1);-webkit-transform:rotateZ(270deg) scale(1.1);transform:rotate(270deg) scale(1.1)}.cube-folding .leaf3:before{-moz-animation-delay:.9s;-webkit-animation-delay:.9s;animation-delay:.9s;background-color:#f2f2f2}.cube-folding .leaf4{-moz-transform:rotateZ(180deg) scale(1.1);-ms-transform:rotateZ(180deg) scale(1.1);-webkit-transform:rotateZ(180deg) scale(1.1);transform:rotate(180deg) scale(1.1)}.cube-folding .leaf4:before{-moz-animation-delay:.6s;-webkit-animation-delay:.6s;animation-delay:.6s;background-color:#e6e6e6}@-moz-keyframes folding{0%,10%{-moz-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-moz-transform:perspective(140px) rotateX(0deg);transform:perspective(140px) rotateX(0);opacity:1}90%,to{-moz-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}@-webkit-keyframes folding{0%,10%{-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-webkit-transform:perspective(140px) rotateX(0deg);transform:perspective(140px) rotateX(0);opacity:1}90%,to{-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}@keyframes folding{0%,10%{-moz-transform:perspective(140px) rotateX(-180deg);-ms-transform:perspective(140px) rotateX(-180deg);-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-moz-transform:perspective(140px) rotateX(0deg);-ms-transform:perspective(140px) rotateX(0deg);-webkit-transform:perspective(140px) rotateX(0deg);transform:perspective(140px) rotateX(0);opacity:1}90%,to{-moz-transform:perspective(140px) rotateY(180deg);-ms-transform:perspective(140px) rotateY(180deg);-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}.cube-wrapper{position:fixed;left:50%;top:50%;margin-top:-50px;margin-left:-50px;width:100px;height:100px;text-align:center}@-moz-keyframes text{to{top:35px}}@-webkit-keyframes text{to{top:35px}}@keyframes text{to{top:35px}}@-moz-keyframes shadow{to{bottom:-18px;width:100px}}@-webkit-keyframes shadow{to{bottom:-18px;width:100px}}@keyframes shadow{to{bottom:-18px;width:100px}}\n", "#preloader{position:fixed;top:0;left:0;width:100%;height:100%}#loader{display:block;position:relative;left:50%;top:50%;width:100px;height:100px;margin:-75px 0 0 -75px;border-radius:50%;border:3px solid transparent;border-top-color:#b4b4b4;-webkit-animation:spin 2s linear infinite;animation:spin 2s linear infinite}#loader:before{content:\"\";position:absolute;inset:5px;border-radius:50%;border:3px solid transparent;border-top-color:#d9d9d9;-webkit-animation:spin 3s linear infinite;animation:spin 3s linear infinite}#loader:after{content:\"\";position:absolute;inset:15px;border-radius:50%;border:3px solid transparent;border-top-color:#fff;-webkit-animation:spin 1.5s linear infinite;animation:spin 1.5s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0)}to{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}\n", "@keyframes loader{0%,10%,to{width:60px;height:60px}65%{width:150px;height:150px}}@keyframes loaderBlock{0%,30%{transform:rotate(0)}55%{background-color:#b4b4b4}to{transform:rotate(90deg)}}@keyframes loaderBlockInverse{0%,20%{transform:rotate(0)}55%{background-color:#d9d9d9}to{transform:rotate(-90deg)}}.loader{position:absolute;top:50%;left:50%;width:60px;height:60px;transform:translate(-50%,-50%) rotate(45deg) translateZ(0);animation:loader 1.2s infinite ease-in-out}.loader span{position:absolute;display:block;width:40px;height:40px;background-color:#fff;animation:loaderBlock 1.2s infinite ease-in-out both}.loader span:nth-child(1){top:0;left:0}.loader span:nth-child(2){top:0;right:0;animation:loaderBlockInverse 1.2s infinite ease-in-out both}.loader span:nth-child(3){bottom:0;left:0;animation:loaderBlockInverse 1.2s infinite ease-in-out both}.loader span:nth-child(4){bottom:0;right:0}\n"] }]
        }], propDecorators: { loadingConfig: [{
                type: Input
            }], accessibilityConfig: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to manage keyboard navigation.
 */
class KeyboardNavigationDirective {
    constructor() {
        /**
         * Output to emit keyboard `code` of the pressed key (keydown).
         */
        this.keyboardNavigation = new EventEmitter();
    }
    /**
     * Listener to catch keyboard's events and call the right method based on the key.
     * For instance, pressing esc, this will call `closeGallery(Action.KEYBOARD)` and so on.
     * If you passed a valid `keyboardConfig` esc, right and left buttons will be customized based on your data.
     * @param e KeyboardEvent caught by the listener.
     */
    onKeyDown(e) {
        if (!this.isOpen) {
            return;
        }
        this.keyboardNavigation.emit(e.code);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: KeyboardNavigationDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: KeyboardNavigationDirective, isStandalone: false, selector: "[ksKeyboardNavigation]", inputs: { isOpen: "isOpen" }, outputs: { keyboardNavigation: "keyboardNavigation" }, host: { listeners: { "window:keydown": "onKeyDown($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: KeyboardNavigationDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksKeyboardNavigation]',
                    standalone: false
                }]
        }], propDecorators: { isOpen: [{
                type: Input
            }], keyboardNavigation: [{
                type: Output
            }], onKeyDown: [{
                type: HostListener,
                args: ['window:keydown', ['$event']]
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
// Inspired from https://stackblitz.com/edit/angular-swipe-events-with-hostlistner?file=src%2Fapp%2Fapp.component.ts
/**
 * Directive to manage swipe events on touch devices.
 */
class SwipeDirective {
    constructor() {
        this.defaultTouch = { x: 0, y: 0, time: 0 };
        /**
         * Output to emit swipe left event. Payload is empty.
         */
        this.swipeLeft = new EventEmitter();
        /**
         * Output to emit swipe right event. Payload is empty.
         */
        this.swipeRight = new EventEmitter();
        /**
         * Output to emit swipe up event. Payload is empty.
         */
        this.swipeUp = new EventEmitter();
        /**
         * Output to emit swipe down event. Payload is empty.
         */
        this.swipeDown = new EventEmitter();
    }
    /**
     * Method called by Angular itself every click thanks to `@HostListener`.
     * @param event TouchEvent payload received on touch
     */
    handleTouch(event) {
        let touch = event.touches[0] || event.changedTouches[0];
        // check the events
        if (event.type === 'touchstart') {
            this.defaultTouch.x = touch.pageX;
            this.defaultTouch.y = touch.pageY;
            this.defaultTouch.time = event.timeStamp;
        }
        else if (event.type === 'touchend') {
            let deltaX = touch.pageX - this.defaultTouch.x;
            let deltaY = touch.pageY - this.defaultTouch.y;
            let deltaTime = event.timeStamp - this.defaultTouch.time;
            // simulate a swipe -> less than 500 ms and more than 60 px
            if (deltaTime < 500) {
                // touch movement lasted less than 500 ms
                if (Math.abs(deltaX) > 60) {
                    // delta x is at least 60 pixels
                    if (deltaX > 0) {
                        this.swipeRight.emit();
                    }
                    else {
                        this.swipeLeft.emit();
                    }
                }
                if (Math.abs(deltaY) > 60) {
                    // delta y is at least 60 pixels
                    if (deltaY > 0) {
                        this.swipeDown.emit();
                    }
                    else {
                        this.swipeUp.emit();
                    }
                }
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SwipeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: SwipeDirective, isStandalone: false, selector: "[ksSwipe]", outputs: { swipeLeft: "swipeLeft", swipeRight: "swipeRight", swipeUp: "swipeUp", swipeDown: "swipeDown" }, host: { listeners: { "touchstart": "handleTouch($event)", "touchend": "handleTouch($event)", "touchcancel": "handleTouch($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: SwipeDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksSwipe]',
                    standalone: false
                }]
        }], propDecorators: { swipeLeft: [{
                type: Output
            }], swipeRight: [{
                type: Output
            }], swipeUp: [{
                type: Output
            }], swipeDown: [{
                type: Output
            }], handleTouch: [{
                type: HostListener,
                args: ['touchstart', ['$event']]
            }, {
                type: HostListener,
                args: ['touchend', ['$event']]
            }, {
                type: HostListener,
                args: ['touchcancel', ['$event']]
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Component with the current image with some additional elements like arrows and side previews.
 */
class CurrentImageComponent extends AccessibleComponent {
    // use public ChangeDetectorRef to be able to call it from spec files to trigger change detection
    // tslint:disable-next-line:no-any
    constructor(platformId, ngZone, ref, configService) {
        super();
        this.platformId = platformId;
        this.ngZone = ngZone;
        this.ref = ref;
        this.configService = configService;
        /**
         * Boolean that it is true if the modal gallery is visible.
         * If yes, also this component should be visible.
         */
        this.isOpen = false;
        /**
         * Output to emit an event when images are loaded. The payload contains an `ImageLoadEvent`.
         */
        this.loadImage = new EventEmitter();
        /**
         * Output to emit any changes of the current image. The payload contains an `ImageModalEvent`.
         */
        this.changeImage = new EventEmitter();
        /**
         * Output to emit an event when the modal gallery is closed. The payload contains an `ImageModalEvent`.
         */
        this.closeGallery = new EventEmitter();
        /**
         * Subject to play modal-gallery.
         */
        this.start$ = new Subject();
        /**
         * Subject to stop modal-gallery.
         */
        this.stop$ = new Subject();
        /**
         * Enum of type `Action` that represents a normal action.
         * Declared here to be used inside the template.
         */
        this.normalAction = Action.NORMAL;
        /**
         * Enum of type `Action` that represents a mouse click on a button.
         * Declared here to be used inside the template.
         */
        this.clickAction = Action.CLICK;
        /**
         * Enum of type `Action` that represents a keyboard action.
         * Declared here to be used inside the template.
         */
        this.keyboardAction = Action.KEYBOARD;
        /**
         * Boolean that it's true when you are watching the first image (currently visible).
         * False by default
         */
        this.isFirstImage = false;
        /**
         * Boolean that it's true when you are watching the last image (currently visible).
         * False by default
         */
        this.isLastImage = false;
        /**
         * Boolean that it's true if an image of the modal gallery is still loading.
         * True by default
         */
        this.loading = true;
    }
    /**
     * Listener to stop the gallery when the mouse pointer is over the current image.
     */
    onMouseEnter() {
        // if carousel feature is disable, don't do anything in any case
        if (!this.slideConfig || !this.slideConfig.playConfig) {
            return;
        }
        if (!this.slideConfig.playConfig.pauseOnHover) {
            return;
        }
        this.stopCarousel();
    }
    /**
     * Listener to play the gallery when the mouse pointer leave the current image.
     */
    onMouseLeave() {
        // if carousel feature is disable, don't do anything in any case
        if (!this.slideConfig || !this.slideConfig.playConfig) {
            return;
        }
        if (!this.slideConfig.playConfig.pauseOnHover || !this.slideConfig.playConfig.autoPlay) {
            return;
        }
        this.playCarousel();
    }
    /**
     * Method ´ngOnInit´ to init configuration.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.buttonsConfig) {
            throw new Error('Internal library error - libConfig and buttonsConfig must be defined');
        }
        this.slideConfig = libConfig.slideConfig;
        this.accessibilityConfig = libConfig.accessibilityConfig;
        this.currentImageConfig = libConfig.currentImageConfig;
        this.keyboardConfig = libConfig.keyboardConfig;
    }
    /**
     * Method ´ngOnChanges´ to update `loading` status and emit events.
     * If the gallery is open, then it will also manage boundary arrows and sliding.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges(changes) {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        const images = changes.images;
        const currentImage = changes.currentImage;
        if (currentImage && currentImage.previousValue !== currentImage.currentValue) {
            this.updateIndexes();
        }
        else if (images && images.previousValue !== images.currentValue) {
            this.updateIndexes();
        }
        const slideConfig = changes.slideConfig;
        if (slideConfig && slideConfig.previousValue !== slideConfig.currentValue) {
            this.slideConfig = libConfig.slideConfig;
        }
    }
    /**
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     */
    ngAfterContentInit() {
        // interval doesn't play well with SSR and protractor,
        // so we should run it in the browser and outside Angular
        if (isPlatformBrowser(this.platformId)) {
            this.ngZone.runOutsideAngular(() => {
                this.start$
                    .pipe(map(() => this.slideConfig && this.slideConfig.playConfig && this.slideConfig.playConfig.autoPlay && this.slideConfig.playConfig.interval), 
                // tslint:disable-next-line:no-any
                filter((interval) => interval > 0), switchMap(interval => timer(interval).pipe(takeUntil(this.stop$))))
                    .subscribe(() => this.ngZone.run(() => {
                    if (!this.isLastImage) {
                        this.nextImage(Action.AUTOPLAY);
                    }
                    this.ref.markForCheck();
                }));
                this.start$.next();
            });
        }
    }
    /**
     * Method to handle keypress based on the `keyboardConfig` input. It gets the code of
     * the key that triggered the keypress event to navigate between images or to close the modal gallery.
     * @param code string of the key that triggered the keypress event
     */
    onKeyPress(code) {
        const esc = this.keyboardConfig && this.keyboardConfig.esc ? this.keyboardConfig.esc : Keyboard.ESC;
        const right = this.keyboardConfig && this.keyboardConfig.right ? this.keyboardConfig.right : Keyboard.RIGHT_ARROW;
        const left = this.keyboardConfig && this.keyboardConfig.left ? this.keyboardConfig.left : Keyboard.LEFT_ARROW;
        switch (code) {
            case esc:
                this.closeGallery.emit(new ImageModalEvent(this.id, Action.KEYBOARD, true));
                break;
            case right:
                this.nextImage(Action.KEYBOARD);
                break;
            case left:
                this.prevImage(Action.KEYBOARD);
                break;
        }
    }
    /**
     * Method to get the image description based on input params.
     * If you provide a full description this will be the visible description, otherwise,
     * it will be built using the `Description` object, concatenating its fields.
     * @param Image image to get its description. If not provided it will be the current image
     * @returns String description of the image (or the current image if not provided)
     * @throws an Error if description isn't available
     */
    getDescriptionToDisplay(image = this.currentImage) {
        if (!this.currentImageConfig || !this.currentImageConfig.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        const imageWithoutDescription = !image.modal || !image.modal.description || image.modal.description === '';
        switch (this.currentImageConfig.description.strategy) {
            case DescriptionStrategy.HIDE_IF_EMPTY:
                return imageWithoutDescription ? '' : image.modal.description + '';
            case DescriptionStrategy.ALWAYS_HIDDEN:
                return '';
            default:
                // ----------- DescriptionStrategy.ALWAYS_VISIBLE -----------------
                return this.buildTextDescription(image, imageWithoutDescription);
        }
    }
    /**
     * Method to get `alt attribute`.
     * `alt` specifies an alternate text for an image, if the image cannot be displayed.
     * @param Image image to get its alt description. If not provided it will be the current image
     * @returns String alt description of the image (or the current image if not provided)
     */
    getAltDescriptionByImage(image = this.currentImage) {
        if (!image) {
            return '';
        }
        return image.modal && image.modal.description ? image.modal.description : `Image ${getIndex(image, this.images) + 1}`;
    }
    /**
     * Method to get the title attributes based on descriptions.
     * This is useful to prevent accessibility issues, because if DescriptionStrategy is ALWAYS_HIDDEN,
     * it prevents an empty string as title.
     * @param Image image to get its description. If not provided it will be the current image
     * @returns String title of the image based on descriptions
     * @throws an Error if description isn't available
     */
    getTitleToDisplay(image = this.currentImage) {
        if (!this.currentImageConfig || !this.currentImageConfig.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        const imageWithoutDescription = !image.modal || !image.modal.description || image.modal.description === '';
        const description = this.buildTextDescription(image, imageWithoutDescription);
        return description;
    }
    /**
     * Method to get the left side preview image.
     * @returns Image the image to show as size preview on the left
     */
    getLeftPreviewImage() {
        if (!this.slideConfig) {
            throw new Error('Internal library error - slideConfig must be defined');
        }
        const currentIndex = getIndex(this.currentImage, this.images);
        if (currentIndex === 0 && this.slideConfig.infinite) {
            // the current image is the first one,
            // so the previous one is the last image
            // because infinite is true
            return this.images[this.images.length - 1];
        }
        this.handleBoundaries(currentIndex);
        return this.images[Math.max(currentIndex - 1, 0)];
    }
    /**
     * Method to get the right side preview image.
     * @returns Image the image to show as size preview on the right
     */
    getRightPreviewImage() {
        if (!this.slideConfig) {
            throw new Error('Internal library error - slideConfig must be defined');
        }
        const currentIndex = getIndex(this.currentImage, this.images);
        if (currentIndex === this.images.length - 1 && this.slideConfig.infinite) {
            // the current image is the last one,
            // so the next one is the first image
            // because infinite is true
            return this.images[0];
        }
        this.handleBoundaries(currentIndex);
        return this.images[Math.min(currentIndex + 1, this.images.length - 1)];
    }
    /**
     * Method called by events from both keyboard and mouse on an image.
     * This will invoke the nextImage method.
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the event or `Action.NORMAL` if not provided
     */
    onImageEvent(event, action = Action.NORMAL) {
        if (!this.currentImageConfig) {
            throw new Error('Internal library error - currentImageConfig must be defined');
        }
        // check if triggered by a mouse click
        // If yes, It should block navigation when navigateOnClick is false
        if (action === Action.CLICK && !this.currentImageConfig.navigateOnClick) {
            // a user has requested to block navigation via configCurrentImage.navigateOnClick property
            return;
        }
        const result = super.handleImageEvent(event);
        if (result === NEXT) {
            this.nextImage(action);
        }
    }
    /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the event or `Action.NORMAL` if not provided
     * @param boolean disable to disable navigation
     */
    onNavigationEvent(direction, event, action = Action.NORMAL, disable = false) {
        if (disable) {
            return;
        }
        const result = super.handleNavigationEvent(direction, event);
        if (result === NEXT) {
            this.nextImage(action);
        }
        else if (result === PREV) {
            this.prevImage(action);
        }
    }
    /**
     * Method to go back to the previous image.
     * @param action Enum of type `Action` that represents the source
     *  action that moved back to the previous image. `Action.NORMAL` by default.
     */
    prevImage(action = Action.NORMAL) {
        // check if prevImage should be blocked
        if (this.isPreventSliding(0)) {
            return;
        }
        const prevImage = this.getPrevImage();
        this.loading = !prevImage.previouslyLoaded;
        this.changeImage.emit(new ImageModalEvent(this.id, action, getIndex(prevImage, this.images)));
        this.start$.next();
    }
    /**
     * Method to go back to the previous image.
     * @param action Enum of type `Action` that represents the source
     *  action that moved to the next image. `Action.NORMAL` by default.
     */
    nextImage(action = Action.NORMAL) {
        // check if nextImage should be blocked
        if (this.isPreventSliding(this.images.length - 1)) {
            return;
        }
        const nextImage = this.getNextImage();
        this.loading = !nextImage.previouslyLoaded;
        this.changeImage.emit(new ImageModalEvent(this.id, action, getIndex(nextImage, this.images)));
        this.start$.next();
    }
    /**
     * Method to emit an event as loadImage output to say that the requested image if loaded.
     * This method is invoked by the javascript's 'load' event on an img tag.
     * @param Event event that triggered the load
     */
    onImageLoad(event) {
        const loadImageData = {
            status: true,
            index: getIndex(this.currentImage, this.images),
            id: this.currentImage.id
        };
        this.loadImage.emit(loadImageData);
        this.loading = false;
    }
    /**
     * Method used by SwipeDirective to support touch gestures (you can also invert the swipe direction with configCurrentImage.invertSwipe).
     * @param action String that represent the direction of the swipe action. 'swiperight' by default.
     */
    swipe(action = 'swiperight') {
        if (!this.currentImageConfig) {
            throw new Error('Internal library error - currentImageConfig must be defined');
        }
        switch (action) {
            case 'swiperight':
                if (this.currentImageConfig.invertSwipe) {
                    this.prevImage(Action.SWIPE);
                }
                else {
                    this.nextImage(Action.SWIPE);
                }
                break;
            case 'swipeleft':
                if (this.currentImageConfig.invertSwipe) {
                    this.nextImage(Action.SWIPE);
                }
                else {
                    this.prevImage(Action.SWIPE);
                }
                break;
            // case this.SWIPE_ACTION.UP:
            //   break;
            // case this.SWIPE_ACTION.DOWN:
            //   break;
        }
    }
    /**
     * Method used in `modal-gallery.component` to get the index of an image to delete.
     * @param Image image to get the index, or the visible image, if not passed
     * @returns number the index of the image
     */
    getIndexToDelete(image = this.currentImage) {
        return getIndex(image, this.images);
    }
    /**
     * Method to play modal gallery.
     */
    playCarousel() {
        this.start$.next();
    }
    /**
     * Stops modal gallery from cycling through items.
     */
    stopCarousel() {
        this.stop$.next();
    }
    /**
     * Method to cleanup resources. In fact, this will stop the modal gallery.
     * This is an angular lifecycle hook that is called when this component is destroyed.
     */
    ngOnDestroy() {
        this.stopCarousel();
    }
    /**
     * Private method to update both `isFirstImage` and `isLastImage` based on
     * the index of the current image.
     * @param number currentIndex is the index of the current image
     */
    handleBoundaries(currentIndex) {
        if (this.images.length === 1) {
            this.isFirstImage = true;
            this.isLastImage = true;
            this.ref.markForCheck();
            return;
        }
        if (!this.slideConfig || this.slideConfig.infinite === true) {
            // infinite sliding enabled
            this.isFirstImage = false;
            this.isLastImage = false;
            this.ref.markForCheck();
        }
        else {
            // execute this only if infinite sliding is disabled
            switch (currentIndex) {
                case 0:
                    this.isFirstImage = true;
                    this.isLastImage = false;
                    this.ref.markForCheck();
                    break;
                case this.images.length - 1:
                    this.isFirstImage = false;
                    this.isLastImage = true;
                    this.ref.markForCheck();
                    break;
                default:
                    this.isFirstImage = false;
                    this.isLastImage = false;
                    this.ref.markForCheck();
                    break;
            }
        }
    }
    /**
     * Private method to check if next/prev actions should be blocked.
     * It checks if slideConfig.infinite === false and if the image index is equals to the input parameter.
     * If yes, it returns true to say that sliding should be blocked, otherwise not.
     * @param number boundaryIndex that could be either the beginning index (0) or the last index
     *  of images (this.images.length - 1).
     * @returns boolean true if slideConfig.infinite === false and the current index is
     *  either the first or the last one.
     */
    isPreventSliding(boundaryIndex) {
        return !!this.slideConfig && this.slideConfig.infinite === false && getIndex(this.currentImage, this.images) === boundaryIndex;
    }
    /**
     * Private method to get the next index.
     * This is necessary because at the end, when you call next again, you'll go to the first image.
     * That happens because all modal images are shown like in a circle.
     */
    getNextImage() {
        const currentIndex = getIndex(this.currentImage, this.images);
        let newIndex = 0;
        if (currentIndex >= 0 && currentIndex < this.images.length - 1) {
            newIndex = currentIndex + 1;
        }
        else {
            newIndex = 0; // start from the first index
        }
        return this.images[newIndex];
    }
    /**
     * Private method to get the previous index.
     * This is necessary because at index 0, when you call prev again, you'll go to the last image.
     * That happens because all modal images are shown like in a circle.
     */
    getPrevImage() {
        const currentIndex = getIndex(this.currentImage, this.images);
        let newIndex = 0;
        if (currentIndex > 0 && currentIndex <= this.images.length - 1) {
            newIndex = currentIndex - 1;
        }
        else {
            newIndex = this.images.length - 1; // start from the last index
        }
        return this.images[newIndex];
    }
    /**
     * Private method to build a text description.
     * This is used also to create titles.
     * @param Image image to get its description. If not provided it will be the current image.
     * @param boolean imageWithoutDescription is a boolean that it's true if the image hasn't a 'modal' description.
     * @returns String description built concatenating image fields with a specific logic.
     */
    buildTextDescription(image, imageWithoutDescription) {
        if (!this.currentImageConfig || !this.currentImageConfig.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        // If customFullDescription use it, otherwise proceed to build a description
        if (this.currentImageConfig.description.customFullDescription && this.currentImageConfig.description.customFullDescription !== '') {
            return this.currentImageConfig.description.customFullDescription;
        }
        const currentIndex = getIndex(image, this.images);
        // If the current image hasn't a description,
        // prevent to write the ' - ' (or this.description.beforeTextDescription)
        const prevDescription = this.currentImageConfig.description.imageText ? this.currentImageConfig.description.imageText : '';
        const midSeparator = this.currentImageConfig.description.numberSeparator ? this.currentImageConfig.description.numberSeparator : '';
        const middleDescription = currentIndex + 1 + midSeparator + this.images.length;
        if (imageWithoutDescription) {
            return prevDescription + middleDescription;
        }
        const currImgDescription = image.modal && image.modal.description ? image.modal.description : '';
        const endDescription = this.currentImageConfig.description.beforeTextDescription + currImgDescription;
        return prevDescription + middleDescription + endDescription;
    }
    /**
     * Private method to call handleBoundaries when ngOnChanges is called.
     */
    updateIndexes() {
        try {
            if (this.isOpen) {
                const index = getIndex(this.currentImage, this.images);
                this.handleBoundaries(index);
            }
        }
        catch (err) {
            console.error('Cannot get the current image index in current-image');
            throw err;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CurrentImageComponent, deps: [{ token: PLATFORM_ID }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: ConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: CurrentImageComponent, isStandalone: false, selector: "ks-current-image", inputs: { id: "id", currentImage: "currentImage", images: "images", isOpen: "isOpen" }, outputs: { loadImage: "loadImage", changeImage: "changeImage", closeGallery: "closeGallery" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<main class=\"main-image-container\"\n      ksKeyboardNavigation [isOpen]=\"isOpen\" (keyboardNavigation)=\"onKeyPress($event)\"\n      [attr.aria-label]=\"accessibilityConfig?.mainContainerAriaLabel\"\n      [title]=\"accessibilityConfig?.mainContainerTitle\">\n\n  <div class=\"left-sub-container\">\n    <a class=\"nav-left {{isFirstImage ? 'no-pointer' : ''}}\"\n       [attr.aria-label]=\"accessibilityConfig?.mainPrevImageAriaLabel\"\n       [tabIndex]=\"isFirstImage ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n      <div class=\"inside {{isFirstImage ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"isFirstImage ? '' : accessibilityConfig?.mainPrevImageTitle\"></div>\n    </a>\n\n    <ng-container *ngIf=\"slideConfig?.sidePreviews?.show\">\n      <ng-container *ngIf=\"getLeftPreviewImage() as leftPreview\">\n        <img *ngIf=\"!isFirstImage; else firstImage\"\n             class=\"inside current-image-previous\"\n             [loading]=\"leftPreview.loading\"\n             [attr.fetchpriority]=\"leftPreview.fetchpriority\"\n             [src]=\"leftPreview.plain?.img ? leftPreview.plain?.img : leftPreview.modal.img\"\n             ksFallbackImage [fallbackImg]=\"leftPreview.plain?.fallbackImg ? leftPreview.plain?.fallbackImg : leftPreview.modal.fallbackImg\"\n             [hidden]=\"loading\"\n             ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\"\n             [attr.aria-label]=\"leftPreview.modal.ariaLabel\"\n             [title]=\"(leftPreview.modal.title || leftPreview.modal.title === '') ? leftPreview.modal.title : getDescriptionToDisplay(leftPreview)\"\n             alt=\"{{leftPreview.modal.alt ? leftPreview.modal.alt : getAltDescriptionByImage(leftPreview)}}\"\n             [tabIndex]=\"0\" role=\"img\"\n             (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\"/>\n        <ng-template #firstImage>\n          <div class=\"current-image-previous hidden\"\n               ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\"></div>\n        </ng-template>\n      </ng-container>\n    </ng-container>\n  </div>\n\n\n  <figure id=\"current-figure\" [style.opacity]=\"loading ? '0' : '1'\">\n    <picture class=\"current-image\">\n      <ng-container *ngFor=\"let source of currentImage.modal?.sources\">\n        <source [media]=\"source.media\" [srcset]=\"source.srcset\">\n      </ng-container>\n      <img [id]=\"currentImage.id\"\n           [loading]=\"currentImage.loading\"\n           [attr.fetchpriority]=\"currentImage.fetchpriority\"\n           class=\"inside\"\n           [ngClass]=\"currentImageConfig?.navigateOnClick ? '' : 'unclickable'\"\n           [src]=\"currentImage.modal.img\"\n           ksFallbackImage [fallbackImg]=\"currentImage.modal.fallbackImg\"\n           [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n           [title]=\"(currentImage.modal.title || currentImage.modal.title === '') ? currentImage.modal.title : getTitleToDisplay()\"\n           alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n           [tabIndex]=\"0\" role=\"img\"\n           (load)=\"onImageLoad($event)\"\n           (click)=\"onImageEvent($event, clickAction)\" (keyup)=\"onImageEvent($event, keyboardAction)\"\n           ksSwipe\n           (swipeLeft)=\"swipe('swipeleft')\"\n           (swipeRight)=\"swipe('swiperight')\"/>\n    </picture>\n    <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n                class=\"inside description\"\n                ksDescription [description]=\"currentImageConfig?.description\"\n                [innerHTML]=\"getDescriptionToDisplay()\">\n    </figcaption>\n  </figure>\n\n  <div class=\"right-sub-container\">\n    <ng-container *ngIf=\"slideConfig?.sidePreviews?.show\">\n      <ng-container *ngIf=\"getRightPreviewImage() as rightPreview\">\n        <img *ngIf=\"!isLastImage; else lastImage\"\n             class=\"inside current-image-next\"\n             [loading]=\"rightPreview.loading\"\n             [attr.fetchpriority]=\"rightPreview.fetchpriority\"\n             [src]=\"rightPreview.plain?.img ? rightPreview.plain?.img : rightPreview.modal.img\"\n             ksFallbackImage [fallbackImg]=\"rightPreview.plain?.fallbackImg ? rightPreview.plain?.fallbackImg : rightPreview.modal.fallbackImg\"\n             [hidden]=\"loading\"\n             ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\"\n             [attr.aria-label]=\"rightPreview.modal.ariaLabel\"\n             [title]=\"(rightPreview.modal.title || rightPreview.modal.title === '') ? rightPreview.modal.title : getDescriptionToDisplay(rightPreview)\"\n             alt=\"{{rightPreview.modal.alt ? rightPreview.modal.alt : getAltDescriptionByImage(rightPreview)}}\"\n             [tabIndex]=\"0\" role=\"img\"\n             (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\"/>\n        <ng-template #lastImage>\n          <div class=\"current-image-next hidden\"\n               ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\">\n          </div>\n        </ng-template>\n      </ng-container>\n    </ng-container>\n\n    <ng-container *ngIf=\"loading && currentImageConfig?.loadingConfig?.enable\">\n      <ks-loading-spinner [loadingConfig]=\"currentImageConfig?.loadingConfig\"\n                          [accessibilityConfig]=\"accessibilityConfig\"></ks-loading-spinner>\n    </ng-container>\n\n    <a class=\"nav-right {{isFirstImage ? 'no-pointer' : ''}}\"\n       [attr.aria-label]=\"accessibilityConfig?.mainNextImageAriaLabel\"\n       [tabIndex]=\"isLastImage ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n      <div class=\"inside {{isLastImage ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"isLastImage ? '' : accessibilityConfig?.mainNextImageTitle\"></div>\n    </a>\n  </div>\n</main>\n", styles: [":host{display:flex;flex-direction:column;justify-content:center}.main-image-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between}.main-image-container .nav,.main-image-container>.right-sub-container>.nav-right,.main-image-container>.left-sub-container>.nav-left{animation:animatezoom 1s;cursor:pointer;transition:all .5s}.main-image-container .nav:hover,.main-image-container>.right-sub-container>.nav-right:hover,.main-image-container>.left-sub-container>.nav-left:hover{transform:scale(1.1)}.main-image-container>.left-sub-container{display:flex;flex-direction:row;justify-content:space-around;align-items:center}.main-image-container>.left-sub-container>.nav-left{margin-right:5px;margin-left:15px}.main-image-container>.left-sub-container>.nav-left.no-pointer{cursor:default!important}.main-image-container>.right-sub-container{display:flex;flex-direction:row;justify-content:space-around;align-items:center}.main-image-container>.right-sub-container>.nav-right{margin-right:15px;margin-left:5px}.main-image-container>.right-sub-container>.nav-right.no-pointer{cursor:default!important}.main-image-container #current-figure{animation:fadein-visible .8s;text-align:center;margin:0;position:relative}.main-image-container #current-figure>.current-image{display:block}.main-image-container #current-figure>.current-image>img{max-width:100%;height:auto;display:block}.main-image-container #current-figure>.current-image>img.unclickable{cursor:not-allowed}.main-image-container #current-figure figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}.main-image-container #current-figure figcaption .description{font-weight:700;text-align:center}.current-image>img{height:auto;max-width:80vw;max-height:60vh;cursor:pointer}@media screen and (min-width: 70vw){.current-image>img{max-width:70vw}}@keyframes fadein-visible{0%{opacity:0}to{opacity:1}}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible08{0%{opacity:0}to{opacity:.8}}@keyframes fadein-semi-visible09{0%{opacity:0}to{opacity:.9}}\n", ".arrow-image,.right-arrow-image,.left-arrow-image,.empty-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:#000;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.left-arrow-image:hover{transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.right-arrow-image:hover{transform:scale(1.2)}\n", "@media only screen and (max-width: 1024px),only screen and (max-device-width: 1024px){.current-image-previous,.current-image-next{display:none}}@media only screen and (min-device-width: 1025px){.current-image-preview,.current-image-next,.current-image-previous{height:auto;cursor:pointer;opacity:.5;animation:fadein-semi-visible05 .8s;filter:alpha(opacity=50)}.current-image-preview:hover,.current-image-next:hover,.current-image-previous:hover{opacity:1;transition-property:opacity;transition:all .5s ease}.current-image-previous{margin-left:10px;margin-right:5px}.current-image-next{margin-right:10px;margin-left:5px}}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}\n"], dependencies: [{ kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoadingSpinnerComponent, selector: "ks-loading-spinner", inputs: ["loadingConfig", "accessibilityConfig"] }, { kind: "directive", type: SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }, { kind: "directive", type: KeyboardNavigationDirective, selector: "[ksKeyboardNavigation]", inputs: ["isOpen"], outputs: ["keyboardNavigation"] }, { kind: "directive", type: DescriptionDirective, selector: "[ksDescription]", inputs: ["description"] }, { kind: "directive", type: FallbackImageDirective, selector: "[ksFallbackImage]", inputs: ["fallbackImg"], outputs: ["fallbackApplied"] }, { kind: "directive", type: SwipeDirective, selector: "[ksSwipe]", outputs: ["swipeLeft", "swipeRight", "swipeUp", "swipeDown"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CurrentImageComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-current-image', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<main class=\"main-image-container\"\n      ksKeyboardNavigation [isOpen]=\"isOpen\" (keyboardNavigation)=\"onKeyPress($event)\"\n      [attr.aria-label]=\"accessibilityConfig?.mainContainerAriaLabel\"\n      [title]=\"accessibilityConfig?.mainContainerTitle\">\n\n  <div class=\"left-sub-container\">\n    <a class=\"nav-left {{isFirstImage ? 'no-pointer' : ''}}\"\n       [attr.aria-label]=\"accessibilityConfig?.mainPrevImageAriaLabel\"\n       [tabIndex]=\"isFirstImage ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n      <div class=\"inside {{isFirstImage ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"isFirstImage ? '' : accessibilityConfig?.mainPrevImageTitle\"></div>\n    </a>\n\n    <ng-container *ngIf=\"slideConfig?.sidePreviews?.show\">\n      <ng-container *ngIf=\"getLeftPreviewImage() as leftPreview\">\n        <img *ngIf=\"!isFirstImage; else firstImage\"\n             class=\"inside current-image-previous\"\n             [loading]=\"leftPreview.loading\"\n             [attr.fetchpriority]=\"leftPreview.fetchpriority\"\n             [src]=\"leftPreview.plain?.img ? leftPreview.plain?.img : leftPreview.modal.img\"\n             ksFallbackImage [fallbackImg]=\"leftPreview.plain?.fallbackImg ? leftPreview.plain?.fallbackImg : leftPreview.modal.fallbackImg\"\n             [hidden]=\"loading\"\n             ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\"\n             [attr.aria-label]=\"leftPreview.modal.ariaLabel\"\n             [title]=\"(leftPreview.modal.title || leftPreview.modal.title === '') ? leftPreview.modal.title : getDescriptionToDisplay(leftPreview)\"\n             alt=\"{{leftPreview.modal.alt ? leftPreview.modal.alt : getAltDescriptionByImage(leftPreview)}}\"\n             [tabIndex]=\"0\" role=\"img\"\n             (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\"/>\n        <ng-template #firstImage>\n          <div class=\"current-image-previous hidden\"\n               ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\"></div>\n        </ng-template>\n      </ng-container>\n    </ng-container>\n  </div>\n\n\n  <figure id=\"current-figure\" [style.opacity]=\"loading ? '0' : '1'\">\n    <picture class=\"current-image\">\n      <ng-container *ngFor=\"let source of currentImage.modal?.sources\">\n        <source [media]=\"source.media\" [srcset]=\"source.srcset\">\n      </ng-container>\n      <img [id]=\"currentImage.id\"\n           [loading]=\"currentImage.loading\"\n           [attr.fetchpriority]=\"currentImage.fetchpriority\"\n           class=\"inside\"\n           [ngClass]=\"currentImageConfig?.navigateOnClick ? '' : 'unclickable'\"\n           [src]=\"currentImage.modal.img\"\n           ksFallbackImage [fallbackImg]=\"currentImage.modal.fallbackImg\"\n           [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n           [title]=\"(currentImage.modal.title || currentImage.modal.title === '') ? currentImage.modal.title : getTitleToDisplay()\"\n           alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n           [tabIndex]=\"0\" role=\"img\"\n           (load)=\"onImageLoad($event)\"\n           (click)=\"onImageEvent($event, clickAction)\" (keyup)=\"onImageEvent($event, keyboardAction)\"\n           ksSwipe\n           (swipeLeft)=\"swipe('swipeleft')\"\n           (swipeRight)=\"swipe('swiperight')\"/>\n    </picture>\n    <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n                class=\"inside description\"\n                ksDescription [description]=\"currentImageConfig?.description\"\n                [innerHTML]=\"getDescriptionToDisplay()\">\n    </figcaption>\n  </figure>\n\n  <div class=\"right-sub-container\">\n    <ng-container *ngIf=\"slideConfig?.sidePreviews?.show\">\n      <ng-container *ngIf=\"getRightPreviewImage() as rightPreview\">\n        <img *ngIf=\"!isLastImage; else lastImage\"\n             class=\"inside current-image-next\"\n             [loading]=\"rightPreview.loading\"\n             [attr.fetchpriority]=\"rightPreview.fetchpriority\"\n             [src]=\"rightPreview.plain?.img ? rightPreview.plain?.img : rightPreview.modal.img\"\n             ksFallbackImage [fallbackImg]=\"rightPreview.plain?.fallbackImg ? rightPreview.plain?.fallbackImg : rightPreview.modal.fallbackImg\"\n             [hidden]=\"loading\"\n             ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\"\n             [attr.aria-label]=\"rightPreview.modal.ariaLabel\"\n             [title]=\"(rightPreview.modal.title || rightPreview.modal.title === '') ? rightPreview.modal.title : getDescriptionToDisplay(rightPreview)\"\n             alt=\"{{rightPreview.modal.alt ? rightPreview.modal.alt : getAltDescriptionByImage(rightPreview)}}\"\n             [tabIndex]=\"0\" role=\"img\"\n             (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\"/>\n        <ng-template #lastImage>\n          <div class=\"current-image-next hidden\"\n               ksSize [sizeConfig]=\"{width: slideConfig?.sidePreviews?.size.width, height: slideConfig?.sidePreviews?.size.height}\">\n          </div>\n        </ng-template>\n      </ng-container>\n    </ng-container>\n\n    <ng-container *ngIf=\"loading && currentImageConfig?.loadingConfig?.enable\">\n      <ks-loading-spinner [loadingConfig]=\"currentImageConfig?.loadingConfig\"\n                          [accessibilityConfig]=\"accessibilityConfig\"></ks-loading-spinner>\n    </ng-container>\n\n    <a class=\"nav-right {{isFirstImage ? 'no-pointer' : ''}}\"\n       [attr.aria-label]=\"accessibilityConfig?.mainNextImageAriaLabel\"\n       [tabIndex]=\"isLastImage ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n      <div class=\"inside {{isLastImage ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"isLastImage ? '' : accessibilityConfig?.mainNextImageTitle\"></div>\n    </a>\n  </div>\n</main>\n", styles: [":host{display:flex;flex-direction:column;justify-content:center}.main-image-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between}.main-image-container .nav,.main-image-container>.right-sub-container>.nav-right,.main-image-container>.left-sub-container>.nav-left{animation:animatezoom 1s;cursor:pointer;transition:all .5s}.main-image-container .nav:hover,.main-image-container>.right-sub-container>.nav-right:hover,.main-image-container>.left-sub-container>.nav-left:hover{transform:scale(1.1)}.main-image-container>.left-sub-container{display:flex;flex-direction:row;justify-content:space-around;align-items:center}.main-image-container>.left-sub-container>.nav-left{margin-right:5px;margin-left:15px}.main-image-container>.left-sub-container>.nav-left.no-pointer{cursor:default!important}.main-image-container>.right-sub-container{display:flex;flex-direction:row;justify-content:space-around;align-items:center}.main-image-container>.right-sub-container>.nav-right{margin-right:15px;margin-left:5px}.main-image-container>.right-sub-container>.nav-right.no-pointer{cursor:default!important}.main-image-container #current-figure{animation:fadein-visible .8s;text-align:center;margin:0;position:relative}.main-image-container #current-figure>.current-image{display:block}.main-image-container #current-figure>.current-image>img{max-width:100%;height:auto;display:block}.main-image-container #current-figure>.current-image>img.unclickable{cursor:not-allowed}.main-image-container #current-figure figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}.main-image-container #current-figure figcaption .description{font-weight:700;text-align:center}.current-image>img{height:auto;max-width:80vw;max-height:60vh;cursor:pointer}@media screen and (min-width: 70vw){.current-image>img{max-width:70vw}}@keyframes fadein-visible{0%{opacity:0}to{opacity:1}}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible08{0%{opacity:0}to{opacity:.8}}@keyframes fadein-semi-visible09{0%{opacity:0}to{opacity:.9}}\n", ".arrow-image,.right-arrow-image,.left-arrow-image,.empty-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:#000;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.left-arrow-image:hover{transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:all .5s}.right-arrow-image:hover{transform:scale(1.2)}\n", "@media only screen and (max-width: 1024px),only screen and (max-device-width: 1024px){.current-image-previous,.current-image-next{display:none}}@media only screen and (min-device-width: 1025px){.current-image-preview,.current-image-next,.current-image-previous{height:auto;cursor:pointer;opacity:.5;animation:fadein-semi-visible05 .8s;filter:alpha(opacity=50)}.current-image-preview:hover,.current-image-next:hover,.current-image-previous:hover{opacity:1;transition-property:opacity;transition:all .5s ease}.current-image-previous{margin-left:10px;margin-right:5px}.current-image-next{margin-right:10px;margin-left:5px}}@keyframes fadein-semi-visible05{0%{opacity:0}to{opacity:.5}}\n"] }]
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [PLATFORM_ID]
                }] }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: ConfigService }], propDecorators: { id: [{
                type: Input
            }], currentImage: [{
                type: Input
            }], images: [{
                type: Input
            }], 
        // @ts-ignore
        isOpen: [{
                type: Input
            }], loadImage: [{
                type: Output
            }], changeImage: [{
                type: Output
            }], closeGallery: [{
                type: Output
            }], onMouseEnter: [{
                type: HostListener,
                args: ['mouseenter']
            }], onMouseLeave: [{
                type: HostListener,
                args: ['mouseleave']
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to change the flex-wrap css property of an element.
 */
class WrapDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to change both width and flex-wrap css properties.
     */
    applyStyle() {
        // TODO is this right???? If wrap is false I cannot apply width and flex-wrap
        if (!this.wrap) {
            return;
        }
        this.renderer.setStyle(this.el.nativeElement, 'width', this.width);
        this.renderer.setStyle(this.el.nativeElement, 'flex-wrap', this.wrap ? 'wrap' : 'nowrap');
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: WrapDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: WrapDirective, isStandalone: false, selector: "[ksWrap]", inputs: { wrap: "wrap", width: "width" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: WrapDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksWrap]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { wrap: [{
                type: Input
            }], width: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to change the flex-direction of an element, based on two inputs (`direction` and `justify`).
 */
class DirectionDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to change both direction and justify of an element.
     */
    applyStyle() {
        if (!this.direction || !this.justify) {
            return;
        }
        this.renderer.setStyle(this.el.nativeElement, 'flex-direction', this.direction);
        this.renderer.setStyle(this.el.nativeElement, 'justify-content', this.justify);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DirectionDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: DirectionDirective, isStandalone: false, selector: "[ksDirection]", inputs: { direction: "direction", justify: "justify" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DirectionDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksDirection]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { direction: [{
                type: Input
            }], justify: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to add an image to an `<a>` tag with some additional custom properties.
 */
class ATagBgImageDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to add an image as background of an `<a>` tag.
     */
    applyStyle() {
        if (!this.image || (!this.image.plain && !this.image.modal)) {
            return;
        }
        const imgPath = this.image.plain && this.image.plain.img ? this.image.plain.img : this.image.modal.img;
        let bg = `url("${imgPath}") ${this.style}`;
        const fallbackImgPath = this.image.plain && this.image.plain.fallbackImg ? this.image.plain.fallbackImg : this.image.modal.fallbackImg;
        if (!!fallbackImgPath) {
            bg += `, url("${fallbackImgPath}") ${this.style}`;
        }
        this.renderer.setStyle(this.el.nativeElement, 'background', bg);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ATagBgImageDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: ATagBgImageDirective, isStandalone: false, selector: "[ksATagBgImage]", inputs: { image: "image", style: "style" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ATagBgImageDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksATagBgImage]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { image: [{
                type: Input
            }], style: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Component with the gallery of thumbs.
 * In receives an array of Images, a boolean to show/hide
 * the gallery (feature used by imagePointer) and a config
 * object to customize the behaviour of this component.
 * Also, it emits click events as outputs.
 */
class PlainGalleryComponent extends AccessibleComponent {
    constructor(configService) {
        super();
        this.configService = configService;
        /**
         * Array of `Image` that represent the model of this library with all images, thumbs and so on.
         */
        this.images = [];
        /**
         * Output to emit an event when an image is clicked.
         */
        this.clickImage = new EventEmitter();
        /**
         * Bi-dimensional array of `Image` object to store images to display as plain gallery.
         * [] by default.
         */
        this.imageGrid = [];
        /**
         * Boolean passed as input to `ks-wrap` directive to configure flex-wrap css property.
         * However it's not enough, because you need to limit the width using `widthStyle` public variable.
         * For more info check https://developer.mozilla.org/it/docs/Web/CSS/flex-wrap
         */
        this.wrapStyle = false;
        /**
         * String passed as input to `ks-wrap` directive to set width to be able to force overflow.
         * In this way, `wrapStyle` (flex-wrap css property) will be used as requested.
         */
        this.widthStyle = '';
    }
    /**
     * Method ´ngOnInit´ to init both `configPlainGallery` calling `initPlainGalleryConfig()`
     * and `imageGrid invoking `initImageGrid()`.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        this.configService.setConfig(this.id, this.config);
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        this.accessibilityConfig = libConfig.accessibilityConfig;
        this.plainGalleryConfig = libConfig.plainGalleryConfig;
        this.initImageGrid();
    }
    /**
     * Method ´ngOnChanges´ to update both `imageGrid` and`plainGalleryConfig`.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges(changes) {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        const imagesChange = changes.images;
        const configChange = changes.config;
        // I'm using !change.firstChange because the first time will be called both onInit and onChange and I don't
        // want to execute initialization two times.
        if (configChange &&
            !configChange.firstChange &&
            (configChange.previousValue !== configChange.currentValue || (!configChange.previousValue && !configChange.currentValue))) {
            this.plainGalleryConfig = libConfig.plainGalleryConfig;
            // this.configPlainGallery = this.initPlainGalleryConfig();
        }
        if (imagesChange && !imagesChange.firstChange && imagesChange.previousValue !== imagesChange.currentValue) {
            this.initImageGrid();
        }
    }
    /**
     * Method called when you click on an image of the plain (or inline) gallery.
     * This will emit the show event with the image as payload.
     * @param Image img is the Image to show
     */
    showModalGalleryByImage(img) {
        const index = this.images.findIndex((val) => val && img && val.id === img.id);
        this.showModalGallery(index);
    }
    /**
     * Method called when you navigate between images.
     * This will emit the show event with the image as payload.
     * @param KeyboardEvent event that triggered the navigation
     * @param Image img is the Image to show
     */
    onNavigationEvent(event, img) {
        const result = super.handleImageEvent(event);
        if (result === NEXT) {
            this.showModalGalleryByImage(img);
        }
    }
    /**
     * Method to get `alt attribute`.
     * `alt` specifies an alternate text for an image, if the image cannot be displayed.
     * @param Image image to get its alt description.
     * @returns string alt description of the image
     */
    getAltPlainDescriptionByImage(image) {
        if (!image) {
            return '';
        }
        return image.plain && image.plain.description ? image.plain.description : `Image ${getIndex(image, this.images) + 1}`;
    }
    /**
     * Method to get the title for an image.
     * @param Image image to get its title
     * @returns string the title of the input image
     */
    getTitleDisplay(image) {
        let description = '';
        if (image.plain && image.plain.description) {
            description = image.plain.description;
        }
        else if (image.modal && image.modal.description) {
            description = image.modal.description;
        }
        const currentIndex = getIndex(image, this.images);
        const prevDescription = 'Image ' + (currentIndex + 1) + '/' + this.images.length;
        let currImgDescription = description ? description : '';
        if (currImgDescription !== '') {
            currImgDescription = ' - ' + currImgDescription;
        }
        return prevDescription + currImgDescription;
    }
    /**
     * Method used in the template to track ids in ngFor.
     * @param number index of the array
     * @param Image item of the array
     * @returns number the id of the item
     */
    trackById(index, item) {
        return item.id;
    }
    /**
     * Method called when you click on an image of the plain (or inline) gallery.
     * This will emit the show event with the index number as payload.
     * @param number index of the clicked image
     */
    showModalGallery(index) {
        this.clickImage.emit(index);
    }
    /**
     * Private method to init both `imageGrid` and other style variables,
     * based on the layout type.
     */
    initImageGrid() {
        if (!this.plainGalleryConfig) {
            throw new Error('Internal library error - plainGalleryConfig must be defined');
        }
        // reset the array to prevent issues in case of GridLayout
        this.imageGrid = [];
        if (this.plainGalleryConfig.layout instanceof LineLayout) {
            const layout = this.plainGalleryConfig.layout;
            const row = this.images.filter((val, i) => i < layout.breakConfig.length || layout.breakConfig.length === -1);
            this.imageGrid = [row];
            this.size = this.plainGalleryConfig.layout.size;
            switch (this.plainGalleryConfig.strategy) {
                case PlainGalleryStrategy.ROW:
                    this.directionStyle = 'row';
                    break;
                case PlainGalleryStrategy.COLUMN:
                    this.directionStyle = 'column';
                    this.wrapStyle = layout.breakConfig.wrap;
                    break;
            }
            this.justifyStyle = layout.justify;
        }
        if (this.plainGalleryConfig.layout instanceof GridLayout) {
            const layout = this.plainGalleryConfig.layout;
            const count = Math.ceil(this.images.length / layout.breakConfig.length);
            let start = 0;
            let end = layout.breakConfig.length - 1;
            for (let j = 0; j < count; j++) {
                const row = this.images.filter((val, i) => i >= start && i <= end);
                this.imageGrid.push(row);
                start = end + 1;
                end = start + layout.breakConfig.length - 1;
            }
            this.size = this.plainGalleryConfig.layout.size;
            const pixels = +layout.size.width.replace('px', '');
            this.widthStyle = pixels * layout.breakConfig.length + pixels / 2 + 'px';
            this.wrapStyle = layout.breakConfig.wrap;
            this.directionStyle = 'row';
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: PlainGalleryComponent, deps: [{ token: ConfigService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: PlainGalleryComponent, isStandalone: false, selector: "ks-plain-gallery", inputs: { id: "id", images: "images", config: "config" }, outputs: { clickImage: "clickImage" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"plain-container\"\n     ksWrap [wrap]=\"wrapStyle\" [width]=\"widthStyle\"\n     ksDirection [direction]=\"directionStyle\" [justify]=\"justifyStyle\"\n     [attr.aria-label]=\"accessibilityConfig?.plainGalleryContentAriaLabel\"\n     [title]=\"accessibilityConfig?.plainGalleryContentTitle\">\n\n  <ng-container *ngFor=\"let imgRow of imageGrid; let i = index\">\n    <ng-container *ngFor=\"let imgCol of imgRow; let j = index\">\n\n      <ng-container *ngIf=\"!plainGalleryConfig?.advanced?.aTags; else aTags\">\n        <img *ngIf=\"imgCol?.modal?.img\"\n             [loading]=\"imgCol.loading\"\n             [attr.fetchpriority]=\"imgCol.fetchpriority\"\n             [src]=\"imgCol.plain?.img! ? imgCol.plain?.img! : imgCol.modal.img\"\n             ksFallbackImage [fallbackImg]=\"imgCol.plain?.fallbackImg ? imgCol.plain?.fallbackImg : imgCol.modal.fallbackImg\"\n             class=\"image\"\n             ksSize [sizeConfig]=\"{width: size?.width!, height: size?.height!}\"\n             [attr.aria-label]=\"imgCol.plain?.ariaLabel\"\n             [title]=\"(imgCol.plain?.title || imgCol.plain?.title === '') ? imgCol.plain?.title : getTitleDisplay(imgCol)\"\n             alt=\"{{imgCol.plain?.alt! ? imgCol.plain?.alt! : getAltPlainDescriptionByImage(imgCol)}}\"\n             [tabIndex]=\"0\" role=\"img\"\n             (click)=\"showModalGalleryByImage(imgCol)\" (keyup)=\"onNavigationEvent($event, imgCol)\"/>\n      </ng-container>\n\n      <!-- Add directive to set background with the image url as param to pass thumb or img-->\n      <!-- to do something like this <a style=\"background: url('path to image') 50% 50%/cover\">.-->\n      <ng-template #aTags>\n        <a *ngIf=\"imgCol?.modal?.img\"\n           class=\"a-tag-image\"\n           ksATagBgImage [image]=\"imgCol\" [style]=\"plainGalleryConfig?.advanced?.additionalBackground\"\n           ksSize [sizeConfig]=\"{width: size?.width!, height: size?.height!}\"\n           [attr.aria-label]=\"imgCol.plain?.ariaLabel\"\n           [title]=\"(imgCol.plain?.title || imgCol.plain?.title === '') ? imgCol.plain?.title : getTitleDisplay(imgCol)\"\n           [tabIndex]=\"0\"\n           (click)=\"showModalGalleryByImage(imgCol)\" (keyup)=\"onNavigationEvent($event, imgCol)\"></a>\n      </ng-template>\n\n    </ng-container>\n  </ng-container>\n\n</div>\n\n", styles: [".plain-container{align-items:center;display:flex}.plain-container .image{cursor:pointer;height:auto;margin:2px;width:50px}.plain-container .a-tag-image{cursor:pointer;margin:2px}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: SizeDirective, selector: "[ksSize]", inputs: ["sizeConfig"] }, { kind: "directive", type: WrapDirective, selector: "[ksWrap]", inputs: ["wrap", "width"] }, { kind: "directive", type: DirectionDirective, selector: "[ksDirection]", inputs: ["direction", "justify"] }, { kind: "directive", type: ATagBgImageDirective, selector: "[ksATagBgImage]", inputs: ["image", "style"] }, { kind: "directive", type: FallbackImageDirective, selector: "[ksFallbackImage]", inputs: ["fallbackImg"], outputs: ["fallbackApplied"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: PlainGalleryComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-plain-gallery', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div class=\"plain-container\"\n     ksWrap [wrap]=\"wrapStyle\" [width]=\"widthStyle\"\n     ksDirection [direction]=\"directionStyle\" [justify]=\"justifyStyle\"\n     [attr.aria-label]=\"accessibilityConfig?.plainGalleryContentAriaLabel\"\n     [title]=\"accessibilityConfig?.plainGalleryContentTitle\">\n\n  <ng-container *ngFor=\"let imgRow of imageGrid; let i = index\">\n    <ng-container *ngFor=\"let imgCol of imgRow; let j = index\">\n\n      <ng-container *ngIf=\"!plainGalleryConfig?.advanced?.aTags; else aTags\">\n        <img *ngIf=\"imgCol?.modal?.img\"\n             [loading]=\"imgCol.loading\"\n             [attr.fetchpriority]=\"imgCol.fetchpriority\"\n             [src]=\"imgCol.plain?.img! ? imgCol.plain?.img! : imgCol.modal.img\"\n             ksFallbackImage [fallbackImg]=\"imgCol.plain?.fallbackImg ? imgCol.plain?.fallbackImg : imgCol.modal.fallbackImg\"\n             class=\"image\"\n             ksSize [sizeConfig]=\"{width: size?.width!, height: size?.height!}\"\n             [attr.aria-label]=\"imgCol.plain?.ariaLabel\"\n             [title]=\"(imgCol.plain?.title || imgCol.plain?.title === '') ? imgCol.plain?.title : getTitleDisplay(imgCol)\"\n             alt=\"{{imgCol.plain?.alt! ? imgCol.plain?.alt! : getAltPlainDescriptionByImage(imgCol)}}\"\n             [tabIndex]=\"0\" role=\"img\"\n             (click)=\"showModalGalleryByImage(imgCol)\" (keyup)=\"onNavigationEvent($event, imgCol)\"/>\n      </ng-container>\n\n      <!-- Add directive to set background with the image url as param to pass thumb or img-->\n      <!-- to do something like this <a style=\"background: url('path to image') 50% 50%/cover\">.-->\n      <ng-template #aTags>\n        <a *ngIf=\"imgCol?.modal?.img\"\n           class=\"a-tag-image\"\n           ksATagBgImage [image]=\"imgCol\" [style]=\"plainGalleryConfig?.advanced?.additionalBackground\"\n           ksSize [sizeConfig]=\"{width: size?.width!, height: size?.height!}\"\n           [attr.aria-label]=\"imgCol.plain?.ariaLabel\"\n           [title]=\"(imgCol.plain?.title || imgCol.plain?.title === '') ? imgCol.plain?.title : getTitleDisplay(imgCol)\"\n           [tabIndex]=\"0\"\n           (click)=\"showModalGalleryByImage(imgCol)\" (keyup)=\"onNavigationEvent($event, imgCol)\"></a>\n      </ng-template>\n\n    </ng-container>\n  </ng-container>\n\n</div>\n\n", styles: [".plain-container{align-items:center;display:flex}.plain-container .image{cursor:pointer;height:auto;margin:2px;width:50px}.plain-container .a-tag-image{cursor:pointer;margin:2px}\n"] }]
        }], ctorParameters: () => [{ type: ConfigService }], propDecorators: { id: [{
                type: Input
            }], images: [{
                type: Input
            }], config: [{
                type: Input
            }], clickImage: [{
                type: Output
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
const DIALOG_DATA = new InjectionToken('DIALOG_DATA');

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Service to check if the provided id is unique
 */
class IdValidatorService {
    constructor() {
        this.ids = new Map();
    }
    /**
     * Method to check and reserve an id for the current instance of the library.
     * In this way, no other instances can use the same id.
     * @param galleryId number or undefined that represents the unique id of the gallery.
     * @return boolean true if success. false is never returned, instead an exception is thrown
     * @throws a error with a message if galleryId is neither unique, < 0 or an integer
     */
    checkAndAdd(galleryId) {
        if (galleryId === undefined || !Number.isInteger(galleryId) || galleryId < 0) {
            throw new Error('You must provide a valid [id]="unique integer > 0 here" to the gallery/carousel in your template');
        }
        if (this.ids.get(galleryId)) {
            throw new Error(`Cannot create gallery with id=${galleryId} because already used in your application. This must be a unique integer >= 0`);
        }
        this.ids.set(galleryId, galleryId);
        return true;
    }
    /**
     * Method to remove a reserved id. In this way you are able to use the id again for another instance of the library.
     * @param galleryId number or undefined that represents the unique id of the gallery.
     * @return boolean true if success. false is never returned, instead an exception is thrown*
     * @throws a error with a message if galleryId is neither integer or < 0
     * * this should be improved without return true, because it doesn't make sense! :(
     */
    remove(galleryId) {
        if (galleryId === undefined || !Number.isInteger(galleryId) || galleryId < 0) {
            throw new Error('You must provide a valid [id]="unique integer > 0 here" to the gallery/carousel in your template');
        }
        this.ids.delete(galleryId);
        return true;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: IdValidatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: IdValidatorService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: IdValidatorService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to close the modal gallery clicking on the semi-transparent background.
 * In fact, it listens for a click on all elements that aren't 'inside' and it emits
 * an event using `@Output clickOutside`.
 */
class ClickOutsideDirective {
    constructor() {
        /**
         * Output to emit an event if the clicked element class doesn't contain 'inside' or it is 'hidden'. The payload is a boolean.
         */
        this.clickOutside = new EventEmitter();
    }
    /**
     * Method called by Angular itself every click thanks to `@HostListener`.
     * @param event MouseEvent
     */
    onClick(event) {
        event.stopPropagation();
        // tslint:disable-next-line:no-any
        const target = event.target;
        if (!this.clickOutsideEnable || !target) {
            return;
        }
        let isInside = false;
        let isHidden = false;
        if (typeof target.className !== 'string') {
            // it happens with @fortawesome/fontawesome 5
            // for some reasons className is an object with 2 empty properties inside
            isInside = true;
        }
        else {
            // in normal scenarios, use classname, because it's a simple string
            isInside = target.className && target.className.includes('inside');
            isHidden = target.className.includes('hidden');
        }
        // if inside => don't close modal gallery
        // if hidden => close modal gallery
        /*
            i i' h | close
            0 1  0 |   1 => close modal gallery
            0 1  1 |   1 => close modal gallery
            1 0  0 |   0
            1 0  1 |   1 => close modal gallery
         */
        if (!isInside || isHidden) {
            // close modal gallery
            this.clickOutside.emit(true);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ClickOutsideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: ClickOutsideDirective, isStandalone: false, selector: "[ksClickOutside]", inputs: { clickOutsideEnable: "clickOutsideEnable" }, outputs: { clickOutside: "clickOutside" }, host: { listeners: { "click": "onClick($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ClickOutsideDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksClickOutside]',
                    standalone: false
                }]
        }], propDecorators: { clickOutsideEnable: [{
                type: Input
            }], clickOutside: [{
                type: Output
            }], onClick: [{
                type: HostListener,
                args: ['click', ['$event']]
            }] } });

class ModalGalleryComponent {
    /**
     * HostListener to catch browser's back button and destroy the gallery.
     * This prevents weired behaviour about scrolling.
     * Added to fix this issue: https://github.com/Ks89/angular-modal-gallery/issues/159
     */
    onPopState() {
        this.closeGallery();
    }
    /**
     * HostListener to catch ctrl+s/meta+s and download the current image.
     * Inspired by https://netbasal.com/add-keyboard-shortcuts-to-your-angular-app-9bf2e89862b3
     */
    onSaveListener(event) {
        event.preventDefault();
        this.downloadImage();
    }
    constructor(dialogContent, modalGalleryService, 
    // tslint:disable-next-line:ban-types
    platformId, changeDetectorRef, idValidatorService, configService, sanitizer) {
        this.dialogContent = dialogContent;
        this.modalGalleryService = modalGalleryService;
        this.platformId = platformId;
        this.changeDetectorRef = changeDetectorRef;
        this.idValidatorService = idValidatorService;
        this.configService = configService;
        this.sanitizer = sanitizer;
        /**
         * Boolean to enable modal-gallery close behaviour when clicking
         * on the semi-transparent background. Enabled by default.
         */
        this.enableCloseOutside = true;
        /**
         * Object of type `AccessibilityConfig` to init custom accessibility features.
         * For instance, it contains titles, alt texts, aria-labels and so on.
         */
        this.accessibilityConfig = KS_DEFAULT_ACCESSIBILITY_CONFIG;
        /**
         * Boolean to open the modal gallery. False by default.
         */
        this.showGallery = false;
        this.id = this.dialogContent.id;
        this.images = this.dialogContent.images;
        this.currentImage = this.dialogContent.currentImage;
        this.libConfig = this.dialogContent.libConfig;
        this.customPreviewsTemplate = this.dialogContent.previewsTemplate;
        this.configService.setConfig(this.id, this.libConfig);
        this.updateImagesSubscription = this.modalGalleryService.updateImages$.subscribe((images) => {
            this.images = images.map((image) => {
                const newImage = Object.assign({}, image, { previouslyLoaded: false });
                return newImage;
            });
            this.initImages();
            this.images.forEach((image) => {
                if (image.id === this.currentImage.id) {
                    this.currentImage = image;
                }
            });
            this.changeDetectorRef.markForCheck();
        });
    }
    /**
     * Method ´ngOnInit´ to init images calling `initImages()`.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.idValidatorService.checkAndAdd(this.id);
        // id is a mandatory input and must a number > 0
        if ((!this.id && this.id !== 0) || this.id < 0) {
            throw new Error(`'[id]="a number >= 0"' is a mandatory input in angular-modal-gallery.` +
                `If you are using multiple instances of this library, please be sure to use different ids`);
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig || !libConfig.dotsConfig) {
            throw new Error('Internal library error - libConfig and dotsConfig must be defined');
        }
        this.dotsConfig = libConfig.dotsConfig;
        setTimeout(() => {
            this.initImages();
        }, 0);
    }
    /**
     * Method called by custom upper buttons.
     * @param event ButtonEvent event payload
     */
    onCustomEmit(event) {
        const eventToEmit = this.getButtonEventToEmit(event);
        this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
        this.modalGalleryService.emitButtonAfterHook(eventToEmit);
    }
    /**
     * Method called by the full-screen upper button.
     * @param event ButtonEvent event payload
     */
    onFullScreen(event) {
        const eventToEmit = this.getButtonEventToEmit(event);
        this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
        // tslint:disable-next-line:no-any
        const doc = document;
        // tslint:disable-next-line:no-any
        const docEl = document.documentElement;
        const fullscreenDisabled = !doc.fullscreenElement && !doc.webkitFullscreenElement;
        // In Safari `requestFullscreen` and `exitFullscreen` are undefined. Safari requires the prefixed version `webkit-`
        // and it doesn't return promises.
        // I cannot call `emitButtonAfterHook` only if requestFullScreen is successful, because there are no guarantees across browsers and
        // I should also handle the case with keyboard "esc" button.
        if (fullscreenDisabled) {
            if (docEl.requestFullscreen) {
                docEl.requestFullscreen()
                    .then(() => {
                })
                    .catch(() => {
                    console.error('Cannot request full screen');
                });
            }
            else if (docEl.webkitRequestFullscreen) {
                // For Safari and it doesn't return a promise
                docEl.webkitRequestFullscreen();
            }
        }
        else {
            if (doc.exitFullscreen) {
                doc.exitFullscreen()
                    .then(() => {
                })
                    .catch(() => {
                    console.error('Cannot request exit full screen');
                });
            }
            else if (doc.webkitExitFullscreen) {
                // For Safari and it doesn't return a promise
                doc.webkitExitFullscreen();
            }
        }
        this.modalGalleryService.emitButtonAfterHook(eventToEmit);
    }
    /**
     * Method called by the delete upper button.
     * @param event ButtonEvent event payload
     */
    onDelete(event) {
        const eventToEmit = this.getButtonEventToEmit(event);
        this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
        if (this.images.length === 1) {
            this.closeGallery();
        }
        if (!this.currentImageComponent) {
            throw new Error('currentImageComponent must be defined');
        }
        const imageIndexToDelete = this.currentImageComponent.getIndexToDelete(event.image);
        if (imageIndexToDelete === this.images.length - 1) {
            // last image
            this.currentImageComponent.prevImage();
        }
        else {
            this.currentImageComponent.nextImage();
        }
        this.modalGalleryService.emitButtonAfterHook(eventToEmit);
    }
    /**
     * Method called by the navigate upper button.
     * @param event ButtonEvent event payload
     */
    onNavigate(event) {
        const eventToEmit = this.getButtonEventToEmit(event);
        this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
        // To support SSR
        if (isPlatformBrowser(this.platformId)) {
            if (eventToEmit.image && eventToEmit.image.modal.extUrl) {
                // where I should open this link? The current tab or another one?
                if (eventToEmit.button && eventToEmit.button.extUrlInNewTab) {
                    // in this case I should use target _blank to open the url in a new tab, however these is a security issue.
                    // Prevent Reverse Tabnabbing's attacks (https://www.owasp.org/index.php/Reverse_Tabnabbing)
                    // Some resources:
                    // - https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Tabnabbing
                    // - https://medium.com/@jitbit/target-blank-the-most-underestimated-vulnerability-ever-96e328301f4c
                    // - https://developer.mozilla.org/en-US/docs/Web/API/Window/open
                    const newWindow = window.open(eventToEmit.image.modal.extUrl, 'noopener,noreferrer,');
                    // it returns null if the call failed, so I have to do this check
                    if (newWindow) {
                        newWindow.opener = null; // required to prevent security issues
                        // emit only in case of success
                        this.modalGalleryService.emitButtonAfterHook(eventToEmit);
                    }
                }
                else {
                    this.updateLocationHref(eventToEmit.image.modal.extUrl);
                    // emit only in case of success
                    this.modalGalleryService.emitButtonAfterHook(eventToEmit);
                }
            }
        }
    }
    /**
     * This method is defined to be spied and replaced in unit testing with a fake method call.
     * It must be public to be able to use jasmine spyOn method.
     * @param newHref string new url
     */
    updateLocationHref(newHref) {
        window.location.href = newHref;
    }
    /**
     * Method called by the download upper button.
     * @param event ButtonEvent event payload
     */
    onDownload(event) {
        const eventToEmit = this.getButtonEventToEmit(event);
        this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
        this.downloadImage();
        this.modalGalleryService.emitButtonAfterHook(eventToEmit);
    }
    /**
     * Method called by the close upper button.
     * @param event ButtonEvent event payload
     * @param action Action that triggered the close method. `Action.NORMAL` by default
     */
    onCloseGalleryButton(event, action = Action.NORMAL) {
        const eventToEmit = this.getButtonEventToEmit(event);
        this.modalGalleryService.emitButtonBeforeHook(eventToEmit);
        this.closeGallery(action, false);
    }
    /**
     * Method called by CurrentImageComponent.
     * @param event ImageModalEvent event payload
     * @param action Action that triggered the close method. `Action.NORMAL` by default
     */
    onCloseGallery(event, action = Action.NORMAL) {
        // remap ImageModalEvent to ButtonEvent
        const buttonEvent = {
            button: {
                type: ButtonType.CLOSE
            },
            image: null,
            action: event.action,
            galleryId: event.galleryId
        };
        this.modalGalleryService.emitButtonBeforeHook(buttonEvent);
        this.closeGallery(action, false);
    }
    /**
     * Method to close the modal gallery specifying the action.
     * @param action Action action type. `Action.NORMAL` by default
     * @param clickOutside boolean that is true if called clicking on the modal background. False by default.
     */
    closeGallery(action = Action.NORMAL, clickOutside = false) {
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        this.modalGalleryService.emitClose(new ImageModalEvent(this.id, action, true));
        this.modalGalleryService.close(this.id, clickOutside);
    }
    /**
     * Method called when the image changes and used to update the `currentImage` object.
     * @param event ImageModalEvent event payload
     */
    onChangeCurrentImage(event) {
        const newIndex = event.result;
        if (newIndex < 0 || newIndex >= this.images.length) {
            return;
        }
        this.currentImage = this.images[newIndex];
        // emit current visible image index
        this.modalGalleryService.emitShow(new ImageModalEvent(this.id, event.action, newIndex + 1));
        // emit first/last event based on newIndex value
        this.emitBoundaryEvent(event.action, newIndex);
    }
    /**
     * Method called when you click 'outside' (i.e. on the semi-transparent background)
     * to close the modal gallery if `enableCloseOutside` is true.
     * @param event boolean that is true to close the modal gallery, false otherwise
     */
    onClickOutside(event) {
        if (event && this.enableCloseOutside) {
            this.closeGallery(Action.CLICK, true);
        }
    }
    /**
     * Method called when an image is loaded and the loading spinner has gone.
     * It sets the previouslyLoaded flag inside the Image to hide loading spinner when displayed again.
     * @param event ImageLoadEvent event payload
     */
    onImageLoad(event) {
        // sets as previously loaded the image with index specified by `event.status`
        this.images = this.images.map((img) => {
            if (img && img.id === event.id) {
                return Object.assign({}, img, { previouslyLoaded: event.status });
            }
            return img;
        });
    }
    /**
     * Method called when a dot is clicked and used to update the current image.
     * @param index number index of the clicked dot
     */
    onClickDot(index) {
        this.currentImage = this.images[index];
    }
    /**
     * Method called when an image preview is clicked and used to update the current image.
     * @param event ImageModalEvent preview image
     */
    onClickPreview(event) {
        this.onChangeCurrentImage(event);
    }
    /**
     * Method to cleanup resources.
     * This is an angular lifecycle hook that is called when this component is destroyed.
     */
    ngOnDestroy() {
        if (this.updateImagesSubscription) {
            this.updateImagesSubscription.unsubscribe();
        }
        this.idValidatorService.remove(this.id);
    }
    /**
     * Method to download the current image, only if `downloadable` is true.
     * @private
     */
    downloadImage() {
        if (this.id === null || this.id === undefined) {
            throw new Error('Internal library error - id must be defined');
        }
        const libConfig = this.configService.getConfig(this.id);
        if (!libConfig) {
            throw new Error('Internal library error - libConfig must be defined');
        }
        const currentImageConfig = libConfig.currentImageConfig;
        if (currentImageConfig && !currentImageConfig.downloadable) {
            return;
        }
        this.downloadImageAllBrowsers();
    }
    /**
     * Method to convert a base64 to a Blob
     * @param base64Data string with base64 data
     * @param contentType string with the MIME type
     * @return Blob converted from the input base64Data
     * @private
     */
    base64toBlob(base64Data, contentType = '') {
        const sliceSize = 1024;
        const byteCharacters = atob(base64Data);
        const bytesLength = byteCharacters.length;
        const slicesCount = Math.ceil(bytesLength / sliceSize);
        const byteArrays = new Array(slicesCount);
        for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
            const begin = sliceIndex * sliceSize;
            const end = Math.min(begin + sliceSize, bytesLength);
            const bytes = new Array(end - begin);
            for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
                bytes[i] = byteCharacters[offset].charCodeAt(0);
            }
            byteArrays[sliceIndex] = new Uint8Array(bytes);
        }
        return new Blob(byteArrays, { type: contentType });
    }
    /**
     * Private method to download the current image for all browsers.
     * @private
     */
    downloadImageAllBrowsers() {
        const link = document.createElement('a');
        let isBase64 = false;
        let img;
        // convert a SafeResourceUrl to a string
        if (typeof this.currentImage.modal.img === 'string') {
            img = this.currentImage.modal.img;
        }
        else {
            // if it's a SafeResourceUrl
            img = this.sanitizer.sanitize(SecurityContext.RESOURCE_URL, this.currentImage.modal.img);
        }
        if (img.includes('data:image/') || img.includes(';base64,')) {
            const extension = img.replace('data:image/', '').split(';base64,')[0];
            const pureBase64 = img.split(';base64,')[1];
            const blob = this.base64toBlob(pureBase64, 'image/' + extension);
            link.href = URL.createObjectURL(blob);
            isBase64 = true;
            link.setAttribute('download', this.getFileName(this.currentImage, isBase64, extension));
        }
        else {
            link.href = img;
            link.setAttribute('download', this.getFileName(this.currentImage, isBase64));
        }
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
    /**
     * Private method to get the `ButtonEvent` to emit, merging the input `ButtonEvent`
     * with the current image.
     * @param event ButtonEvent event payload to return
     * @returns ButtonEvent event payload with the current image included
     * @private
     */
    getButtonEventToEmit(event) {
        return Object.assign(event, { image: this.currentImage });
    }
    /**
     * Private method to get the file name from an input path.
     * This is used either to get the image's name from its path or from the Image itself,
     * if specified as 'downloadFileName' by the user.
     * @param image Image image to extract its file name
     * @param isBase64 boolean to set if the image is a base64 file or not. False by default.
     * @param base64Extension string to force the extension of the base64 image. Empty string by default.
     * @returns string string file name of the input image.
     * @private
     */
    getFileName(image, isBase64 = false, base64Extension = '') {
        if (!image.modal.downloadFileName || image.modal.downloadFileName.length === 0) {
            if (isBase64) {
                return `Image-${image.id}.${base64Extension !== '' ? base64Extension : 'png'}`;
            }
            else {
                return image.modal.img.replace(/^.*[\\\/]/, '');
            }
        }
        else {
            return image.modal.downloadFileName;
        }
    }
    /**
     * Private method to initialize `images` as array of `Image`s.
     * Also, it will emit ImageModalEvent to say that images are loaded.
     * @private
     */
    initImages() {
        this.modalGalleryService.emitHasData(new ImageModalEvent(this.id, Action.LOAD, true));
        const currentIndex = this.images.indexOf(this.currentImage);
        // emit a new ImageModalEvent with the index of the current image
        this.modalGalleryService.emitShow(new ImageModalEvent(this.id, Action.LOAD, currentIndex + 1));
        // emit first/last event based on newIndex value
        this.emitBoundaryEvent(Action.NORMAL, currentIndex);
        this.showGallery = this.images.length > 0;
    }
    /**
     * Private method to emit events when either the last or the first image are visible.
     * @param action Action Enum of type Action that represents the source of the event that changed the
     *  current image to the first one or the last one.
     * @param indexToCheck number is the index number of the image (the first or the last one).
     * @private
     */
    emitBoundaryEvent(action, indexToCheck) {
        // to emit first/last event
        switch (indexToCheck) {
            case 0:
                this.modalGalleryService.emitFirstImage(new ImageModalEvent(this.id, action, true));
                break;
            case this.images.length - 1:
                this.modalGalleryService.emitLastImage(new ImageModalEvent(this.id, action, true));
                break;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ModalGalleryComponent, deps: [{ token: DIALOG_DATA }, { token: ModalGalleryService }, { token: PLATFORM_ID }, { token: i0.ChangeDetectorRef }, { token: IdValidatorService }, { token: ConfigService }, { token: i2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: ModalGalleryComponent, isStandalone: false, selector: "ks-modal-gallery", host: { listeners: { "window:popstate": "onPopState()", "document:keydown.code.control.keyS": "onSaveListener($event)", "document:keydown.code.meta.keyS": "onSaveListener($event)" } }, viewQueries: [{ propertyName: "currentImageComponent", first: true, predicate: CurrentImageComponent, descendants: true, static: true }], ngImport: i0, template: "<div id=\"modal-gallery-wrapper\"\n     [attr.aria-label]=\"accessibilityConfig.modalGalleryContentAriaLabel\"\n     [title]=\"accessibilityConfig.modalGalleryContentTitle\"\n     ksClickOutside [clickOutsideEnable]=\"enableCloseOutside\"\n     (clickOutside)=\"onClickOutside($event)\">\n\n  <div id=\"flex-min-height-ie-fix\">\n    <div id=\"modal-gallery-container\">\n\n      <ks-upper-buttons [id]=\"id\"\n                        [currentImage]=\"currentImage\"\n                        (delete)=\"onDelete($event)\"\n                        (navigate)=\"onNavigate($event)\"\n                        (download)=\"onDownload($event)\"\n                        (closeButton)=\"onCloseGalleryButton($event)\"\n                        (fullscreen)=\"onFullScreen($event)\"\n                        (customEmit)=\"onCustomEmit($event)\"></ks-upper-buttons>\n\n      <ks-current-image [id]=\"id\"\n                        [images]=\"images\"\n                        [currentImage]=\"currentImage\"\n                        [isOpen]=\"true\"\n                        (loadImage)=\"onImageLoad($event)\"\n                        (changeImage)=\"onChangeCurrentImage($event)\"\n                        (closeGallery)=\"onCloseGallery($event)\"></ks-current-image>\n\n      <div>\n        <ks-dots [id]=\"id\"\n                 [images]=\"images\"\n                 [currentImage]=\"currentImage\"\n                 [dotsConfig]=\"dotsConfig\"\n                 (clickDot)=\"onClickDot($event)\"></ks-dots>\n\n        <ks-previews [id]=\"id\"\n                     [images]=\"images\"\n                     [currentImage]=\"currentImage\"\n                     [customTemplate]=\"customPreviewsTemplate\"\n                     (clickPreview)=\"onClickPreview($event)\"></ks-previews>\n      </div>\n    </div>\n  </div>\n</div>\n", styles: ["#flex-min-height-ie-fix{display:flex;flex-direction:column;justify-content:center}#modal-gallery-container{display:flex;flex-direction:column;justify-content:space-between;min-width:100vw;min-height:100vh}\n"], dependencies: [{ kind: "component", type: UpperButtonsComponent, selector: "ks-upper-buttons", inputs: ["id", "currentImage"], outputs: ["refresh", "delete", "navigate", "download", "closeButton", "fullscreen", "customEmit"] }, { kind: "component", type: DotsComponent, selector: "ks-dots", inputs: ["id", "currentImage", "images", "dotsConfig"], outputs: ["clickDot"] }, { kind: "component", type: PreviewsComponent, selector: "ks-previews", inputs: ["id", "currentImage", "images", "customTemplate"], outputs: ["clickPreview"] }, { kind: "component", type: CurrentImageComponent, selector: "ks-current-image", inputs: ["id", "currentImage", "images", "isOpen"], outputs: ["loadImage", "changeImage", "closeGallery"] }, { kind: "directive", type: ClickOutsideDirective, selector: "[ksClickOutside]", inputs: ["clickOutsideEnable"], outputs: ["clickOutside"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ModalGalleryComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ks-modal-gallery', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div id=\"modal-gallery-wrapper\"\n     [attr.aria-label]=\"accessibilityConfig.modalGalleryContentAriaLabel\"\n     [title]=\"accessibilityConfig.modalGalleryContentTitle\"\n     ksClickOutside [clickOutsideEnable]=\"enableCloseOutside\"\n     (clickOutside)=\"onClickOutside($event)\">\n\n  <div id=\"flex-min-height-ie-fix\">\n    <div id=\"modal-gallery-container\">\n\n      <ks-upper-buttons [id]=\"id\"\n                        [currentImage]=\"currentImage\"\n                        (delete)=\"onDelete($event)\"\n                        (navigate)=\"onNavigate($event)\"\n                        (download)=\"onDownload($event)\"\n                        (closeButton)=\"onCloseGalleryButton($event)\"\n                        (fullscreen)=\"onFullScreen($event)\"\n                        (customEmit)=\"onCustomEmit($event)\"></ks-upper-buttons>\n\n      <ks-current-image [id]=\"id\"\n                        [images]=\"images\"\n                        [currentImage]=\"currentImage\"\n                        [isOpen]=\"true\"\n                        (loadImage)=\"onImageLoad($event)\"\n                        (changeImage)=\"onChangeCurrentImage($event)\"\n                        (closeGallery)=\"onCloseGallery($event)\"></ks-current-image>\n\n      <div>\n        <ks-dots [id]=\"id\"\n                 [images]=\"images\"\n                 [currentImage]=\"currentImage\"\n                 [dotsConfig]=\"dotsConfig\"\n                 (clickDot)=\"onClickDot($event)\"></ks-dots>\n\n        <ks-previews [id]=\"id\"\n                     [images]=\"images\"\n                     [currentImage]=\"currentImage\"\n                     [customTemplate]=\"customPreviewsTemplate\"\n                     (clickPreview)=\"onClickPreview($event)\"></ks-previews>\n      </div>\n    </div>\n  </div>\n</div>\n", styles: ["#flex-min-height-ie-fix{display:flex;flex-direction:column;justify-content:center}#modal-gallery-container{display:flex;flex-direction:column;justify-content:space-between;min-width:100vw;min-height:100vh}\n"] }]
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Inject,
                    args: [DIALOG_DATA]
                }] }, { type: ModalGalleryService }, { type: Object, decorators: [{
                    type: Inject,
                    args: [PLATFORM_ID]
                }] }, { type: i0.ChangeDetectorRef }, { type: IdValidatorService }, { type: ConfigService }, { type: i2.DomSanitizer }], propDecorators: { currentImageComponent: [{
                type: ViewChild,
                args: [CurrentImageComponent, { static: true }]
            }], onPopState: [{
                type: HostListener,
                args: ['window:popstate']
            }], onSaveListener: [{
                type: HostListener,
                args: ['document:keydown.code.control.keyS', ['$event']]
            }, {
                type: HostListener,
                args: ['document:keydown.code.meta.keyS', ['$event']]
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Array of all components.
 */
const COMPONENTS = [
    PlainGalleryComponent,
    CarouselComponent,
    CarouselPreviewsComponent,
    UpperButtonsComponent,
    DotsComponent,
    PreviewsComponent,
    CurrentImageComponent,
    LoadingSpinnerComponent,
    AccessibleComponent,
    ModalGalleryComponent
];

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Directive to change margins of an element.
 */
class MarginDirective {
    constructor(renderer, el) {
        this.renderer = renderer;
        this.el = el;
    }
    /**
     * Method ´ngOnInit´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    ngOnInit() {
        this.applyStyle();
    }
    /**
     * Method ´ngOnChanges´ to apply the style of this directive.
     * This is an angular lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    ngOnChanges() {
        this.applyStyle();
    }
    /**
     * Private method to change both width and height of an element.
     */
    applyStyle() {
        if (this.marginLeft) {
            this.renderer.setStyle(this.el.nativeElement, 'margin-left', this.marginLeft);
        }
        if (this.marginRight) {
            this.renderer.setStyle(this.el.nativeElement, 'margin-right', this.marginRight);
        }
        if (this.marginTop) {
            this.renderer.setStyle(this.el.nativeElement, 'margin-top', this.marginTop);
        }
        if (this.marginBottom) {
            this.renderer.setStyle(this.el.nativeElement, 'margin-bottom', this.marginBottom);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MarginDirective, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.5", type: MarginDirective, isStandalone: false, selector: "[ksMargin]", inputs: { marginLeft: "marginLeft", marginRight: "marginRight", marginTop: "marginTop", marginBottom: "marginBottom" }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MarginDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ksMargin]',
                    standalone: false
                }]
        }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }], propDecorators: { marginLeft: [{
                type: Input
            }], marginRight: [{
                type: Input
            }], marginTop: [{
                type: Input
            }], marginBottom: [{
                type: Input
            }] } });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Array of all directives.
 */
const DIRECTIVES = [
    ClickOutsideDirective,
    SizeDirective,
    KeyboardNavigationDirective,
    WrapDirective,
    DirectionDirective,
    ATagBgImageDirective,
    DescriptionDirective,
    MarginDirective,
    MaxSizeDirective,
    FallbackImageDirective,
    SwipeDirective
];

class AttachToOverlayService {
    constructor(injector, modalGalleryService) {
        this.injector = injector;
        this.modalGalleryService = modalGalleryService;
    }
    /**
     * To be called by a provider with the APP_INITIALIZER token.
     */
    initialize() {
        this.modalGalleryService.triggerAttachToOverlay.subscribe(payload => this.attachToOverlay(payload));
    }
    /**
     * Private method to attach ModalGalleryComponent to the overlay.
     * @param payload {@link AttachToOverlayPayload} with all necessary information
     * @private
     */
    attachToOverlay(payload) {
        const injector = Injector.create({
            parent: this.injector,
            providers: [
                { provide: ModalGalleryRef, useValue: payload.dialogRef },
                { provide: DIALOG_DATA, useValue: payload.config }
            ]
        });
        const containerPortal = new ComponentPortal(ModalGalleryComponent, null, injector);
        payload.overlayRef.attach(containerPortal);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: AttachToOverlayService, deps: [{ token: i0.Injector }, { token: ModalGalleryService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: AttachToOverlayService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: AttachToOverlayService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i0.Injector }, { type: ModalGalleryService }] });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Module to import it in the root module of your application.
 */
class GalleryModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GalleryModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: GalleryModule, declarations: [PlainGalleryComponent, CarouselComponent, CarouselPreviewsComponent, UpperButtonsComponent, DotsComponent, PreviewsComponent, CurrentImageComponent, LoadingSpinnerComponent, AccessibleComponent, ModalGalleryComponent, ClickOutsideDirective, SizeDirective, KeyboardNavigationDirective, WrapDirective, DirectionDirective, ATagBgImageDirective, DescriptionDirective, MarginDirective, MaxSizeDirective, FallbackImageDirective, SwipeDirective], imports: [CommonModule, OverlayModule], exports: [PlainGalleryComponent, CarouselComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GalleryModule, providers: [
            {
                provide: APP_INITIALIZER,
                multi: true,
                deps: [AttachToOverlayService],
                useFactory: (service) => {
                    return () => service.initialize();
                }
            }
        ], imports: [CommonModule, OverlayModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GalleryModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [CommonModule, OverlayModule],
                    declarations: [COMPONENTS, DIRECTIVES],
                    providers: [
                        {
                            provide: APP_INITIALIZER,
                            multi: true,
                            deps: [AttachToOverlayService],
                            useFactory: (service) => {
                                return () => service.initialize();
                            }
                        }
                    ],
                    exports: [PlainGalleryComponent, CarouselComponent]
                }]
        }] });

/*
 The MIT License (MIT)

 Copyright (c) 2017-2024 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
/**
 * Index file to export all interfaces, enums, classes and so on.
 * This file represents the public apis.
 */

/**
 * Generated bundle index. Do not edit.
 */

export { Action, ButtonType, ButtonsStrategy, CarouselComponent, DescriptionStrategy, GalleryModule, GridLayout, Image, ImageEvent, ImageModalEvent, KS_DEFAULT_ACCESSIBILITY_CONFIG, KS_DEFAULT_BTN_CLOSE, KS_DEFAULT_BTN_DELETE, KS_DEFAULT_BTN_DOWNLOAD, KS_DEFAULT_BTN_EXTURL, KS_DEFAULT_BTN_FULL_SCREEN, KS_DEFAULT_SIZE, LineLayout, LoadingType, ModalGalleryComponent, ModalGalleryRef, ModalGalleryService, PlainGalleryComponent, PlainGalleryStrategy };
//# sourceMappingURL=ks89-angular-modal-gallery.mjs.map