UNPKG

omni-carousel

Version:

A lightweight carousel to enhance scrollable areas

148 lines (144 loc) 4.06 kB
import { Emitter, Unsubscribe } from 'nanoevents'; type ScrollAlign = 'start' | 'center'; type ScrollSteps = 'one' | 'auto'; interface OmniAPI { init: () => void; setup: () => void; destroy: () => void; goTo: (index: number) => void; next: () => void; prev: () => void; on: <K extends keyof OmniEvents>(event: K, callback: OmniEvents[K]) => Unsubscribe; } interface Options { selectors?: Partial<Selectors>; scrollSteps?: ScrollSteps; scrollAlign?: ScrollAlign; hasEqualWidths?: boolean; hasCenterMode?: boolean; indicatorNumbers?: boolean; transitionHelpers?: boolean; preloadAdjacentImages?: boolean; } interface Selectors { track: string; slide: string; prevButton: string; nextButton: string; startButton: string; endButton: string; indicatorArea: string; indicator: string; } /** * Types for custom Omni events */ interface OmniEvents { 'omni:visibility:change': (data: { state: State; slide: HTMLElement; fullIntersecting: boolean; partIntersecting: boolean; wasFullIntersecting: boolean; wasPartIntersecting: boolean; startBoundaryChanged: boolean; endBoundaryChanged: boolean; }) => void; 'omni:dimensions:change': (data: { width: number; scrollWidth: number; }) => void; 'omni:nav:prev': () => void; 'omni:nav:next': () => void; 'omni:nav:index': (data: { index: number; }) => void; 'omni:init': () => void; 'omni:setup': () => void; 'omni:destroy': (data?: { mode?: 'full' | 'partial'; }) => void; } interface OmniElements { root: HTMLElement; track: HTMLElement; slides: HTMLElement[]; prevButton?: HTMLButtonElement; nextButton?: HTMLButtonElement; startButton?: HTMLButtonElement; endButton?: HTMLButtonElement; indicatorArea?: HTMLElement; invisibleAnchor?: HTMLElement; } interface Config { scrollAlign: ScrollAlign; scrollSteps: ScrollSteps; selectors: Selectors; hasEqualWidths: boolean; hasCenterMode: boolean; indicatorNumbers: boolean; transitionHelpers: boolean; preloadAdjacentImages: boolean; } /** * Dynamic state that changes during carousel operation */ interface State { width: number; scrollWidth: number; containerLeft?: number; itemSpacing?: number; itemWidth?: number; itemWidthMap: Map<number, number>; indicatorSpacing?: number; indicatorWidth?: number; fullItems: HTMLElement[]; partItems: HTMLElement[]; startItemFullIntersecting: boolean; endItemFullIntersecting: boolean; hasIndicators: boolean; indicatorOverflow: boolean; centeredItemIndex?: number; previousCenteredItemIndex?: number; detectedBlinkEngine?: boolean; hasOldInvisibleAnchors?: boolean; addedTrackCSSPosition?: boolean; centeredGroupItems: number[]; previousCenteredGroupItems: number[]; debouncedCenterIndicators?: ((context: Context) => void); slideIndexMap: Map<HTMLElement, number>; } /** * Combined context containing all carousel data */ interface Context { config: Config; elements: OmniElements & { indicators: HTMLButtonElement[]; }; state: State; utils: Utils; eventEmitter: Emitter<OmniEvents>; } /** * Utility functions for working with carousel state */ interface Utils { getElementRect: (element: HTMLElement, property?: 'width' | 'left') => { width: number; left: number; } | number; getItemIndex: (slide: HTMLElement | undefined) => number; getItemWidth: (index: number) => number; getContainerLeft: () => number; } /** * Adds basic carousel functionality to a scrollable area * * @param element - The carousel element * @param options - Configuration options * * @returns A public API object with a few methods for controlling the carousel */ declare const createOmniCarousel: (root: HTMLElement, options?: Options) => OmniAPI; export { createOmniCarousel };