kinetic-slider
Version:
A WebGL-powered kinetic slider component using PIXI.js
828 lines (823 loc) • 27.6 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
var KineticSlider_module = require('./KineticSlider.module.css.cjs');
var pixi_js = require('pixi.js');
var ResourceManager = require('./managers/ResourceManager.cjs');
var AtlasManager = require('./managers/AtlasManager.cjs');
var RenderScheduler = require('./managers/RenderScheduler.cjs');
var UpdateTypes = require('./managers/UpdateTypes.cjs');
var FrameThrottler = require('./managers/FrameThrottler.cjs');
var AnimationCoordinator = require('./managers/AnimationCoordinator.cjs');
var SlidingWindowManager = require('./managers/SlidingWindowManager.cjs');
require('pixi-filters');
require('./managers/ShaderResourceManager.cjs');
require('./filters/advancedBloomFilter.cjs');
require('./filters/blurFilter.cjs');
require('./filters/colorMatrixFilter.cjs');
require('./filters/dropShadowFilter.cjs');
require('gsap');
require('./filters/tiltShiftFilter.cjs');
var FilterFactory = require('./filters/FilterFactory.cjs');
var useDisplacementEffects = require('./hooks/useDisplacementEffects.cjs');
var useFilters = require('./hooks/useFilters.cjs');
var useSlides = require('./hooks/useSlides.cjs');
var useTextContainers = require('./hooks/useTextContainers.cjs');
var useMouseTracking = require('./hooks/useMouseTracking.cjs');
var useIdleTimer = require('./hooks/useIdleTimer.cjs');
var useNavigation = require('./hooks/useNavigation.cjs');
var useExternalNav = require('./hooks/useExternalNav.cjs');
var useTouchSwipe = require('./hooks/useTouchSwipe.cjs');
var useMouseDrag = require('./hooks/useMouseDrag.cjs');
var useTextTilt = require('./hooks/useTextTilt.cjs');
var useResizeHandler = require('./hooks/useResizeHandler.cjs');
var ImportHelpers = require('./ImportHelpers.cjs');
var assetPreload = require('./utils/assetPreload.cjs');
const FILTER_COORDINATION_EVENT = "kinetic-slider:filter-update";
const KineticSlider = ({
// Content sources
images = [],
texts = [],
slidesBasePath = "/images/",
// Displacement settings
backgroundDisplacementSpriteLocation = "/images/background-displace.jpg",
cursorDisplacementSpriteLocation = "/images/cursor-displace.png",
cursorImgEffect = true,
cursorTextEffect = true,
cursorScaleIntensity = 0.65,
cursorMomentum = 0.14,
// Cursor displacement sizing options
cursorDisplacementSizing = "natural",
cursorDisplacementWidth,
cursorDisplacementHeight,
// Text styling
textTitleColor = "white",
textTitleSize = 64,
mobileTextTitleSize = 40,
textTitleLetterspacing = 2,
textTitleFontFamily,
textSubTitleColor = "white",
textSubTitleSize = 24,
mobileTextSubTitleSize = 18,
textSubTitleLetterspacing = 1,
textSubTitleOffsetTop = 10,
mobileTextSubTitleOffsetTop = 5,
textSubTitleFontFamily,
// Animation settings
maxContainerShiftFraction = 0.05,
swipeScaleIntensity = 2,
transitionScaleIntensity = 30,
// Navigation settings
externalNav = false,
navElement = { prev: ".main-nav.prev", next: ".main-nav.next" },
buttonMode = false,
// Filter configurations
imageFilters,
textFilters,
// Atlas configuration
slidesAtlas = "slides-atlas",
effectsAtlas = "effects-atlas",
useEffectsAtlas = false,
useSlidesAtlas = false
}) => {
console.log("KineticSlider received props:", {
useSlidesAtlas,
useEffectsAtlas,
slidesAtlas,
effectsAtlas
});
const sliderRef = react.useRef(null);
const [isClient, setIsClient] = react.useState(false);
const [currentSlideIndex, setCurrentSlideIndex] = react.useState(0);
const [isInteracting, setIsInteracting] = react.useState(false);
const [isAppReady, setIsAppReady] = react.useState(false);
const [assetsLoaded, setAssetsLoaded] = react.useState(false);
const cursorActiveRef = react.useRef(false);
const scheduler = RenderScheduler.RenderScheduler.getInstance();
const resourceManagerRef = react.useRef(null);
const slidingWindowManagerRef = react.useRef(null);
const animationCoordinator = AnimationCoordinator.AnimationCoordinator.getInstance();
react.useEffect(() => {
if (typeof window === "undefined") return;
scheduler.configureThrottling({
targetFps: 60,
strategy: FrameThrottler.ThrottleStrategy.PRIORITY
});
return () => {
scheduler.clearQueue();
};
}, [scheduler]);
const atlasManagerRef = react.useRef(null);
const appRef = react.useRef(null);
const slidesRef = react.useRef([]);
const textContainersRef = react.useRef([]);
const backgroundDisplacementSpriteRef = react.useRef(null);
const cursorDisplacementSpriteRef = react.useRef(null);
const bgDispFilterRef = react.useRef(null);
const cursorDispFilterRef = react.useRef(null);
const currentIndexRef = react.useRef(0);
react.useEffect(() => {
setIsClient(true);
}, []);
react.useEffect(() => {
const componentId = `kinetic-slider-${Math.random().toString(36).substring(2, 9)}`;
resourceManagerRef.current = new ResourceManager.default(componentId, {
enableMetrics: true,
enableShaderPooling: true,
logLevel: "warn"
});
FilterFactory.FilterFactory.initialize({
enableShaderPooling: true,
enableDebug: false,
lazyLoadConfig: {
unloadTimeoutMs: 12e4,
// 2 minutes
maxCachedModules: 20,
enablePrefetching: true,
retryFailedLoads: true,
maxRetries: 3
}
});
atlasManagerRef.current = new AtlasManager.AtlasManager({
debug: true,
preferAtlas: true,
cacheFrameTextures: true,
basePath: "/atlas"
}, resourceManagerRef.current);
if (resourceManagerRef.current) {
animationCoordinator.setResourceManager(resourceManagerRef.current);
}
slidingWindowManagerRef.current = new SlidingWindowManager.default({
totalSlides: images.length,
initialIndex: 0,
windowSize: 2,
// Default: current slide ±2
debug: false
}, resourceManagerRef.current);
return () => {
if (resourceManagerRef.current) {
console.log("Component unmounting - disposing all resources");
resourceManagerRef.current.markUnmounting();
resourceManagerRef.current.dispose();
resourceManagerRef.current = null;
}
if (atlasManagerRef.current) {
atlasManagerRef.current.dispose();
atlasManagerRef.current = null;
}
slidingWindowManagerRef.current = null;
};
}, [images.length, animationCoordinator]);
const pixiRefs = {
app: appRef,
slides: slidesRef,
textContainers: textContainersRef,
backgroundDisplacementSprite: backgroundDisplacementSpriteRef,
cursorDisplacementSprite: cursorDisplacementSpriteRef,
bgDispFilter: bgDispFilterRef,
cursorDispFilter: cursorDispFilterRef,
currentIndex: currentIndexRef
};
const hookProps = {
images,
texts,
slidesBasePath,
backgroundDisplacementSpriteLocation,
cursorDisplacementSpriteLocation,
cursorImgEffect,
cursorTextEffect,
cursorScaleIntensity,
cursorMomentum,
cursorDisplacementSizing,
cursorDisplacementWidth,
cursorDisplacementHeight,
textTitleColor,
textTitleSize,
mobileTextTitleSize,
textTitleLetterspacing,
textTitleFontFamily,
textSubTitleColor,
textSubTitleSize,
mobileTextSubTitleSize,
textSubTitleLetterspacing,
textSubTitleOffsetTop,
mobileTextSubTitleOffsetTop,
textSubTitleFontFamily,
maxContainerShiftFraction,
swipeScaleIntensity,
transitionScaleIntensity,
imageFilters,
textFilters,
slidesAtlas,
effectsAtlas,
useSlidesAtlas,
useEffectsAtlas
};
const hookParams = {
sliderRef,
pixi: pixiRefs,
props: hookProps,
resourceManager: resourceManagerRef.current,
atlasManager: atlasManagerRef.current,
slidingWindowManager: slidingWindowManagerRef.current
};
const { showDisplacementEffects, hideDisplacementEffects } = useDisplacementEffects.useDisplacementEffects({
sliderRef,
bgDispFilterRef,
cursorDispFilterRef,
backgroundDisplacementSpriteRef,
cursorDisplacementSpriteRef,
appRef,
backgroundDisplacementSpriteLocation,
cursorDisplacementSpriteLocation,
cursorImgEffect,
cursorScaleIntensity,
cursorDisplacementSizing,
cursorDisplacementWidth,
cursorDisplacementHeight,
resourceManager: resourceManagerRef.current,
atlasManager: atlasManagerRef.current || void 0,
effectsAtlas,
useEffectsAtlas
});
const {
updateFilterIntensities,
resetAllFilters,
activateFilterEffects,
isInitialized: filtersInitialized,
isActive: filtersActive,
setFiltersActive
} = useFilters.useFilters(hookParams);
react.useEffect(() => {
if (!isAppReady || !assetsLoaded) {
console.log("Skipping filter coordination - not ready", {
filtersInitialized,
isAppReady,
assetsLoaded
});
return;
}
if (!filtersInitialized && typeof activateFilterEffects === "function") {
console.log("Attempting to initialize filters during coordination");
activateFilterEffects();
}
console.log(`Filter coordination - isInteracting: ${isInteracting}, filtersActive: ${filtersActive}`);
if (isInteracting) {
console.log("Interaction started - activating effects");
showDisplacementEffects();
if (typeof activateFilterEffects === "function") {
console.log("Using activateFilterEffects");
activateFilterEffects();
} else {
console.log("Using updateFilterIntensities");
updateFilterIntensities(true, true);
}
} else {
console.log("Interaction ended - deactivating effects");
hideDisplacementEffects();
updateFilterIntensities(false);
}
}, [
isInteracting,
isAppReady,
assetsLoaded,
filtersInitialized,
filtersActive,
showDisplacementEffects,
hideDisplacementEffects,
updateFilterIntensities,
activateFilterEffects
]);
react.useEffect(() => {
if (!isAppReady || !assetsLoaded) {
resetAllFilters();
}
return () => {
resetAllFilters();
};
}, [isAppReady, assetsLoaded, resetAllFilters]);
react.useEffect(() => {
if (typeof window === "undefined" || !isClient) return;
const loadAssets = async () => {
try {
console.log("Preloading assets and fonts...");
if (atlasManagerRef.current) {
if (slidesAtlas) {
await atlasManagerRef.current.loadAtlas(
slidesAtlas,
`/atlas/${slidesAtlas}.json`,
`/atlas/${slidesAtlas}.png`
);
}
if (effectsAtlas) {
await atlasManagerRef.current.loadAtlas(
effectsAtlas,
`/atlas/${effectsAtlas}.json`,
`/atlas/${effectsAtlas}.png`
);
}
}
await assetPreload.preloadKineticSliderAssets(
images,
backgroundDisplacementSpriteLocation,
cursorDisplacementSpriteLocation,
textTitleFontFamily,
textSubTitleFontFamily
);
setAssetsLoaded(true);
console.log("Assets and fonts preloaded successfully");
} catch (error) {
console.error("Failed to preload assets:", error);
setAssetsLoaded(true);
}
};
loadAssets();
}, [
isClient,
images,
backgroundDisplacementSpriteLocation,
cursorDisplacementSpriteLocation,
textTitleFontFamily,
textSubTitleFontFamily,
slidesAtlas,
effectsAtlas
]);
react.useEffect(() => {
if (typeof window === "undefined" || !sliderRef.current || appRef.current || !assetsLoaded) return;
const initPixi = async () => {
try {
console.log("Loading PixiJS dependencies...");
const { gsap, pixi, pixiPlugin } = await ImportHelpers.loadKineticSliderDependencies();
if (typeof window !== "undefined" && pixiPlugin) {
gsap.registerPlugin(pixiPlugin);
if (pixiPlugin.registerPIXI) {
pixiPlugin.registerPIXI(pixi);
}
}
console.log("Creating Pixi.js application...");
const app = new pixi_js.Application();
await app.init({
width: sliderRef.current?.clientWidth || 800,
height: sliderRef.current?.clientHeight || 600,
backgroundAlpha: 0,
resizeTo: sliderRef.current || void 0
});
if (resourceManagerRef.current) {
resourceManagerRef.current.trackPixiApp(app);
}
if (sliderRef.current) {
sliderRef.current.appendChild(app.canvas);
}
appRef.current = app;
const stage = new pixi_js.Container();
app.stage.addChild(stage);
if (resourceManagerRef.current) {
resourceManagerRef.current.trackDisplayObject(stage);
}
setIsAppReady(true);
console.log("Pixi.js application initialized");
} catch (error) {
console.error("Failed to initialize Pixi.js application:", error);
}
};
initPixi();
return () => {
if (appRef.current) {
if (sliderRef.current) {
const canvas = sliderRef.current.querySelector("canvas");
if (canvas) {
sliderRef.current.removeChild(canvas);
}
}
appRef.current = null;
setIsAppReady(false);
}
};
}, [sliderRef.current, assetsLoaded]);
react.useEffect(() => {
if (typeof window === "undefined" || !isAppReady) return;
if (!hookProps.imageFilters && !hookProps.textFilters) return;
const getFilterTypes = (config) => {
if (!config) return [];
const configs = Array.isArray(config) ? config : [config];
return configs.filter((c) => c && c.type && c.enabled !== false).map((c) => c.type);
};
const imageFilterTypes = getFilterTypes(hookProps.imageFilters);
const textFilterTypes = getFilterTypes(hookProps.textFilters);
const allFilterTypes = [.../* @__PURE__ */ new Set([...imageFilterTypes, ...textFilterTypes])];
if (allFilterTypes.length > 0) {
console.log(`Prefetching ${allFilterTypes.length} filter types:`, allFilterTypes);
FilterFactory.FilterFactory.prefetchFilterModules(allFilterTypes, "high");
}
}, [isAppReady, hookProps.imageFilters, hookProps.textFilters]);
const handleSlideChange = react.useCallback((newIndex) => {
currentIndexRef.current = newIndex;
setCurrentSlideIndex(newIndex);
if (filtersInitialized) {
if (isInteracting) {
console.log("Cursor is within canvas - applying filters immediately with critical priority");
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.DISPLACEMENT_EFFECT,
() => {
showDisplacementEffects();
},
"critical"
);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.FILTER_UPDATE,
() => {
currentIndexRef.current = newIndex;
if (typeof activateFilterEffects === "function") {
activateFilterEffects();
setFiltersActive(true);
}
},
"critical"
);
} else {
activateFilterEffects();
const transitionDuration = 1e3;
setTimeout(() => {
if (!isInteracting) {
updateFilterIntensities(false);
hideDisplacementEffects();
}
}, transitionDuration);
}
}
}, [
filtersInitialized,
isInteracting,
activateFilterEffects,
updateFilterIntensities,
hideDisplacementEffects,
showDisplacementEffects,
scheduler,
setFiltersActive
]);
const { nextSlide, prevSlide } = useSlides.useSlides({
...hookParams,
onSlideChange: handleSlideChange
});
useTextContainers.default({
sliderRef,
appRef,
slidesRef,
textContainersRef,
currentIndex: currentIndexRef,
buttonMode,
texts,
textTitleColor,
textTitleSize,
mobileTextTitleSize,
textTitleLetterspacing,
textTitleFontFamily,
textSubTitleColor,
textSubTitleSize,
mobileTextSubTitleSize,
textSubTitleLetterspacing,
textSubTitleOffsetTop,
mobileTextSubTitleOffsetTop,
textSubTitleFontFamily,
resourceManager: resourceManagerRef.current
});
useMouseTracking.default({
...hookParams,
backgroundDisplacementSpriteRef,
cursorDisplacementSpriteRef,
cursorImgEffect,
cursorMomentum
});
useIdleTimer.default({
sliderRef,
cursorActive: cursorActiveRef,
bgDispFilterRef,
cursorDispFilterRef,
cursorImgEffect,
defaultBgFilterScale: 20,
defaultCursorFilterScale: 10,
resourceManager: resourceManagerRef.current
});
const handleNext = react.useCallback(() => {
if (!appRef.current || !isAppReady || slidesRef.current.length === 0) return;
const nextIndex = (currentSlideIndex + 1) % slidesRef.current.length;
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.SLIDE_TRANSITION,
() => {
nextSlide(nextIndex);
currentIndexRef.current = nextIndex;
setCurrentSlideIndex(nextIndex);
setTimeout(() => {
console.log("Scheduling effects after slide change (next)");
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.DISPLACEMENT_EFFECT,
() => {
showDisplacementEffects();
},
// Use critical priority if cursor is within the canvas
isInteracting ? "critical" : void 0
);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.FILTER_UPDATE,
() => {
currentIndexRef.current = nextIndex;
if (typeof activateFilterEffects === "function") {
activateFilterEffects();
if (isInteracting) {
setFiltersActive(true);
}
}
},
// Use critical priority if cursor is within the canvas
isInteracting ? "critical" : void 0
);
}, 100);
}
);
}, [
appRef,
isAppReady,
slidesRef,
currentSlideIndex,
nextSlide,
isInteracting,
showDisplacementEffects,
activateFilterEffects,
scheduler,
setFiltersActive
]);
const handlePrev = react.useCallback(() => {
if (!appRef.current || !isAppReady || slidesRef.current.length === 0) return;
const prevIndex = (currentSlideIndex - 1 + slidesRef.current.length) % slidesRef.current.length;
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.SLIDE_TRANSITION,
() => {
prevSlide(prevIndex);
currentIndexRef.current = prevIndex;
setCurrentSlideIndex(prevIndex);
setTimeout(() => {
console.log("Scheduling effects after slide change (prev)");
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.DISPLACEMENT_EFFECT,
() => {
showDisplacementEffects();
},
// Use critical priority if cursor is within the canvas
isInteracting ? "critical" : void 0
);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.FILTER_UPDATE,
() => {
currentIndexRef.current = prevIndex;
if (typeof activateFilterEffects === "function") {
activateFilterEffects();
if (isInteracting) {
setFiltersActive(true);
}
}
},
// Use critical priority if cursor is within the canvas
isInteracting ? "critical" : void 0
);
}, 100);
}
);
}, [
appRef,
isAppReady,
slidesRef,
currentSlideIndex,
prevSlide,
isInteracting,
showDisplacementEffects,
activateFilterEffects,
scheduler,
setFiltersActive
]);
react.useEffect(() => {
if (!appRef.current || !isAppReady) return;
currentIndexRef.current = currentSlideIndex;
}, [appRef.current, currentSlideIndex, isAppReady]);
useNavigation.default({
onNext: handleNext,
onPrev: handlePrev,
enableKeyboardNav: true
});
useExternalNav.default({
externalNav,
navElement,
handleNext,
handlePrev
});
useTouchSwipe.default({
sliderRef,
onSwipeLeft: handleNext,
onSwipeRight: handlePrev
});
useMouseDrag.default({
sliderRef,
slidesRef,
currentIndex: currentIndexRef,
swipeScaleIntensity,
swipeDistance: typeof window !== "undefined" ? window.innerWidth * 0.2 : 200,
onSwipeLeft: handleNext,
onSwipeRight: handlePrev
});
useTextTilt.default({
sliderRef,
textContainersRef,
currentIndex: currentIndexRef,
cursorTextEffect,
maxContainerShiftFraction,
bgDispFilterRef,
cursorDispFilterRef,
cursorImgEffect
});
useResizeHandler.default({
sliderRef,
appRef,
slidesRef,
textContainersRef,
backgroundDisplacementSpriteRef,
cursorDisplacementSpriteRef
});
const handleMouseEnter = react.useCallback(() => {
if (!isAppReady) return;
console.log("Mouse entered the slider - activating effects immediately", {
filtersInitialized,
filtersActive,
hasActivateFunction: typeof activateFilterEffects === "function",
hasUpdateFunction: typeof updateFilterIntensities === "function",
currentSlideIndex
});
cursorActiveRef.current = true;
setIsInteracting(true);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.DISPLACEMENT_EFFECT,
() => {
showDisplacementEffects();
console.log("Displacement effects activated");
},
"critical"
);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.FILTER_UPDATE,
() => {
if (!filtersInitialized && typeof activateFilterEffects === "function") {
console.log("Filters not initialized, initializing now");
activateFilterEffects();
} else if (typeof activateFilterEffects === "function") {
console.log("Using activateFilterEffects function for slide", currentSlideIndex);
activateFilterEffects();
} else if (typeof updateFilterIntensities === "function") {
console.log("Using updateFilterIntensities function with force=true");
updateFilterIntensities(true, true);
}
setFiltersActive(true);
console.log("Filter activation completed with critical priority");
},
"critical"
);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.FILTER_UPDATE,
() => {
console.log("Final render update after mouse enter completed");
console.log("Filter state after render:", {
filtersActive,
bgDispFilterEnabled: bgDispFilterRef.current?.enabled,
cursorDispFilterEnabled: cursorDispFilterRef.current?.enabled,
currentSlideIndex
});
},
"critical"
);
}, [
isAppReady,
showDisplacementEffects,
updateFilterIntensities,
activateFilterEffects,
filtersInitialized,
filtersActive,
setFiltersActive,
currentSlideIndex,
scheduler
]);
const handleMouseLeave = react.useCallback(() => {
if (!isAppReady) return;
setIsInteracting(false);
const event1 = new CustomEvent(FILTER_COORDINATION_EVENT, {
detail: {
type: "background-displacement",
intensity: 0,
timestamp: Date.now(),
source: "slider-component",
priority: "critical"
}
});
window.dispatchEvent(event1);
const event2 = new CustomEvent(FILTER_COORDINATION_EVENT, {
detail: {
type: "cursor-displacement",
intensity: 0,
timestamp: Date.now(),
source: "slider-component",
priority: "critical"
}
});
window.dispatchEvent(event2);
updateFilterIntensities(false, true);
scheduler.scheduleTypedUpdate(
"slider",
UpdateTypes.UpdateType.FILTER_UPDATE,
() => {
},
"critical"
);
}, [isAppReady, setIsInteracting, updateFilterIntensities, scheduler]);
react.useEffect(() => {
return () => {
resetAllFilters();
if (resourceManagerRef.current) {
resourceManagerRef.current.clearPendingUpdates();
}
const transitionTimeouts = Array.from(document.querySelectorAll(`[data-slider-id="${sliderRef.current?.id}"]`)).map((el) => parseInt(el.getAttribute("data-timeout-id") || "0")).filter((id) => id > 0);
transitionTimeouts.forEach(clearTimeout);
};
}, [resetAllFilters]);
react.useEffect(() => {
const handleError = (error) => {
console.error("Filter system error:", error);
resetAllFilters();
hideDisplacementEffects();
};
window.addEventListener("error", (e) => handleError(e.error));
return () => window.removeEventListener("error", (e) => handleError(e.error));
}, [resetAllFilters, hideDisplacementEffects]);
react.useEffect(() => {
return () => {
if (resourceManagerRef.current) {
resourceManagerRef.current.clearPendingUpdates();
resourceManagerRef.current.markUnmounting();
}
};
}, []);
react.useEffect(() => {
if (!resourceManagerRef.current) return;
let frameCount = 0;
let lastTime = performance.now();
let fps = 60;
const monitorPerformance = () => {
frameCount++;
const currentTime = performance.now();
const elapsed = currentTime - lastTime;
if (elapsed > 1e3) {
fps = frameCount * 1e3 / elapsed;
frameCount = 0;
lastTime = currentTime;
if (resourceManagerRef.current && fps < 55) {
resourceManagerRef.current.autoOptimizeFilters(fps, 55);
}
}
performanceMonitorId = requestAnimationFrame(monitorPerformance);
};
let performanceMonitorId = requestAnimationFrame(monitorPerformance);
return () => {
if (performanceMonitorId) {
cancelAnimationFrame(performanceMonitorId);
}
};
}, [resourceManagerRef]);
return /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: KineticSlider_module.default.kineticSlider,
ref: sliderRef,
onMouseEnter: handleMouseEnter,
onMouseLeave: handleMouseLeave,
children: [
(!isAppReady || !assetsLoaded) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: KineticSlider_module.default.placeholder, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: KineticSlider_module.default.loadingIndicator, children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: KineticSlider_module.default.spinner }),
/* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading slider..." })
] }) }),
!externalNav && isClient && /* @__PURE__ */ jsxRuntime.jsxs("nav", { children: [
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handlePrev, className: KineticSlider_module.default.prev, children: "Prev" }),
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleNext, className: KineticSlider_module.default.next, children: "Next" })
] })
]
}
);
};
exports.default = KineticSlider;
//# sourceMappingURL=KineticSlider.cjs.map