UNPKG

cfc-ds

Version:

Design System do Conselho Federal de Contabilidade baseado no govbr-ds

467 lines 95.9 kB
import { Component, ContentChild, EventEmitter, Input, Output, TemplateRef, ViewChild } from '@angular/core'; import { fromEvent, interval } from 'rxjs'; import { tap } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@angular/flex-layout/extended"; export class CarouselComponent { items = []; config = { loop: false, autoPlay: false, autoPlayInterval: 5000, showNavigationButtons: true, showPlayButtons: false, showIndicator: true, navigationButtonsPosition: 'outside', // 'inside' ou 'outside' indicatorPosition: 'inside', // 'inside' ou 'outside' indicatorType: 'simple', itemsPerPage: 1, navigationType: 'page', transitionDuration: 300, transitionType: 'slide', enableTouch: true }; pageChange = new EventEmitter(); itemClick = new EventEmitter(); carouselStage; carouselContent; contentTemplate; currentPageIndex = 0; totalPages = 0; isPlaying = false; isPaused = false; isHovering = false; isDragging = false; dragStartX = 0; dragCurrentX = 0; initialTransform = 0; currentTransform = 0; loadedImages = new Set(); adjacentImagesLoaded = false; autoPlaySubscription; touchStartX = 0; touchEndX = 0; touchStartY = 0; touchStartTime = 0; swipeSubscriptions = []; mousedownSubscription; mousemoveSubscription; mouseupSubscription; mouseleaveSubscription; get currentPage() { return this.currentPageIndex + 1; } get pages() { return Array.from({ length: this.totalPages }, (_, i) => i); } get blocks() { const blocksCount = Math.ceil(this.items.length / (this.config.itemsPerPage ?? 1)); return Array.from({ length: blocksCount }, (_, i) => i); } ngOnInit() { // Verificar e ajustar config para indicador textual if (this.config.indicatorType === 'text') { this.config.indicatorPosition = 'outside'; } this.calculateTotalPages(); this.initializeCarousel(); // Pré-carregar a primeira imagem e as adjacentes if (this.items.length > 0) { this.preloadAdjacentImages(0); } if (this.config.autoPlay) { this.play(); } } ngAfterViewInit() { if (this.config.enableTouch) { this.setupTouchEvents(); this.setupMouseEvents(); } } ngOnDestroy() { this.stopAutoPlay(); this.cleanupTouchEvents(); this.cleanupMouseEvents(); } onMouseEnter() { this.isHovering = true; if (this.config.autoPlay && this.isPlaying) { this.pauseAutoPlay(); } } onMouseLeave() { this.isHovering = false; if (this.config.autoPlay && this.isPaused) { this.resumeAutoPlay(); } } calculateTotalPages() { if (this.config.navigationType === 'block') { this.totalPages = Math.ceil(this.items.length / (this.config.itemsPerPage ?? 1)); } else { this.totalPages = this.items.length; } } initializeCarousel() { if (this.items.length > 0) { this.items.forEach((item, index) => { item.active = index === 0; }); } } goToPage(pageIndex) { if (pageIndex < 0 || pageIndex >= this.totalPages) { if (this.config.loop) { pageIndex = pageIndex < 0 ? this.totalPages - 1 : 0; } else { return; } } // Pré-carregar imagens adjacentes antes da transição this.preloadAdjacentImages(pageIndex); this.currentPageIndex = pageIndex; // Atualizar estado de ativo para os itens if (this.config.navigationType === 'block') { const startIndex = this.currentPageIndex * (this.config.itemsPerPage ?? 1); this.items.forEach((item, index) => { item.active = index >= startIndex && index < startIndex + (this.config.itemsPerPage ?? 1); }); } else { this.items.forEach((item, index) => { item.active = index === this.currentPageIndex; }); } this.updateContentTransform(this.currentPageIndex); this.pageChange.emit(this.currentPageIndex); } // Método para pré-carregar imagens adjacentes preloadAdjacentImages(currentIndex) { // Determinar quais imagens devem ser pré-carregadas (atual, anterior e próxima) const indicesToPreload = [ currentIndex, Math.max(0, currentIndex - 1), Math.min(this.totalPages - 1, currentIndex + 1) ]; // Filtrar índices únicos const uniqueIndices = [...new Set(indicesToPreload)]; // Pré-carregar cada imagem uniqueIndices.forEach(index => { if (index >= 0 && index < this.items.length) { const item = this.items[index]; if (item.imageUrl && !this.loadedImages.has(item.imageUrl)) { this.preloadImage(item.imageUrl); } } }); } // Método para pré-carregar uma única imagem preloadImage(imageUrl) { if (!imageUrl || this.loadedImages.has(imageUrl)) return; const img = new Image(); img.onload = () => { this.loadedImages.add(imageUrl); }; img.src = imageUrl; } // Método para aplicar a transformação ao conteúdo updateContentTransform(pageIndex, animationOverride = '') { if (!this.carouselContent || !this.carouselContent.nativeElement) return; const element = this.carouselContent.nativeElement; const translateX = -pageIndex * 100; // Aplicar a transição antes de mudar a transformação element.style.transition = animationOverride || `transform ${this.config.transitionDuration}ms ease-in-out`; // Pequeno delay antes de aplicar a transformação para garantir que a transição seja registrada setTimeout(() => { element.style.transform = `translateX(${translateX}%)`; this.currentTransform = translateX; }, 10); } next() { this.goToPage(this.currentPageIndex + 1); } prev() { this.goToPage(this.currentPageIndex - 1); } play() { if (this.isPlaying) { return; } this.isPlaying = true; this.isPaused = false; this.autoPlaySubscription = interval(this.config.autoPlayInterval) .pipe(tap(() => { if (!this.isHovering && !this.isDragging) { if (this.currentPageIndex === this.totalPages - 1 && !this.config.loop) { this.stopAutoPlay(); } else { this.next(); } } })) .subscribe(); } pauseAutoPlay() { this.isPaused = true; this.stopAutoPlay(); } resumeAutoPlay() { if (this.isPaused) { this.play(); } } pause() { this.pauseAutoPlay(); } togglePlay() { if (this.isPlaying) { this.pause(); } else { this.play(); } } stopAutoPlay() { if (this.autoPlaySubscription) { this.autoPlaySubscription.unsubscribe(); this.autoPlaySubscription = undefined; this.isPlaying = false; } } setupTouchEvents() { if (!this.carouselStage || !this.carouselStage.nativeElement) { return; } const element = this.carouselStage.nativeElement; // Usando eventos nativos para melhor desempenho element.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: true }); element.addEventListener('touchmove', this.handleTouchMove.bind(this), { passive: false }); element.addEventListener('touchend', this.handleTouchEnd.bind(this), { passive: true }); } handleTouchStart(event) { if (this.isPlaying) { this.pauseAutoPlay(); } this.touchStartX = event.touches[0].clientX; this.touchStartY = event.touches[0].clientY; this.touchStartTime = Date.now(); this.isDragging = true; if (this.carouselContent && this.carouselContent.nativeElement) { const style = window.getComputedStyle(this.carouselContent.nativeElement); const matrix = new WebKitCSSMatrix(style.transform); this.initialTransform = matrix.m41 / this.carouselContent.nativeElement.offsetWidth * 100; this.currentTransform = this.initialTransform; // Remover transição para movimento suave durante o arrasto this.carouselContent.nativeElement.style.transition = 'none'; } } handleTouchMove(event) { if (!this.isDragging) return; const touch = event.touches[0]; const deltaX = touch.clientX - this.touchStartX; const deltaY = touch.clientY - this.touchStartY; // Verificar se o deslizamento é horizontal antes de prevenir comportamento padrão if (Math.abs(deltaX) > Math.abs(deltaY)) { event.preventDefault(); } if (this.carouselContent && this.carouselContent.nativeElement) { const containerWidth = this.carouselContent.nativeElement.offsetWidth; const movePercentage = (deltaX / containerWidth) * 100; // Adicionar resistência nas bordas quando não estiver em loop let newTransform = this.initialTransform + movePercentage; if (!this.config.loop) { if (this.currentPageIndex === 0 && movePercentage > 0) { newTransform = this.initialTransform + (movePercentage / 3); // Resistência no início } else if (this.currentPageIndex === this.totalPages - 1 && movePercentage < 0) { newTransform = this.initialTransform + (movePercentage / 3); // Resistência no final } } this.carouselContent.nativeElement.style.transform = `translateX(${newTransform}%)`; this.currentTransform = newTransform; } } handleTouchEnd(event) { if (!this.isDragging) return; const touchEndTime = Date.now(); const touchDuration = touchEndTime - this.touchStartTime; this.touchEndX = event.changedTouches[0].clientX; const deltaX = this.touchEndX - this.touchStartX; // Calcular velocidade do movimento para determinar swipe const velocity = Math.abs(deltaX) / touchDuration; // Determinar o comportamento com base no movimento e velocidade let newPage = this.currentPageIndex; if (Math.abs(deltaX) > 100 || velocity > 0.5) { // Movimento significativo ou swipe rápido newPage = deltaX > 0 ? this.currentPageIndex - 1 : this.currentPageIndex + 1; } else { // Baseado na porcentagem de movimento const movedPercentage = Math.abs(deltaX) / (this.carouselStage?.nativeElement.offsetWidth || 1); if (movedPercentage > 0.2) { newPage = deltaX > 0 ? this.currentPageIndex - 1 : this.currentPageIndex + 1; } } this.isDragging = false; // Voltar para o slide atual ou ir para o próximo/anterior if (this.carouselContent && this.carouselContent.nativeElement) { this.carouselContent.nativeElement.style.transition = `transform ${this.config.transitionDuration}ms var(--animation-ease-in-out)`; this.goToPage(newPage); } // Restaurar autoplay se necessário if (this.isPaused) { this.resumeAutoPlay(); } } // Adicionar suporte a eventos de mouse para desktop setupMouseEvents() { if (!this.carouselStage || !this.carouselStage.nativeElement) return; const element = this.carouselStage.nativeElement; this.mousedownSubscription = fromEvent(element, 'mousedown') .subscribe(this.handleMouseDown.bind(this)); this.mousemoveSubscription = fromEvent(document, 'mousemove') .subscribe(this.handleMouseMove.bind(this)); this.mouseupSubscription = fromEvent(document, 'mouseup') .subscribe(this.handleMouseUp.bind(this)); this.mouseleaveSubscription = fromEvent(document, 'mouseleave') .subscribe(this.handleMouseUp.bind(this)); } handleMouseDown(event) { // Só capturar cliques com botão esquerdo if (event.button !== 0) return; // Prevenir comportamento padrão (seleção de texto) event.preventDefault(); if (this.isPlaying) { this.pauseAutoPlay(); } this.dragStartX = event.clientX; this.isDragging = true; if (this.carouselContent && this.carouselContent.nativeElement) { const style = window.getComputedStyle(this.carouselContent.nativeElement); const matrix = new WebKitCSSMatrix(style.transform); this.initialTransform = matrix.m41 / this.carouselContent.nativeElement.offsetWidth * 100; this.currentTransform = this.initialTransform; this.carouselContent.nativeElement.style.transition = 'none'; // Cursor de arrasto document.body.style.cursor = 'grabbing'; } } handleMouseMove(event) { if (!this.isDragging) return; this.dragCurrentX = event.clientX; const deltaX = this.dragCurrentX - this.dragStartX; if (this.carouselContent && this.carouselContent.nativeElement) { const containerWidth = this.carouselContent.nativeElement.offsetWidth; const movePercentage = (deltaX / containerWidth) * 100; // Adicionar resistência nas bordas quando não estiver em loop let newTransform = this.initialTransform + movePercentage; if (!this.config.loop) { if (this.currentPageIndex === 0 && movePercentage > 0) { newTransform = this.initialTransform + (movePercentage / 3); } else if (this.currentPageIndex === this.totalPages - 1 && movePercentage < 0) { newTransform = this.initialTransform + (movePercentage / 3); } } this.carouselContent.nativeElement.style.transform = `translateX(${newTransform}%)`; this.currentTransform = newTransform; } } handleMouseUp(event) { if (!this.isDragging) return; document.body.style.cursor = ''; this.isDragging = false; if (this.dragStartX !== 0 && this.dragCurrentX !== 0) { const deltaX = this.dragCurrentX - this.dragStartX; let newPage = this.currentPageIndex; // Determinar se deve mudar de slide com base na distância do movimento if (Math.abs(deltaX) > 100) { newPage = deltaX > 0 ? this.currentPageIndex - 1 : this.currentPageIndex + 1; } else { const movedPercentage = Math.abs(deltaX) / (this.carouselStage?.nativeElement.offsetWidth || 1); if (movedPercentage > 0.2) { newPage = deltaX > 0 ? this.currentPageIndex - 1 : this.currentPageIndex + 1; } } if (this.carouselContent && this.carouselContent.nativeElement) { this.carouselContent.nativeElement.style.transition = `transform ${this.config.transitionDuration}ms var(--animation-ease-in-out)`; this.goToPage(newPage); } } this.dragStartX = 0; this.dragCurrentX = 0; // Restaurar autoplay se necessário if (this.isPaused) { this.resumeAutoPlay(); } } cleanupTouchEvents() { if (this.carouselStage && this.carouselStage.nativeElement) { const element = this.carouselStage.nativeElement; element.removeEventListener('touchstart', this.handleTouchStart.bind(this)); element.removeEventListener('touchmove', this.handleTouchMove.bind(this)); element.removeEventListener('touchend', this.handleTouchEnd.bind(this)); } this.swipeSubscriptions.forEach(sub => sub.unsubscribe()); this.swipeSubscriptions = []; } cleanupMouseEvents() { this.mousedownSubscription?.unsubscribe(); this.mousemoveSubscription?.unsubscribe(); this.mouseupSubscription?.unsubscribe(); this.mouseleaveSubscription?.unsubscribe(); } isFirstPage() { return this.currentPageIndex === 0; } isLastPage() { return this.currentPageIndex === this.totalPages - 1; } shouldDisableNavButton(direction) { if (this.config.loop) { return false; } return direction === 'prev' ? this.isFirstPage() : this.isLastPage(); } trackByFn(index, item) { return item.id || index; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: CarouselComponent, selector: "cfc-carousel", inputs: { items: "items", config: "config" }, outputs: { pageChange: "pageChange", itemClick: "itemClick" }, queries: [{ propertyName: "contentTemplate", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "carouselStage", first: true, predicate: ["carouselStage"], descendants: true }, { propertyName: "carouselContent", first: true, predicate: ["carouselContent"], descendants: true }], ngImport: i0, template: "<div class=\"carousel-wrapper\">\r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (anterior) outside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'outside'\"\r\n class=\"carousel-nav-button carousel-prev-button outside\"\r\n [disabled]=\"shouldDisableNavButton('prev')\"\r\n (click)=\"prev()\">\r\n <i class=\"fas fa-angle-left\"></i>\r\n </button>\r\n <div class=\"carousel-container\"\r\n (mouseenter)=\"onMouseEnter()\"\r\n (mouseleave)=\"onMouseLeave()\">\r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (anterior) inside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'inside'\"\r\n class=\"carousel-nav-button carousel-prev-button inside\"\r\n [disabled]=\"shouldDisableNavButton('prev')\"\r\n (click)=\"prev()\">\r\n <i class=\"fas fa-angle-left\"></i>\r\n </button>\r\n <!-- Palco (\u00E1rea de conte\u00FAdo) -->\r\n <div class=\"carousel-stage\" #carouselStage\r\n [class.is-dragging]=\"isDragging\">\r\n <!-- Modifica\u00E7\u00E3o no carousel-content -->\r\n <div class=\"carousel-content\" #carouselContent>\r\n <ng-container *ngFor=\"let item of items; let i = index; trackBy: trackByFn\">\r\n <div class=\"carousel-item\"\r\n [class.active]=\"item.active\"\r\n [class.dragging]=\"isDragging\"\r\n (click)=\"!isDragging && itemClick.emit(item)\">\r\n <!-- Renderiza\u00E7\u00E3o de imagem com tratamento para pr\u00E9-carregamento -->\r\n <div *ngIf=\"item.imageUrl\" class=\"carousel-image-container\">\r\n <!-- Modificado para carregar imagem diretamente, mas usar opacity para o efeito de fade -->\r\n <img \r\n [src]=\"item.imageUrl\" \r\n [alt]=\"item.imageAlt || item.title || ''\" \r\n class=\"carousel-image\"\r\n [ngClass]=\"{'lazyloaded': loadedImages.has(item.imageUrl)}\"\r\n (load)=\"loadedImages.add(item.imageUrl)\">\r\n \r\n <!-- Imagem de placeholder enquanto carrega -->\r\n <div *ngIf=\"!loadedImages.has(item.imageUrl)\" class=\"carousel-image-placeholder\"></div>\r\n </div>\r\n\r\n <!-- Resto do conte\u00FAdo permanece igual -->\r\n <ng-container *ngIf=\"!item.imageUrl || contentTemplate\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n \r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (pr\u00F3ximo) inside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'inside'\"\r\n class=\"carousel-nav-button carousel-next-button inside\"\r\n [disabled]=\"shouldDisableNavButton('next')\"\r\n (click)=\"next()\">\r\n <i class=\"fas fa-angle-right\"></i>\r\n </button>\r\n\r\n <!-- Bot\u00E3o de reprodu\u00E7\u00E3o (interno ao palco) -->\r\n <div *ngIf=\"config.showPlayButtons && config.navigationButtonsPosition === 'inside'\"\r\n class=\"carousel-play-button-container\">\r\n <button class=\"carousel-play-button\" (click)=\"togglePlay()\">\r\n <i [class]=\"isPlaying ? 'fas fa-pause' : 'fas fa-play'\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Indicador de p\u00E1ginas (interno ao palco) -->\r\n <div *ngIf=\"config.showIndicator && config.indicatorPosition === 'inside'\"\r\n class=\"carousel-indicator-container inside\">\r\n <div *ngIf=\"config.indicatorType === 'simple'\" class=\"carousel-indicator\">\r\n <span *ngFor=\"let page of pages\"\r\n class=\"indicator-dot\"\r\n [class.active]=\"page === currentPageIndex\"\r\n (click)=\"goToPage(page)\"></span>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (pr\u00F3ximo) outside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'outside'\"\r\n class=\"carousel-nav-button carousel-next-button outside\"\r\n [disabled]=\"shouldDisableNavButton('next')\"\r\n (click)=\"next()\">\r\n <i class=\"fas fa-angle-right\"></i>\r\n </button>\r\n</div>\r\n\r\n<!-- Bot\u00E3o de reprodu\u00E7\u00E3o (externo ao palco) -->\r\n<div *ngIf=\"config.showPlayButtons && config.navigationButtonsPosition === 'outside'\"\r\n class=\"carousel-play-button-container outside\">\r\n <button class=\"carousel-play-button\" (click)=\"togglePlay()\">\r\n <i [class]=\"isPlaying ? 'fas fa-pause' : 'fas fa-play'\"></i>\r\n </button>\r\n</div>\r\n\r\n<!-- Indicador de p\u00E1ginas (externo ao palco) -->\r\n<div *ngIf=\"config.showIndicator && config.indicatorPosition === 'outside'\"\r\n class=\"carousel-indicator-container outside\">\r\n <div *ngIf=\"config.indicatorType === 'simple'\" class=\"carousel-indicator\">\r\n <span *ngFor=\"let page of pages\"\r\n class=\"indicator-dot\"\r\n [class.active]=\"page === currentPageIndex\"\r\n (click)=\"goToPage(page)\"></span>\r\n </div>\r\n <div *ngIf=\"config.indicatorType === 'text'\" class=\"carousel-indicator-text\">\r\n {{ currentPage }}/{{ totalPages }}\r\n </div>\r\n</div>\r\n\r\n<!-- Template para o conte\u00FAdo -->\r\n<ng-template #itemTemplate let-item>\r\n <ng-content *ngIf=\"!contentTemplate\"></ng-content>\r\n <ng-container *ngIf=\"contentTemplate\">\r\n <ng-container *ngTemplateOutlet=\"contentTemplate; context: {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n</ng-template>\r\n<ng-content select=\"[carouselContent]\"></ng-content>", styles: [":host{display:block}.carousel-wrapper{display:flex;align-items:center;position:relative;width:100%}.carousel-container{position:relative;width:100%;overflow:hidden}.carousel-container:not(:hover) .carousel-play-button-container:not(.outside){opacity:0;transition:opacity .3s ease}.carousel-container:hover .carousel-play-button-container:not(.outside){opacity:1;transition:opacity .3s ease}.carousel-stage{position:relative;overflow:hidden;width:100%;touch-action:pan-y;-webkit-user-select:none;user-select:none;cursor:grab}.carousel-stage.is-dragging{cursor:grabbing}.carousel-content{display:flex;position:relative;height:100%;width:100%;will-change:transform;touch-action:none;transition:transform .3s ease-in-out}.carousel-block{display:flex;width:100%;position:relative;transition:transform var(--transition-duration, .3s) var(--animation-ease-in-out)}.carousel-block .carousel-item{flex-shrink:0;width:100%;height:100%;position:relative;flex:0 0 100%}.carousel-block .carousel-block .carousel-item{width:calc((100% - (var(--items-per-page, 3) - 1) * var(--item-spacing, 20px)) / var(--items-per-page, 3))}.carousel-block .carousel-item.dragging{pointer-events:none}.carousel-item{flex-shrink:0;width:100%;height:100%;position:relative}.carousel-block .carousel-item{width:calc((100% - (var(--items-per-page, 3) - 1) * var(--item-spacing, 20px)) / var(--items-per-page, 3))}.carousel-item.dragging{pointer-events:none}.carousel-image-container{position:relative;width:100%;height:100%;overflow:hidden}.carousel-image{width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .3s ease-in-out}.carousel-image.lazyloaded{opacity:1}.carousel-overlay{position:absolute;bottom:0;left:0;right:0;background:#000000b3;color:#fff;padding:15px}.carousel-overlay h3{margin:0 0 8px;font-size:1.2em}.carousel-overlay p{margin:0;font-size:.9em}.carousel-nav-button{background:#ffffff80;border:none;border-radius:50%;width:40px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer;z-index:2;transition:background-color .3s}.carousel-nav-button:hover{background:#fffc}.carousel-nav-button:disabled{opacity:.3;cursor:not-allowed}.carousel-nav-button.inside{position:absolute;top:50%;transform:translateY(-50%)}.carousel-nav-button.outside{margin:0 10px}.carousel-nav-button.carousel-prev-button.inside{left:10px}.carousel-nav-button.carousel-next-button.inside{right:10px}.carousel-play-button-container{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:3}.carousel-play-button-container.outside{position:relative;top:auto;left:auto;transform:none;display:flex;justify-content:center;margin:10px 0;width:100%}.carousel-play-button-container .carousel-play-button{background:#00000080;color:#fff;border:none;border-radius:50%;width:40px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:background-color .3s,opacity .3s}.carousel-play-button-container .carousel-play-button:hover{background:#000c}.carousel-indicator-container{display:flex;justify-content:center;align-items:center}.carousel-indicator-container.inside{position:absolute;bottom:10px;left:0;right:0;z-index:3}.carousel-indicator-container.outside{margin-top:10px;width:100%}.carousel-indicator-container .carousel-indicator{display:flex;gap:8px}.carousel-indicator-container .carousel-indicator .indicator-dot{width:10px;height:10px;border-radius:50%;background-color:#0000004d;cursor:pointer;transition:background-color .3s ease}.carousel-indicator-container .carousel-indicator .indicator-dot.active{background-color:#0057b7}.carousel-indicator-container .carousel-indicator .indicator-dot:hover{background-color:#00000080}.carousel-indicator-container .carousel-indicator-text{padding:5px 15px;border-radius:4px;font-size:14px;font-weight:500;color:#333;display:inline-block;text-align:center;min-width:60px}@keyframes bounce-left{0%,to{transform:translate(0)}50%{transform:translate(10px)}}@keyframes bounce-right{0%,to{transform:translate(0)}50%{transform:translate(-10px)}}@media (max-width: 768px){.carousel-overlay h3{font-size:1em}.carousel-overlay p{font-size:.8em}.carousel-nav-button,.carousel-play-button{width:30px;height:30px;font-size:12px}}@media (max-width: 576px){.carousel-nav-button.inside{display:none}.carousel-play-button-container .carousel-play-button{width:25px;height:25px;font-size:10px}}.carousel-image-placeholder{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#f0f0f0;display:flex;align-items:center;justify-content:center}.carousel-image-placeholder:after{content:\"\";width:30px;height:30px;border-radius:50%;border:2px solid rgba(0,0,0,.2);border-top-color:#333;animation:spin 1s infinite linear}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: CarouselComponent, decorators: [{ type: Component, args: [{ selector: 'cfc-carousel', template: "<div class=\"carousel-wrapper\">\r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (anterior) outside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'outside'\"\r\n class=\"carousel-nav-button carousel-prev-button outside\"\r\n [disabled]=\"shouldDisableNavButton('prev')\"\r\n (click)=\"prev()\">\r\n <i class=\"fas fa-angle-left\"></i>\r\n </button>\r\n <div class=\"carousel-container\"\r\n (mouseenter)=\"onMouseEnter()\"\r\n (mouseleave)=\"onMouseLeave()\">\r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (anterior) inside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'inside'\"\r\n class=\"carousel-nav-button carousel-prev-button inside\"\r\n [disabled]=\"shouldDisableNavButton('prev')\"\r\n (click)=\"prev()\">\r\n <i class=\"fas fa-angle-left\"></i>\r\n </button>\r\n <!-- Palco (\u00E1rea de conte\u00FAdo) -->\r\n <div class=\"carousel-stage\" #carouselStage\r\n [class.is-dragging]=\"isDragging\">\r\n <!-- Modifica\u00E7\u00E3o no carousel-content -->\r\n <div class=\"carousel-content\" #carouselContent>\r\n <ng-container *ngFor=\"let item of items; let i = index; trackBy: trackByFn\">\r\n <div class=\"carousel-item\"\r\n [class.active]=\"item.active\"\r\n [class.dragging]=\"isDragging\"\r\n (click)=\"!isDragging && itemClick.emit(item)\">\r\n <!-- Renderiza\u00E7\u00E3o de imagem com tratamento para pr\u00E9-carregamento -->\r\n <div *ngIf=\"item.imageUrl\" class=\"carousel-image-container\">\r\n <!-- Modificado para carregar imagem diretamente, mas usar opacity para o efeito de fade -->\r\n <img \r\n [src]=\"item.imageUrl\" \r\n [alt]=\"item.imageAlt || item.title || ''\" \r\n class=\"carousel-image\"\r\n [ngClass]=\"{'lazyloaded': loadedImages.has(item.imageUrl)}\"\r\n (load)=\"loadedImages.add(item.imageUrl)\">\r\n \r\n <!-- Imagem de placeholder enquanto carrega -->\r\n <div *ngIf=\"!loadedImages.has(item.imageUrl)\" class=\"carousel-image-placeholder\"></div>\r\n </div>\r\n\r\n <!-- Resto do conte\u00FAdo permanece igual -->\r\n <ng-container *ngIf=\"!item.imageUrl || contentTemplate\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </ng-container>\r\n </div>\r\n </div>\r\n \r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (pr\u00F3ximo) inside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'inside'\"\r\n class=\"carousel-nav-button carousel-next-button inside\"\r\n [disabled]=\"shouldDisableNavButton('next')\"\r\n (click)=\"next()\">\r\n <i class=\"fas fa-angle-right\"></i>\r\n </button>\r\n\r\n <!-- Bot\u00E3o de reprodu\u00E7\u00E3o (interno ao palco) -->\r\n <div *ngIf=\"config.showPlayButtons && config.navigationButtonsPosition === 'inside'\"\r\n class=\"carousel-play-button-container\">\r\n <button class=\"carousel-play-button\" (click)=\"togglePlay()\">\r\n <i [class]=\"isPlaying ? 'fas fa-pause' : 'fas fa-play'\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Indicador de p\u00E1ginas (interno ao palco) -->\r\n <div *ngIf=\"config.showIndicator && config.indicatorPosition === 'inside'\"\r\n class=\"carousel-indicator-container inside\">\r\n <div *ngIf=\"config.indicatorType === 'simple'\" class=\"carousel-indicator\">\r\n <span *ngFor=\"let page of pages\"\r\n class=\"indicator-dot\"\r\n [class.active]=\"page === currentPageIndex\"\r\n (click)=\"goToPage(page)\"></span>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- Bot\u00E3o de navega\u00E7\u00E3o (pr\u00F3ximo) outside -->\r\n <button *ngIf=\"config.showNavigationButtons && config.navigationButtonsPosition === 'outside'\"\r\n class=\"carousel-nav-button carousel-next-button outside\"\r\n [disabled]=\"shouldDisableNavButton('next')\"\r\n (click)=\"next()\">\r\n <i class=\"fas fa-angle-right\"></i>\r\n </button>\r\n</div>\r\n\r\n<!-- Bot\u00E3o de reprodu\u00E7\u00E3o (externo ao palco) -->\r\n<div *ngIf=\"config.showPlayButtons && config.navigationButtonsPosition === 'outside'\"\r\n class=\"carousel-play-button-container outside\">\r\n <button class=\"carousel-play-button\" (click)=\"togglePlay()\">\r\n <i [class]=\"isPlaying ? 'fas fa-pause' : 'fas fa-play'\"></i>\r\n </button>\r\n</div>\r\n\r\n<!-- Indicador de p\u00E1ginas (externo ao palco) -->\r\n<div *ngIf=\"config.showIndicator && config.indicatorPosition === 'outside'\"\r\n class=\"carousel-indicator-container outside\">\r\n <div *ngIf=\"config.indicatorType === 'simple'\" class=\"carousel-indicator\">\r\n <span *ngFor=\"let page of pages\"\r\n class=\"indicator-dot\"\r\n [class.active]=\"page === currentPageIndex\"\r\n (click)=\"goToPage(page)\"></span>\r\n </div>\r\n <div *ngIf=\"config.indicatorType === 'text'\" class=\"carousel-indicator-text\">\r\n {{ currentPage }}/{{ totalPages }}\r\n </div>\r\n</div>\r\n\r\n<!-- Template para o conte\u00FAdo -->\r\n<ng-template #itemTemplate let-item>\r\n <ng-content *ngIf=\"!contentTemplate\"></ng-content>\r\n <ng-container *ngIf=\"contentTemplate\">\r\n <ng-container *ngTemplateOutlet=\"contentTemplate; context: {$implicit: item}\"></ng-container>\r\n </ng-container>\r\n</ng-template>\r\n<ng-content select=\"[carouselContent]\"></ng-content>", styles: [":host{display:block}.carousel-wrapper{display:flex;align-items:center;position:relative;width:100%}.carousel-container{position:relative;width:100%;overflow:hidden}.carousel-container:not(:hover) .carousel-play-button-container:not(.outside){opacity:0;transition:opacity .3s ease}.carousel-container:hover .carousel-play-button-container:not(.outside){opacity:1;transition:opacity .3s ease}.carousel-stage{position:relative;overflow:hidden;width:100%;touch-action:pan-y;-webkit-user-select:none;user-select:none;cursor:grab}.carousel-stage.is-dragging{cursor:grabbing}.carousel-content{display:flex;position:relative;height:100%;width:100%;will-change:transform;touch-action:none;transition:transform .3s ease-in-out}.carousel-block{display:flex;width:100%;position:relative;transition:transform var(--transition-duration, .3s) var(--animation-ease-in-out)}.carousel-block .carousel-item{flex-shrink:0;width:100%;height:100%;position:relative;flex:0 0 100%}.carousel-block .carousel-block .carousel-item{width:calc((100% - (var(--items-per-page, 3) - 1) * var(--item-spacing, 20px)) / var(--items-per-page, 3))}.carousel-block .carousel-item.dragging{pointer-events:none}.carousel-item{flex-shrink:0;width:100%;height:100%;position:relative}.carousel-block .carousel-item{width:calc((100% - (var(--items-per-page, 3) - 1) * var(--item-spacing, 20px)) / var(--items-per-page, 3))}.carousel-item.dragging{pointer-events:none}.carousel-image-container{position:relative;width:100%;height:100%;overflow:hidden}.carousel-image{width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .3s ease-in-out}.carousel-image.lazyloaded{opacity:1}.carousel-overlay{position:absolute;bottom:0;left:0;right:0;background:#000000b3;color:#fff;padding:15px}.carousel-overlay h3{margin:0 0 8px;font-size:1.2em}.carousel-overlay p{margin:0;font-size:.9em}.carousel-nav-button{background:#ffffff80;border:none;border-radius:50%;width:40px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer;z-index:2;transition:background-color .3s}.carousel-nav-button:hover{background:#fffc}.carousel-nav-button:disabled{opacity:.3;cursor:not-allowed}.carousel-nav-button.inside{position:absolute;top:50%;transform:translateY(-50%)}.carousel-nav-button.outside{margin:0 10px}.carousel-nav-button.carousel-prev-button.inside{left:10px}.carousel-nav-button.carousel-next-button.inside{right:10px}.carousel-play-button-container{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:3}.carousel-play-button-container.outside{position:relative;top:auto;left:auto;transform:none;display:flex;justify-content:center;margin:10px 0;width:100%}.carousel-play-button-container .carousel-play-button{background:#00000080;color:#fff;border:none;border-radius:50%;width:40px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:background-color .3s,opacity .3s}.carousel-play-button-container .carousel-play-button:hover{background:#000c}.carousel-indicator-container{display:flex;justify-content:center;align-items:center}.carousel-indicator-container.inside{position:absolute;bottom:10px;left:0;right:0;z-index:3}.carousel-indicator-container.outside{margin-top:10px;width:100%}.carousel-indicator-container .carousel-indicator{display:flex;gap:8px}.carousel-indicator-container .carousel-indicator .indicator-dot{width:10px;height:10px;border-radius:50%;background-color:#0000004d;cursor:pointer;transition:background-color .3s ease}.carousel-indicator-container .carousel-indicator .indicator-dot.active{background-color:#0057b7}.carousel-indicator-container .carousel-indicator .indicator-dot:hover{background-color:#00000080}.carousel-indicator-container .carousel-indicator-text{padding:5px 15px;border-radius:4px;font-size:14px;font-weight:500;color:#333;display:inline-block;text-align:center;min-width:60px}@keyframes bounce-left{0%,to{transform:translate(0)}50%{transform:translate(10px)}}@keyframes bounce-right{0%,to{transform:translate(0)}50%{transform:translate(-10px)}}@media (max-width: 768px){.carousel-overlay h3{font-size:1em}.carousel-overlay p{font-size:.8em}.carousel-nav-button,.carousel-play-button{width:30px;height:30px;font-size:12px}}@media (max-width: 576px){.carousel-nav-button.inside{display:none}.carousel-play-button-container .carousel-play-button{width:25px;height:25px;font-size:10px}}.carousel-image-placeholder{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#f0f0f0;display:flex;align-items:center;justify-content:center}.carousel-image-placeholder:after{content:\"\";width:30px;height:30px;border-radius:50%;border:2px solid rgba(0,0,0,.2);border-top-color:#333;animation:spin 1s infinite linear}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }] }], propDecorators: { items: [{ type: Input }], config: [{ type: Input }], pageChange: [{ type: Output }], itemClick: [{ type: Output }], carouselStage: [{ type: ViewChild, args: ['carouselStage'] }], carouselContent: [{ type: ViewChild, args: ['carouselContent'] }], contentTemplate: [{ type: ContentChild, args: [TemplateRef] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Fyb3VzZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY2ZjLWRzL3NyYy9saWIvY29tcG9uZW50cy9jYXJvdXNlbC9jYXJvdXNlbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jZmMtZHMvc3JjL2xpYi9jb21wb25lbnRzL2Nhcm91c2VsL2Nhcm91c2VsLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUVaLFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUNOLFdBQVcsRUFDWCxTQUFTLEVBRVYsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBQ3pELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7OztBQVFyQyxNQUFNLE9BQU8saUJBQWlCO0lBQ25CLEtBQUssR0FBbUIsRUFBRSxDQUFDO0lBQzNCLE1BQU0sR0FBbUI7UUFDaEMsSUFBSSxFQUFFLEtBQUs7UUFDWCxRQUFRLEVBQUUsS0FBSztRQUNmLGdCQUFnQixFQUFFLElBQUk7UUFDdEIscUJBQXFCLEVBQUUsSUFBSTtRQUMzQixlQUFlLEVBQUUsS0FBSztRQUN0QixhQUFhLEVBQUUsSUFBSTtRQUNuQix5QkFBeUIsRUFBRSxTQUFTLEVBQUUsd0JBQXdCO1FBQzlELGlCQUFpQixFQUFFLFFBQVEsRUFBVSx3QkFBd0I7UUFDN0QsYUFBYSxFQUFFLFFBQVE7UUFDdkIsWUFBWSxFQUFFLENBQUM7UUFDZixjQUFjLEVBQUUsTUFBTTtRQUN0QixrQkFBa0IsRUFBRSxHQUFHO1FBQ3ZCLGNBQWMsRUFBRSxPQUFPO1FBQ3ZCLFdBQVcsRUFBRSxJQUFJO0tBQ2xCLENBQUM7SUFFUSxVQUFVLEdBQUcsSUFBSSxZQUFZLEVBQVUs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