-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(esl-carousel): add
grid
renderer with capability to render mul…
…ti row (column) carousel Co-authored-by: Anna <abarmina@exadel.com>
- Loading branch information
Showing
5 changed files
with
149 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
src/modules/esl-carousel/renderers/esl-carousel.grid.renderer.less
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
.esl-carousel-grid-renderer { | ||
[esl-carousel-slides] { | ||
display: grid; | ||
grid-template-rows: 1fr 1fr; | ||
grid-auto-columns: auto; | ||
grid-auto-flow: column; | ||
|
||
transition: none; | ||
max-width: 100%; | ||
max-height: 100%; | ||
} | ||
|
||
&.esl-carousel-vertical [esl-carousel-slides] { | ||
grid-template-columns: 1fr 1fr; | ||
grid-auto-rows: auto; | ||
grid-auto-flow: row; | ||
} | ||
|
||
&[animating] [esl-carousel-slides] { | ||
transition: transform 0.25s linear; | ||
} | ||
|
||
&.esl-carousel-horizontal [esl-carousel-slide] { | ||
width: var(--esl-slide-size); | ||
} | ||
&.esl-carousel-vertical [esl-carousel-slide] { | ||
height: var(--esl-slide-size); | ||
} | ||
} |
89 changes: 89 additions & 0 deletions
89
src/modules/esl-carousel/renderers/esl-carousel.grid.renderer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import {prop, memoize} from '../../esl-utils/decorators'; | ||
import {ESLCarouselRenderer} from '../core/esl-carousel.renderer'; | ||
import {ESLDefaultCarouselRenderer} from './esl-carousel.default.renderer'; | ||
|
||
import type {ESLCarouselDirection} from '../core/nav/esl-carousel.nav.types'; | ||
import type {ESLCarouselActionParams} from '../core/esl-carousel'; | ||
|
||
@ESLCarouselRenderer.register | ||
export class ESLGridCarouselRenderer extends ESLDefaultCarouselRenderer { | ||
public static override is = 'grid'; | ||
public static override classes: string[] = ['esl-carousel-grid-renderer']; | ||
|
||
/** Slide count per carousel dimension */ | ||
@prop(2, {readonly: true}) | ||
public readonly ROWS: number; | ||
|
||
/** @returns fake slides collection to fill the last "row" in grid mode */ | ||
@memoize() | ||
public get $fakeSlides(): HTMLElement[] { | ||
const count = this.$carousel.$slides.length % this.ROWS; | ||
if (count === 0) return []; | ||
return Array.from({length: this.ROWS - count}, () => document.createElement('div')); | ||
} | ||
|
||
/** @returns all slides including {@link $fakeSlides} slides created in grid mode */ | ||
public override get $slides(): HTMLElement[] { | ||
return (this.$carousel.$slides || []).concat(this.$fakeSlides); | ||
} | ||
|
||
/** | ||
* Processes binding of defined renderer to the carousel {@link ESLCarousel}. | ||
* Prepare to renderer animation. | ||
*/ | ||
public override onBind(): void { | ||
memoize.clear(this, '$fakeSlides'); | ||
this.$area.append(...this.$fakeSlides); | ||
super.onBind(); | ||
} | ||
|
||
/** | ||
* Processes unbinding of defined renderer from the carousel {@link ESLCarousel}. | ||
* Clear animation. | ||
*/ | ||
public override onUnbind(): void { | ||
this.$fakeSlides.forEach((el) => el.remove()); | ||
super.onUnbind(); | ||
} | ||
|
||
/** | ||
* Processes changing slides | ||
* Normalize actual active index to the first slide in the current dimension ('row') | ||
*/ | ||
public override async navigate(index: number, direction: ESLCarouselDirection, {activator}: ESLCarouselActionParams): Promise<void> { | ||
await super.navigate(index - (index % this.ROWS), direction, {activator}); | ||
} | ||
|
||
/** Processes animation. */ | ||
public override async onAnimate(nextIndex: number, direction: ESLCarouselDirection): Promise<void> { | ||
const {activeIndex, $slidesArea} = this.$carousel; | ||
this.currentIndex = activeIndex; | ||
if (!$slidesArea) return; | ||
const step = this.ROWS * (direction === 'next' ? 1 : -1); | ||
while (this.currentIndex !== nextIndex) await this.onStepAnimate(step); | ||
} | ||
|
||
protected override indexByOffset(offset: number): number { | ||
return super.indexByOffset(offset * this.ROWS); | ||
} | ||
|
||
/** | ||
* @returns count of slides to be rendered (reserved) before the first slide does not include fake slides | ||
*/ | ||
protected override calcReserveCount(back?: boolean): number { | ||
const reserve = super.calcReserveCount(back); | ||
return reserve - (reserve % this.ROWS); | ||
} | ||
|
||
/** Sets min size for slides */ | ||
protected override resize(): void { | ||
if (!this.$area) return; | ||
const areaStyles = getComputedStyle(this.$area); | ||
|
||
this.gap = parseFloat(this.vertical ? areaStyles.rowGap : areaStyles.columnGap); | ||
const areaSize = parseFloat(this.vertical ? areaStyles.height : areaStyles.width); | ||
const count = Math.floor(this.count / this.ROWS); | ||
this.slideSize = Math.floor((areaSize - this.gap * (count - 1)) / count); | ||
this.$area.style.setProperty(ESLDefaultCarouselRenderer.SIZE_PROP, this.slideSize + 'px'); | ||
} | ||
} |