wj-elements 0.3.8 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/base-path.js +16 -2
  2. package/dist/base-path.js.map +1 -1
  3. package/dist/dark.css +9 -0
  4. package/dist/{icon-DVyMc4Wv.js → icon-CReYMzAK.js} +2 -2
  5. package/dist/{icon-DVyMc4Wv.js.map → icon-CReYMzAK.js.map} +1 -1
  6. package/dist/light.css +9 -0
  7. package/dist/packages/utils/permissions.d.ts +9 -9
  8. package/dist/packages/wje-accordion/accordion.element.d.ts +3 -6
  9. package/dist/packages/wje-accordion-item/accordion-item.element.d.ts +27 -6
  10. package/dist/packages/wje-animation/animation.element.d.ts +10 -2
  11. package/dist/packages/wje-aside/aside.element.d.ts +10 -6
  12. package/dist/packages/wje-avatar/avatar.element.d.ts +19 -11
  13. package/dist/packages/wje-carousel/carousel.element.d.ts +78 -3
  14. package/dist/packages/wje-carousel-item/carousel-item.element.d.ts +5 -0
  15. package/dist/packages/wje-input/input.element.d.ts +2 -0
  16. package/dist/packages/wje-textarea/textarea.element.d.ts +2 -0
  17. package/dist/packages/wje-toast/toast.element.d.ts +80 -10
  18. package/dist/permissions.js +7 -7
  19. package/dist/permissions.js.map +1 -1
  20. package/dist/styles.css +58 -5
  21. package/dist/wje-accordion-item.js +18 -18
  22. package/dist/wje-accordion-item.js.map +1 -1
  23. package/dist/wje-accordion.js.map +1 -1
  24. package/dist/wje-animation.js +2 -2
  25. package/dist/wje-animation.js.map +1 -1
  26. package/dist/wje-aside.js +1 -1
  27. package/dist/wje-aside.js.map +1 -1
  28. package/dist/wje-avatar.js.map +1 -1
  29. package/dist/wje-button.js +1 -1
  30. package/dist/wje-carousel-item.js +19 -1
  31. package/dist/wje-carousel-item.js.map +1 -1
  32. package/dist/wje-carousel.js +208 -57
  33. package/dist/wje-carousel.js.map +1 -1
  34. package/dist/wje-element.js +4 -4
  35. package/dist/wje-element.js.map +1 -1
  36. package/dist/wje-file-upload-item.js +1 -1
  37. package/dist/wje-icon.js +1 -1
  38. package/dist/wje-img-comparer.js +1 -1
  39. package/dist/wje-input.js +14 -3
  40. package/dist/wje-input.js.map +1 -1
  41. package/dist/wje-master.js +1 -1
  42. package/dist/wje-option.js +1 -1
  43. package/dist/wje-pagination.js +1 -1
  44. package/dist/wje-select.js +2 -2
  45. package/dist/wje-textarea.js +1 -1
  46. package/dist/wje-textarea.js.map +1 -1
  47. package/dist/wje-toast.js +383 -11
  48. package/dist/wje-toast.js.map +1 -1
  49. package/package.json +4 -3
