ember-bootstrap
Version:
Bootstrap components for Ember.js
219 lines (198 loc) • 4.77 kB
text/typescript
import Component from '@glimmer/component';
import { next } from '@ember/runloop';
import { ref } from 'ember-ref-bucket';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { registerDestructor } from '@ember/destroyable';
import type Owner from '@ember/owner';
import type { PresentationState } from '../bs-carousel';
export type DirectionalClassName = keyof Pick<CarouselSlide, 'left' | 'right'>;
export type OrderClassName = keyof Pick<CarouselSlide, 'prev' | 'next'>;
export interface CarouselSlideSignature {
Args: {
currentSlide?: CarouselSlide;
directionalClassName?: DirectionalClassName | null;
followingSlide?: CarouselSlide;
orderClassName?: OrderClassName | null;
presentationState?: PresentationState | null;
registerChild?: (slide: CarouselSlide) => void;
unregisterChild?: (slide: CarouselSlide) => void;
};
Blocks: {
default: [];
};
Element: HTMLElement;
}
/**
A visible user-defined slide.
See [Components.Carousel](Components.Carousel.html) for examples.
@class CarouselSlide
@namespace Components
@extends Component
@public
*/
export default class CarouselSlide extends Component<CarouselSlideSignature> {
/**
* @property _element
* @type null | HTMLElement
* @private
*/
_element: HTMLElement | null = null;
/**
* Defines slide visibility.
*
* @property active
* @type boolean
* @private
*/
active = this.isCurrentSlide && this.args.presentationState === null;
/**
* @private
* @property isCurrentSlide
* @type boolean
*/
get isCurrentSlide() {
return this.args.currentSlide === this;
}
/**
* @private
* @property isFollowingSlide
* @type boolean
*/
get isFollowingSlide() {
return this.args.followingSlide === this;
}
/**
* Slide is moving to the left.
*
* @property left
* @type boolean
* @private
*/
left = false;
/**
* Next to appear in a left sliding.
*
* @property next
* @type boolean
* @private
*/
next = false;
/**
* Next to appear in a right sliding.
*
* @property prev
* @type boolean
* @private
*/
prev = false;
/**
* Slide is moving to the right.
*
* @property right
* @type boolean
* @private
*/
right = false;
constructor(owner: Owner, args: CarouselSlideSignature['Args']) {
super(owner, args);
args.registerChild?.(this);
registerDestructor(this, () => {
this.args.unregisterChild?.(this);
});
}
/**
* Coordinates the execution of a presentation.
*
* @method presentationStateObserver
* @private
*/
presentationStateObserver() {
if (!this.active) {
this.active = this.isCurrentSlide && this.args.presentationState === null;
}
const presentationState = this.args.presentationState;
if (this.isCurrentSlide) {
switch (presentationState) {
case 'didTransition':
this.currentSlideDidTransition();
break;
case 'willTransit':
this.currentSlideWillTransit();
break;
}
}
if (this.isFollowingSlide) {
switch (presentationState) {
case 'didTransition':
this.followingSlideDidTransition();
break;
case 'willTransit':
this.followingSlideWillTransit();
break;
}
}
}
/**
* @method currentSlideDidTransition
* @private
*/
currentSlideDidTransition() {
if (this.args.directionalClassName) {
this[this.args.directionalClassName] = false;
}
this.active = false;
}
/**
* @method currentSlideWillTransit
* @private
*/
currentSlideWillTransit() {
this.active = true;
next(this, function (this: CarouselSlide) {
if (this.args.directionalClassName) {
this[this.args.directionalClassName] = true;
}
});
}
/**
* @method followingSlideDidTransition
* @private
*/
followingSlideDidTransition() {
this.active = true;
if (this.args.directionalClassName) {
this[this.args.directionalClassName] = false;
}
if (this.args.orderClassName) {
this[this.args.orderClassName] = false;
}
}
/**
* @method followingSlideWillTransit
* @private
*/
followingSlideWillTransit() {
if (this.args.orderClassName) {
this[this.args.orderClassName] = true;
}
next(this, () => {
this.reflow();
if (this.args.directionalClassName) {
this[this.args.directionalClassName] = true;
}
});
}
/**
* Makes things more stable, especially when fast changing.
*/
reflow() {
this._element?.offsetHeight;
}
}