UNPKG

kinetic-slider

Version:

A WebGL-powered kinetic slider component using PIXI.js

284 lines (283 loc) 12 kB
import { Application, Sprite, Container, DisplacementFilter, Filter, Texture } from 'pixi.js'; import { AtlasManager } from "./managers/AtlasManager"; import type { RefObject } from "react"; import ResourceManager from "./managers/ResourceManager"; import { type BaseFilterConfig, type FilterConfig, type FilterType } from './filters/types'; import SlidingWindowManager from './managers/SlidingWindowManager'; export { type FilterConfig, type FilterType }; /** * Navigation element selectors for external controls * @property {string} prev - CSS selector for the previous button * @property {string} next - CSS selector for the next button */ export type NavElement = { prev: string; next: string; }; /** * Text content pair for slides containing title and subtitle * @typedef {[string, string]} TextPair * @description A tuple representing [title, subtitle] text content for a slide */ export type TextPair = [string, string]; /** * Represents a pending filter update in the batch queue * @property {string} filterId - Unique identifier for the filter * @property {Partial<BaseFilterConfig>} changes - The changes to apply to the filter * @property {number} timestamp - When the update was queued */ export interface PendingFilterUpdate { filterId: string; changes: Partial<BaseFilterConfig>; timestamp: number; } /** * Configuration for filter batching behavior * @property {number} bufferMs - How long to wait before applying updates (in milliseconds) * @property {number} maxBatchSize - Maximum number of updates to process in a single batch */ export interface FilterBatchConfig { bufferMs: number; maxBatchSize: number; } /** * Represents the difference between two filter states * @property {boolean} hasChanged - Whether any properties have changed * @property {Partial<BaseFilterConfig>} changedProperties - Only the properties that have changed */ export interface FilterDiff { hasChanged: boolean; changedProperties: Partial<BaseFilterConfig>; } /** * Options for cursor displacement sizing behavior * @typedef {('natural'|'fullscreen'|'custom')} CursorDisplacementSizingMode * @description * - 'natural': Uses the displacement image's natural dimensions * - 'fullscreen': Sizes the displacement effect to cover the entire viewport * - 'custom': Uses the provided width and height values */ export type CursorDisplacementSizingMode = 'natural' | 'fullscreen' | 'custom'; /** * Props for the KineticSlider component */ export interface KineticSliderProps { /** Array of image paths to display as slides */ images: string[]; /** Array of text pairs [title, subtitle] to display on slides */ texts: TextPair[]; /** Base path for slide images, used for atlas frame lookup */ slidesBasePath?: string; /** Path to the background displacement sprite image */ backgroundDisplacementSpriteLocation?: string; /** Path to the cursor displacement sprite image */ cursorDisplacementSpriteLocation?: string; /** Whether to enable the cursor image displacement effect */ cursorImgEffect?: boolean; /** Whether to enable the cursor text displacement effect */ cursorTextEffect?: boolean; /** Scale intensity of the cursor displacement effect (default: 0.65) */ cursorScaleIntensity?: number; /** Momentum factor for cursor movement (default: 0.14) */ cursorMomentum?: number; /** * Controls how the cursor displacement texture is sized * - 'natural': Uses the image's natural dimensions * - 'fullscreen': Sizes to the viewport dimensions * - 'custom': Uses custom width/height values */ cursorDisplacementSizing?: CursorDisplacementSizingMode; /** Custom width in pixels for the cursor displacement effect (used when sizing is 'custom') */ cursorDisplacementWidth?: number; /** Custom height in pixels for the cursor displacement effect (used when sizing is 'custom') */ cursorDisplacementHeight?: number; /** Filter configuration(s) to apply to slide images */ imageFilters?: FilterConfig | FilterConfig[]; /** Filter configuration(s) to apply to slide text */ textFilters?: FilterConfig | FilterConfig[]; /** Color of the title text */ textTitleColor?: string; /** Font size of the title text in pixels */ textTitleSize?: number; /** Font size of the title text on mobile devices */ mobileTextTitleSize?: number; /** Letter spacing of the title text */ textTitleLetterspacing?: number; /** Font family for the title text */ textTitleFontFamily?: string; /** Color of the subtitle text */ textSubTitleColor?: string; /** Font size of the subtitle text in pixels */ textSubTitleSize?: number; /** Font size of the subtitle text on mobile devices */ mobileTextSubTitleSize?: number; /** Letter spacing of the subtitle text */ textSubTitleLetterspacing?: number; /** Vertical offset for the subtitle text from the title */ textSubTitleOffsetTop?: number; /** Vertical offset for the subtitle text on mobile devices */ mobileTextSubTitleOffsetTop?: number; /** Font family for the subtitle text */ textSubTitleFontFamily?: string; /** Maximum fraction of container width/height to shift during mouse interaction */ maxContainerShiftFraction?: number; /** Intensity of the displacement effect during swipe */ swipeScaleIntensity?: number; /** Intensity of the displacement effect during transitions */ transitionScaleIntensity?: number; /** Whether to use external navigation elements instead of built-in navigation */ externalNav?: boolean; /** Selectors for external navigation elements */ navElement?: NavElement; /** Whether to show the cursor as a pointer over slides */ buttonMode?: boolean; /** Atlas name for slide textures */ slidesAtlas?: string; /** Atlas name for effect textures */ effectsAtlas?: string; /** Whether to use atlas for effect textures */ useEffectsAtlas?: boolean; /** Whether to use atlas for slide textures */ useSlidesAtlas?: boolean; } /** * Enhanced Sprite with additional properties for animation and scaling * @extends Sprite */ export interface EnhancedSprite extends Sprite { /** Base scale value for the sprite, used for animations */ baseScale?: number; /** Flag indicating if this is a placeholder sprite */ _isPlaceholder?: boolean; /** Index of the slide this placeholder represents */ _placeholderIndex?: number; /** Original texture to restore when converting from placeholder back to full sprite */ _originalTexture?: Texture; /** Loading state for the sprite */ _loadingState?: 'uninitialized' | 'loading' | 'loaded' | 'error'; /** Whether this sprite is within the current visibility window */ _inVisibilityWindow?: boolean; } /** * References to core PIXI objects used across hooks */ export interface PixiRefs { /** Reference to the main PIXI Application instance */ app: React.MutableRefObject<Application | null>; /** Reference to the array of slide sprites */ slides: React.MutableRefObject<EnhancedSprite[]>; /** Reference to the array of text containers */ textContainers: React.MutableRefObject<Container[]>; /** Reference to the background displacement sprite */ backgroundDisplacementSprite: React.MutableRefObject<Sprite | null>; /** Reference to the cursor displacement sprite */ cursorDisplacementSprite: React.MutableRefObject<Sprite | null>; /** Reference to the background displacement filter */ bgDispFilter: React.MutableRefObject<DisplacementFilter | null>; /** Reference to the cursor displacement filter */ cursorDispFilter: React.MutableRefObject<DisplacementFilter | null>; /** Reference to the index of the current slide */ currentIndex: React.MutableRefObject<number>; } /** * Result of applying a filter, containing the filter instance and control methods */ export interface FilterApplicationResult { /** The PIXI filter instance */ filter: Filter; /** Function to update the intensity of the filter */ updateIntensity: (intensity: number) => void; /** Function to reset the filter to its default state */ reset: () => void; } /** * Shared hook parameters containing refs and props for reuse across hooks */ export interface HookParams { /** Reference to the slider DOM element */ sliderRef: React.RefObject<HTMLDivElement | null>; /** Object containing references to PIXI objects */ pixi: PixiRefs; /** Component props */ props: KineticSliderProps; /** Callback function for slide change */ onSlideChange?: (index: number) => void; /** Sliding window manager for optimizing slide loading */ slidingWindowManager?: SlidingWindowManager | null; } /** * Props for the loading indicator component */ export interface LoadingIndicatorProps { /** Optional message to display during loading */ message?: string; } /** * Result of the usePixiApp hook, containing initialization state and resources * @interface UsePixiAppResult */ export interface UsePixiAppResult { /** References to PIXI objects */ pixiRefs: PixiRefs; /** Atlas manager instance for texture management */ atlasManager: AtlasManager | null; /** Whether the PIXI app is fully initialized */ isInitialized: boolean; /** Whether the PIXI app is currently initializing */ isInitializing: boolean; /** Loading progress information */ loadingProgress: { /** Whether assets are currently loading */ isLoading: boolean; /** Progress percentage (0-100) */ progress: number; /** Number of assets that have been loaded */ assetsLoaded: number; /** Total number of assets to load */ assetsTotal: number; }; } /** * Props for the useDisplacementEffects hook */ export interface UseDisplacementEffectsProps { /** Reference to the slider DOM element */ sliderRef: RefObject<HTMLDivElement | null>; /** Reference to the background displacement filter */ bgDispFilterRef: RefObject<DisplacementFilter | null>; /** Reference to the cursor displacement filter */ cursorDispFilterRef: RefObject<DisplacementFilter | null>; /** Reference to the background displacement sprite */ backgroundDisplacementSpriteRef: RefObject<Sprite | null>; /** Reference to the cursor displacement sprite */ cursorDisplacementSpriteRef: RefObject<Sprite | null>; /** Reference to the PIXI application */ appRef: RefObject<Application | null>; /** Path to the background displacement sprite image */ backgroundDisplacementSpriteLocation: string; /** Path to the cursor displacement sprite image */ cursorDisplacementSpriteLocation: string; /** Whether to enable the cursor image displacement effect */ cursorImgEffect: boolean; /** Scale intensity of the cursor displacement effect */ cursorScaleIntensity: number; /** * Controls how the cursor displacement texture is sized * - 'natural': Uses the image's natural dimensions * - 'fullscreen': Sizes to the viewport dimensions * - 'custom': Uses custom width/height values */ cursorDisplacementSizing?: CursorDisplacementSizingMode; /** Custom width in pixels for the cursor displacement effect (used when sizing is 'custom') */ cursorDisplacementWidth?: number; /** Custom height in pixels for the cursor displacement effect (used when sizing is 'custom') */ cursorDisplacementHeight?: number; /** Resource manager instance for tracking and disposing resources */ resourceManager?: ResourceManager | null; /** Atlas manager instance for texture management */ atlasManager?: AtlasManager | null; /** Name of the effects atlas */ effectsAtlas?: string; /** Whether to use atlas for effects instead of individual images */ useEffectsAtlas?: boolean; }