@@ -1 +1 @@
1
- {"version":3,"file":"wje-avatar.js","sources":["../packages/wje-avatar/service/service.js","../packages/wje-avatar/avatar.element.js","../packages/wje-avatar/avatar.js"],"sourcesContent":["/**\n * Generates an HSL color value based on the input text.\n * @param {string} text The input text to generate the HSL color.\n * @param {number} [s] The saturation value (in percentage) for the HSL color.\n * @param {number} [l] The lightness value (in percentage) for the HSL color.\n * @returns {string} - The HSL color string in the format `hsl(h, s%, l%)`.\n * @description\n * This function computes a hash from the input text and uses it to generate\n * a hue value. The hue is combined with the provided saturation and lightness\n * values to create an HSL color. This can be useful for consistently assigning\n * colors based on text input, such as for avatars or tags.\n * @example\n * // Returns 'hsl(180, 40%, 65%)'\n * getHsl('example');\n * @example\n * // Returns 'hsl(300, 50%, 70%)'\n * getHsl('test', 50, 70);\n */\nexport function getHsl(text, s = 40, l = 75) {\n let str = text;\n let hash = 0;\n\n for (let i = 0; i < str?.length; i++) {\n hash = str.charCodeAt(i) + hash * 31;\n }\n\n let h = hash % 360;\n\n return `hsl(${h}, ${s}%, ${l}%)`;\n}\n\n/**\n * Generates background and text HSL colors for avatars based on input text.\n * The text color is a darker, more saturated variant of the background color\n * to ensure sufficient contrast while keeping the same hue.\n *\n * @param {string} text The input text (e.g. initials or name).\n * @returns {{ background: string, color: string }}\n */\nexport function getAvatarColors(text) {\n let hash = 0;\n for (let i = 0; i < text?.length; i++) {\n hash = text.charCodeAt(i) + hash * 31;\n }\n\n const h = Math.abs(hash) % 360;\n\n // 👇 Figma-like pastel background\n const bgS = 30;\n const bgL = 88;\n\n // 👇 Softer text color (same hue)\n const textS = 50;\n const textL = 48;\n\n return {\n background: `hsl(${h}, ${bgS}%, ${bgL}%)`,\n color: `hsl(${h}, ${textS}%, ${textL}%)`\n };\n}\n\n/**\n * Generates initials from a given string.\n * @param {string} string The input string, typically a full name.\n * @param {number} [length] The desired number of initials (default is 2).\n * @returns {string} - The generated initials in uppercase.\n * @description\n * This function takes a string, splits it by spaces, and generates initials.\n * It always includes the first character of the first word. If the input string\n * contains more than one word and the `length` parameter is greater than 1, it\n * also includes the first character of the last word.\n * @example\n * // Returns 'JD'\n * getInitials('John Doe');\n * @example\n * // Returns 'J'\n * getInitials('John');\n * @example\n * // Returns 'JM'\n * getInitials('John Michael Doe', 2);\n */\nexport function getInitials(string, length = 2) {\n let names = string.split(' ');\n let initials = names[0].substring(0, 1).toUpperCase();\n\n if (names.length > 1 && length > 1) {\n initials += names[names.length - 1].substring(0, 1).toUpperCase();\n }\n return initials;\n}\n","import { default as WJElement } from '../wje-element/element.js';\nimport { getHsl, getInitials, getAvatarColors } from './service/service.js';\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This class represents an Avatar element, extending the WJElement class.\n * @documentation https://elements.webjet.sk/components/avatar\n * @status stable\n * @augments WJElement\n * @slot - The avatar main content.\n * @csspart native - The component's native wrapper.\n * @cssproperty --wje-avatar-width;\n * @cssproperty --wje-avatar-height;\n * @cssproperty --wje-avatar-font-size;\n * @cssproperty --wje-avatar-font-weight;\n * @cssproperty --wje-avatar-color;\n * @cssproperty --wje-avatar-background-color;\n * @cssproperty --wje-avatar-border-radius;\n * @cssproperty --wje-avatar-border-color;\n * @cssproperty --wje-avatar-border-width;\n * @cssproperty --wje-avatar-border-style;\n * @tag wje-avatar\n */\nexport default class Avatar extends WJElement {\n /**\n * Avatar class constructor.\n */\n constructor() {\n super();\n }\n\n /**\n * Sets the value of the 'label' attribute for the element.\n * @param {string} value The new value to be set for the 'label' attribute.\n */\n set label(value) {\n this.setAttribute('label', value);\n }\n\n /**\n * Retrieves the value of the 'label' attribute for the element.\n * If the attribute is not set, it defaults to an empty string.\n * @returns {string} The value of the 'label' attribute or an empty string if not defined.\n */\n get label() {\n return this.getAttribute('label') || '';\n }\n\n /**\n * Sets the value of initials for the element by updating\n * the 'initials' attribute with the provided value.\n * @param {string} value The value to be set as the initials.\n */\n set initials(value) {\n this.setAttribute('initials', '');\n }\n\n /**\n * Retrieves the value of the 'initials' attribute if it exists.\n * @returns {boolean} Returns true if the 'initials' attribute is present, otherwise false.\n */\n get initials() {\n return this.hasAttribute('initials') || false;\n }\n\n /**\n * Sets the size attribute for the element.\n * @param {string | number} value The value to set for the size attribute.\n */\n set size(value) {\n this.setAttribute('size', value);\n }\n\n /**\n * Retrieves the size attribute of the element. If the size attribute\n * is not defined, it returns the default value 'medium'.\n * @returns {string} The size value of the element or 'medium' if not specified.\n */\n get size() {\n return this.getAttribute('size') || 'medium';\n }\n\n /**\n * Class name for the Avatar element.\n */\n className = 'Avatar';\n\n /**\n * Getter for cssStyleSheet.\n * @returns {string} styles\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n * @static\n * @returns {Array<string>}\n */\n static get observedAttributes() {\n return ['initials', 'label'];\n }\n\n /**\n * Method to setup attributes.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n this.syncAria();\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n super.attributeChangedCallback?.(name, oldValue, newValue);\n if (name === 'label' || name === 'initials') {\n this.syncAria();\n }\n }\n\n /**\n * Method to draw the avatar element and return a document fragment.\n * @returns {object} fragment - The document fragment\n */\n draw() {\n let fragment = document.createDocumentFragment();\n\n let element = document.createElement('div');\n element.setAttribute('part', 'native');\n element.classList.add('native-avatar');\n\n let slot = document.createElement('slot');\n\n element.appendChild(slot);\n\n if (this.initials) {\n let initials = getInitials(this.label);\n const { background, color } = getAvatarColors(initials);\n\n this.style.setProperty('--wje-avatar-background-color', background);\n this.style.setProperty('--wje-avatar-color', color);\n\n element.innerText = initials;\n } else {\n let slotIcon = document.createElement('slot');\n slotIcon.setAttribute('name', 'icon');\n\n element.appendChild(slotIcon);\n }\n\n let status = document.createElement('slot');\n status.setAttribute('name', 'status');\n status.setAttribute('part', 'status');\n\n let secondary = document.createElement('slot');\n secondary.setAttribute('name', 'secondary');\n secondary.setAttribute('part', 'secondary');\n\n element.appendChild(status);\n element.appendChild(secondary);\n\n fragment.appendChild(element);\n\n return fragment;\n }\n\n /**\n * Syncs ARIA attributes on the host element.\n */\n syncAria() {\n const label = this.label?.trim();\n if (label) {\n this.setAriaState({ label });\n }\n }\n\n /**\n * Method to check if the avatar is an image.\n * @returns {boolean} - True if the avatar is an image, false otherwise\n */\n isImage() {\n return this.getElementsByTagName('wje-img').length > 0;\n }\n}\n","import Avatar from './avatar.element.js';\n\nexport default Avatar;\n\nAvatar.define('wje-avatar', Avatar);\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wje-avatar.js","sources":["../packages/wje-avatar/service/service.js","../packages/wje-avatar/avatar.element.js","../packages/wje-avatar/avatar.js"],"sourcesContent":["/**\n * Generates an HSL color value based on the input text.\n * @param {string} text The input text to generate the HSL color.\n * @param {number} [s] The saturation value (in percentage) for the HSL color.\n * @param {number} [l] The lightness value (in percentage) for the HSL color.\n * @returns {string} - The HSL color string in the format `hsl(h, s%, l%)`.\n * @description\n * This function computes a hash from the input text and uses it to generate\n * a hue value. The hue is combined with the provided saturation and lightness\n * values to create an HSL color. This can be useful for consistently assigning\n * colors based on text input, such as for avatars or tags.\n * @example\n * // Returns 'hsl(180, 40%, 65%)'\n * getHsl('example');\n * @example\n * // Returns 'hsl(300, 50%, 70%)'\n * getHsl('test', 50, 70);\n */\nexport function getHsl(text, s = 40, l = 75) {\n let str = text;\n let hash = 0;\n\n for (let i = 0; i < str?.length; i++) {\n hash = str.charCodeAt(i) + hash * 31;\n }\n\n let h = hash % 360;\n\n return `hsl(${h}, ${s}%, ${l}%)`;\n}\n\n/**\n * Generates background and text HSL colors for avatars based on input text.\n * The text color is a darker, more saturated variant of the background color\n * to ensure sufficient contrast while keeping the same hue.\n *\n * @param {string} text The input text (e.g. initials or name).\n * @returns {{ background: string, color: string }}\n */\nexport function getAvatarColors(text) {\n let hash = 0;\n for (let i = 0; i < text?.length; i++) {\n hash = text.charCodeAt(i) + hash * 31;\n }\n\n const h = Math.abs(hash) % 360;\n\n // 👇 Figma-like pastel background\n const bgS = 30;\n const bgL = 88;\n\n // 👇 Softer text color (same hue)\n const textS = 50;\n const textL = 48;\n\n return {\n background: `hsl(${h}, ${bgS}%, ${bgL}%)`,\n color: `hsl(${h}, ${textS}%, ${textL}%)`\n };\n}\n\n/**\n * Generates initials from a given string.\n * @param {string} string The input string, typically a full name.\n * @param {number} [length] The desired number of initials (default is 2).\n * @returns {string} - The generated initials in uppercase.\n * @description\n * This function takes a string, splits it by spaces, and generates initials.\n * It always includes the first character of the first word. If the input string\n * contains more than one word and the `length` parameter is greater than 1, it\n * also includes the first character of the last word.\n * @example\n * // Returns 'JD'\n * getInitials('John Doe');\n * @example\n * // Returns 'J'\n * getInitials('John');\n * @example\n * // Returns 'JM'\n * getInitials('John Michael Doe', 2);\n */\nexport function getInitials(string, length = 2) {\n let names = string.split(' ');\n let initials = names[0].substring(0, 1).toUpperCase();\n\n if (names.length > 1 && length > 1) {\n initials += names[names.length - 1].substring(0, 1).toUpperCase();\n }\n return initials;\n}\n","import { default as WJElement } from '../wje-element/element.js';\nimport { getHsl, getInitials, getAvatarColors } from './service/service.js';\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This class represents an Avatar element, extending the WJElement class.\n * @documentation https://elements.webjet.sk/components/avatar\n * @status stable\n * @augments WJElement\n * @attribute {boolean} initials - Renders generated initials from `label` instead of the default slotted content.\n * @attribute {string} label - Provides the source text for generated initials and the accessible label of the avatar.\n * @attribute {string} size - Selects a predefined avatar size such as `small`, `medium`, `normal`, `large`, or larger variants.\n * @attribute {string} status-placement - Positions the `status` slot on one of the avatar corners.\n * @slot default - Slot for the main avatar content, typically an image.\n * @slot icon - Slot for an icon rendered inside the avatar.\n * @slot status - Slot for a status badge or indicator positioned on the avatar edge.\n * @slot secondary - Slot for additional secondary content rendered with the avatar.\n * @csspart native - The component's native wrapper.\n * @csspart status - The positioned slot container for status content.\n * @csspart secondary - The slot container for secondary avatar content.\n * @cssproperty [--wje-avatar-size] - Controls the overall rendered size of the avatar shell.\n * @cssproperty [--wje-avatar-font-size] - Controls the font size used for initials and text content.\n * @cssproperty [--wje-avatar-font-weight] - Controls the font weight used for initials and text content.\n * @cssproperty [--wje-avatar-color] - Controls the text color inside the avatar.\n * @cssproperty [--wje-avatar-background-color] - Controls the background color of the avatar surface.\n * @cssproperty [--wje-avatar-border-radius] - Controls the avatar border radius.\n * @cssproperty [--wje-avatar-border-color] - Controls the avatar border color when a border is applied.\n * @cssproperty [--wje-avatar-border-width] - Controls the avatar border width when a border is applied.\n * @cssproperty [--wje-avatar-border-style] - Controls the avatar border style when a border is applied.\n * @tag wje-avatar\n */\nexport default class Avatar extends WJElement {\n /**\n * Avatar class constructor.\n */\n constructor() {\n super();\n }\n\n /**\n * Sets the value of the 'label' attribute for the element.\n * @param {string} value The new value to be set for the 'label' attribute.\n */\n set label(value) {\n this.setAttribute('label', value);\n }\n\n /**\n * Retrieves the value of the 'label' attribute for the element.\n * If the attribute is not set, it defaults to an empty string.\n * @returns {string} The value of the 'label' attribute or an empty string if not defined.\n */\n get label() {\n return this.getAttribute('label') || '';\n }\n\n /**\n * Sets the value of initials for the element by updating\n * the 'initials' attribute with the provided value.\n * @param {string} value The value to be set as the initials.\n */\n set initials(value) {\n this.setAttribute('initials', '');\n }\n\n /**\n * Retrieves the value of the 'initials' attribute if it exists.\n * @returns {boolean} Returns true if the 'initials' attribute is present, otherwise false.\n */\n get initials() {\n return this.hasAttribute('initials') || false;\n }\n\n /**\n * Sets the size attribute for the element.\n * @param {string | number} value The value to set for the size attribute.\n */\n set size(value) {\n this.setAttribute('size', value);\n }\n\n /**\n * Retrieves the size attribute of the element. If the size attribute\n * is not defined, it returns the default value 'medium'.\n * @returns {string} The size value of the element or 'medium' if not specified.\n */\n get size() {\n return this.getAttribute('size') || 'medium';\n }\n\n /**\n * Class name for the Avatar element.\n */\n className = 'Avatar';\n\n /**\n * Getter for cssStyleSheet.\n * @returns {string} styles\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n * @static\n * @returns {Array<string>}\n */\n static get observedAttributes() {\n return ['initials', 'label'];\n }\n\n /**\n * Method to setup attributes.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n this.syncAria();\n }\n\n attributeChangedCallback(name, oldValue, newValue) {\n super.attributeChangedCallback?.(name, oldValue, newValue);\n if (name === 'label' || name === 'initials') {\n this.syncAria();\n }\n }\n\n /**\n * Method to draw the avatar element and return a document fragment.\n * @returns {object} fragment - The document fragment\n */\n draw() {\n let fragment = document.createDocumentFragment();\n\n let element = document.createElement('div');\n element.setAttribute('part', 'native');\n element.classList.add('native-avatar');\n\n let slot = document.createElement('slot');\n\n element.appendChild(slot);\n\n if (this.initials) {\n let initials = getInitials(this.label);\n const { background, color } = getAvatarColors(initials);\n\n this.style.setProperty('--wje-avatar-background-color', background);\n this.style.setProperty('--wje-avatar-color', color);\n\n element.innerText = initials;\n } else {\n let slotIcon = document.createElement('slot');\n slotIcon.setAttribute('name', 'icon');\n\n element.appendChild(slotIcon);\n }\n\n let status = document.createElement('slot');\n status.setAttribute('name', 'status');\n status.setAttribute('part', 'status');\n\n let secondary = document.createElement('slot');\n secondary.setAttribute('name', 'secondary');\n secondary.setAttribute('part', 'secondary');\n\n element.appendChild(status);\n element.appendChild(secondary);\n\n fragment.appendChild(element);\n\n return fragment;\n }\n\n /**\n * Syncs ARIA attributes on the host element.\n */\n syncAria() {\n const label = this.label?.trim();\n if (label) {\n this.setAriaState({ label });\n }\n }\n\n /**\n * Method to check if the avatar is an image.\n * @returns {boolean} - True if the avatar is an image, false otherwise\n */\n isImage() {\n return this.getElementsByTagName('wje-img').length > 0;\n }\n}\n","import Avatar from './avatar.element.js';\n\nexport default Avatar;\n\nAvatar.define('wje-avatar', Avatar);\n"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ var _Button_instances, populateCustomEvent_fn;
11
11
  import { b as bindRouterLinks } from "./router-links-wjqCnncc.js";
12
12
  import { bool } from "./utils.js";
13
13
  import WJElement from "./wje-element.js";
14
- import { I as Icon } from "./icon-DVyMc4Wv.js";
14
+ import { I as Icon } from "./icon-CReYMzAK.js";
15
15
  import { WjElementUtils } from "./element-utils.js";
16
16
  import { event } from "./event.js";
17
17
  const styles = "/*\n[ WJ Button ]\n*/\n\n/*PRIMARY*/\n.wje-button-solid.wje-color-primary {\n background-color: var(--wje-color-primary-9);\n border-color: var(--wje-color-primary-9);\n color: var(--wje-color-contrast-0);\n}\n\n.wje-button-outline.wje-color-primary {\n background-color: var(--wje-color-primary-1);\n border-color: var(--wje-color-primary-9);\n color: var(--wje-color-primary-9);\n}\n\n.wje-button-link.wje-color-primary {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-primary-9);\n}\n\n/*COMPLETE*/\n.wje-button-solid.wje-color-complete {\n background-color: var(--wje-color-complete-9);\n border-color: var(--wje-color-complete-9);\n color: var(--wje-color-contrast-0);\n}\n\n.wje-button-outline.wje-color-complete {\n background-color: var(--wje-color-complete-1);\n border-color: var(--wje-color-complete-9);\n color: var(--wje-color-complete-9);\n}\n\n.wje-button-link.wje-color-complete {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-complete-9);\n}\n\n/*SUCCESS*/\n.wje-button-solid.wje-color-success {\n background-color: var(--wje-color-success-9);\n border-color: var(--wje-color-success-9);\n color: var(--wje-color-contrast-0);\n}\n\n.wje-button-outline.wje-color-success {\n background-color: var(--wje-color-success-1);\n border-color: var(--wje-color-success-9);\n color: var(--wje-color-success-9);\n}\n\n.wje-button-link.wje-color-success {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-success-9);\n}\n\n/*WARNING*/\n.wje-button-solid.wje-color-warning {\n background-color: var(--wje-color-warning-9);\n border-color: var(--wje-color-warning-9);\n color: var(--wje-color-black);\n}\n\n.wje-button-outline.wje-color-warning {\n background-color: var(--wje-color-warning-1);\n border-color: var(--wje-color-warning-11);\n color: var(--wje-color-warning-11);\n}\n\n.wje-button-link.wje-color-warning {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-warning-11);\n}\n\n/*DANGER*/\n.wje-button-solid.wje-color-danger {\n background-color: var(--wje-color-danger-9);\n border-color: var(--wje-color-danger-9);\n color: var(--wje-color-contrast-0);\n}\n\n.wje-button-outline.wje-color-danger {\n background-color: var(--wje-color-danger-1);\n border-color: var(--wje-color-danger-9);\n color: var(--wje-color-danger-9);\n}\n\n.wje-button-link.wje-color-danger {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-danger-9);\n}\n\n/*NEUTRAL*/\n.wje-button-solid.wje-color-info {\n background-color: var(--wje-color-contrast-9);\n border-color: var(--wje-color-contrast-9);\n color: var(--wje-color-contrast-0);\n}\n\n.wje-button-outline.wje-color-info {\n background-color: var(--wje-color-contrast-1);\n border-color: var(--wje-color-contrast-9);\n color: var(--wje-color-contrast-9);\n}\n\n.wje-button-link.wje-color-info {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-contrast-9);\n}\n\n/*DEFAULT*/\n.wje-button-solid.wje-color-default {\n background-color: var(--wje-color-contrast-0);\n border-color: var(--wje-color-contrast-3);\n color: var(--wje-color-contrast-11);\n}\n\n.wje-button-outline.wje-color-default {\n background-color: var(--wje-color-contrast-1);\n border-color: var(--wje-color-contrast-5);\n color: var(--wje-color-contrast-11);\n}\n\n.wje-button-link.wje-color-default {\n background-color: transparent;\n border-color: transparent;\n color: var(--wje-color-contrast-11);\n}\n\n:host {\n --wje-padding-top: 0.4rem;\n --wje-padding-start: 0.5rem;\n --wje-padding-end: 0.5rem;\n --wje-padding-bottom: 0.4rem;\n\n display: inline-flex;\n position: relative;\n width: auto;\n cursor: pointer;\n margin-inline: var(--wje-button-margin-inline);\n}\n\n:host(.wje-button-group-button) {\n display: block;\n}\n\n.native-button {\n font-family: var(--wje-font-family);\n font-size: var(--wje-font-size);\n display: flex;\n position: relative;\n align-items: center;\n width: 100%;\n height: 100%;\n min-height: inherit;\n /*overflow: hidden;*/ /* Sposobovalo problemy s badge a tooltip */\n border-width: var(--wje-button-border-width);\n border-style: var(--wje-button-border-style);\n border-color: var(--wje-button-border-color);\n background-color: transparent;\n /*color: var(--wje-button-color);*/\n line-height: 1;\n contain: layout style;\n cursor: pointer;\n z-index: 0;\n box-sizing: border-box;\n appearance: none;\n margin: 0;\n border-radius: var(--wje-button-border-radius);\n padding-top: var(--wje-padding-top);\n padding-bottom: var(--wje-padding-bottom);\n padding-inline: var(--wje-padding-start) var(--wje-padding-end);\n white-space: nowrap;\n}\n\n.native-button:hover {\n outline-style: solid;\n outline-width: var(--wje-button-outline-width);\n transition: outline-width 0.1s linear;\n}\n\n@media (any-hover: hover) {\n .wje-button-solid.wje-color-primary:hover {\n background-color: var(--wje-color-primary-9);\n border-color: var(--wje-color-primary-9);\n color: var(--wje-color-contrast-0);\n outline-color: var(--wje-color-primary-2);\n }\n\n .wje-button-outline.wje-color-primary:hover {\n background-color: var(--wje-color-primary-1);\n border-color: var(--wje-color-primary-9);\n color: var(--wje-color-primary-9);\n outline-color: var(--wje-color-primary-2);\n }\n\n .wje-button-link.wje-color-primary:hover {\n background-color: var(--wje-color-primary-1);\n border-color: transparent;\n color: var(--wje-color-primary-9);\n outline-color: transparent;\n outline-width: 0;\n }\n\n .wje-button-solid.wje-color-complete:hover {\n background-color: var(--wje-color-complete-9);\n border-color: var(--wje-color-complete-9);\n color: var(--wje-color-contrast-0);\n outline-color: var(--wje-color-complete-2);\n }\n\n .wje-button-outline.wje-color-complete:hover {\n background-color: var(--wje-color-complete-1);\n border-color: var(--wje-color-complete-9);\n color: var(--wje-color-complete-9);\n outline-color: var(--wje-color-complete-2);\n }\n\n .wje-button-link.wje-color-complete:hover {\n background-color: var(--wje-color-complete-1);\n border-color: transparent;\n color: var(--wje-color-complete-9);\n outline-color: transparent;\n outline-width: 0;\n }\n\n .wje-button-solid.wje-color-success:hover {\n background-color: var(--wje-color-success-9);\n border-color: var(--wje-color-success-9);\n color: var(--wje-color-contrast-0);\n outline-color: var(--wje-color-success-2);\n }\n\n .wje-button-outline.wje-color-success:hover {\n background-color: var(--wje-color-success-1);\n border-color: var(--wje-color-success-9);\n color: var(--wje-color-success-9);\n outline-color: var(--wje-color-success-2);\n }\n\n .wje-button-link.wje-color-success:hover {\n background-color: var(--wje-color-success-1);\n border-color: transparent;\n color: var(--wje-color-success-9);\n outline-color: transparent;\n outline-width: 0;\n }\n\n .wje-button-solid.wje-color-warning:hover {\n background-color: var(--wje-color-warning-9);\n border-color: var(--wje-color-warning-9);\n color: var(--wje-color-black);\n outline-color: var(--wje-color-warning-2);\n }\n\n .wje-button-outline.wje-color-warning:hover {\n background-color: var(--wje-color-warning-1);\n border-color: var(--wje-color-warning-11);\n color: var(--wje-color-warning-11);\n outline-color: var(--wje-color-warning-2);\n }\n\n .wje-button-link.wje-color-warning:hover {\n background-color: var(--wje-color-warning-1);\n border-color: transparent;\n color: var(--wje-color-warning-11);\n outline-color: transparent;\n outline-width: 0;\n }\n\n .wje-button-solid.wje-color-danger:hover {\n background-color: var(--wje-color-danger-9);\n border-color: var(--wje-color-danger-9);\n color: var(--wje-color-contrast-0);\n outline-color: var(--wje-color-danger-2);\n }\n\n .wje-button-outline.wje-color-danger:hover {\n background-color: var(--wje-color-danger-1);\n border-color: var(--wje-color-danger-9);\n color: var(--wje-color-danger-9);\n outline-color: var(--wje-color-danger-2);\n }\n\n .wje-button-link.wje-color-danger:hover {\n background-color: var(--wje-color-danger-1);\n border-color: transparent;\n color: var(--wje-color-danger-9);\n outline-color: transparent;\n outline-width: 0;\n }\n\n .wje-button-solid.wje-color-info:hover {\n background-color: var(--wje-color-contrast-9);\n border-color: var(--wje-color-contrast-9);\n color: var(--wje-color-contrast-0);\n outline-color: var(--wje-color-contrast-3);\n }\n\n .wje-button-outline.wje-color-info:hover {\n background-color: var(--wje-color-contrast-1);\n border-color: var(--wje-color-contrast-9);\n color: var(--wje-color-contrast-9);\n outline-color: var(--wje-color-contrast-3);\n }\n\n .wje-button-link.wje-color-info:hover {\n background-color: var(--wje-color-contrast-3);\n border-color: transparent;\n color: var(--wje-color-contrast-11);\n outline-color: transparent;\n outline-width: 0;\n }\n\n .wje-button-solid.wje-color-default:hover {\n background-color: var(--wje-color-contrast-0);\n border-color: var(--wje-color-contrast-3);\n color: var(--wje-color-contrast-11);\n outline-color: var(--wje-color-contrast-3);\n }\n\n .wje-button-outline.wje-color-default:hover {\n background-color: var(--wje-color-contrast-2);\n border-color: var(--wje-color-contrast-5);\n color: var(--wje-color-contrast-11);\n outline-color: var(--wje-color-contrast-3);\n }\n\n .wje-button-link.wje-color-default:hover {\n background-color: var(--wje-color-contrast-3);\n border-color: transparent;\n color: var(--wje-color-contrast-11);\n outline-color: transparent;\n outline-width: 0;\n }\n}\n\n.button-inner {\n display: flex;\n position: relative;\n flex-flow: row nowrap;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n z-index: 1;\n line-height: normal;\n}\n\n/*\n[ Link ]\n*/\n\n.wje-button-link {\n border-width: var(--wje-button-border-width);\n border-radius: var(--wje-button-border-radius);\n border-color: transparent;\n background-color: transparent;\n}\n\n/*\n[ Disabled ]\n*/\n\n.wje-button-disabled {\n cursor: default;\n opacity: 0.5;\n pointer-events: none;\n}\n\n/*\n[ Round ]\n*/\n\n:host([round]) .native-button {\n border-radius: var(--wje-border-radius-pill);\n}\n\n:host([circle]) .native-button {\n border-radius: var(--wje-border-radius-circle);\n aspect-ratio: 1/1;\n width: 1.988rem;\n display: flex;\n align-items: center;\n --wje-padding-top: 0;\n --wje-padding-start: 0;\n --wje-padding-end: 0;\n --wje-padding-bottom: 0;\n}\n\n:host([size='small']) .native-button {\n --wje-padding-top: 0.25rem;\n --wje-padding-start: 0.25rem;\n --wje-padding-end: 0.25rem;\n --wje-padding-bottom: 0.25rem;\n}\n\n:host([size='large']) .native-button {\n --wje-padding-top: 0.6rem;\n --wje-padding-start: 0.7rem;\n --wje-padding-end: 0.7rem;\n --wje-padding-bottom: 0.6rem;\n}\n\n:host([size='small'][circle]) .native-button {\n width: 1.688rem;\n --wje-padding-top: 0;\n --wje-padding-start: 0;\n --wje-padding-end: 0;\n --wje-padding-bottom: 0;\n}\n\n:host([size='large'][circle]) .native-button {\n width: 2.388rem;\n --wje-padding-top: 0;\n --wje-padding-start: 0;\n --wje-padding-end: 0;\n --wje-padding-bottom: 0;\n}\n\n::slotted(wje-icon[slot='start']) {\n margin: 0 0.3rem 0 0;\n}\n\n::slotted(wje-icon[slot='end']) {\n margin: 0 -0.2rem 0 0.3rem;\n}\n\n:host(:not([only-caret])) slot[name='caret'] {\n padding: 0 0 0 0.3rem;\n}\n\n:host([only-caret]) {\n .native-button {\n aspect-ratio: 1/1;\n width: 1.988rem;\n display: flex;\n align-items: center;\n }\n slot[name='caret'] {\n padding: 0;\n display: block;\n }\n}\n\n::slotted([slot='toggle']) {\n display: none;\n}\n\n::slotted([slot='toggle'].show) {\n display: block;\n}\n";
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import WJElement from "./wje-element.js";
5
5
  import { event } from "./event.js";
6
- const styles = "/*\n[ WJ Carousel Item ]\n*/\n\n:host {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-direction: column;\n width: var(--wje-carousel-size, 100%);\n max-height: 100%;\n aspect-ratio: var(--wje-carousel-item-aspect-ratio);\n scroll-snap-align: center;\n scroll-snap-stop: always;\n}\n\n.native-carousel-item {\n width: 100%;\n height: 100%;\n display: flex;\n}\n::slotted(wje-img) {\n width: 100% !important;\n height: 100% !important;\n object-fit: contain;\n display: flex;\n}\n";
6
+ const styles = "/*\n[ WJ Carousel Item ]\n*/\n\n:host {\n display: flex;\n align-items: stretch;\n justify-content: flex-start;\n flex-direction: column;\n width: var(--wje-carousel-item-basis, var(--wje-carousel-size, 100%));\n min-width: 0;\n max-width: 100%;\n max-height: 100%;\n align-self: stretch;\n aspect-ratio: var(--wje-carousel-item-aspect-ratio, inherit);\n scroll-snap-align: start;\n scroll-snap-stop: always;\n box-sizing: border-box;\n}\n\n.native-carousel-item {\n width: 100%;\n height: 100%;\n display: flex;\n flex: 1 1 auto;\n align-items: stretch;\n justify-content: flex-start;\n min-width: 0;\n box-sizing: border-box;\n}\n\nslot {\n display: flex;\n width: 100%;\n height: 100%;\n flex: 1 1 auto;\n align-items: stretch;\n justify-content: center;\n min-width: 0;\n}\n\n:host([single-content]) ::slotted(*) {\n width: 100%;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n::slotted(wje-img) {\n width: 100% !important;\n height: 100% !important;\n object-fit: contain;\n display: flex;\n}\n";
7
7
  class CarouselItem extends WJElement {
8
8
  /**
9
9
  * CarouselItem constructor method.
@@ -46,6 +46,7 @@ class CarouselItem extends WJElement {
46
46
  native.classList.add("native-carousel-item");
47
47
  native.setAttribute("part", "native");
48
48
  let slot = document.createElement("slot");
49
+ this.defaultSlot = slot;
49
50
  native.appendChild(slot);
50
51
  fragment.appendChild(native);
51
52
  return fragment;
@@ -55,6 +56,23 @@ class CarouselItem extends WJElement {
55
56
  */
56
57
  afterDraw() {
57
58
  event.addListener(this, "click", "wje-carousel-item:click");
59
+ this.syncContentLayoutMode();
60
+ if (this.defaultSlot && !this.defaultSlot.dataset.wjeCarouselItemBound) {
61
+ this.defaultSlot.addEventListener("slotchange", () => this.syncContentLayoutMode());
62
+ this.defaultSlot.dataset.wjeCarouselItemBound = "true";
63
+ }
64
+ }
65
+ /**
66
+ * Keeps a simple layout hint for single-wrapper content.
67
+ */
68
+ syncContentLayoutMode() {
69
+ var _a;
70
+ const assignedElements = ((_a = this.defaultSlot) == null ? void 0 : _a.assignedElements({ flatten: true })) || [];
71
+ if (assignedElements.length === 1) {
72
+ this.setAttribute("single-content", "");
73
+ return;
74
+ }
75
+ this.removeAttribute("single-content");
58
76
  }
59
77
  }
60
78
  WJElement.define("wje-carousel-item", CarouselItem);
@@ -1 +1 @@
1
- {"version":3,"file":"wje-carousel-item.js","sources":["../packages/wje-carousel-item/carousel-item.element.js","../packages/wje-carousel-item/carousel-item.js"],"sourcesContent":["import { default as WJElement, event } from '../wje-element/element.js';\n\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This class represents CarouselItem element, extending the WJElement class.\n * @documentation https://elements.webjet.sk/components/carousel-item\n * @status stable\n * @augments WJElement\n * @slot - The carousel item main content.\n * @csspart native - The component's native wrapper.\n * @cssproperty [--wje-carousel-item-background-color=transparent] - Background color of the component;\n * @cssproperty [--wje-carousel-item-border-color=--wje-color-contrast-4] - Border color of the component;\n * @cssproperty [--wje-carousel-item-color=--wje-color-contrast-11] - Color of the component;\n * @cssproperty [--wje-carousel-item-border-radius=--wje-border-radius-medium] - Border radius of the component;\n * @cssproperty [--wje-carousel-item-border-width=1px] - Border width of the component;\n * @cssproperty [--wje-carousel-item-border-style=solid] - Border style of the component;\n * @cssproperty [--wje-carousel-item-border-color=--wje-color-contrast-1] - Border color of the component;\n * @cssproperty [--wje-carousel-item-margin-inline=0] - Margin inline of the component;\n */\nexport default class CarouselItem extends WJElement {\n /**\n * CarouselItem constructor method.\n */\n constructor() {\n super();\n }\n\n /**\n * Class name for the CarouselItem element.\n * @type {string}\n */\n className = 'CarouselItem';\n\n /**\n * Getter for the CSS stylesheet.\n * @returns {*}\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Getter for the observed attributes.\n * @returns {*[]}\n */\n static get observedAttributes() {\n return [];\n }\n\n /**\n * Sets up the attributes for the CarouselItem.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n }\n\n /**\n * Draws the CarouselItem element.\n * @returns {DocumentFragment}\n */\n draw() {\n let fragment = document.createDocumentFragment();\n\n let native = document.createElement('div');\n native.classList.add('native-carousel-item');\n native.setAttribute('part', 'native');\n\n let slot = document.createElement('slot');\n\n native.appendChild(slot);\n\n fragment.appendChild(native);\n\n return fragment;\n }\n\n /**\n * After draw event for the CarouselItem element.\n */\n afterDraw() {\n event.addListener(this, 'click', 'wje-carousel-item:click');\n }\n}\n","import { default as WJElement } from '../wje-element/element.js';\nimport CarouselItem from './carousel-item.element.js';\n\n// export * from \"./carousel-item.element.js\";\nexport default CarouselItem;\n\nWJElement.define('wje-carousel-item', CarouselItem);\n"],"names":[],"mappings":";;;;;;AAoBe,MAAM,qBAAqB,UAAU;AAAA;AAAA;AAAA;AAAA,EAIhD,cAAc;AACV,UAAK;AAOT;AAAA;AAAA;AAAA;AAAA,qCAAY;AAAA,EANZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,WAAW,gBAAgB;AACvB,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,qBAAqB;AAC5B,WAAO,CAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB;AACd,SAAK,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO;AACH,QAAI,WAAW,SAAS,uBAAsB;AAE9C,QAAI,SAAS,SAAS,cAAc,KAAK;AACzC,WAAO,UAAU,IAAI,sBAAsB;AAC3C,WAAO,aAAa,QAAQ,QAAQ;AAEpC,QAAI,OAAO,SAAS,cAAc,MAAM;AAExC,WAAO,YAAY,IAAI;AAEvB,aAAS,YAAY,MAAM;AAE3B,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY;AACR,UAAM,YAAY,MAAM,SAAS,yBAAyB;AAAA,EAC9D;AACJ;AC7EA,UAAU,OAAO,qBAAqB,YAAY;"}
1
+ {"version":3,"file":"wje-carousel-item.js","sources":["../packages/wje-carousel-item/carousel-item.element.js","../packages/wje-carousel-item/carousel-item.js"],"sourcesContent":["import { default as WJElement, event } from '../wje-element/element.js';\n\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This class represents CarouselItem element, extending the WJElement class.\n * @documentation https://elements.webjet.sk/components/carousel-item\n * @status stable\n * @augments WJElement\n * @slot - The carousel item main content.\n * @csspart native - The component's native wrapper.\n * @cssproperty [--wje-carousel-item-background-color=transparent] - Background color of the component;\n * @cssproperty [--wje-carousel-item-border-color=--wje-color-contrast-4] - Border color of the component;\n * @cssproperty [--wje-carousel-item-color=--wje-color-contrast-11] - Color of the component;\n * @cssproperty [--wje-carousel-item-border-radius=--wje-border-radius-medium] - Border radius of the component;\n * @cssproperty [--wje-carousel-item-border-width=1px] - Border width of the component;\n * @cssproperty [--wje-carousel-item-border-style=solid] - Border style of the component;\n * @cssproperty [--wje-carousel-item-border-color=--wje-color-contrast-1] - Border color of the component;\n * @cssproperty [--wje-carousel-item-margin-inline=0] - Margin inline of the component;\n */\nexport default class CarouselItem extends WJElement {\n /**\n * CarouselItem constructor method.\n */\n constructor() {\n super();\n }\n\n /**\n * Class name for the CarouselItem element.\n * @type {string}\n */\n className = 'CarouselItem';\n\n /**\n * Getter for the CSS stylesheet.\n * @returns {*}\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Getter for the observed attributes.\n * @returns {*[]}\n */\n static get observedAttributes() {\n return [];\n }\n\n /**\n * Sets up the attributes for the CarouselItem.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n }\n\n /**\n * Draws the CarouselItem element.\n * @returns {DocumentFragment}\n */\n draw() {\n let fragment = document.createDocumentFragment();\n\n let native = document.createElement('div');\n native.classList.add('native-carousel-item');\n native.setAttribute('part', 'native');\n\n let slot = document.createElement('slot');\n this.defaultSlot = slot;\n\n native.appendChild(slot);\n\n fragment.appendChild(native);\n\n return fragment;\n }\n\n /**\n * After draw event for the CarouselItem element.\n */\n afterDraw() {\n event.addListener(this, 'click', 'wje-carousel-item:click');\n this.syncContentLayoutMode();\n\n if (this.defaultSlot && !this.defaultSlot.dataset.wjeCarouselItemBound) {\n this.defaultSlot.addEventListener('slotchange', () => this.syncContentLayoutMode());\n this.defaultSlot.dataset.wjeCarouselItemBound = 'true';\n }\n }\n\n /**\n * Keeps a simple layout hint for single-wrapper content.\n */\n syncContentLayoutMode() {\n const assignedElements = this.defaultSlot?.assignedElements({ flatten: true }) || [];\n\n if (assignedElements.length === 1) {\n this.setAttribute('single-content', '');\n return;\n }\n\n this.removeAttribute('single-content');\n }\n}\n","import { default as WJElement } from '../wje-element/element.js';\nimport CarouselItem from './carousel-item.element.js';\n\n// export * from \"./carousel-item.element.js\";\nexport default CarouselItem;\n\nWJElement.define('wje-carousel-item', CarouselItem);\n"],"names":[],"mappings":";;;;;;AAoBe,MAAM,qBAAqB,UAAU;AAAA;AAAA;AAAA;AAAA,EAIhD,cAAc;AACV,UAAK;AAOT;AAAA;AAAA;AAAA;AAAA,qCAAY;AAAA,EANZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,WAAW,gBAAgB;AACvB,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,qBAAqB;AAC5B,WAAO,CAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB;AACd,SAAK,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO;AACH,QAAI,WAAW,SAAS,uBAAsB;AAE9C,QAAI,SAAS,SAAS,cAAc,KAAK;AACzC,WAAO,UAAU,IAAI,sBAAsB;AAC3C,WAAO,aAAa,QAAQ,QAAQ;AAEpC,QAAI,OAAO,SAAS,cAAc,MAAM;AACxC,SAAK,cAAc;AAEnB,WAAO,YAAY,IAAI;AAEvB,aAAS,YAAY,MAAM;AAE3B,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY;AACR,UAAM,YAAY,MAAM,SAAS,yBAAyB;AAC1D,SAAK,sBAAqB;AAE1B,QAAI,KAAK,eAAe,CAAC,KAAK,YAAY,QAAQ,sBAAsB;AACpE,WAAK,YAAY,iBAAiB,cAAc,MAAM,KAAK,uBAAuB;AAClF,WAAK,YAAY,QAAQ,uBAAuB;AAAA,IACpD;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB;;AACpB,UAAM,qBAAmB,UAAK,gBAAL,mBAAkB,iBAAiB,EAAE,SAAS,KAAI,OAAO,CAAA;AAElF,QAAI,iBAAiB,WAAW,GAAG;AAC/B,WAAK,aAAa,kBAAkB,EAAE;AACtC;AAAA,IACJ;AAEA,SAAK,gBAAgB,gBAAgB;AAAA,EACzC;AACJ;AClGA,UAAU,OAAO,qBAAqB,YAAY;"}
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import WJElement from "./wje-element.js";
5
- const styles = '/*\n[ Carousel ]\n*/\n\n.native-carousel {\n position: relative;\n width: var(--wje-carousel-width, 100%);\n height: var(--wje-carousel-height, 300px);\n scroll-behavior: smooth;\n}\n\n.slides-wrapper {\n position: relative;\n width: var(--wje-carousel-width, 100%);\n height: var(--wje-carousel-height, 300px);\n}\n\n.carousel-slides {\n display: flex;\n transition: transform 0.5s ease;\n align-items: center;\n justify-items: center;\n overflow: auto;\n overscroll-behavior-x: contain;\n scrollbar-width: none;\n -ms-overflow-style: none;\n aspect-ratio: var(--wje-aspect-ratio, 4 / 3);\n scroll-snap-type: x mandatory;\n scroll-padding-inline: 0;\n overflow-y: hidden;\n padding-inline: var(--wje-spacing-inline, 0);\n gap: 0.5rem;\n}\n\n.carousel-slides::-webkit-scrollbar {\n display: none;\n}\n\n::slotted(wje-carousel-item) {\n flex: 0 0 var(--wje-carousel-size);\n height: 100%;\n}\n\n/*NAVIGATION*/\n\n[name="prev"], [name="next"] {\n display: block;\n position: absolute;\n top: 50%;\n border: none;\n cursor: pointer;\n z-index: 2;\n}\n\n[name="prev"] {\n left: -1rem;\n transform: translate(-100%, -50%);\n}\n\n[name="next"] {\n right: -1rem;\n transform: translate(100%, -50%);\n}\n\n/*PAGINATION*/\n\n.pagination {\n position: relative;\n left: 50%;\n transform: translate(-50%, 0);\n display: flex;\n z-index: 2;\n justify-content: center;\n padding-block: 1rem;\n}\n.pagination-item {\n cursor: pointer;\n height: 15px;\n width: 15px;\n margin: 0 2px;\n background-color: var(--wje-color-contrast-4);\n display: inline-block;\n border-radius: 50%;\n}\n.pagination-item.active {\n background-color: var(--wje-color);\n}\n\n/*THUMBNAILS*/\n\n.thumbnails {\n display: flex;\n justify-content: center;\n align-items: center;\n overflow-x: auto;\n gap: 0.5rem;\n padding: 0 0.5rem;\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n box-sizing: border-box;\n overflow-y: hidden;\n wje-thumbnail {\n --wje-thumbnail-width: 48px;\n --wje-thumbnail-height: 48px;\n --wje-thumbnail-border-radius: 0;\n cursor: pointer;\n border: 1px solid transparent;\n }\n .active {\n border: 1px solid var(--wje-color-primary-11);\n }\n}\n';
5
+ const styles = '/*\n[ Carousel ]\n*/\n\n:host {\n display: block;\n width: var(--wje-carousel-width, 100%);\n max-width: 100%;\n box-sizing: border-box;\n}\n\n.native-carousel {\n position: relative;\n width: 100%;\n height: var(--wje-carousel-height, 300px);\n scroll-behavior: smooth;\n box-sizing: border-box;\n}\n\n.slides-wrapper {\n position: relative;\n display: flex;\n align-items: stretch;\n width: 100%;\n height: var(--wje-carousel-height, 300px);\n box-sizing: border-box;\n}\n\n.carousel-slides {\n display: flex;\n flex: 1 1 auto;\n transition: transform 0.5s ease;\n align-items: stretch;\n overflow: auto;\n overscroll-behavior-x: contain;\n scrollbar-width: none;\n -ms-overflow-style: none;\n aspect-ratio: var(--wje-aspect-ratio, 4 / 3);\n scroll-snap-type: x mandatory;\n scroll-padding-inline: var(--wje-spacing-inline, 0);\n overflow-y: hidden;\n padding-inline: var(--wje-spacing-inline, 0);\n gap: var(--wje-carousel-gap, 0.5rem);\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n box-sizing: border-box;\n}\n\n.carousel-slides::-webkit-scrollbar {\n display: none;\n}\n\n::slotted(wje-carousel-item) {\n flex: 0 0 var(--wje-carousel-item-basis, var(--wje-carousel-size));\n width: var(--wje-carousel-item-basis, var(--wje-carousel-size));\n min-width: 0;\n max-width: 100%;\n align-self: stretch;\n height: 100%;\n box-sizing: border-box;\n}\n\n/*NAVIGATION*/\n\n[name="prev"], [name="next"] {\n display: block;\n position: absolute;\n top: 50%;\n border: none;\n cursor: pointer;\n z-index: 2;\n}\n\n[name="prev"] {\n left: -1rem;\n transform: translate(-100%, -50%);\n}\n\n[name="next"] {\n right: -1rem;\n transform: translate(100%, -50%);\n}\n\n/*PAGINATION*/\n\n.pagination {\n position: relative;\n left: 50%;\n transform: translate(-50%, 0);\n display: flex;\n z-index: 2;\n justify-content: center;\n padding-block: 1rem;\n}\n.pagination-item {\n cursor: pointer;\n height: 15px;\n width: 15px;\n margin: 0 2px;\n background-color: var(--wje-color-contrast-4);\n display: inline-block;\n border-radius: 50%;\n}\n.pagination-item.active {\n background-color: var(--wje-color);\n}\n\n/*THUMBNAILS*/\n\n.thumbnails {\n display: flex;\n justify-content: center;\n align-items: center;\n overflow-x: auto;\n gap: 0.5rem;\n padding: 0 0.5rem;\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n box-sizing: border-box;\n overflow-y: hidden;\n wje-thumbnail {\n --wje-thumbnail-width: 48px;\n --wje-thumbnail-height: 48px;\n --wje-thumbnail-border-radius: 0;\n cursor: pointer;\n border: 1px solid transparent;\n }\n .active {\n border: 1px solid var(--wje-color-primary-11);\n }\n}\n';
6
6
  class Carousel extends WJElement {
7
7
  /**
8
8
  * Carousel constructor method.
@@ -58,6 +58,13 @@ class Carousel extends WJElement {
58
58
  get loop() {
59
59
  return this.hasAttribute("loop");
60
60
  }
61
+ /**
62
+ * Continuous loop attribute.
63
+ * @returns {boolean}
64
+ */
65
+ get continuousLoop() {
66
+ return this.hasAttribute("continuous-loop");
67
+ }
61
68
  /**
62
69
  * Getter for the CSS stylesheet.
63
70
  * @returns {*}
@@ -70,7 +77,7 @@ class Carousel extends WJElement {
70
77
  * @returns {string[]}
71
78
  */
72
79
  static get observedAttributes() {
73
- return ["active-slide"];
80
+ return ["active-slide", "slide-per-page", "continuous-loop"];
74
81
  }
75
82
  /**
76
83
  * Sets up the attributes for the Carousel.
@@ -83,6 +90,14 @@ class Carousel extends WJElement {
83
90
  if (this.pagination) this.changePagination();
84
91
  if (this.thumbnails) this.changeThumbnails();
85
92
  }
93
+ if (["slide-per-page", "continuous-loop"].includes(name) && old !== newName && this.slides) {
94
+ this.syncSlideMetrics();
95
+ if (this.loop) {
96
+ this.refresh();
97
+ return;
98
+ }
99
+ this.goToSlide(this.activeSlide, "auto");
100
+ }
86
101
  }
87
102
  /**
88
103
  * Sets up the attributes for the Carousel.
@@ -95,6 +110,8 @@ class Carousel extends WJElement {
95
110
  * Before draw method for the Carousel.
96
111
  */
97
112
  beforeDraw() {
113
+ this.syncSlideMetrics();
114
+ this.removeLoopClones();
98
115
  this.cloneFirstAndLastItems();
99
116
  }
100
117
  /**
@@ -149,31 +166,28 @@ class Carousel extends WJElement {
149
166
  this.getSlidesWithClones().forEach((slide, i) => {
150
167
  this.intersectionObserver.observe(slide);
151
168
  });
152
- this.slidePerPage = this.getAttribute("slide-per-page") || 1;
153
- let carouselSize = 100 / +this.slidePerPage;
154
- this.style.setProperty("--wje-carousel-size", carouselSize + "%");
169
+ this.syncSlideMetrics();
155
170
  this.goToSlide(this.activeSlide, "auto");
156
- requestAnimationFrame(() => requestAnimationFrame(() => this.syncActiveToCenter()));
171
+ requestAnimationFrame(() => requestAnimationFrame(() => this.syncActiveToSnapStart()));
157
172
  this.slides.addEventListener("scrollend", (e) => {
158
- this.syncActiveToCenter();
173
+ this.syncActiveToSnapStart();
159
174
  });
160
175
  this.syncAria();
161
176
  }
162
177
  /**
163
- * Sync `activeSlide` to the slide whose center is closest to the container center.
178
+ * Sync `activeSlide` to the slide whose leading edge is closest to the snap start.
164
179
  */
165
- syncActiveToCenter() {
180
+ syncActiveToSnapStart() {
166
181
  this.getSlides();
167
182
  const withClones = this.getSlidesWithClones();
168
183
  if (!withClones.length) return;
169
184
  const containerRect = this.slides.getBoundingClientRect();
170
- const containerCenterX = containerRect.left + containerRect.width / 2;
185
+ const snapStartX = containerRect.left + this.getScrollPaddingInlineStart();
171
186
  let best = null;
172
187
  let bestDist = Infinity;
173
188
  withClones.forEach((el) => {
174
189
  const r = el.getBoundingClientRect();
175
- const center = r.left + r.width / 2;
176
- const dist = Math.abs(center - containerCenterX);
190
+ const dist = Math.abs(r.left - snapStartX);
177
191
  if (dist < bestDist) {
178
192
  bestDist = dist;
179
193
  best = el;
@@ -184,10 +198,42 @@ class Carousel extends WJElement {
184
198
  if (vIndex === -1) return;
185
199
  const logicalIndex = this.getLogicalIndexForVisual(vIndex);
186
200
  this.activeSlide = logicalIndex;
187
- if (this.loop && (vIndex === 0 || vIndex === withClones.length - 1)) {
201
+ this.setActiveVisualSlide(vIndex);
202
+ const canonicalVisualIndex = this.getVisualIndexForLogical(logicalIndex);
203
+ if (canonicalVisualIndex !== vIndex) {
188
204
  this.goToSlide(logicalIndex, "auto");
189
205
  }
190
206
  }
207
+ /**
208
+ * Syncs computed CSS variables derived from `slide-per-page`.
209
+ */
210
+ syncSlideMetrics() {
211
+ this.slidePerPage = Math.max(parseInt(this.getAttribute("slide-per-page"), 10) || 1, 1);
212
+ const visibleGapCount = Math.max(this.slidePerPage - 1, 0);
213
+ const computedItemSize = `calc((100% - (${visibleGapCount} * var(--wje-carousel-gap, 0.5rem))) / ${this.slidePerPage})`;
214
+ this.style.setProperty("--wje-carousel-slides-per-page", `${this.slidePerPage}`);
215
+ this.style.setProperty("--wje-carousel-visible-gap-count", `${visibleGapCount}`);
216
+ this.style.setProperty("--wje-carousel-size", computedItemSize);
217
+ this.style.setProperty("--wje-carousel-item-basis", "var(--wje-carousel-size)");
218
+ }
219
+ /**
220
+ * Returns the inline scroll padding used by the snap area.
221
+ * @returns {number}
222
+ */
223
+ getScrollPaddingInlineStart() {
224
+ if (!this.slides) return 0;
225
+ const styles2 = getComputedStyle(this.slides);
226
+ return parseFloat(styles2.scrollPaddingInlineStart || styles2.scrollPaddingLeft || "0") || 0;
227
+ }
228
+ /**
229
+ * Returns the interaction scroll behavior for UI controls.
230
+ * Continuous multi-slide loops use instant snapping to avoid blank edge states
231
+ * while the browser is still animating a previous smooth scroll.
232
+ * @returns {ScrollBehavior|string}
233
+ */
234
+ getControlBehavior() {
235
+ return this.continuousLoop && this.slidePerPage > 1 ? "auto" : "smooth";
236
+ }
191
237
  /**
192
238
  * Sets up the IntersectionObserver for the Carousel.
193
239
  */
@@ -218,11 +264,10 @@ class Carousel extends WJElement {
218
264
  goToSlide(index, behavior = "smooth", next = true) {
219
265
  const slides = this.getSlides();
220
266
  const withClones = this.getSlidesWithClones();
221
- withClones.forEach((slide) => slide.classList.remove("active"));
222
- const maxIndex = Math.max(slides.length - 1, 0);
267
+ const maxIndex = this.getMaxVisibleStartIndex(slides.length);
223
268
  let logical;
224
269
  if (this.loop && slides.length > 0) {
225
- logical = (index % slides.length + slides.length) % slides.length;
270
+ logical = this.normalizeLoopIndex(index, slides.length);
226
271
  } else {
227
272
  logical = Math.min(Math.max(index, 0), maxIndex);
228
273
  }
@@ -230,22 +275,25 @@ class Carousel extends WJElement {
230
275
  const vIndex = this.getVisualIndexForLogical(logical);
231
276
  const targetEl = withClones[vIndex];
232
277
  if (!targetEl) return;
233
- targetEl.classList.add("active");
234
- const targetRect = targetEl.getBoundingClientRect();
235
- const containerRect = this.slides.getBoundingClientRect();
236
- this.slides.scrollTo({
237
- left: targetRect.left - containerRect.left + this.slides.scrollLeft,
238
- top: targetRect.top - containerRect.top + this.slides.scrollTop,
239
- behavior: behavior === "smooth" ? "smooth" : "auto"
240
- });
278
+ this.setActiveVisualSlide(vIndex);
279
+ this.scrollToVisualIndex(vIndex, behavior);
241
280
  if (this.navigation && !this.loop) {
242
281
  this.nextButton.removeAttribute("disabled");
243
282
  this.prevButton.removeAttribute("disabled");
244
- if (this.activeSlide === slides.length - 1) this.nextButton.setAttribute("disabled", "");
283
+ if (this.activeSlide === maxIndex) this.nextButton.setAttribute("disabled", "");
245
284
  if (this.activeSlide === 0) this.prevButton.setAttribute("disabled", "");
246
285
  }
247
286
  this.syncAria();
248
287
  }
288
+ /**
289
+ * Sets the active class on the currently targeted visual slide and removes it elsewhere.
290
+ * @param {number} vIndex
291
+ */
292
+ setActiveVisualSlide(vIndex) {
293
+ this.getSlidesWithClones().forEach((slide, index) => {
294
+ slide.classList.toggle("active", index === vIndex);
295
+ });
296
+ }
249
297
  /**
250
298
  * Syncs ARIA attributes on the carousel and slides.
251
299
  */
@@ -273,14 +321,88 @@ class Carousel extends WJElement {
273
321
  cloneFirstAndLastItems() {
274
322
  const items = this.getSlides();
275
323
  if (items.length && this.loop) {
276
- const firstItemClone = items[0].cloneNode(true);
277
- firstItemClone.classList.add("clone");
278
- this.append(firstItemClone);
279
- const lastItemClone = items[items.length - 1].cloneNode(true);
280
- lastItemClone.classList.add("clone");
281
- this.insertBefore(lastItemClone, items[0]);
324
+ const cloneCount = this.getLoopCloneCount(items.length);
325
+ const firstOriginal = items[0];
326
+ items.slice(items.length - cloneCount).forEach((item) => {
327
+ const clone = this.createLoopClone(item);
328
+ this.insertBefore(clone, firstOriginal);
329
+ });
330
+ items.slice(0, cloneCount).forEach((item) => {
331
+ const clone = this.createLoopClone(item);
332
+ this.append(clone);
333
+ });
282
334
  }
283
335
  }
336
+ /**
337
+ * Creates a sanitized loop clone that does not inherit transient render state
338
+ * such as inline `visibility: hidden` from the source slide.
339
+ * @param {HTMLElement} item
340
+ * @returns {HTMLElement}
341
+ */
342
+ createLoopClone(item) {
343
+ var _a;
344
+ const clone = item.cloneNode(true);
345
+ clone.classList.add("clone");
346
+ clone.classList.remove("active");
347
+ clone.style.removeProperty("visibility");
348
+ if (!((_a = clone.getAttribute("style")) == null ? void 0 : _a.trim())) {
349
+ clone.removeAttribute("style");
350
+ }
351
+ return clone;
352
+ }
353
+ /**
354
+ * Removes loop clones so they can be rebuilt for the current configuration.
355
+ */
356
+ removeLoopClones() {
357
+ this.querySelectorAll("wje-carousel-item.clone").forEach((clone) => clone.remove());
358
+ }
359
+ /**
360
+ * Returns how many slides should be cloned on each side when loop is enabled.
361
+ * @param {number} totalSlides
362
+ * @returns {number}
363
+ */
364
+ getLoopCloneCount(totalSlides = this.getSlides().length) {
365
+ if (!this.loop || !totalSlides) return 0;
366
+ return this.continuousLoop ? Math.min(this.slidePerPage, totalSlides) : 1;
367
+ }
368
+ /**
369
+ * Scrolls the carousel to a visual slide index.
370
+ * @param {number} vIndex
371
+ * @param {ScrollBehavior|string} behavior
372
+ */
373
+ scrollToVisualIndex(vIndex, behavior = "smooth") {
374
+ const withClones = this.getSlidesWithClones();
375
+ const firstEl = withClones[0];
376
+ const targetEl = withClones[vIndex];
377
+ if (!firstEl || !targetEl || !this.slides) return;
378
+ const firstRect = firstEl.getBoundingClientRect();
379
+ const targetRect = targetEl.getBoundingClientRect();
380
+ const contentOffsetLeft = targetRect.left - firstRect.left;
381
+ const nextLeft = contentOffsetLeft - this.getScrollPaddingInlineStart();
382
+ const targetLeft = Math.max(nextLeft, 0);
383
+ if (behavior === "smooth") {
384
+ this.slides.scrollTo({
385
+ left: targetLeft,
386
+ top: this.slides.scrollTop,
387
+ behavior: "smooth"
388
+ });
389
+ return;
390
+ }
391
+ if (this.snapRestoreFrame) {
392
+ cancelAnimationFrame(this.snapRestoreFrame);
393
+ }
394
+ const inlineSnapType = this.slides.style.scrollSnapType;
395
+ this.slides.style.scrollSnapType = "none";
396
+ this.slides.scrollTo({
397
+ left: targetLeft,
398
+ top: this.slides.scrollTop,
399
+ behavior: "auto"
400
+ });
401
+ this.snapRestoreFrame = requestAnimationFrame(() => {
402
+ this.slides.style.scrollSnapType = inlineSnapType;
403
+ this.snapRestoreFrame = null;
404
+ });
405
+ }
284
406
  /**
285
407
  * Goes to the next slide.
286
408
  */
@@ -304,11 +426,8 @@ class Carousel extends WJElement {
304
426
  */
305
427
  changePagination() {
306
428
  if (this.pagination) {
307
- this.removeActiveSlide();
308
429
  this.context.querySelectorAll(".pagination-item").forEach((item, i) => {
309
- if (i === this.activeSlide) {
310
- item.classList.add("active");
311
- }
430
+ item.classList.toggle("active", i === this.activeSlide);
312
431
  });
313
432
  }
314
433
  }
@@ -317,11 +436,8 @@ class Carousel extends WJElement {
317
436
  */
318
437
  changeThumbnails() {
319
438
  if (this.thumbnails) {
320
- this.removeActiveSlide();
321
439
  this.context.querySelectorAll("wje-thumbnail").forEach((item, i) => {
322
- if (i === this.activeSlide) {
323
- item.classList.add("active");
324
- }
440
+ item.classList.toggle("active", i === this.activeSlide);
325
441
  });
326
442
  }
327
443
  }
@@ -337,9 +453,6 @@ class Carousel extends WJElement {
337
453
  nextButton.setAttribute("slot", "next");
338
454
  nextButton.innerHTML = '<wje-icon name="chevron-right" size="large"></wje-icon>';
339
455
  nextButton.classList.add("next");
340
- nextButton.addEventListener("click", (e) => {
341
- this.nextSlide();
342
- });
343
456
  return nextButton;
344
457
  }
345
458
  /**
@@ -354,9 +467,6 @@ class Carousel extends WJElement {
354
467
  previousButton.setAttribute("slot", "prev");
355
468
  previousButton.innerHTML = '<wje-icon name="chevron-left" size="large"></wje-icon>';
356
469
  previousButton.classList.add("prev");
357
- previousButton.addEventListener("click", (e) => {
358
- this.previousSlide();
359
- });
360
470
  return previousButton;
361
471
  }
362
472
  /**
@@ -367,14 +477,13 @@ class Carousel extends WJElement {
367
477
  const pagination = document.createElement("div");
368
478
  pagination.setAttribute("part", "pagination");
369
479
  pagination.classList.add("pagination");
370
- const slides = this.getSlides();
371
- slides.forEach((slide, i) => {
480
+ this.getPaginationIndexes().forEach((i) => {
372
481
  const paginationItem = document.createElement("div");
373
482
  paginationItem.classList.add("pagination-item");
374
483
  paginationItem.addEventListener("click", (e) => {
375
484
  this.removeActiveSlide();
376
485
  e.target.classList.add("active");
377
- this.goToSlide(i);
486
+ this.goToSlide(i, this.getControlBehavior());
378
487
  });
379
488
  pagination.append(paginationItem);
380
489
  });
@@ -394,7 +503,7 @@ class Carousel extends WJElement {
394
503
  thumbnail.addEventListener("click", (e) => {
395
504
  this.removeActiveSlide();
396
505
  e.target.closest("wje-thumbnail").classList.add("active");
397
- this.goToSlide(i);
506
+ this.goToSlide(i, this.getControlBehavior());
398
507
  });
399
508
  thumbnails.append(thumbnail);
400
509
  });
@@ -404,13 +513,13 @@ class Carousel extends WJElement {
404
513
  * Goes to the next slide.
405
514
  */
406
515
  nextSlide() {
407
- this.goToSlide(this.activeSlide + this.slidePerPage);
516
+ this.goToSlide(this.activeSlide + 1, this.getControlBehavior());
408
517
  }
409
518
  /**
410
519
  * Goes to the previous slide.
411
520
  */
412
521
  previousSlide() {
413
- this.goToSlide(this.activeSlide - this.slidePerPage);
522
+ this.goToSlide(this.activeSlide - 1, this.getControlBehavior());
414
523
  }
415
524
  /**
416
525
  * Goes to the slide.
@@ -428,16 +537,58 @@ class Carousel extends WJElement {
428
537
  }
429
538
  /** Maps logical index -> visual index (accounts for leading clone when loop=true) */
430
539
  getVisualIndexForLogical(index) {
431
- return this.loop ? index + 1 : index;
540
+ return this.loop ? index + this.getLoopCloneCount() : index;
432
541
  }
433
542
  /** Maps visual index -> logical index (handles clones at 0 and last when loop=true) */
434
543
  getLogicalIndexForVisual(vIndex) {
435
544
  const slides = this.getSlides();
436
- const withClones = this.getSlidesWithClones();
437
- if (!this.loop) return vIndex;
438
- if (vIndex === 0) return slides.length - 1;
439
- if (vIndex === withClones.length - 1) return 0;
440
- return vIndex - 1;
545
+ const maxIndex = this.getMaxVisibleStartIndex(slides.length);
546
+ const cloneCount = this.getLoopCloneCount(slides.length);
547
+ if (!this.loop) return Math.min(Math.max(vIndex, 0), maxIndex);
548
+ if (this.continuousLoop) {
549
+ if (vIndex < cloneCount) return slides.length - cloneCount + vIndex;
550
+ if (vIndex >= cloneCount + slides.length) return vIndex - (cloneCount + slides.length);
551
+ return vIndex - cloneCount;
552
+ }
553
+ if (vIndex < cloneCount) return maxIndex;
554
+ if (vIndex >= cloneCount + slides.length) return 0;
555
+ return Math.min(Math.max(vIndex - cloneCount, 0), maxIndex);
556
+ }
557
+ /**
558
+ * Returns the maximum logical slide index that can still render a full viewport.
559
+ * @param {number} totalSlides
560
+ * @returns {number}
561
+ */
562
+ getMaxVisibleStartIndex(totalSlides = this.getSlides().length) {
563
+ const visibleSlides = Math.min(this.slidePerPage, totalSlides);
564
+ return Math.max(totalSlides - visibleSlides, 0);
565
+ }
566
+ /**
567
+ * Normalizes a logical index for the active loop mode.
568
+ * @param {number} index
569
+ * @param {number} totalSlides
570
+ * @returns {number}
571
+ */
572
+ normalizeLoopIndex(index, totalSlides = this.getSlides().length) {
573
+ const logicalCount = this.getLoopLogicalCount(totalSlides);
574
+ if (!logicalCount) return 0;
575
+ return (index % logicalCount + logicalCount) % logicalCount;
576
+ }
577
+ /**
578
+ * Returns how many logical positions are reachable for the current loop mode.
579
+ * @param {number} totalSlides
580
+ * @returns {number}
581
+ */
582
+ getLoopLogicalCount(totalSlides = this.getSlides().length) {
583
+ if (!totalSlides) return 0;
584
+ return this.continuousLoop ? totalSlides : this.getMaxVisibleStartIndex(totalSlides) + 1;
585
+ }
586
+ /**
587
+ * Returns the pagination indexes for the current carousel mode.
588
+ * @returns {number[]}
589
+ */
590
+ getPaginationIndexes() {
591
+ return Array.from({ length: this.getLoopLogicalCount() }, (_, index) => index);
441
592
  }
442
593
  /**
443
594
  * Goes to the slide.