carousel-angular
Version:
A simple carousel component for Angular 14+ based on 'angular-responsive-carousel' by Ivy Laboratory http://ivylab.space
1 lines • 96.6 kB
Source Map (JSON)
{"version":3,"file":"carousel-angular.mjs","sources":["../../projects/carousel-angular/src/lib/touches.ts","../../projects/carousel-angular/src/lib/carousel.ts","../../projects/carousel-angular/src/lib/container.ts","../../projects/carousel-angular/src/lib/cells.ts","../../projects/carousel-angular/src/lib/slide.ts","../../projects/carousel-angular/src/lib/utils.ts","../../projects/carousel-angular/src/lib/carousel.component.ts","../../projects/carousel-angular/src/lib/carousel.component.html","../../projects/carousel-angular/src/lib/carousel.module.ts","../../projects/carousel-angular/src/public-api.ts","../../projects/carousel-angular/src/carousel-angular.ts"],"sourcesContent":["export interface Properties {\n element: HTMLElement;\n listeners?: 'auto' | 'mouse and touch';\n touchListeners?: any;\n mouseListeners?: any;\n otherListeners?: any;\n resize?: boolean;\n}\n\nexport type EventType =\n | undefined\n | 'touchend'\n | 'pan'\n | 'pinch'\n | 'horizontal-swipe'\n | 'vertical-swipe'\n | 'tap'\n | 'longtap';\nexport type TouchHandler =\n | 'handleTouchstart'\n | 'handleTouchmove'\n | 'handleTouchend';\nexport type MouseHandler =\n | 'handleMousedown'\n | 'handleMousemove'\n | 'handleMouseup';\n\nexport class Touches {\n properties: Properties;\n\n element: HTMLElement;\n\n elementPosition: ClientRect;\n\n eventType: EventType = undefined;\n\n handlers: any = {};\n\n startX = 0;\n\n startY = 0;\n\n lastTap = 0;\n\n doubleTapTimeout: any;\n\n doubleTapMinTimeout = 300;\n\n tapMinTimeout = 200;\n\n touchstartTime = 0;\n\n i = 0;\n\n isMousedown = false;\n\n _touchListeners: any = {\n touchstart: 'handleTouchstart',\n touchmove: 'handleTouchmove',\n touchend: 'handleTouchend'\n };\n\n _mouseListeners: any = {\n mousedown: 'handleMousedown',\n mousemove: 'handleMousemove',\n mouseup: 'handleMouseup',\n wheel: 'handleWheel'\n };\n\n _otherListeners: any = {\n resize: 'handleResize'\n };\n\n get touchListeners() {\n return this.properties.touchListeners\n ? this.properties.touchListeners\n : this._touchListeners;\n }\n\n get mouseListeners() {\n return this.properties.mouseListeners\n ? this.properties.mouseListeners\n : this._mouseListeners;\n }\n\n get otherListeners() {\n return this.properties.otherListeners\n ? this.properties.otherListeners\n : this._otherListeners;\n }\n\n constructor(properties: Properties) {\n this.properties = properties;\n this.element = this.properties.element;\n this.elementPosition = this.getElementPosition();\n\n this.toggleEventListeners('addEventListener');\n }\n\n destroy() {\n this.toggleEventListeners('removeEventListener');\n }\n\n toggleEventListeners(action: 'addEventListener' | 'removeEventListener') {\n let listeners;\n\n if (this.properties.listeners === 'mouse and touch') {\n listeners = Object.assign(this.touchListeners, this.mouseListeners);\n } else {\n listeners = this.detectTouchScreen()\n ? this.touchListeners\n : this.mouseListeners;\n }\n\n if (this.properties.resize) {\n listeners = Object.assign(listeners, this.otherListeners);\n }\n\n for (const listener in listeners) {\n const handler: MouseHandler = listeners[listener];\n\n // Window\n if (listener === 'resize') {\n if (action === 'addEventListener') {\n window.addEventListener(listener, this[handler], false);\n }\n if (action === 'removeEventListener') {\n window.removeEventListener(listener, this[handler], false);\n }\n // Document\n } else if (listener === 'mouseup' || listener === 'mousemove') {\n if (action === 'addEventListener') {\n document.addEventListener(listener, this[handler], {\n passive: false\n });\n }\n if (action === 'removeEventListener') {\n document.removeEventListener(listener, this[handler], false);\n }\n // Element\n } else {\n if (action === 'addEventListener') {\n this.element.addEventListener(listener, this[handler], false);\n }\n if (action === 'removeEventListener') {\n this.element.removeEventListener(listener, this[handler], false);\n }\n }\n }\n }\n\n addEventListeners(listener: string) {\n const handler: MouseHandler = this._mouseListeners[listener];\n window.addEventListener(listener, this[handler], false);\n }\n\n removeEventListeners(listener: string) {\n const handler: MouseHandler = this._mouseListeners[listener];\n window.removeEventListener(listener, this[handler], false);\n }\n\n /*\n * Listeners\n */\n\n /* Touchstart */\n\n handleTouchstart = (event: any) => {\n this.elementPosition = this.getElementPosition();\n this.touchstartTime = new Date().getTime();\n\n if (this.eventType === undefined) {\n this.getTouchstartPosition(event);\n }\n\n this.runHandler('touchstart', event);\n };\n\n /* Touchmove */\n\n handleTouchmove = (event: any) => {\n const { touches } = event;\n\n // Pan\n if (this.detectPan(touches)) {\n this.runHandler('pan', event);\n }\n\n // Pinch\n if (this.detectPinch(event)) {\n this.runHandler('pinch', event);\n }\n\n // Linear swipe\n switch (this.detectLinearSwipe(event)) {\n case 'horizontal-swipe':\n event.swipeType = 'horizontal-swipe';\n this.runHandler('horizontal-swipe', event);\n break;\n case 'vertical-swipe':\n event.swipeType = 'vertical-swipe';\n this.runHandler('vertical-swipe', event);\n break;\n }\n\n // Linear swipe\n if (\n this.detectLinearSwipe(event) ||\n this.eventType === 'horizontal-swipe' ||\n this.eventType === 'vertical-swipe'\n ) {\n this.handleLinearSwipe(event);\n }\n };\n\n handleLinearSwipe(event: any) {\n // event.preventDefault();\n\n this.i++;\n\n if (this.i > 3) {\n this.eventType = this.getLinearSwipeType(event);\n }\n\n if (this.eventType === 'horizontal-swipe') {\n this.runHandler('horizontal-swipe', event);\n }\n\n if (this.eventType === 'vertical-swipe') {\n this.runHandler('vertical-swipe', event);\n }\n }\n\n /* Touchend */\n\n handleTouchend = (event: any) => {\n const { touches } = event;\n\n // Double Tap\n if (this.detectDoubleTap()) {\n this.runHandler('double-tap', event);\n }\n\n // Tap\n this.detectTap();\n\n this.runHandler('touchend', event);\n this.eventType = 'touchend';\n\n if (touches && touches.length === 0) {\n this.eventType = undefined;\n this.i = 0;\n }\n };\n\n /* Mousedown */\n\n handleMousedown = (event: any) => {\n this.isMousedown = true;\n this.elementPosition = this.getElementPosition();\n this.touchstartTime = new Date().getTime();\n\n if (this.eventType === undefined) {\n this.getMousedownPosition(event);\n }\n\n this.runHandler('mousedown', event);\n };\n\n /* Mousemove */\n\n handleMousemove = (event: any) => {\n // event.preventDefault();\n\n if (!this.isMousedown) {\n return;\n }\n\n // Pan\n this.runHandler('pan', event);\n\n // Linear swipe\n switch (this.detectLinearSwipe(event)) {\n case 'horizontal-swipe':\n event.swipeType = 'horizontal-swipe';\n this.runHandler('horizontal-swipe', event);\n break;\n case 'vertical-swipe':\n event.swipeType = 'vertical-swipe';\n this.runHandler('vertical-swipe', event);\n break;\n }\n\n // Linear swipe\n if (\n this.detectLinearSwipe(event) ||\n this.eventType === 'horizontal-swipe' ||\n this.eventType === 'vertical-swipe'\n ) {\n this.handleLinearSwipe(event);\n }\n };\n\n /* Mouseup */\n\n handleMouseup = (event: any) => {\n // Tap\n this.detectTap();\n\n this.isMousedown = false;\n this.runHandler('mouseup', event);\n this.eventType = undefined;\n this.i = 0;\n };\n\n /* Wheel */\n\n handleWheel = (event: any) => {\n this.runHandler('wheel', event);\n };\n\n /* Resize */\n\n handleResize = (event: any) => {\n this.runHandler('resize', event);\n };\n\n runHandler(eventName: any, response: any) {\n if (this.handlers[eventName]) {\n this.handlers[eventName](response);\n }\n }\n\n /*\n * Detection\n */\n\n detectPan(touches: any) {\n return (\n (touches.length === 1 && !this.eventType) || this.eventType === 'pan'\n );\n }\n\n detectDoubleTap() {\n if (this.eventType != undefined) {\n return;\n }\n\n const currentTime = new Date().getTime();\n const tapLength = currentTime - this.lastTap;\n\n clearTimeout(this.doubleTapTimeout);\n\n if (tapLength < this.doubleTapMinTimeout && tapLength > 0) {\n return true;\n }\n this.doubleTapTimeout = setTimeout(() => {\n clearTimeout(this.doubleTapTimeout);\n }, this.doubleTapMinTimeout);\n\n this.lastTap = currentTime;\n\n return undefined;\n }\n\n detectTap(): void {\n if (this.eventType != undefined) {\n return;\n }\n\n const currentTime = new Date().getTime();\n const tapLength = currentTime - this.touchstartTime;\n\n if (tapLength > 0) {\n if (tapLength < this.tapMinTimeout) {\n this.runHandler('tap', event);\n } else {\n this.runHandler('longtap', event);\n }\n }\n }\n\n detectPinch(event: any) {\n const { touches } = event;\n return (\n (touches.length === 2 && this.eventType === undefined) ||\n this.eventType === 'pinch'\n );\n }\n\n detectLinearSwipe(event: any) {\n const { touches } = event;\n\n if (touches) {\n if (\n (touches.length === 1 && !this.eventType) ||\n this.eventType === 'horizontal-swipe' ||\n this.eventType === 'vertical-swipe'\n ) {\n return this.getLinearSwipeType(event);\n }\n } else if (\n !this.eventType ||\n this.eventType === 'horizontal-swipe' ||\n this.eventType === 'vertical-swipe'\n ) {\n return this.getLinearSwipeType(event);\n }\n\n return undefined;\n }\n\n getLinearSwipeType(event: any) {\n if (\n this.eventType !== 'horizontal-swipe' &&\n this.eventType !== 'vertical-swipe'\n ) {\n const movementX = Math.abs(this.moveLeft(0, event) - this.startX);\n const movementY = Math.abs(this.moveTop(0, event) - this.startY);\n\n if (movementY * 3 > movementX) {\n return 'vertical-swipe';\n }\n return 'horizontal-swipe';\n }\n return this.eventType;\n }\n\n getElementPosition() {\n return this.element.getBoundingClientRect();\n }\n\n getTouchstartPosition(event: any) {\n this.startX = event.touches[0].clientX - this.elementPosition.left;\n this.startY = event.touches[0].clientY - this.elementPosition.top;\n }\n\n getMousedownPosition(event: any) {\n this.startX = event.clientX - this.elementPosition.left;\n this.startY = event.clientY - this.elementPosition.top;\n }\n\n moveLeft(index: any, event: any) {\n const { touches } = event;\n\n if (touches) {\n return touches[index].clientX - this.elementPosition.left;\n }\n return event.clientX - this.elementPosition.left;\n }\n\n moveTop(index: any, event: any) {\n const { touches } = event;\n\n if (touches) {\n return touches[index].clientY - this.elementPosition.top;\n }\n return event.clientY - this.elementPosition.top;\n }\n\n detectTouchScreen() {\n const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');\n const mq = function (query: any) {\n return window.matchMedia(query).matches;\n };\n\n if ('ontouchstart' in window) {\n return true;\n }\n\n // include the 'heartz' as a way to have a non matching MQ to help terminate the join\n // https://git.io/vznFH\n const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(\n ''\n );\n return mq(query);\n }\n\n /* Public properties and methods */\n on(event: EventType, handler: Function) {\n if (event) {\n this.handlers[event] = handler;\n }\n }\n}\n","import { Properties } from './interfaces';\n\nexport class Carousel {\n cellsElement: HTMLElement | undefined;\n\n visibleWidth!: number;\n\n autoplayId: any = null;\n\n get cellLength() {\n return this.cells.cellLength;\n }\n\n get lastCellIndex() {\n return this.cells.cellLength - 1;\n }\n\n get overflowCellsLimit() {\n return this.utils.overflowCellsLimit;\n }\n\n get autoplayIsPossible() {\n return this.properties.autoplayIsPossible;\n }\n\n get margin() {\n return this.properties.margin;\n }\n\n get minSwipeDistance() {\n return this.properties.minSwipeDistance;\n }\n\n get transitionDuration() {\n return this.properties.transitionDuration;\n }\n\n get transitionTimingFunction() {\n return this.properties.transitionTimingFunction;\n }\n\n get fullCellWidth() {\n return this.properties.cellWidth + this.margin;\n }\n\n get numberOfVisibleCells() {\n return this.utils.numberOfVisibleCells;\n }\n\n get slideCounter() {\n return this.slide.counter;\n }\n\n constructor(\n private properties: Properties,\n private utils: any,\n private cells: any,\n private container: any,\n private slide: any\n ) {\n this.init();\n }\n\n updateProperties(properties: Properties) {\n this.properties = properties;\n }\n\n init() {\n this.cellsElement = this.properties.cellsElement;\n this.visibleWidth =\n this.properties.visibleWidth ||\n this.cellsElement!.parentElement!.clientWidth;\n }\n\n destroy() {\n clearInterval(this.autoplayId);\n }\n\n lineUpCells() {\n this.cells.lineUp();\n }\n\n handleTouchstart = (event: any) => {\n this.container.handleTouchstart();\n this.slide.handleTouchstart(event);\n };\n\n handleHorizontalSwipe = (event: any) => {\n this.container.handleHorizontalSwipe();\n };\n\n handleTouchend = (event: any) => {\n if (this.properties.freeScroll) {\n this.container.handleTouchend();\n } else {\n this.container.handleTouchend(true);\n this.slide.handleTouchend(event);\n }\n };\n\n handleTransitionend() {\n this.slide.handleTransitionend();\n }\n\n next(length = 1) {\n if (!this.isNextArrowDisabled()) {\n this.slide.next(length);\n }\n }\n\n prev(length = 1) {\n this.slide.prev(length);\n }\n\n isNextArrowDisabled = () => this.slide.isNextArrowDisabled();\n\n isPrevArrowDisabled = () => this.slide.isPrevArrowDisabled();\n\n autoplay() {\n if (this.autoplayId === null) {\n this.autoplayId = setInterval(() => {\n if (this.autoplayIsPossible) {\n this.next();\n }\n }, this.properties.autoplayInterval);\n }\n }\n\n stopAutoplay() {\n if (this.autoplayId != null) {\n clearInterval(this.autoplayId);\n this.autoplayId = null;\n }\n }\n}\n","import { Properties as CarouselProperties } from './interfaces';\n\nexport class Container {\n /* The index of the new position relative to\n * the active index, for example -1 or +1\n */\n initialPositionX = 0;\n\n initialElementPositionX = 0;\n\n pullLimit = 100;\n\n startTime = 0;\n\n startX = 0;\n\n moveX = 0;\n\n isSwipeInProgress = false;\n\n get visibleWidth() {\n return this.utils.visibleWidth;\n }\n\n get overflowCellsLimit() {\n return this.utils.overflowCellsLimit;\n }\n\n get element() {\n return this.carouselProperties.cellsElement;\n }\n\n get freeScroll() {\n return this.carouselProperties.freeScroll;\n }\n\n get fullCellWidth() {\n return this.carouselProperties.cellWidth + this.carouselProperties.margin;\n }\n\n get numberOfVisibleCells() {\n return this.utils.numberOfVisibleCells;\n }\n\n get transitionDuration() {\n return this.carouselProperties.transitionDuration;\n }\n\n get transitionTimingFunction() {\n return this.carouselProperties.transitionTimingFunction;\n }\n\n get cellLength() {\n return this.cells.cellLength;\n }\n\n get tooFewCells() {\n return this.numberOfVisibleCells > this.cellLength;\n }\n\n get disabled() {\n return this.tooFewCells;\n }\n\n get margin() {\n return this.carouselProperties.margin;\n }\n\n constructor(\n private carouselProperties: CarouselProperties,\n private utils: any,\n private cells: any\n ) {\n this.init();\n }\n\n updateProperties(carouselProperties: CarouselProperties) {\n this.carouselProperties = carouselProperties;\n }\n\n init() {\n this.setWidth();\n }\n\n handleTouchstart() {\n this.startX = this.utils.getStartX(event);\n this.startTime = new Date().getTime();\n this.initialElementPositionX = this.getInitialElementPositionX();\n }\n\n handleHorizontalSwipe() {\n if (this.disabled) {\n return;\n }\n\n if (!this.isSwipeInProgress) {\n this.startX = this.utils.getStartX(event);\n this.startTime = new Date().getTime();\n this.initialElementPositionX = this.getInitialElementPositionX();\n }\n\n this.isSwipeInProgress = true;\n this.moveX = this.utils.getMoveX(event);\n this.move();\n }\n\n handleTouchend(simpleProcessing = false) {\n if (this.disabled) {\n return;\n }\n\n /* If touchend was passed to the Slide class */\n if (simpleProcessing) {\n this.isSwipeInProgress = false;\n return;\n }\n\n this.isSwipeInProgress = false;\n this.finishMoving();\n this.clearInitialValues();\n }\n\n move() {\n let positionX: number = this.getMovePositionX();\n const isPulled = this.detectPulled();\n const direction = this.getDirection();\n\n if (isPulled) {\n if (\n (isPulled.edge === 'left' && direction === 'right') ||\n (isPulled.edge === 'right' && direction === 'left')\n ) {\n positionX = this.slowdownOnPull(positionX);\n }\n }\n\n this.transformPositionX(positionX, 0);\n\n if (this.freeScroll) {\n this.initialPositionX = positionX;\n }\n\n if (isPulled) {\n if (isPulled.edge === 'left' && isPulled.overflowX > this.pullLimit) {\n this.initialPositionX = 0;\n }\n if (isPulled.edge === 'right' && isPulled.overflowX > this.pullLimit) {\n this.initialPositionX = positionX;\n }\n }\n }\n\n getMovePositionX() {\n const distance = this.getDistance();\n return this.initialElementPositionX - distance;\n }\n\n getDistance() {\n return this.startX - this.moveX;\n }\n\n /* If the container is pulled out of the left or right border */\n detectPulled() {\n const currentPositionX = this.getCurrentPositionX();\n\n if (currentPositionX > 0) {\n return {\n edge: 'left',\n positionX: currentPositionX,\n overflowX: Math.abs(currentPositionX)\n };\n }\n\n if (currentPositionX < this.getEndPosition()) {\n return {\n edge: 'right',\n positionX: currentPositionX,\n overflowX: Math.abs(currentPositionX - this.getEndPosition())\n };\n }\n\n return undefined;\n }\n\n slowdownOnPull(_positionX: number) {\n let distance = Math.abs(this.getDistance());\n const endPosition = this.getEndPosition();\n const isPulled = this.detectPulled();\n\n if (!isPulled) {\n return 0;\n }\n\n const decelerationRatio = 3 + isPulled.overflowX / 50;\n let positionX = 0;\n\n if (isPulled.edge === 'left') {\n if (this.initialElementPositionX < 0) {\n distance -= Math.abs(this.initialElementPositionX);\n }\n\n const rubberPositionX = distance / decelerationRatio;\n positionX = rubberPositionX;\n\n if (this.initialElementPositionX > 0) {\n positionX = this.initialElementPositionX + rubberPositionX;\n }\n\n if (positionX > this.pullLimit) {\n positionX = this.pullLimit;\n }\n }\n\n if (isPulled.edge === 'right') {\n const rubberPositionX =\n endPosition +\n (this.initialElementPositionX - distance - endPosition) /\n decelerationRatio;\n const containerWidth = this.getWidth();\n\n positionX = rubberPositionX;\n\n if (\n this.initialElementPositionX < -(containerWidth - this.visibleWidth)\n ) {\n positionX =\n containerWidth -\n this.visibleWidth +\n this.initialElementPositionX +\n rubberPositionX;\n }\n\n if (positionX < endPosition - this.pullLimit) {\n positionX = endPosition - this.pullLimit;\n }\n }\n\n return positionX;\n }\n\n finishMoving() {\n const positionX = this.getMovePositionX();\n let newPositionX = 0;\n\n if (this.freeScroll) {\n newPositionX = this.getInertia();\n }\n\n /* Align container while pulling */\n newPositionX = this.getAlignedPositionOnPull(newPositionX);\n\n this.transformPositionX(newPositionX);\n this.setInitialPosition(positionX);\n }\n\n /* Returns the new position of the container with inertia */\n getInertia() {\n const distance = this.getDistance();\n const currentTime = new Date().getTime();\n const tapLength = currentTime - this.startTime;\n const inertia = (distance / tapLength) * 100;\n\n return this.initialPositionX - inertia;\n }\n\n getAlignedPositionOnPull(newPositionX: number) {\n const direction = this.getDirection();\n\n if (direction === 'left') {\n const endPosition = this.getEndPosition();\n if (newPositionX < endPosition) {\n return endPosition;\n }\n }\n\n return newPositionX;\n }\n\n getCurrentPositionX() {\n const parentPosition = this.element!.parentElement!.getBoundingClientRect();\n const position = this.element.getBoundingClientRect();\n return position.left - parentPosition.left;\n }\n\n getEndPosition() {\n const width = this.getWidth();\n const visibleWidth = this.element!.parentElement!.clientWidth;\n return visibleWidth - width;\n }\n\n transformPositionX(value: number, duration = this.transitionDuration) {\n if (value === undefined) {\n return;\n }\n\n this.element.style.transition = `transform ${duration}ms ${this.transitionTimingFunction}`;\n this.element.style.transform = `translateX(${value}px)`;\n }\n\n getWidth() {\n return this.cellLength * this.fullCellWidth;\n }\n\n setWidth() {\n const width = this.getWidth();\n this.element.style.width = `${width}px`;\n }\n\n setInitialPosition(position: number) {\n this.initialPositionX = position;\n }\n\n getElementPosition() {\n return this.element.getBoundingClientRect();\n }\n\n getInitialElementPositionX() {\n const carouselElementPosition =\n this.utils.getCarouselElementPosition().left;\n return this.getElementPosition().left - carouselElementPosition;\n }\n\n clearInitialValues() {\n this.startX = this.moveX = 0;\n }\n\n getDirection() {\n const direction = Math.sign(this.startX - this.moveX);\n\n if (direction === -1) {\n return 'right';\n }\n if (direction === 1) {\n return 'left';\n }\n\n return undefined;\n }\n}\n","import { Properties as CarouselProperties } from './interfaces';\n\nexport class Cells {\n cells: HTMLCollection | undefined;\n\n element!: HTMLElement;\n\n visibleWidth: number | undefined;\n\n counter = 0;\n\n get cellLength() {\n return this.cells ? this.cells.length : 0;\n }\n\n get fullCellWidth() {\n return this.carouselProperties.cellWidth + this.carouselProperties.margin;\n }\n\n get cellLengthInLightDOMMode() {\n return this.cellLength;\n }\n\n get numberOfVisibleCells() {\n return this.utils.numberOfVisibleCells;\n }\n\n get overflowCellsLimit() {\n return this.utils.overflowCellsLimit;\n }\n\n constructor(\n private carouselProperties: CarouselProperties,\n private utils: any\n ) {\n this.init(carouselProperties);\n }\n\n updateProperties(carouselProperties: CarouselProperties) {\n this.carouselProperties = carouselProperties;\n }\n\n lineUp() {\n const cells = this.element ? this.element.children : [];\n\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i];\n const positionX = this.getCellPositionInContainer(i);\n (cell as HTMLElement).style.transform = `translateX(${positionX}px)`;\n (\n cell as HTMLElement\n ).style.width = `${this.carouselProperties.cellWidth}px`;\n }\n }\n\n ifSequenceOfCellsIsChanged() {\n const cells: any = this.element.children;\n return cells[0].style.transform !== 'translateX(0px)';\n }\n\n getCellPositionInContainer(cellIndexInDOMTree: number) {\n return cellIndexInDOMTree * this.fullCellWidth;\n }\n\n setCounter(value: number) {\n this.counter = value;\n }\n\n init(carouselProperties: CarouselProperties) {\n this.element = this.carouselProperties.cellsElement;\n this.cells = this.element.children;\n this.visibleWidth =\n this.carouselProperties.visibleWidth ||\n this.element!.parentElement!.clientWidth;\n }\n}\n","import { Properties as CarouselProperties } from './interfaces';\n\nexport interface Properties {\n carouselProperties: CarouselProperties;\n}\n\nexport class Slide {\n slideLength = 0;\n\n isSlideInProgress = false;\n\n direction: 'left' | 'right' | undefined;\n\n counter = 0;\n\n _counter = 0;\n\n distance = 0;\n\n distanceAbs = 0;\n\n visibleWidth!: number;\n\n isNotClickOnArrow = false;\n\n initialPositionX = 0;\n\n currentPositionX = 0;\n\n /* The slide length has been limited by the limitSlideLength() method */\n isSlideLengthLimited = false;\n\n get fullCellWidth() {\n return this.carouselProperties.cellWidth + this.carouselProperties.margin;\n }\n\n get margin() {\n return this.carouselProperties.margin;\n }\n\n get minSwipeDistance() {\n return this.carouselProperties.minSwipeDistance;\n }\n\n get numberOfVisibleCells() {\n return this.utils.numberOfVisibleCells;\n }\n\n get visibleCellsOverflowContainer() {\n return this.utils.visibleCellsOverflowContainer;\n }\n\n /* The position to which the container returns after each slide\n * in the light DUM tree mode.\n */\n get fixedContainerPosition() {\n return -(this.overflowCellsLimit * this.fullCellWidth);\n }\n\n get overflowCellsLimit() {\n return this.utils.overflowCellsLimit;\n }\n\n /* Number of cell elements in the DUM tree */\n get cellLength() {\n return this.cells.cellLength;\n }\n\n constructor(\n private carouselProperties: CarouselProperties,\n private utils: any,\n private cells: any,\n private container: any\n ) {\n this.init();\n }\n\n updateProperties(carouselProperties: CarouselProperties) {\n this.carouselProperties = carouselProperties;\n this.setVisibleWidth();\n }\n\n init() {\n this.visibleWidth =\n this.carouselProperties.visibleWidth ||\n this.carouselProperties.hostElement.clientWidth;\n }\n\n handleTouchstart() {\n /* Touchstart event is not called for arrow */\n this.isNotClickOnArrow = true;\n this.isSlideLengthLimited = false;\n\n if (!this.isSlideInProgress) {\n this.initialPositionX = this.container.getCurrentPositionX();\n }\n }\n\n handleTouchend() {\n if (!this.isNotClickOnArrow) {\n return;\n }\n this.currentPositionX = this.container.getCurrentPositionX();\n this.distanceAbs = Math.abs(this.initialPositionX - this.currentPositionX);\n this.distance = this.initialPositionX - this.currentPositionX;\n this.direction = this.getDirection();\n this.isNotClickOnArrow = false;\n this.handleSlide();\n }\n\n handleTransitionend() {\n this.setCounter();\n this.isSlideInProgress = false;\n }\n\n handleSlide(customSlideLength: number | undefined = undefined) {\n const isUsingButton = customSlideLength;\n let newPositionX;\n\n if ((isUsingButton && this.isSlideInProgress) || !this.direction) {\n return;\n }\n\n /* Custom slide length is used in arrows */\n if (customSlideLength) {\n this.slideLength = this.limitSlideLength(customSlideLength);\n\n if (!this.isSlideInProgress) {\n this.initialPositionX = this.container.getCurrentPositionX();\n }\n } else {\n this.slideLength = this.getSlideLength(this.distanceAbs);\n }\n\n /* Store intermediate counter value */\n this._counter = this.getPreliminaryCounter();\n\n if (this.direction === 'left') {\n if (!customSlideLength) {\n this.slideLength = this.limitSlideLength(\n this.getSlideLength(this.distanceAbs)\n );\n }\n\n this._counter = this.getPreliminaryCounter();\n const isSlidesEnd = this.isSlidesEnd(this._counter);\n newPositionX = this.getPositionByIndex(this._counter);\n\n if (isSlidesEnd) {\n this._counter = this.counter;\n\n newPositionX = this.getPositionByIndex(this.counter);\n this.slideLength = 0;\n }\n }\n\n if (this.direction === 'right') {\n if (!customSlideLength) {\n this.slideLength = this.getSlideLength(this.distanceAbs);\n }\n\n if (this._counter < 0) {\n this._counter = this.counter;\n this.slideLength = this.counter;\n }\n\n newPositionX = this.getPositionByIndex(this.counter - this.slideLength);\n }\n\n if (this.container.getCurrentPositionX() !== newPositionX) {\n this.isSlideInProgress = true;\n this.container.transformPositionX(newPositionX);\n }\n }\n\n next(length = 1) {\n this.direction = 'left';\n this.handleSlide(length);\n }\n\n prev(length = 1) {\n this.direction = 'right';\n this.handleSlide(length);\n }\n\n select(index: number) {\n if (index > this.cellLength - 1) {\n return;\n }\n\n if (index > this.counter) {\n const length = index - this.counter;\n this.next(length);\n }\n\n if (index < this.counter) {\n const length = this.counter - index;\n this.prev(length);\n }\n }\n\n getPreliminaryCounter() {\n if (this.direction === 'left') {\n return this.counter + this.slideLength;\n }\n\n if (this.direction === 'right') {\n return this.counter - this.slideLength;\n }\n\n return 0;\n }\n\n /*\n * Limits the length of the slide during calls to the next() and prev()\n * methods if the specified position is outside the cell length\n */\n limitSlideLength(slideLength: number) {\n if (slideLength > 1) {\n for (let i = 0; i < slideLength; i++) {\n const newCounter = this.counter + (slideLength - i);\n\n if (!this.isSlidesEnd(newCounter)) {\n slideLength -= i;\n this.isSlideLengthLimited = i > 0;\n break;\n }\n }\n }\n return slideLength;\n }\n\n /* Offset the container to show the last cell completely */\n getPositionCorrection(counter: number) {\n let correction = 0;\n const isLastSlide = this.isLastSlide(counter);\n\n if (this.isSlideLengthLimited || isLastSlide) {\n const cellsWidth =\n this.cells.cellLengthInLightDOMMode * this.fullCellWidth;\n\n if (this.visibleWidth < cellsWidth) {\n correction = -(\n this.numberOfVisibleCells * this.fullCellWidth -\n this.visibleWidth -\n this.margin\n );\n }\n\n if (correction >= -this.margin) {\n correction = 0;\n }\n }\n\n return correction;\n }\n\n getSlideLength(distanceAbs: number) {\n let length = Math.floor(distanceAbs / this.fullCellWidth);\n\n if (distanceAbs % this.fullCellWidth >= this.minSwipeDistance) {\n length++;\n }\n\n return length;\n }\n\n getDistanceAbs() {\n return Math.abs(this.initialPositionX - this.currentPositionX);\n }\n\n getDirection() {\n const direction = Math.sign(this.initialPositionX - this.currentPositionX);\n\n if (direction === -1) {\n return 'right';\n }\n if (direction === 1) {\n return 'left';\n }\n\n return undefined;\n }\n\n isSlidesEnd(counter: number) {\n const margin = this.visibleCellsOverflowContainer ? 1 : 0;\n const imageLength = this.cells.cellLength;\n\n return imageLength - counter + margin < this.numberOfVisibleCells;\n }\n\n isLastSlide(counter: number) {\n return this.isSlidesEnd(counter + 1);\n }\n\n setCounter() {\n if (this.direction === 'left') {\n this.counter += this.slideLength;\n }\n\n if (this.direction === 'right') {\n this.counter -= this.slideLength;\n }\n }\n\n getPositionByIndex(_counter: number) {\n let correction = this.getPositionCorrection(\n this.counter + this.slideLength\n );\n let position;\n\n if (correction !== 0) {\n correction += this.fullCellWidth;\n }\n\n if (this.direction === 'right') {\n correction = 0;\n }\n\n position = -(_counter * this.fullCellWidth - correction);\n\n position = this.provideSafePosition(position);\n\n return position;\n }\n\n provideSafePosition(position: number) {\n const endPosition = this.container.getEndPosition();\n\n if (this.direction === 'left') {\n if (position > 0) {\n position = 0;\n }\n }\n\n if (this.direction === 'right') {\n if (position < endPosition) {\n position = endPosition;\n }\n }\n\n return position;\n }\n\n getPositionWithoutCorrection(value: number) {\n const remainder = Math.round(value) % this.fullCellWidth;\n\n if (remainder !== 0) {\n return value - (this.fullCellWidth + remainder);\n }\n return value;\n }\n\n isNextArrowDisabled() {\n return (\n this.isLastSlide(this.counter) ||\n (!this.visibleCellsOverflowContainer &&\n this.cellLength <= this.numberOfVisibleCells) ||\n (this.visibleCellsOverflowContainer &&\n this.cellLength < this.numberOfVisibleCells)\n );\n }\n\n isPrevArrowDisabled() {\n return this.counter === 0;\n }\n\n alignContainerFast() {\n if (this.ifLeftDOMModeToBeginning(this.counter)) {\n /* If we have already exited the light DOM mode but\n * the cells are still out of place\n */\n if (this.cells.ifSequenceOfCellsIsChanged()) {\n const positionX = -(this.counter * this.fullCellWidth);\n this.container.transformPositionX(positionX, 0);\n\n this.cells.setCounter(this.counter);\n this.cells.lineUp();\n }\n }\n }\n\n ifLeftDOMModeToBeginning(counter: number) {\n let flag;\n\n if (counter <= this.overflowCellsLimit) {\n flag = true;\n }\n\n if (this.counter <= this.overflowCellsLimit) {\n flag = true;\n }\n\n return flag;\n }\n\n setVisibleWidth() {\n this.visibleWidth =\n this.carouselProperties.visibleWidth ||\n this.carouselProperties.hostElement.clientWidth;\n }\n}\n","import { Properties as CarouselProperties } from './interfaces';\n\nexport class Utils {\n get margin() {\n return this.carouselProperties.margin;\n }\n\n get overflowCellsLimit() {\n return this.carouselProperties.overflowCellsLimit;\n }\n\n get numberOfVisibleCells() {\n return Math.ceil(this.visibleWidth / this.fullCellWidth);\n }\n\n get visibleCellsOverflowContainer() {\n return (\n this.numberOfVisibleCells * this.fullCellWidth - this.margin >\n this.visibleWidth\n );\n }\n\n get fullCellWidth() {\n return this.carouselProperties.cellWidth + this.carouselProperties.margin;\n }\n\n get visibleWidth() {\n return (\n this.carouselProperties.visibleWidth ||\n this.carouselProperties!.cellsElement!.parentElement!.clientWidth\n );\n }\n\n constructor(private carouselProperties: CarouselProperties) {}\n\n updateProperties(carouselProperties: CarouselProperties) {\n this.carouselProperties = carouselProperties;\n }\n\n getStartX(event: any) {\n const { touches } = event;\n const carouselElementPosition = this.getCarouselElementPosition().left;\n let startX;\n\n if (touches) {\n startX = touches[0].clientX - carouselElementPosition;\n } else {\n startX = event.clientX - carouselElementPosition;\n }\n\n return startX;\n }\n\n getMoveX(event: any) {\n const { touches } = event;\n const carouselElementPositionX = this.getCarouselElementPosition().left;\n\n if (touches) {\n return touches[0].clientX - carouselElementPositionX;\n }\n return event.clientX - carouselElementPositionX;\n }\n\n getCarouselElementPosition() {\n return this.carouselProperties.hostElement.getBoundingClientRect();\n }\n}\n","import {\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n HostBinding,\n HostListener,\n Input,\n Output,\n OnDestroy,\n SimpleChanges\n} from '@angular/core';\n\nimport { Properties as CarouselProperties } from './interfaces';\nimport { Touches } from './touches';\nimport { Carousel } from './carousel';\nimport { Container } from './container';\nimport { Cells } from './cells';\nimport { Slide } from './slide';\nimport { Utils } from './utils';\n\n@Component({\n selector: 'carousel, [carousel]',\n templateUrl: './carousel.component.html',\n styleUrls: ['./carousel.component.sass']\n})\nexport class CarouselComponent implements OnDestroy {\n carousel: any;\n\n container: any;\n\n utils: any;\n\n cells: any;\n\n slide: any;\n\n touches: any;\n\n landscapeMode: any;\n\n _isCounter = false;\n\n _cellWidth: number | '100%' = 200;\n\n isMoving = false;\n\n isNgContent = false;\n\n cellLength!: number;\n\n dotsArr: any;\n\n carouselProperties!: CarouselProperties;\n\n savedCarouselWidth!: number;\n\n get slideCounter() {\n if (this.carousel) {\n return this.carousel.slideCounter;\n }\n }\n\n get lapCounter() {\n if (this.carousel) {\n return this.carousel.lapCounter;\n }\n }\n\n get isLandscape() {\n return window.innerWidth > window.innerHeight;\n }\n\n get isSafari(): any {\n const ua = navigator.userAgent.toLowerCase();\n if (ua.indexOf('safari') !== -1) {\n return !(ua.indexOf('chrome') > -1);\n }\n }\n\n get counter() {\n const counter = this.slideCounter;\n return counter + 1 + this.counterSeparator + this.cellLength;\n }\n\n get cellsElement() {\n return this.elementRef.nativeElement.querySelector('.carousel-cells');\n }\n\n get isArrows() {\n return this.arrows && !this.freeScroll;\n }\n\n get isCounter() {\n return this._isCounter && this.cellLength > 1;\n }\n\n get activeDotIndex() {\n return this.slideCounter % this.cellLength;\n }\n\n get cellLimit() {\n if (this.carousel) {\n return this.carousel.cellLimit;\n }\n }\n\n get carouselWidth() {\n return this.elementRef.nativeElement.clientWidth;\n }\n\n @Output() events: EventEmitter<any> = new EventEmitter<any>();\n\n @Input() id!: number;\n\n @Input() height = 450;\n\n @Input() width!: number;\n\n @Input() autoplay = true;\n\n @Input() autoplayInterval = 5000;\n\n @Input() pauseOnHover = true;\n\n @Input() dots = false;\n\n @Input() borderRadius!: number;\n\n @Input() margin = 10;\n\n @Input() objectFit: 'contain' | 'cover' | 'none' = 'cover';\n\n @Input() minSwipeDistance = 10;\n\n @Input() transitionDuration = 200;\n\n @Input() transitionTimingFunction:\n | 'ease'\n | 'ease-in'\n | 'ease-out'\n | 'ease-in-out'\n | 'linear' = 'ease-out';\n\n @Input() videoProperties: any;\n\n @Input() counterSeparator = ' / ';\n\n @Input() overflowCellsLimit = 3;\n\n @Input() listeners: 'auto' | 'mouse and touch' = 'mouse and touch';\n\n @Input() cellsToShow = 1;\n\n @Input() cellsToScroll = 1;\n\n @Input() freeScroll = false;\n\n @Input() arrows = true;\n\n @Input() arrowsOutside = false;\n\n @Input() arrowsTheme: 'light' | 'dark' = 'light';\n\n @Input('cellWidth') set cellWidth(value: number | '100%') {\n if (value) {\n this._cellWidth = value;\n }\n }\n\n @Input('counter') set isCounter(value: boolean) {\n if (value) {\n this._isCounter = value;\n }\n }\n\n @HostBinding('class.carousel') hostClassCarousel = true;\n\n @HostBinding('style.height') hostStyleHeight!: string;\n\n @HostBinding('style.width') hostStyleWidth!: string;\n\n @HostListener('window:resize', ['$event'])\n onWindowResize(event: any) {\n if (this.utils.visibleWidth !== this.savedCarouselWidth) {\n this.resize();\n }\n }\n\n @HostListener('mouseenter', ['$event'])\n onMouseEnter() {\n if (this.autoplay && this.pauseOnHover) {\n this.carouselProperties.autoplayIsPossible = false;\n this.carousel.stopAutoplay();\n }\n }\n\n @HostListener('mouseleave', ['$event'])\n onMouseLeave() {\n if (this.autoplay && this.pauseOnHover) {\n this.carouselProperties.autoplayIsPossible = true;\n this.carousel.autoplay();\n }\n }\n\n @HostListener('dragstart', ['$event'])\n onDragStart() {\n return false;\n }\n\n constructor(private elementRef: ElementRef, private ref: ChangeDetectorRef) {}\n\n ngOnInit() {\n this.isNgContent = this.cellsElement.children.length > 0;\n\n this.touches = new Touches({\n element: this.cellsElement,\n listeners: this.listeners,\n mouseListeners: {\n mousedown: 'handleMousedown',\n mouseup: 'handleMouseup'\n }\n });\n\n this.touches.on('touchstart', this.handleTouchstart);\n this.touches.on('horizontal-swipe', this.handleHorizontalSwipe);\n this.touches.on('touchend', this.handleTouchend);\n this.touches.on('mousedown', this.handleTouchstart);\n this.touches.on('mouseup', this.handleTouchend);\n this.touches.on('tap', this.handleTap);\n\n this.setDimensions();\n }\n\n ngAfterViewInit() {\n this.initCarousel();\n this.cellLength = this.getCellLength();\n this.dotsArr = Array(this.cellLength).fill(1);\n this.ref.detectChanges();\n this.carousel.lineUpCells();\n this.savedCarouselWidth = this.carouselWidth;\n\n /* Start detecting changes in the DOM tree */\n this.detectDomChanges();\n }\n\n ngOnChanges(changes: SimpleChanges) {\n const isFirstChange = Object.values(changes).some(change => change.isFirstChange());\n if (!isFirstChange && (changes.width || changes.height)) {\n this.setDimensions();\n this.initCarousel();\n this.carousel.lineUpCells();\n this.ref.detectChanges();\n }\n }\n\n ngOnDestroy() {\n this.touches.destroy();\n // this.carousel.destroy();\n }\n\n initCarousel() {\n this.carouselProperties = {\n id: this.id,\n cellsElement:\n this.elementRef.nativeElement.querySelector('.carousel-cells'),\n hostElement: this.elementRef.nativeElement,\n cellWidth: this.getCellWidth(),\n autoplayInterval: this.autoplayInterval,\n autoplayIsPossible: true,\n overflowCellsLimit: this.overflowCellsLimit,\n visibleWidth: this.width,\n margin: this.margin,\n minSwipeDistance: this.minSwipeDistance,\n transitionDuration: this.transitionDuration,\n transitionTimingFunction: this.transitionTimingFunction,\n videoProperties: this.videoProperties,\n eventHandler: this.events,\n freeScroll: this.freeScroll\n };\n\n this.utils = new Utils(this.carouselProperties);\n this.cells = new Cells(this.carouselProperties, this.utils);\n this.container = new Container(\n this.carouselProperties,\n this.utils,\n this.cells\n );\n this.slide = new Slide(\n this.carouselProperties,\n this.utils,\n this.cells,\n this.container\n );\n\n if (this.autoplay && this.carousel) {\n this.carousel.stopAutoplay();\n }\n this.carousel = new Carousel(\n this.carouselProperties,\n this.utils,\n this.cells,\n this.container,\n this.slide\n );\n\n if (this.autoplay) {\n this.carousel.autoplay();\n }\n }\n\n resize() {\n this.landscapeMode = this.isLandscape;\n this.savedCarouselWidth = this.carouselWidth;\n\n this.carouselProperties.cellWidth = this.getCellWidth();\n this.cells.updateProperties(this.carouselProperties);\n this.carousel.updateProperties(this.carouselProperties);\n this.container.updateProperties(this.carouselProperties);\n this.slide.updateProperties(this.carouselProperties);\n this.utils.updateProperties(this.carouselProperties);\n this.carousel.lineUpCells();\n this.slide.select(0);\n this.ref.detectChanges();\n }\n\n detectDomChanges() {\n const observer = new MutationObserver((mutations) => {\n this.onDomChanges();\n });\n\n const config = {\n attributes: true,\n childList: true,\n characterData: true\n };\n observer.observe(this.cellsElement, config);\n }\n\n onDomChanges() {\n this.cellLength = this.getCellLength();\n this.carousel.lineUpCells();\n this.ref.detectChanges();\n }\n\n setDimensions() {\n this.hostStyleHeight = `${this.height}px`;\n this.hostStyleWidth = `${this.width}px`;\n }\n\n handleTouchstart = (event: any) => {\n this.touches.addEventListeners('mousemove', 'handleMousemove');\n this.carousel.handleTouchstart(event);\n this.isMoving = true;\n };\n\n handleHorizontalSwipe = (event: any) => {\n event.preventDefault();\n this.carousel.handleHorizontalSwipe(event);\n };\n\n handleTouchend = (event: any) => {\n const { touches } = event;\n this.carousel.handleTouchend(event);\n this.touches.removeEventListeners('mousemove', 'handleMousemove');\n this.isMoving = false;\n };\n\n handleTap = (event: any) => {\n const outboundEvent: any = {\n name: 'click'\n };\n const nodes = Array.prototype.slice.call(this.cellsElement.children);\n const cellElement = event.srcElement.closest('.carousel-cell');\n const i = nodes.indexOf(cellElement);\n const cellIndex = nodes.indexOf(cellElement);\n\n outboundEvent.cellIndex = cellIndex;\n };\n\n handleTransitionendCellContainer(event: any) {\n if (event.target.className === 'carousel-cells') {\n this.carousel.handleTransitionend();\n }\n }\n\n getCellWidth() {\n const elementWidth = this.carouselWidth;\n\n if (this.cellsToShow) {\n const margin = this.cellsToShow > 1 ? this.margin : 0;\n const totalMargin = margin * (this.cellsToShow - 1);\n return (elementWidth - totalMargin) / this.cellsToShow;\n }\n\n if (this._cellWidth === '100%') {\n return elementWidth;\n }\n return this._cellWidth;\n }\n\n next() {\n this.carousel.next(this.cellsToScroll);\n this.carousel.stopAutoplay();\n }\n\n prev() {\n this.carousel.prev(this.cellsToScroll);\n this.carousel.stopAutoplay();\n }\n\n isNextArrowDisabled() {\n if (this.carousel) {\n return this.carousel.isNextArrowDisabled();\n }\n }\n\n isPrevArrowDisabled() {\n if (this.carousel) {\n return this.carousel.isPrevArrowDisabled();\n }\n }\n\n getCellLength() {\n return this.cellsElement.children.length;\n }\n}\n","<div class=\"carousel-counter\" *ngIf=\"isCounter\">{{counter}}</div>\r\n\r\n<div class=\"carousel-container\" [class.carousel-moving]=\"isMoving\">\r\n\t<div class=\"carousel-cells\" #cells (transitionend)=\"handleTransitionendCellContainer($event)\">\r\n\t\t<ng-content></ng-content>\r\n\t</div>\r\n\r\n\t<div class=\"carousel-dots\" *ngIf=\"dots\">\r\n\t\t<div class=\"carousel-dot\" [class.carousel-dot-active]=\"i === activeDotIndex\" *ngFor=\"let dot of dotsArr; index as i\"></div>\r\n\t</div>\r\n</div>\r\n\r\n<div class=\"carousel-arrows\"\r\n\t[class.carousel-arrows-outside]=\"arrowsOutside\"\r\n\t[class.carousel-dark-arrows]=\"arrowsTheme === 'dark'\"\r\n\t*ngIf=\"isArrows\">\r\n\r\n\t<div class=\"carousel-arrow carousel-arrow-prev\" [class.carousel-arrow-disabled]=\"isPrevArrowDisabled()\" (click)=\"prev()\"></div>\r\n\t<div class=\"carousel-arrow carousel-arrow-next\" [class.carousel-arrow-disabled]=\"isNextArrowDisabled()\" (click)=\"next()\"></div>\r\n</div>\r\n","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { CarouselComponent } from './carousel.component';\n\n@NgModule({\n declarations: [CarouselComponent],\n imports: [CommonModule],\n exports: [CarouselComponent],\n providers: [],\n bootstrap: [],\n entryComponents: [CarouselComponent]\n})\nexport class IvyCarouselModule {}\n","/*\n * Public API Surface of carousel-angular\n */\n\nexport * from './lib/carousel.module';\nexport * from './lib/carousel.component';\nexport * from './lib/interfaces';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;MA2Ba,OAAO,CAAA;AAgElB,IAAA,WAAA,CAAY,UAAsB,EAAA;AAzDlC,QAAA,IAAS,CAAA,SAAA,GAAc,SAAS,CAAC;AAEjC,QAAA,IAAQ,CAAA,QAAA,GAAQ,EAAE,CAAC;AAEnB,QAAA,IAAM,CAAA,MAAA,GAAG,CAAC,CAAC;AAEX,QAAA,IAAM,CAAA,MAAA,GAAG,CAAC,CAAC;AAEX,QAAA,IAAO,CAAA,OAAA,GAAG,CAAC,CAAC;AAIZ,QAAA,IAAmB,CAAA,mBAAA,GAAG,GAAG,CAAC;AAE1B,QAAA,IAAa,CAAA,aAAA,GAAG,GAAG,CAAC;AAEpB,QAAA,IAAc,CAAA,cAAA,GAAG,CAAC,CAAC;AAEnB,QAAA,IAAC,CAAA,CAAA,GAAG,CAAC,CAAC;AAEN,QAAA,IAAW,CAAA,WAAA,GAAG,KAAK,CAAC;QAEpB,IAAA,CAAA,eAAe,GAAQ;AACrB,YAAA,UAAU,EAAE,kBAAkB;AAC9B,YAAA,SAAS,EAAE,iBAAiB;AAC5B,YAAA,QAAQ,EAAE,gBAAgB;SAC3B,CAAC;QAEF,IAAA,CAAA,eAAe,GAAQ;AACrB,YAAA,SAAS,EAAE,iBAAiB;AAC5B,YAAA,SAAS,EAAE,iBAAiB;AAC5B,YAAA,OAAO,EAAE,eAAe;AACxB,YAAA,KAAK,EAAE,aAAa;SACrB,CAAC;QAEF,IAAA,CAAA,eAAe,GAAQ;AACrB,YAAA,MAAM,EAAE,cAAc;SACvB,CAAC;AA0FF;;AAEG;;AAIH,QAAA,IAAA,CAAA,gBAAgB,GAAG,CAAC,KAAU,KAAI;AAChC,YAAA,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACjD,IAAI,CAAC,cAAc,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;AAE3C,YAAA,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE;AAChC,gBAAA,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;AACnC,aAAA;AAED,YAAA,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;AACvC,SAAC,CAAC;;AAIF,QAAA,IAAA,CAAA,eAAe,GAAG,CAAC,KAAU,KAAI;AAC/B,YAAA,MAAM,EAAE,OAAO,