UNPKG

@alegendstale/holly-components

Version:

Reusable UI components created using lit

139 lines (131 loc) 4.26 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { css, html, LitElement } from 'lit'; import { query } from 'lit/decorators.js'; import { EventEmitter } from '../../utils/EventEmitter.js'; import { condCustomElement } from '../../decorators/condCustomElement.js'; let CarouselScroller = class CarouselScroller extends LitElement { constructor() { super(); this.slotChildren = []; this.emitter = new EventEmitter(); this.currentSlide = 0; this.debouncers = new WeakMap(); this.emitter.on('slotsLoaded', (slotChildren) => { this.slotChildren = slotChildren; }); } disconnectedCallback() { super.disconnectedCallback(); this.emitter.clear(); } render() { return html ` <div class="container"> <button @click=${this.scrollToPrevSlide}><</button> <button @click=${this.scrollToNextSlide}>></button> <div> <slot @slotchange=${this.slotChange}></slot> </div> </div> `; } getCurrentSlide() { return this.slotChildren[this.currentSlide - 1]; } scrollToPrevSlide() { this.currentSlide = this.currentSlide === 0 ? (this.currentSlide = this.slotChildren.length - 1) : this.currentSlide - 1; this.slotChildren .at(this.currentSlide) ?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } scrollToNextSlide() { this.currentSlide = this.currentSlide === this.slotChildren.length - 1 ? 0 : this.currentSlide + 1; this.slotChildren .at(this.currentSlide) ?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } slotChange() { const slotElements = Array.from(this.slotEl .assignedElements() .map((element) => element)); clearTimeout(this.debouncers.get(this.slotEl)); const timeoutId = setTimeout(() => this.emitter.emit('slotsLoaded', slotElements), 100); this.debouncers.set(this.slotEl, timeoutId); } }; CarouselScroller.styles = css ` :host { --padding: 40px; --margin: 80px; } .container { width: 600px; height: 400px; margin: 20px; border-radius: 20px; overflow: hidden; position: relative; & > button { position: absolute; width: var(--padding); height: calc(var(--padding) * 2); z-index: 1; background-color: #00000080; border: none; bottom: calc(50% - var(--padding)); font-size: 32px; &:hover { background-color: #6352b880; } &:nth-child(1) { left: 0; border-top-right-radius: 314px; border-bottom-right-radius: 314px; } &:nth-child(2) { right: 0; border-top-left-radius: 314px; border-bottom-left-radius: 314px; } } & > div { display: flex; overflow-x: scroll; position: relative; scroll-behavior: smooth; scroll-snap-type: x mandatory; scrollbar-width: none; padding: 0 var(--padding); } ::slotted(*) { display: flex; flex-direction: column; justify-content: center; min-height: calc(400px - var(--margin)); min-width: calc(600px - var(--margin)); max-height: calc(400px - var(--margin)); max-width: calc(600px - var(--margin)); background: white; scroll-snap-align: center; padding: calc(var(--margin) / 2); } } `; __decorate([ query('slot') ], CarouselScroller.prototype, "slotEl", void 0); CarouselScroller = __decorate([ condCustomElement('carousel-scroller') ], CarouselScroller); export { CarouselScroller };