# VistaView v2 Documentation - Full > Generated: 2026-06-26T11:51:13.463Z > This file contains the complete VistaView documentation in a single document. > Website: https://vistaview.jujiplay.com > GitHub: https://github.com/juji/vistaview > npm: https://www.npmjs.com/package/vistaview ## About VistaView VistaView is a lightweight, modern image lightbox library for the web. Zero dependencies, and highly customizable. ## Table of Contents 1. [Index](#index) 2. [Core](#core) 3. [Framework Integrations](#framework-integrations) 4. [Extensions](#extensions) 5. [Styling & Theming](#styling--theming) 6. [API Reference](#api-reference) --- ## Index --- # VistaView A lightweight, modern image lightbox library for the web. Zero dependencies, and highly customizable. Path: /index import CreateGallerySection from '../../components/home/CreateGallerySection.astro'; import ThemeSelection from '../../components/home/ThemeSelection.astro'; import ExtensionsSection from '../../components/home/ExtensionsSection.astro'; ---

VistaView is inspired by PhotoSwipe. Created by juji. --- ## Core --- # Installation How to install VistaView in your project Path: /core/installation ![npm version](https://img.shields.io/npm/v/vistaview?label=VistaView) VistaView is a lightweight image lightbox library that can be installed via npm or used directly from a CDN. ## Package Manager Installation import { Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npm install vistaview ``` ```bash yarn add vistaview ``` ```bash pnpm add vistaview ``` ```bash bun add vistaview ``` ## CDN Installation For quick prototyping or non-bundler environments, use the UMD build via CDN. Use these URLs for the latest published version: ### unpkg ```html ``` ### jsDelivr ```html ``` ## Bundle Sizes VistaView is lightweight and optimized for production. Bundle sizes are for v2: - **Core Library (ESM):** 0.71 KB (0.24 KB gzip) - **Core Library (UMD):** 40.16 KB (10.73 KB gzip) - **CSS:** 7.71 KB (1.80 KB gzip) ## Browser Support VistaView works in all modern browsers: - Chrome (latest) - Firefox (latest) - Safari (latest) - Edge (latest) ## Framework Integrations VistaView provides official bindings for popular frameworks. Each integration ships a component (recommended) and a hook/composable for more advanced use cases: - **[React](/integrations/react)** – `VistaView` component + `useVistaView` hook, exports `VistaViewProps` and `VistaComponentRef` types - **[Vue 3](/integrations/vue)** – `VistaView` component + `useVistaView` composable, exports `VistaViewProps` and `VistaComponentRef` types - **[Svelte](/integrations/svelte)** – `VistaView` component + `useVistaView` hook, exports `VistaViewProps` and `VistaComponentRef` types - **[Solid](/integrations/solid)** – `VistaView` component + `useVistaView` hook, exports `VistaViewProps` type - **[Vanilla JS](/integrations/vanilla)** – Direct `vistaView()` API, no wrapper needed All framework packages are imported from the same `vistaview` package using subpath exports: ```ts import { VistaView, useVistaView } from 'vistaview/react'; import { VistaView, useVistaView } from 'vistaview/vue'; import { VistaView, useVistaView } from 'vistaview/svelte'; import { VistaView, useVistaView } from 'vistaview/solid'; ``` ## Next Steps - Follow an [Integration guide](/integrations/react) for your framework - Explore [configuration options](/core/configuration/complete) - Learn about [extensions](/extensions/overview) --- # Lifecycle Functions Override default lifecycle behavior with custom functions Path: /core/configuration/advanced You can override default lifecycle functions to customize behavior at different stages: ```typescript import { vistaView, // lifecycle functions init, open, imageSetup, transition, close, } from 'vistaview'; vistaView({ elements: '#gallery a', // Custom initialization (runs once on instance creation) initFunction: (vistaView) => { console.log('Custom init'); init(vistaView); // Call default init }, // Custom open behavior (runs when lightbox opens) openFunction: (vistaView) => { console.log('Custom open'); open(vistaView); // Call default open }, // Custom setup when navigating between images imageSetupFunction: (data, vistaView) => { console.log('Setting up image:', data.index.to); imageSetup(data, vistaView); // Call default imageSetup }, // Custom transition animation transitionFunction: async (data, abortSignal, vistaView) => { console.log('Custom transition'); // Use default transition return transition(data, abortSignal, vistaView); }, // Custom close behavior (runs when lightbox closes) closeFunction: (vistaView) => { console.log('Custom close'); close(vistaView); // Call default close }, }); ``` See the [API Reference](/api-reference/main-function) for more details on these functions. --- # Animation Options Configure animation timing and behavior in VistaView Path: /core/configuration/animation ## animationDurationBase Base multiplier for all animation timings in VistaView. This unitless value is multiplied to create different animation durations throughout the lightbox. **How it works:** - The base value is multiplied by `1ms`, `2ms`, etc. to create proportional timings - Primary animations (open, close, transitions): `333ms` (1× base) - Delays and sequential animations: `666ms` (2× base) - Changing this value scales all animations proportionally, maintaining timing relationships **Default:** `333` ```typescript vistaView({ elements: '#gallery a', animationDurationBase: 333, // default }); ``` ## rapidLimit Defines the time threshold (in milliseconds) for detecting rapid navigation. When users navigate faster than this limit, VistaView skips transition animations for better performance. **How it works:** - If the time between image swaps is **less than** `rapidLimit`, it's considered a "rapid swap" - During rapid swaps, transition animations are skipped and images swap instantly - After rapid navigation stops, there's a 333ms cooldown before normal transitions resume - This prevents stuttering when users rapidly click next/prev or hold down arrow keys **Default:** `222` (222ms) ```typescript vistaView({ elements: '#gallery a', rapidLimit: 222, // default }); ``` --- # Basic Configuration Get started with basic VistaView configuration Path: /core/configuration/basic Learn the fundamentals of configuring VistaView for your image galleries. ## Minimal Setup The simplest way to use VistaView requires just two things: importing the library and specifying which elements to use. ### Using Anchor Tags (Recommended) The recommended approach uses anchor tags wrapping images: ```html ``` ```typescript import { vistaView } from 'vistaview'; import 'vistaview/style.css'; vistaView({ elements: '#gallery a', }); ``` Benefits: - Progressive loading from thumbnail to full-size - Works without JavaScript - SEO-friendly ### Using Images Directly You can also select images directly: ```html ``` ```typescript vistaView({ elements: '#gallery img', }); ``` ### Using Array of Images You can also pass an array of image configuration objects directly: ```typescript import type { VistaImgConfig } from 'vistaview'; const images: VistaImgConfig[] = [ { src: '/images/photo1.jpg', alt: 'Photo 1' }, { src: '/images/photo2.jpg', alt: 'Photo 2' }, { src: '/images/photo3.jpg', alt: 'Photo 3', srcSet: '/images/photo3-800.jpg 800w, /images/photo3-1200.jpg 1200w', }, ]; vistaView({ elements: images, }); ``` **VistaImgConfig Type:** ```typescript interface VistaImgConfig { src: string; // Full-size image URL (required) alt?: string; // Alt text for the image srcSet?: string; // Responsive image srcset attribute } ``` **Note:** Thumbnails are not supported when using an array. This approach is best for programmatically generated galleries. ## Return Value The `vistaView` function returns an instance with methods to control the lightbox programmatically: ```typescript const vista = vistaView({ elements: '#gallery a', }); // Available methods: vista.open(0); // Open lightbox at index 0 vista.close(); // Close the lightbox vista.next(); // Navigate to next image vista.prev(); // Navigate to previous image vista.view(2); // Jump to image at index 2 vista.zoomIn(); // Zoom in vista.zoomOut(); // Zoom out vista.getCurrentIndex(); // Get current image index vista.reset(); // Recalculate elements; for selectors: re-queries DOM and re-attaches click listeners; for arrays: updates element count only vista.destroy(); // Clean up and remove lightbox ``` **VistaInterface Type:** ```typescript interface VistaInterface { open: (startIndex?: number) => void; // Open at specific index close: () => Promise; // Close lightbox reset: () => void; // For selectors: re-queries DOM & re-attaches click listeners; For arrays: updates count only next: () => void; // Go to next image prev: () => void; // Go to previous image zoomIn: () => void; // Zoom in current image zoomOut: () => void; // Zoom out current image destroy: () => void; // Remove lightbox completely getCurrentIndex: () => number; // Get current image index view: (index: number) => void; // Navigate to specific index } ``` ## Multiple Gallery Configurations When you need different lightbox configurations across different sections of your application, you have two main approaches: ### Approach 1: Multiple Instances (Recommended) Create separate VistaView instances for each gallery with different configurations: ```typescript // Product gallery with zoom enabled const productGallery = vistaView({ elements: '#product-images a', maxZoomLevel: 3, arrowOnSmallScreens: true, controls: { topRight: ['zoomIn', 'zoomOut', 'close'], }, }); // Portfolio gallery with minimal UI const portfolioGallery = vistaView({ elements: '#portfolio a', maxZoomLevel: 1, // No zoom keyboardListeners: false, controls: { topRight: ['close'], }, }); // Blog gallery with downloads import { download } from 'vistaview/extensions/download'; const blogGallery = vistaView({ elements: '#blog-post img', extensions: [download()], }); ``` **Advantages:** - Each gallery is independent with its own configuration - Different extensions per gallery - No need to reconfigure or reset - Straightforward and maintainable **Memory:** - Each instance maintains its own state and event listeners - Automatically cleaned up when you call `destroy()` ### Approach 2: Single Instance with Dynamic Content Use a single instance and update content dynamically. The approach differs based on whether you use selectors or arrays: #### With String Selectors (DOM-based) Update the DOM, then call `reset()` to re-query elements and re-attach listeners: ```typescript const vista = vistaView({ elements: '#dynamic-gallery a', maxZoomLevel: 2, }); // Example Async function to fetch and update gallery async function updateGallery(category: string) { const response = await fetch(`/api/images?category=${category}`); const images = await response.json(); const gallery = document.querySelector('#dynamic-gallery'); // Update DOM gallery.innerHTML = images .map( (img: { src: string; alt: string }) => ` ${img.alt} ` ) .join(''); // Re-query DOM and re-attach click listeners vista.reset(); } ``` **How `reset()` works with selectors:** - Re-queries the DOM using the original selector - Updates `state.elmLength` - Removes and re-attaches click event listeners - Images become clickable automatically #### With Arrays (Programmatic) Mutate the array reference, then call `reset()` to update count: ```typescript // Create array that will be mutated const currentImages: VistaImgConfig[] = []; const vista = vistaView({ elements: currentImages, // Stores the array reference maxZoomLevel: 2, }); // Example Async function to fetch and update gallery async function updateGallery(category: string) { const response = await fetch(`/api/images?category=${category}`); const images = await response.json(); // Mutate the original array (don't reassign!) currentImages.length = 0; currentImages.push(...images); // Update element count vista.reset(); } ``` **How `reset()` works with arrays:** - Reads `this.elements.length` to update count - Does NOT attach click listeners (arrays have no DOM elements) - You must call `open()` programmatically **Advantages (both):** - Single instance reduces memory - Good for SPAs with dynamic content - All content shares same configuration **Limitations (both):** - Cannot change configuration after initialization - All galleries share same settings (zoom, extensions, controls) ### When to Destroy Instances Always destroy instances when they're no longer needed: ```typescript // Before page navigation in SPAs function cleanup() { productGallery.destroy(); portfolioGallery.destroy(); blogGallery.destroy(); } // the following example in react and Vue // is only needed if you are using // hooks, composable, or creating and managing you own instance. // In React - basic cleanup useEffect(() => { const vista = vistaView({ elements: '#gallery a' }); return () => vista.destroy(); }, []); // In React - destroy and recreate when data changes const [images, setImages] = useState([]); useEffect(() => { const vista = vistaView({ elements: images, // Works for both: arrays, or '#gallery a' when DOM re-renders maxZoomLevel: 2, }); return () => vista.destroy(); }, [images]); // In Vue onUnmounted(() => { vista.destroy(); }); ``` ## Next Steps - Explore [Animation Options](/core/configuration/animation) for timing control - Discover [Controls](/core/configuration/controls) for UI customization - See all available options in the [Complete Options](/core/configuration/complete) --- # Options Complete reference of all VistaView configuration options Path: /core/configuration/complete This page provides a comprehensive reference of all available configuration options for VistaView. ## Default Options The value you see here are the default values. ```typescript vistaView({ // Required: specify elements elements: string | VistaImgConfig[], // Animation & Timing animationDurationBase: 333, // Base animation duration in ms rapidLimit: 222, // Minimum time between rapid actions in ms // Zoom & Navigation maxZoomLevel: 2, // Maximum zoom multiplier (1 = 100%, 2 = 200%, etc.) // Number of adjacent images to preload on each side preloads: 1, // UI Controls keyboardListeners: true, // Enable keyboard navigation arrowOnSmallScreens: false, // Show prev/next arrows on screens < 768px initialZIndex: 1, // Starting z-index for the lightbox // Control Placement controls: { topLeft: ['indexDisplay'], // Array of control names topRight: ['zoomIn', 'zoomOut', 'close'], topCenter: [], bottomLeft: ['description'], bottomRight: [], bottomCenter: [], }, // Extensions extensions: [], // Array of extension objects // Event Callbacks onOpen: (vistaView) => {}, // Called when lightbox opens onClose: (vistaView) => {}, // Called when lightbox closes onImageView: (data, vistaView) => {}, // Called when viewing an image onContentChange: (content, vistaView) => {}, // Called when image content changes // Lifecycle: Custom Behavior Functions (override defaults) initFunction: undefined, // Custom initialization (default: sets up swipe gestures) openFunction: undefined, // Custom open behavior (default: positions image container) imageSetupFunction: undefined, // Custom setup when navigating (default: none) transitionFunction: undefined, // Custom transition animation (default: slide animation) closeFunction: undefined, // Custom close behavior (default: none) }); ``` ## Detailed Documentation For detailed explanations and examples of each option, refer to the specific configuration sections: - **[Basic Configuration](/core/configuration/basic)** - Getting started essentials - **[Animation Options](/core/configuration/animation)** - Timing and transitions - **[Zoom Options](/core/configuration/zoom)** - Zoom behavior - **[Preloading](/core/configuration/preloading)** - Image preloading settings - **[Control Configuration](/core/configuration/controls)** - UI controls placement - **[Keyboard & UI Options](/core/configuration/keyboard)** - Keyboard and mobile settings - **[Z-Index Configuration](/core/configuration/z-index)** - Z-index stacking - **[Event Callbacks](/core/configuration/events)** - Lifecycle events - **[Data Attributes](/core/configuration/data-attributes)** - HTML data attributes - **[Lifecycle Functions](/core/configuration/lifecycle)** - Custom behavior overrides --- # Data Attributes Use HTML data attributes to customize VistaView behavior Path: /core/configuration/data-attributes VistaView uses data attributes to customize how images are displayed in the lightbox. These attributes provide fine-grained control over individual images without requiring JavaScript configuration. ## Available Attributes | Attribute | Description | Priority | | ----------------------- | ----------------------- | -------- | | `data-vistaview-src` | Full-size image URL | Highest | | `data-vistaview-srcset` | Responsive image srcset | Highest | | `data-vistaview-alt` | Alt text for lightbox | Highest | ## Attribute Priority VistaView follows a specific priority order when parsing elements: ### Image Source (`src`) 1. `data-vistaview-src` (highest priority) 2. `href` attribute (for `` tags) 3. `src` attribute (on the element itself) 4. `src` attribute (on child `` tag) ### Responsive Images (`srcset`) 1. `data-vistaview-srcset` (highest priority) 2. `srcset` attribute (on the element itself) 3. `srcset` attribute (on child `` tag) ### Alt Text (`alt`) 1. `data-vistaview-alt` (highest priority) 2. `alt` attribute (on the element itself) 3. `alt` attribute (on child `` tag) ## Examples ### Basic Override Override the lightbox image URL while keeping the thumbnail: ```html My image ``` ### Responsive Images Provide different images based on the displayed image size. VistaView dynamically selects the most appropriate image as the image size changes: ```html Responsive image ``` **How it works:** - VistaView monitors the **image's display width** (not viewport width) and automatically switches to the optimal image from the srcset - The image display width depends on the viewport and the image's aspect ratio (portrait images are constrained by height, landscape by width) - Accounts for device pixel ratio (DPI) for high-resolution displays (e.g., Retina screens) - Selects the smallest image that meets or exceeds the required display width - Dynamically swaps images during opening animation and zoom gestures **Format:** `"url {width}w, url {width}w, ..."` where width descriptors specify the image's actual pixel width. :::note[Width descriptors only] VistaView only supports the `w` (width) descriptor. Density descriptors like `1x` or `2x` are **not supported**. Use width descriptors with pixel values (e.g., `800w`, `1200w`) to enable responsive image selection. ::: **Example with pixel calculations:** ```html Adaptive resolution ``` ### Custom Alt Text Display different text in the thumbnail vs lightbox: ```html Thumbnail caption ``` ### Combining Attributes Use multiple attributes together. When both `src` and `srcset` are provided, `srcset` takes precedence and `src` serves as fallback: ```html Click to view ``` **Priority order:** If `srcset` is available, VistaView uses responsive selection. The `src` attribute (or `data-vistaview-src`) is used only when `srcset` is not provided. --- # Control Configuration Configure UI controls placement and behavior Path: /core/configuration/controls ## Built-in Controls VistaView includes these built-in controls: | Control | Description | | -------------- | ----------------------------------------- | | `indexDisplay` | Shows current image index (e.g., "1 / 5") | | `zoomIn` | Zoom into the image | | `zoomOut` | Zoom out of the image | | `close` | Close the lightbox | | `description` | Shows the image alt text | ## Control Placement ```typescript vistaView({ elements: '#gallery a', controls: { topLeft: ['indexDisplay'], topRight: ['zoomIn', 'zoomOut', 'close'], bottomLeft: ['description'], bottomRight: [], bottomCenter: [], }, }); ``` ## Adding Extension Controls Extensions can add custom controls. See the [Extensions documentation](/extensions/overview) for available extensions. ```typescript import { download } from 'vistaview/extensions/download'; vistaView({ elements: '#gallery a', controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], // Add 'download' }, extensions: [download()], // Register extension }); ``` --- # Event Callbacks Handle VistaView lifecycle events Path: /core/configuration/events ## onOpen Called when the lightbox opens: ```typescript import type { VistaView } from 'vistaview'; vistaView({ elements: '#gallery a', onOpen: (vistaView: VistaView) => { console.log('Lightbox opened', vistaView); }, }); ``` ## onClose Called when the lightbox closes: ```typescript import type { VistaView } from 'vistaview'; vistaView({ elements: '#gallery a', onClose: (vistaView: VistaView) => { console.log('Lightbox closed', vistaView); }, }); ``` ## onImageView Called when viewing an image (including on open): ```typescript import type { VistaView, VistaData, VistaBox } from 'vistaview'; vistaView({ elements: '#gallery a', onImageView: (data: VistaData, vistaView: VistaView) => { console.log('Viewing image:', data.index.to); console.log('Previous image:', data.index.from); console.log('Navigation direction:', data.via); // Access the current and previous images if (data.images.to) { console.log('Current images:', data.images.to); } // Access HTML elements if (data.htmlElements.to) { console.log('Current HTML elements:', data.htmlElements.to); } }, }); ``` **Parameters:** - `data: VistaData` - Navigation data - `vistaView: VistaView` - The VistaView instance **VistaData type:** ```typescript type VistaData = { htmlElements: { from: HTMLElement[] | null; // Previous HTML elements to: HTMLElement[] | null; // Current HTML elements }; images: { from: VistaBox[] | null; // Previous VistaBox instances to: VistaBox[] | null; // Current VistaBox instances }; index: { from: number | null; // Previous image index (null on initial open) to: number | null; // Current image index }; via: { next: boolean; // True if navigated via next prev: boolean; // True if navigated via prev }; }; ``` ## onContentChange Called when the current image's content state changes (after zoom, pan, or when image finishes loading): ```typescript import type { VistaView, VistaImageClone } from 'vistaview'; vistaView({ elements: '#gallery a', onContentChange: (content: VistaImageClone, vistaView: VistaView) => { console.log('Image state changed'); console.log('Current dimensions:', content.state.width, content.state.height); console.log('Transform:', content.state.transform); console.log('Zoom level:', content.state.transform.scale); }, }); ``` **Use cases:** - Track zoom level changes - Monitor image dimensions during resize - Sync image state with external UI - Analytics for user interactions **Parameters:** - `content: VistaImageClone` - Current image state (dimensions, transform, config) - `vistaView: VistaView` - The VistaView instance **VistaImageClone type:** ```typescript type VistaImageClone = { config: { src: string; // Image source URL alt?: string; // Alt text srcSet?: string; // Responsive image srcset }; origin: { src: string; // Original source from HTML srcSet: string; // Original srcset from HTML borderRadius: string; // Original border radius objectFit: string; // Original object-fit value } | null; parsedSrcSet?: { src: string; width: number; }[]; element: string; // HTML string of the image element thumb?: string; // HTML string of thumbnail (if exists) index: number; // Image index in gallery pos: number; // Position relative to current (-1, 0, 1) state: { width: number; // Current display width (px) height: number; // Current display height (px) transform: { x: number; // Transform X offset (px) y: number; // Transform Y offset (px) scale: number; // Scale factor (1 = normal) }; translate: { x: number; // CSS translate X (px) y: number; // CSS translate Y (px) }; }; }; ``` --- # Extensions Add extended functionality to VistaView Path: /core/configuration/extensions ## extensions Array of extension functions that add functionality to VistaView. Extensions can add UI controls, handle different content types (videos, maps), or modify lightbox behavior. See the [Extensions Overview](/extensions/overview) for complete documentation on all available extensions and their usage. **Type:** `VistaExtension[]` **Default:** `[]` (no extensions) ```typescript import { vistaView } from 'vistaview'; import { download } from 'vistaview/extensions/download'; import { youtubeVideo } from 'vistaview/extensions/youtube-video'; vistaView({ elements: '#gallery a', controls: { // Add 'download' to controls for download extension topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download(), youtubeVideo()], }); ``` **Note:** Some extensions like `download` require adding their control name to the `controls` configuration. ## Available Extensions VistaView provides optional extensions for: - **UI Controls** - Download buttons, image story overlays - **Video Platforms** - YouTube, Vimeo, Dailymotion, Wistia, Vidyard, Streamable - **Maps** - Google Maps, Mapbox, OpenStreetMap - **Development** - Logger for debugging See the [Extensions Overview](/extensions/overview) for complete documentation on all available extensions and their usage. --- # Configuration Complete configuration reference for VistaView Path: /core/configuration --- # Keyboard & Touch Navigation Configure keyboard shortcuts and touch gestures for desktop and mobile users Path: /core/configuration/keyboard ## Keyboard Navigation VistaView includes **built-in keyboard navigation** that's enabled by default. ### Keyboard Shortcuts When the lightbox is open, the following keyboard shortcuts are available: - **Arrow Left** (←) - Navigate to previous image - **Arrow Right** (→) - Navigate to next image - **Arrow Up** (↑) - Zoom in - **Arrow Down** (↓) - Zoom out - **Escape** (Esc) - Close lightbox ### Configuration Control keyboard navigation via the `keyboardListeners` option: ```typescript vistaView({ elements: '#gallery a', keyboardListeners: true, // Default: enabled }); ``` To disable keyboard navigation: ```typescript vistaView({ elements: '#gallery a', keyboardListeners: false, }); ``` ## Touch Gestures VistaView automatically handles touch gestures with **no configuration needed**. All gestures work out-of-the-box on mobile devices. ### Pinch-to-Zoom Use two fingers to zoom in and out: - **Two-finger pinch out** - Zoom in - **Two-finger pinch in** - Zoom out The zoom is centered around the touch point (centroid of your fingers) for intuitive interaction. VistaView includes a cooldown period (111ms) after pinch gestures to prevent conflicts with other touch interactions. ### Swipe Navigation Single-finger swipe gestures for navigation: - **Horizontal swipe right** (>64px) - Navigate to previous image - **Horizontal swipe left** (>64px) - Navigate to next image - **Vertical swipe down** (>144px) - Close lightbox **Note:** Swipe gestures only work when the image is not zoomed in. When zoomed, single-finger drag is used for panning. ### Pan/Drag When an image is zoomed in: - **Single finger drag** - Pan around the zoomed image Pan is disabled at normal zoom level to allow swipe gestures for navigation and closing. ### Scroll-to-Zoom On devices with a mouse or trackpad: - **Scroll wheel** - Zoom in/out around cursor position ## Mobile-Specific Options ### arrowOnSmallScreens Control whether navigation arrows are shown on mobile devices: ```typescript vistaView({ elements: '#gallery a', arrowOnSmallScreens: true, // Show arrows on screens < 768px (default: false) }); ``` By default, navigation arrows are hidden on screens smaller than 768px to provide a cleaner interface where users can swipe. Enable this option if you want to show arrow buttons on mobile devices. ## Advanced: Custom Touch Handling For custom touch behaviors and gesture tracking, use the `registerPointerListener()` method: ```typescript const vista = vistaView({ elements: '#gallery a' }); vista.registerPointerListener((e) => { // Track pointer events console.log('Event type:', e.event); // 'down' | 'move' | 'up' | 'cancel' console.log('Active pointers:', e.pointers.length); console.log('Pointer position:', e.pointer.x, e.pointer.y); console.log('Zoom/pinch active:', e.hasInternalExecution); // Access current state console.log('Is zoomed:', e.state.zoomedIn); console.log('Current index:', e.state.currentIndex); }); ``` ### VistaExternalPointerListenerArgs Properties - `event` - Event type: `'down'`, `'move'`, `'up'`, or `'cancel'` - `pointer` - Current pointer data (x, y, movementX, movementY, id) - `pointers` - Array of all active touch points/pointers - `lastPointerLen` - Previous number of active pointers - `state` - Current [VistaState](/api-reference/classes/vistastate) instance - `hasInternalExecution` - `true` when VistaView is handling the gesture (zoom/pinch) - `abortController` - Controller to abort ongoing animations ### Example: Custom Gesture Detection ```typescript vista.registerPointerListener((e) => { // Skip if VistaView is handling the event (zooming/pinching) if (e.hasInternalExecution) return; // Detect three-finger tap if (e.event === 'down' && e.pointers.length === 3) { console.log('Three-finger tap detected!'); // Custom action here } // Track swipe velocity if (e.event === 'move' && e.pointers.length === 1) { const velocity = Math.sqrt(e.pointer.movementX ** 2 + e.pointer.movementY ** 2); console.log('Swipe velocity:', velocity); } }); ``` ## Customizing Swipe Behavior The default swipe gesture behavior is implemented in VistaView's `initFunction` lifecycle hook. You can extend or replace this behavior: ```typescript import { init as defaultInit } from 'vistaview/defaults/init'; vistaView({ elements: '#gallery a', initFunction: (vistaView) => { // Call default behavior (sets up swipe gestures) defaultInit(vistaView); // Add your custom initialization vistaView.registerPointerListener((e) => { // Your custom gesture handling if (e.event === 'down' && e.pointers.length === 3) { console.log('Three-finger tap!'); } }); }, }); ``` **Default initFunction behavior:** - Registers a pointer listener for single-touch swipe gestures - Vertical swipe down (>144px) closes the lightbox - Horizontal swipe left/right (>64px) navigates between images - Provides visual feedback during swipe (translates the image container) To completely replace the default swipe behavior, provide your own `initFunction` without calling `defaultInit()`. See [Lifecycle Functions](/core/configuration/lifecycle) for more details on customizing behavior. ## Related - [VistaPointers API](/api-reference/classes/vistapointers) - Low-level pointer tracking - [registerPointerListener()](/api-reference/classes/vistaview#registerpointerlistener) - Method documentation - [VistaState](/api-reference/classes/vistastate) - State management - [Lifecycle Functions](/core/configuration/lifecycle) - Custom behavior overrides --- # Lifecycle Functions Override default lifecycle behavior with custom functions Path: /core/configuration/lifecycle You can override default lifecycle functions to customize behavior at different stages: ```typescript import { vistaView, // lifecycle functions init, open, imageSetup, transition, close, } from 'vistaview'; import type { VistaView, VistaData } from 'vistaview'; vistaView({ elements: '#gallery a', // Custom initialization (runs once on instance creation) initFunction: (vistaView: VistaView) => { console.log('Custom init'); // default init, just here to show the actual init init(vistaView); }, // Custom open behavior (runs when lightbox opens) openFunction: (vistaView: VistaView) => { console.log('Custom open'); // default open, just here to show the actual open open(vistaView); }, // Custom setup when navigating between images imageSetupFunction: (data: VistaData, vistaView: VistaView) => { console.log('Setting up image:', data.index.to); // default imageSetup, just here to show the actual imageSetup imageSetup(data, vistaView); }, // Custom transition animation transitionFunction: async ( data: VistaData, abortSignal: AbortSignal, vistaView: VistaView ): Promise<{ cleanup: () => void; transitionEnded: Promise } | undefined> => { console.log('Custom transition'); // default transition, just here to show the actual transition return transition(data, abortSignal, vistaView); }, // Custom close behavior (runs when lightbox closes) closeFunction: (vistaView: VistaView) => { console.log('Custom close'); // default close, just here to show the actual close close(vistaView); }, }); ``` ## VistaData Type The `data` parameter passed to lifecycle functions contains information about the current and previous images: ```typescript interface VistaData { htmlElements: { from: HTMLElement[] | null; to: HTMLElement[] | null; }; images: { from: VistaBox[] | null; to: VistaBox[] | null; }; index: { from: number | null; to: number | null; }; via: { next: boolean; prev: boolean; }; } ``` See the [API Reference](/api-reference/main-function) for more details on these functions. --- # Preloading Configure image preloading for better navigation performance Path: /core/configuration/preloading ## preloads Number of adjacent images to preload: ```typescript vistaView({ elements: '#gallery a', preloads: 1, // default }); ``` **How it works:** - Preloads adjacent images on both sides (previous and next) - `preloads: 1` → loads 3 images total (current + 1 before + 1 after) - `preloads: 2` → loads 5 images total (current + 2 before + 2 after) - `preloads: 0` → only loads current image (saves bandwidth but causes loading delays) **Trade-offs:** - Higher values: Faster navigation, smoother experience, more bandwidth usage - Lower values: Less bandwidth, but visible loading delays when navigating --- # Z-Index Configuration Configure z-index stacking for the lightbox Path: /core/configuration/z-index ## initialZIndex Set the z-index for the lightbox when opening or closing. When active, the lightbox automatically uses the maximum z-index (`2147483647`) to appear above all content. **Default:** `1` **Most users should leave this at the default value.** ```typescript vistaView({ elements: '#gallery a', initialZIndex: 1, // default }); ``` ## Why leave it at 1? VistaView renders its container at the bottom of the page (end of DOM). With the default `initialZIndex: 1`, it then brings the image to the center and raises the z-index to the maximum z-index. In effect, this requires z-index ordering: - Your **sticky header** should use `z-index: 2` or higher to appear above the opening/closing lightbox ## Example with sticky header ```css /* Your sticky header */ .site-header { position: sticky; z-index: 2; /* Appears above closed lightbox (z-index: 1) */ } ``` ## How it works - **Closed state:** Uses `initialZIndex` value (default: 1) - **Active state:** Switches to `2147483647` (max z-index) in the middle of animation - always above everything - **Closing state:** Transitions back to `initialZIndex` during animation :::tip Only change `initialZIndex` if you have z-index stacking context conflicts. For typical sticky headers, just set your header to `z-index: 2` or higher. ::: --- # Zoom Options Configure zoom behavior in VistaView Path: /core/configuration/zoom ## maxZoomLevel Defines the maximum zoom level as a multiplier of the image's natural dimensions. **How it works:** - VistaView maintains three zoom levels: - **Minimum (0.5×)**: 50% of fitted size - zooming below this triggers close - **Fitted**: Image fitted to viewport while maintaining aspect ratio - **Maximum**: Natural image dimensions × `maxZoomLevel` - Zoom automatically corrects if exceeded: - Over maximum → animates back to max - Under normal (but not closing) → animates back to fitted size **Default:** `2` (200% of natural size) ```typescript vistaView({ elements: '#gallery a', maxZoomLevel: 2, // default - allows zoom to 200% of natural size }); ``` **Example:** If an image is 1600×1200px and displays at 800×600px to fit the viewport: - Minimum zoom: 400×300px (50% of fitted) - Normal zoom: 800×600px (fitted to viewport) - Maximum zoom: 3200×2400px (200% of natural 1600×1200px) --- ## Framework Integrations --- # Getting Started with React Learn how to integrate VistaView with React applications Path: /integrations/react VistaView provides official React bindings that offer both declarative components and hooks for React applications. ## Installation import { Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npm install vistaview ``` ```bash yarn add vistaview ``` ```bash pnpm add vistaview ``` ```bash bun add vistaview ``` ## Component Approach (Recommended) The `VistaView` component provides a declarative way to create image galleries: ```tsx 'use client'; // Required for Next.js and other React Server Components frameworks import { VistaView } from 'vistaview/react'; import 'vistaview/style.css'; function Gallery() { return ( Photo 1 Photo 2 ); } ``` ### With Ref for Imperative Control We expose the API and root container on the component ref as `{ vistaView, container }`. 💡 **Types:** You can import `VistaComponentRef` from `vistaview/react` (see the [Type Reference](#type-reference)): ```tsx 'use client'; // Required for Next.js and other React Server Components frameworks import { useRef } from 'react'; import { VistaView } from 'vistaview/react'; import type { VistaComponentRef } from 'vistaview/react'; import 'vistaview/style.css'; function Gallery() { const compRef = useRef(null); return ( <> Photo ); } ``` ### With Options ```tsx 'use client'; // Required for Next.js and other React Server Components frameworks import { VistaView } from 'vistaview/react'; import type { VistaOpt, VistaView } from 'vistaview'; import 'vistaview/style.css'; // Define options outside component to prevent recreation on every render const options: VistaOpt = { maxZoomLevel: 3, preloads: 2, animationDurationBase: 400, onOpen: (vistaView: VistaView): void => { console.log('Gallery opened'); }, onClose: (vistaView: VistaView): void => { console.log('Gallery closed'); }, }; function Gallery() { return ( // selector defaults to '> a' Photo 1 Photo 2 ); } ``` ## With Extensions ```tsx 'use client'; // Required for Next.js and other React Server Components frameworks import { VistaView } from 'vistaview/react'; import { download } from 'vistaview/extensions/download'; import 'vistaview/style.css'; // Define options outside component to prevent recreation on every render const extensionOptions = { controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download()], }; function Gallery() { return ( Photo 1 ); } ``` ## Hook Approach Use the `useVistaView` hook for more control over the gallery instance: ```tsx 'use client'; // Required for Next.js and other React Server Components frameworks import { useVistaView } from 'vistaview/react'; import { download } from 'vistaview/extensions/download'; import 'vistaview/style.css'; function Gallery() { const vista = useVistaView({ elements: '#gallery > a', controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download()], }); return ( ); } ``` ### Type Reference **`VistaViewProps`** ```ts interface VistaViewProps { children: ReactNode; selector?: string; // defaults to "> a" options?: VistaOpt; // passes through to core options ref?: React.Ref; } ``` - **children**: The gallery markup (usually `` items). - **selector**: CSS selector used to locate items inside the container. - **options**: Configuration passed to the core `VistaView` instance (`VistaOpt`). - **ref**: React ref that receives a `VistaComponentRef` for imperative control. **`VistaComponentRef`** ```ts type VistaComponentRef = { vistaView: VistaInterface | null; container: HTMLDivElement | null } | null; ``` - **vistaView**: The runtime API instance (`VistaInterface`) — use it to call `.open()`, `.next()`, `.prev()`, `.zoomIn()`, `.zoomOut()`, `.close()`, `.destroy()`, etc. - **container**: The root DOM element that wraps the gallery — useful for queries or DOM measurements. **Related types** - `VistaOpt` — core configuration object (see `/core/configuration/complete` or `main/src/lib/types.ts` for full shape). - `VistaInterface` — runtime API methods available on `vistaView`. **Import example** ```ts import type { VistaComponentRef, VistaViewProps } from 'vistaview/react'; ``` ## Next Steps - Explore [configuration options](/core/configuration/complete) - Learn about [extensions](/extensions/overview) - Customize the [styling](/styling/themes) --- # Getting Started with Solid Learn how to integrate VistaView with Solid applications Path: /integrations/solid VistaView provides a `useVistaView` hook for SolidJS applications. ## Installation import { Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npm install vistaview ``` ```bash yarn add vistaview ``` ```bash pnpm add vistaview ``` ```bash bun add vistaview ``` ## Component Approach (Recommended) The `VistaView` component is the recommended way to use VistaView in Solid applications: ```tsx import { VistaView } from 'vistaview/solid'; import 'vistaview/style.css'; function Gallery() { return ( Photo 1 Photo 2 ); } ``` ## Hook Approach Use the `useVistaView` hook when you need more control: ```tsx import { useVistaView } from 'vistaview/solid'; import 'vistaview/style.css'; function Gallery() { const galleryId = 'vistaview-demo'; const vista = useVistaView({ elements: `#${galleryId} > a`, }); return ( <> ); } ``` ## Imperative Control with Component Access the API through the `componentRef` callback prop: ```tsx import { VistaView } from 'vistaview/solid'; import type { VistaInterface } from 'vistaview'; import 'vistaview/style.css'; function Gallery() { let vista: VistaInterface | null = null; let container: HTMLDivElement | undefined; return ( <> { vista = api?.vistaView ?? null; container = api?.container; }} > Photo ); } ``` ## With Options ```tsx import { useVistaView } from 'vistaview/solid'; import type { VistaOpt } from 'vistaview'; import 'vistaview/style.css'; // Define options outside component to prevent recreation on every render const options: VistaOpt = { maxZoomLevel: 3, preloads: 2, animationDurationBase: 400, onOpen: (vistaView) => console.log('Gallery opened'), onClose: (vistaView) => console.log('Gallery closed'), }; function Gallery() { const id = 'gallery-' + Math.random().toString(36).slice(2); const vista = useVistaView({ elements: `#${id} > a`, ...options, }); return ( ); } ``` ## With Extensions ```tsx import { useVistaView } from 'vistaview/solid'; import { download } from 'vistaview/extensions/download'; import 'vistaview/style.css'; function Gallery() { const id = 'gallery-' + Math.random().toString(36).slice(2); const vista = useVistaView({ elements: `#${id} > a`, controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download()], }); return ( ); } ``` ## Reactive Updates VistaView works with Solid's reactive system: ```tsx import { createSignal } from 'solid-js'; import { useVistaView } from 'vistaview/solid'; import 'vistaview/style.css'; function Gallery() { const [images, setImages] = createSignal([ { src: '/images/photo1.jpg', alt: 'Photo 1' }, { src: '/images/photo2.jpg', alt: 'Photo 2' }, ]); const id = 'gallery-' + Math.random().toString(36).slice(2); const vista = useVistaView({ elements: `#${id} > a`, }); return (
{images().map((img) => ( {img.alt} ))}
); } ``` ## SolidStart VistaView works with SolidStart. Make sure to use client-side rendering: ```tsx import { lazy } from 'solid-js'; const Gallery = lazy(() => import('./Gallery')); function Page() { return ( ); } ``` ## Next Steps - Explore [configuration options](/core/configuration/complete) - Learn about [extensions](/extensions/overview) - Customize the [styling](/styling/themes) --- # Getting Started with Svelte Learn how to integrate VistaView with Svelte applications Path: /integrations/svelte VistaView provides a `VistaView` Svelte component (recommended) and a lower-level `useVistaView` hook for advanced use cases. ## Installation import { Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npm install vistaview ``` ```bash yarn add vistaview ``` ```bash pnpm add vistaview ``` ```bash bun add vistaview ``` ## Component-first usage (recommended) The recommended, primary way to use VistaView in Svelte is the `VistaView` component. It handles lifecycle, DOM changes, and provides a simple imperative API via `bind:this` and `getApi()`. ### Basic example ```svelte Photo 1 Photo 2 ``` ### Imperative Control If you need programmatic access to the gallery API, use the `vistaRef` callback prop: ```svelte { vista = api?.vistaView ?? null; container = api?.container ?? null; }}> Photo ``` ### Options ```svelte Photo 1 ``` ### Extensions ```svelte Photo 1 ``` > **Tip:** prefer the component when your gallery content is dynamic, as it observes DOM changes and re-initializes automatically. ## Hook approach (advanced) The `useVistaView` hook is a lower-level API. Use it for non-component contexts or when you need manual control. The hook handles lifecycle internally (`onMount`/`onDestroy`), so you can call it at the top level. ```svelte ``` ## Low-level usage You can call the core `vistaView` function directly when embedding in non-component contexts: ```svelte ``` ## SvelteKit Use the `VistaView` component in SvelteKit apps; it handles lifecycle and DOM updates automatically. If you need the hook, initialize it inside `onMount` to avoid SSR issues. ## Types ```ts import type { VistaViewProps, VistaComponentRef } from 'vistaview/svelte'; ``` ## Best practices & troubleshooting - Prefer the component for most cases (dynamic content, SvelteKit, simpler lifecycle). - Keep `options` objects stable (define outside render scope) to avoid unnecessary re-initializations. - Use optional chaining (e.g., `comp?.getApi()?.vistaView?.open(0)`) when calling methods that may not be ready yet. - If using the hook and the DOM changes dynamically, re-initialize or prefer the component. ## Next Steps - Explore [configuration options](/core/configuration/complete) - Learn about [extensions](/extensions/overview) - Customize the [styling](/styling/themes) --- # Getting Started with Vanilla JavaScript Learn how to use VistaView with vanilla JavaScript Path: /integrations/vanilla VistaView works perfectly with vanilla JavaScript - no framework needed! ## Installation import { Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npm install vistaview ``` ```bash yarn add vistaview ``` ```bash pnpm add vistaview ``` ```bash bun add vistaview ``` ```javascript import { vistaView } from 'vistaview'; import 'vistaview/style.css'; const gallery = vistaView({ elements: '#gallery a', }); ``` ### Using CDN (UMD) For quick prototyping or non-bundler environments: ```html ``` ### Using jsDelivr CDN ```html ``` ## Basic Usage ```html ``` ## With Control Buttons ```html ``` ## Using Data Attributes You can use `data-vistaview-src` to specify high-resolution images: ```html ``` ## With Extensions (ESM) ```html ``` ## With Extensions (UMD) ```html ``` ## Using with Images Array Instead of DOM elements, you can pass an array of image objects: ```javascript vistaView({ elements: [ { src: '/images/photo1.jpg', alt: 'Photo 1' }, { src: '/images/photo2-800.jpg', alt: 'Photo 2', srcSet: '/images/photo2-800.jpg 800w, /images/photo2-1200.jpg 1200w', }, ], }); ``` **Note:** When using an array, thumbnails are not supported. Use DOM elements if you need progressive loading. ## Available Methods ```javascript const gallery = vistaView({ elements: '#gallery a' }); // Open lightbox at specific index (0-based) gallery.open(0); // Close lightbox gallery.close(); // Navigate to next image gallery.next(); // Navigate to previous image gallery.prev(); // Go to specific image gallery.view(2); // Get current image index const currentIndex = gallery.getCurrentIndex(); // Destroy instance and cleanup gallery.destroy(); ``` ## Event Callbacks ```javascript vistaView({ elements: '#gallery a', onOpen: (vistaView) => { console.log('Gallery opened'); }, onClose: (vistaView) => { console.log('Gallery closed'); }, onImageView: (data) => { console.log('Viewing image:', data.index.to); }, }); ``` ## Next Steps - Explore [configuration options](/core/configuration/complete) - Learn about [extensions](/extensions/overview) - Customize the [styling](/styling/themes) --- # Getting Started with Vue Learn how to integrate VistaView with Vue 3 applications Path: /integrations/vue VistaView provides official Vue 3 bindings with both a declarative component and a composable. ## Installation import { Tabs, TabItem } from '@astrojs/starlight/components'; ```bash npm install vistaview ``` ```bash yarn add vistaview ``` ```bash pnpm add vistaview ``` ```bash bun add vistaview ``` ## Component Approach (Recommended) The `VistaView` component provides a declarative way to create image galleries. Any additional HTML attributes (e.g., `class`, `style`, `data-*`, `aria-*`) passed to the component are forwarded to the root `
`. ```vue ``` > **Note:** The `selector` prop defaults to `"> a"`, so you can omit it when your gallery contains direct `` children. ### With Ref for Imperative Control We expose both the imperative API and the root DOM element on the component ref. Use a typed component ref to access `vistaView` (API) and `container` (DOM): ```vue ``` > Note: `compRef.value?.vistaView` gives the API and `compRef.value?.container` gives the root DOM element. ### With Options ```vue ``` ## Composable Approach Use the `useVistaView` composable for more control: ```vue ``` ## With Extensions Extensions can be used with both the component and composable approaches. ### Component with Extensions ```vue ``` ### Composable with Extensions ```vue ``` ## Options API If you prefer the Options API: ```vue ``` ## Next Steps - Explore [configuration options](/core/configuration/complete) - Learn about [extensions](/extensions/overview) - Customize the [styling](/styling/themes) --- ## Extensions --- # Extensions Overview Extend VistaView with powerful extensions Path: /extensions/overview VistaView provides optional extensions for additional functionality. Extensions are available in both ESM and UMD formats and can add UI controls, handle different content types, or modify behavior. ## Extension Types ### UI Extensions Add interactive controls to the lightbox: - **[Download](/extensions/download)** - Download button for saving high-resolution images - **[Image Story](/extensions/image-story)** - Display rich HTML content alongside images ### Video Platform Extensions Embed videos from popular platforms: - **[YouTube](/extensions/youtube-video)** - Embed YouTube videos - **[Vimeo](/extensions/vimeo-video)** - Embed Vimeo videos - **[Dailymotion](/extensions/dailymotion-video)** - Embed Dailymotion videos - **[Wistia](/extensions/wistia-video)** - Embed Wistia videos - **[Vidyard](/extensions/vidyard-video)** - Embed Vidyard videos - **[Streamable](/extensions/streamable-video)** - Embed Streamable videos ### Map Extensions Embed interactive maps: - **[Google Maps](/extensions/google-maps)** - Embed Google Maps (requires API key) - **[Mapbox](/extensions/mapbox)** - Embed Mapbox GL JS maps (requires access token) - **[OpenStreetMap](/extensions/openstreetmap)** - Embed OpenStreetMap with Leaflet.js (free) ### Development Extensions - **[Logger](/extensions/logger)** - Debug extension that logs all lifecycle events ## Using Extensions ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { download } from 'vistaview/extensions/download'; import { youtubeVideo } from 'vistaview/extensions/youtube-video'; vistaView({ elements: '#gallery > a', controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download(), youtubeVideo()], }); ``` ### UMD (CDN) ```html ``` ## Extension Sizes All extensions are optimized for minimal bundle size: | Extension | ESM Size | UMD Size | | ----------------- | ------------------------ | ----------------------- | | logger | 0.60 KB (0.26 KB gzip) | 0.72 KB (0.36 KB gzip) | | download | 1.58 KB (0.78 KB gzip) | 1.50 KB (0.81 KB gzip) | | streamable-video | 2.53 KB (1.13 KB gzip) | 2.22 KB (1.12 KB gzip) | | vimeo-video | 2.44 KB (1.12 KB gzip) | 2.18 KB (1.11 KB gzip) | | vidyard-video | 2.53 KB (1.13 KB gzip) | 2.24 KB (1.11 KB gzip) | | dailymotion-video | 2.63 KB (1.15 KB gzip) | 2.30 KB (1.14 KB gzip) | | wistia-video | 2.73 KB (1.24 KB gzip) | 2.45 KB (1.24 KB gzip) | | youtube-video | 2.89 KB (1.30 KB gzip) | 2.56 KB (1.28 KB gzip) | | google-maps | 3.53 KB (1.54 KB gzip) | 3.07 KB (1.49 KB gzip) | | openstreetmap | 4.75 KB (1.88 KB gzip) | 4.10 KB (1.77 KB gzip) | | mapbox | 4.91 KB (1.90 KB gzip) | 4.32 KB (1.80 KB gzip) | | image-story | 29.56 KB (10.06 KB gzip) | 23.36 KB (9.27 KB gzip) | ## Creating Custom Extensions Want to create your own extension? Check out the [Extensions Authoring Guide](/extensions/authoring). ## Extension Capabilities Extensions can: - **Add UI controls** - Buttons, panels, overlays - **Handle custom content** - Videos, maps, 3D models, etc. - **Modify behavior** - Custom transitions, interactions - **Track events** - Analytics, logging, debugging - **Enhance functionality** - Download, share, annotations ## Next Steps - Browse individual [extension documentation](/extensions/download) - Learn to [create your own extensions](/extensions/authoring) - See the [API Reference](/api-reference/main-function) --- # Streamable Video Extension Embed Streamable videos in the lightbox Path: /extensions/streamable-video The Streamable Video extension allows you to embed Streamable videos in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { streamableVideo } from 'vistaview/extensions/streamable-video'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [streamableVideo()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links pointing to Streamable video URLs: ```html ``` ## Supported URL Formats The extension automatically detects and parses these Streamable URL formats: - `https://streamable.com/VIDEO_ID` - `https://streamable.com/e/VIDEO_ID` ## Features - **Autoplay** - Videos automatically start playing when opened - **Responsive sizing** - Videos maintain 16:9 aspect ratio - **Full controls** - All Streamable player controls available ## Video Size The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Bundle Size - **ESM:** 2.69 KB (1.24 KB gzip) - **UMD:** 13.73 KB (4.19 KB gzip) ## Limitations - **No zoom controls** - Videos cannot be zoomed like images - **Requires internet connection** - Videos stream from Streamable - **Public videos only** - Extension works with publicly accessible videos ## Next Steps - Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # Vidyard Video Extension Embed Vidyard videos in the lightbox Path: /extensions/vidyard-video The Vidyard Video extension allows you to embed Vidyard videos in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { vidyardVideo } from 'vistaview/extensions/vidyard-video'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [vidyardVideo()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links pointing to Vidyard video URLs: ```html ``` ## Supported URL Formats The extension automatically detects and parses Vidyard video URLs containing video IDs. ## Features - **Autoplay** - Videos automatically start playing when opened - **Responsive sizing** - Videos maintain 16:9 aspect ratio - **Full controls** - All Vidyard player controls available - **High quality** - Videos play at the best available quality ## Video Size The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Bundle Size - **ESM:** 2.73 KB (1.24 KB gzip) - **UMD:** 13.75 KB (4.19 KB gzip) ## Limitations - **No zoom controls** - Videos cannot be zoomed like images - **Requires internet connection** - Videos stream from Vidyard - **Vidyard account required** - Videos must be hosted on Vidyard ## Next Steps - Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # Download Extension Add a download button to save images Path: /extensions/download The Download extension adds a button that allows users to download the currently viewed high-resolution image. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { download } from 'vistaview/extensions/download'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download()], }); ``` ### UMD (CDN) ```html ``` ## Features - **Download button** - Adds a download control to the lightbox - **Automatic filename** - Uses the image's alt text as the download filename - **Loading state** - Shows a pulsing animation while downloading - **Cross-origin support** - Handles CORS-protected images via fetch ## Usage The download button appears in the control area you specify. When clicked, it: 1. Fetches the high-resolution image 2. Creates a blob URL 3. Triggers a download with the image's alt text as the filename 4. Cleans up the temporary blob URL ## Customization ### Control Position ```javascript vistaView({ elements: '#gallery > a', controls: { topRight: ['download', 'close'], // Position at top right // Or: topLeft: ['download'], // Position at top left bottomRight: ['download'], // Position at bottom right }, extensions: [download()], }); ``` ### Styling The download button uses the standard VistaView control styling and can be customized with CSS: ```css .vvw-ctrl-download { --vvw-ui-bg-color: rgba(0, 150, 255, 0.3); } .vvw-ctrl-download:hover { --vvw-ui-bg-color: rgba(0, 150, 255, 0.5); } /* Pulsing animation during download */ .vvw-ctrl-download.vvw--pulsing { animation: pulse 1s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } ``` ## Bundle Size - **ESM:** 1.42 KB (0.70 KB gzip) - **UMD:** 1.41 KB (0.79 KB gzip) ## Browser Compatibility Works in all modern browsers that support: - Fetch API - Blob URLs - Download attribute on anchor elements For older browsers, consider using a polyfill or the extension will gracefully fail. ## Example ```javascript import { vistaView } from 'vistaview'; import { download } from 'vistaview/extensions/download'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download()], }); ``` ```html ``` When users click the download button, the image will be saved with the filename based on the alt text (e.g., "Beautiful Sunset.jpg"). ## Next Steps - Explore other [extensions](/extensions/overview) - Learn about [creating custom extensions](/extensions/authoring) - See the [configuration options](/core/configuration/complete) --- # Dailymotion Video Extension Embed Dailymotion videos in the lightbox Path: /extensions/dailymotion-video The Dailymotion Video extension allows you to embed Dailymotion videos in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { dailymotionVideo } from 'vistaview/extensions/dailymotion-video'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [dailymotionVideo()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links pointing to Dailymotion video URLs: ```html ``` ## Automatic Thumbnail Generation The extension provides helper functions to generate Dailymotion thumbnail URLs from video URLs: ```javascript import { getDailymotionThumbnail, parseDailymotionVideoId, } from 'vistaview/extensions/dailymotion-video'; // Generate thumbnail URL from video URL const thumbnailUrl = getDailymotionThumbnail('https://www.dailymotion.com/video/x8abcde'); // Returns: "https://www.dailymotion.com/thumbnail/video/x8abcde" // Or extract just the video ID const videoId = parseDailymotionVideoId('https://dai.ly/x8abcde'); // Returns: "x8abcde" ``` ## Complete Example ```html ``` ## Supported URL Formats The extension automatically detects and parses these Dailymotion URL formats: - `https://www.dailymotion.com/video/VIDEO_ID` - `https://dailymotion.com/video/VIDEO_ID` - `https://dai.ly/VIDEO_ID` ## Features - **Autoplay** - Videos automatically start playing when opened - **Responsive sizing** - Videos maintain 16:9 aspect ratio - **Full controls** - All Dailymotion player controls available - **High quality** - Videos play at the best available quality ## Mixing Images and Videos You can mix images and Dailymotion videos in the same gallery: ```html ``` ## Video Size The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Bundle Size - **ESM:** 2.80 KB (1.26 KB gzip) - **UMD:** 13.82 KB (4.21 KB gzip) ## Limitations - **No zoom controls** - Videos cannot be zoomed like images - **Requires internet connection** - Videos stream from Dailymotion - **Dailymotion Terms of Service** - Ensure compliance with Dailymotion's ToS - **Regional restrictions** - Some videos may be region-restricted ## Example with Multiple Video Platforms ```javascript import { vistaView } from 'vistaview'; import { youtubeVideo } from 'vistaview/extensions/youtube-video'; import { vimeoVideo } from 'vistaview/extensions/vimeo-video'; import { dailymotionVideo } from 'vistaview/extensions/dailymotion-video'; vistaView({ elements: '#gallery > a', extensions: [youtubeVideo(), vimeoVideo(), dailymotionVideo()], }); ``` ## Next Steps - Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # Mapbox Extension Embed Mapbox GL JS maps in the lightbox Path: /extensions/mapbox The Mapbox extension allows you to embed interactive Mapbox GL JS maps in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { mapbox } from 'vistaview/extensions/mapbox'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [mapbox({ accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN' })], }); ``` ### UMD (CDN) ```html ``` ## Requirements You need a Mapbox access token to use this extension. Get one from [Mapbox](https://account.mapbox.com/). ## Configuration ### accessToken (required) Your Mapbox access token: ```javascript mapbox({ accessToken: 'pk.your_mapbox_token_here', }); ``` ## Usage Create links with Mapbox-compatible coordinate URLs: ```html ``` ## URL Format Use this format in your `href` attribute: ``` mapbox://LATITUDE,LONGITUDE,ZOOM ``` Example: ``` mapbox://40.7580,-73.9855,15 ``` Parameters: - **LATITUDE**: Latitude coordinate (e.g., 40.7580) - **LONGITUDE**: Longitude coordinate (e.g., -73.9855) - **ZOOM**: Zoom level (1-22, where 1 is world view and 22 is street level) ## Features - **Interactive maps** - Full Mapbox GL JS functionality - **Responsive sizing** - Maps adapt to lightbox size - **Multiple styles** - Streets, satellite, outdoors, etc. - **Smooth animations** - Hardware-accelerated rendering - **Vector tiles** - Sharp rendering at any zoom level ## Map Size The extension creates maps with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Map Styles By default, the extension uses Mapbox's standard style. You can customize this by modifying the extension code or creating a custom version. ## Mixing Images and Maps You can mix images and Mapbox maps in the same gallery: ```html ``` ## Bundle Size - **ESM:** 4.99 KB (1.93 KB gzip) - **UMD:** 15.63 KB (4.81 KB gzip) Note: Mapbox GL JS library (~500KB) is loaded from CDN when a map is displayed. ## Free Tier Mapbox offers a generous free tier: - 50,000 map loads per month - No credit card required to start Check [Mapbox pricing](https://www.mapbox.com/pricing) for current limits. ## Limitations - **Requires access token** - Must have valid Mapbox token - **Usage limits** - Subject to Mapbox API quotas - **Internet connection required** - Maps load from Mapbox servers - **Large library** - Mapbox GL JS is loaded from CDN (~500KB) ## Security **Best practices:** 1. Use public tokens (start with `pk.`) for client-side use 2. Restrict tokens to specific URLs in production 3. Monitor usage in Mapbox dashboard 4. Rotate tokens periodically ## Next Steps - Try other map extensions: [Google Maps](/extensions/google-maps), [OpenStreetMap](/extensions/openstreetmap) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # OpenStreetMap Extension Embed OpenStreetMap with Leaflet.js in the lightbox (Free) Path: /extensions/openstreetmap The OpenStreetMap extension allows you to embed interactive OpenStreetMap maps using Leaflet.js in the VistaView lightbox. **No API key required** - completely free! ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { openStreetMap } from 'vistaview/extensions/openstreetmap'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [openStreetMap()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links with OpenStreetMap-compatible coordinate URLs: ```html ``` ## URL Format Use this format in your `href` attribute: ``` osm://LATITUDE,LONGITUDE,ZOOM ``` Example: ``` osm://40.7580,-73.9855,15 ``` Parameters: - **LATITUDE**: Latitude coordinate (e.g., 40.7580) - **LONGITUDE**: Longitude coordinate (e.g., -73.9855) - **ZOOM**: Zoom level (1-19, where 1 is world view and 19 is street level) ## Features - **100% Free** - No API keys, no billing, no usage limits - **Interactive maps** - Full Leaflet.js functionality - **Responsive sizing** - Maps adapt to lightbox size - **Zoom controls** - Standard map controls - **Attribution** - Properly credits OpenStreetMap contributors ## Map Size The extension creates maps with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Mixing Images and Maps You can mix images and OpenStreetMap maps in the same gallery: ```html ``` ## Bundle Size - **ESM:** 4.79 KB (1.90 KB gzip) - **UMD:** 15.43 KB (4.79 KB gzip) Note: Leaflet.js library (~150KB) is loaded from CDN when a map is displayed. ## Why Choose OpenStreetMap? ### Advantages - ✅ **Completely free** - No API keys or billing - ✅ **No usage limits** - Unlimited map loads - ✅ **Open source** - Community-driven project - ✅ **Privacy-friendly** - No tracking by default - ✅ **Lightweight** - Smaller than commercial alternatives ### Considerations - Map styles are more basic than commercial providers - Fewer built-in features compared to Google Maps/Mapbox - Relies on community tile servers ## Tile Servers By default, the extension uses OpenStreetMap's tile servers. Please be respectful: - Don't make excessive requests - Cache tiles when possible - Consider using your own tile server for high-traffic sites For production sites with high traffic, consider: - [Mapbox](https://www.mapbox.com/) (has free tier) - Self-hosted tile server - Commercial OpenStreetMap providers ## Customization The extension uses standard OpenStreetMap tiles. To use custom tile servers or styles, you'll need to create a custom version based on the extension source code. ## Attribution The extension automatically includes proper attribution to OpenStreetMap contributors as required by the OpenStreetMap license. ## Limitations - **Internet connection required** - Maps load from tile servers - **Basic styling** - Standard OpenStreetMap appearance only - **Tile server load** - Respect the free tile server's resources ## Example with Multiple Maps ```html ``` ## Next Steps - Try other map extensions: [Google Maps](/extensions/google-maps), [Mapbox](/extensions/mapbox) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # Image Story Extension Display rich HTML content alongside images Path: /extensions/image-story The Image Story extension allows you to display rich HTML content (stories, descriptions, captions) below images in the lightbox. Content is loaded on-demand and cached for performance. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { imageStory } from 'vistaview/extensions/image-story'; import 'vistaview/style.css'; import 'vistaview/styles/extensions/image-story.css'; vistaView({ elements: '#gallery > a', extensions: [ imageStory({ getStory: async (index) => { const response = await fetch(`/api/stories/${index}`); const data = await response.json(); return { content: data.html }; }, }), ], }); ``` ### UMD (CDN) ```html ``` ## Configuration ### getStory (required) A function that returns a promise resolving to a story object: ```typescript getStory: (imageIndex: number) => Promise; ``` **StoryResult interface:** ```typescript interface StoryResult { content: string; // HTML content (will be sanitized) onLoad?: () => void; // Called when story is displayed onUnload?: () => void; // Called when navigating away } ``` ### maxStoryCache (optional) Maximum number of stories to keep in memory. Default: `5` ```javascript imageStory({ getStory: async (index) => { /* ... */ }, maxStoryCache: 10, // Keep 10 stories cached }); ``` ## Features - **Rich HTML content** - Display formatted text, images, links, etc. - **On-demand loading** - Stories are fetched only when needed - **Smart caching** - Recently viewed stories are cached - **Auto-sanitization** - HTML is automatically sanitized using DOMPurify - **Expandable panel** - Users can expand/collapse the story - **Lifecycle hooks** - onLoad/onUnload for custom behavior ## Usage Examples ### Basic Usage ```javascript import { imageStory } from 'vistaview/extensions/image-story'; vistaView({ elements: '#gallery > a', extensions: [ imageStory({ getStory: async (index) => ({ content: `

Image ${index + 1}

This is the story for image ${index + 1}.

`, }), }), ], }); ``` ### Fetching from API ```javascript imageStory({ getStory: async (index) => { try { const response = await fetch(`/api/stories/${index}`); const data = await response.json(); return { content: `

${data.title}

${data.description}

By ${data.author} on ${data.date}

`, }; } catch (error) { return { content: '

Story could not be loaded.

', }; } }, }); ``` ### With Lifecycle Hooks ```javascript imageStory({ getStory: async (index) => { const response = await fetch(`/api/stories/${index}`); const data = await response.json(); return { content: data.html, onLoad: () => { console.log(`Story ${index} loaded`); // Track analytics gtag('event', 'story_view', { story_id: index }); }, onUnload: () => { console.log(`Story ${index} unloaded`); // Cleanup any event listeners }, }; }, }); ``` ### With Static Stories ```javascript const stories = [ { title: 'Sunset at the Beach', content: 'A beautiful evening captured at the coast...', }, { title: 'Mountain Peak', content: 'Hiking adventure to the summit...', }, ]; imageStory({ getStory: async (index) => ({ content: `

${stories[index].title}

${stories[index].content}

`, }), }); ``` ## Styling The extension includes default styles, but you can customize: ```css /* Story container */ .vvw-story { /* Positioned at bottom of lightbox */ } /* Story text area */ .vvw-story-text { background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(10px); color: white; padding: 16px; border-radius: 8px; } /* Expanded state */ .vvw-story-text.expanded { max-height: 400px; overflow-y: auto; } /* Expand/collapse button */ .vvw-story-button { background: rgba(255, 255, 255, 0.1); border: none; color: white; cursor: pointer; } ``` ## Security The extension automatically sanitizes HTML content using DOMPurify to prevent XSS attacks. However, you should still: 1. **Validate input** on your server 2. **Use Content Security Policy** (CSP) headers 3. **Sanitize user-generated content** before storing ## Performance ### Caching Stories are cached in memory to avoid redundant API calls: ```javascript imageStory({ getStory: async (index) => { // This is only called once per image (until cache eviction) return await fetchStory(index); }, maxStoryCache: 10, // Adjust based on memory constraints }); ``` ### Lazy Loading Stories are only fetched when the user navigates to an image, not during initialization. ### Cache Eviction When the cache exceeds `maxStoryCache`, the oldest entries are evicted (FIFO). ## Bundle Size - **ESM:** 33.60 KB (10.84 KB gzip) - **UMD:** 25.28 KB (9.81 KB gzip) - **CSS:** 2.52 KB (0.72 KB gzip) Note: Includes DOMPurify for HTML sanitization. ## Next Steps - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) - See [configuration options](/core/configuration/complete) --- # Google Maps Extension Embed interactive Google Maps in the lightbox Path: /extensions/google-maps The Google Maps extension allows you to embed interactive Google Maps in the VistaView lightbox. It displays a static image initially, then loads an interactive iframe embed when opened. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { googleMaps } from 'vistaview/extensions/google-maps'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [googleMaps()], }); ``` ### UMD (CDN) ```html ``` ## Requirements **No API key required** for basic functionality. The extension uses Google Maps' free iframe embed for the interactive map. An API key is **only needed** if you want to auto-generate static map thumbnails when no `` tag is provided (using Google Maps Static API). ## Configuration All configuration options are optional: ### apiKey Your Google Maps API key. **Required to use the Google Maps Static API for generating static map images.** The `getGoogleMapsStaticImage` function uses this to create Static API URLs. The extension will also use this to generate an image if the origin thumbnail image is not available. ```javascript googleMaps({ apiKey: 'YOUR_GOOGLE_MAPS_API_KEY', }); ``` ### zoom Default zoom level for auto-generated thumbnails (1-20). Default: `15`. ### width Width for auto-generated thumbnails in pixels. Default: `800`. ### height Height for auto-generated thumbnails in pixels. Default: `600`. ### mapType Map type for auto-generated thumbnails: `'roadmap'`, `'satellite'`, `'hybrid'`, or `'terrain'`. Default: `'roadmap'`. ## Usage ### Basic Usage (Recommended) Provide your own thumbnail images - no API key needed: ```html ``` ### Generate Static Map Thumbnails Use `getGoogleMapsStaticImage` to create Google Maps Static API thumbnail URLs: ```javascript import { getGoogleMapsStaticImage, parseGoogleMapsLocation, } from 'vistaview/extensions/google-maps'; // Parse the Google Maps URL const url = 'https://www.google.com/maps/@40.7580,-73.9855,15z'; const location = parseGoogleMapsLocation(url); // Generate static map image URL const staticImageUrl = getGoogleMapsStaticImage(location, { apiKey: 'YOUR_API_KEY', zoom: 15, width: 800, height: 600, mapType: 'roadmap', }); console.log(staticImageUrl); // https://maps.googleapis.com/maps/api/staticmap?center=40.7580,-73.9855&zoom=15&size=800x600&maptype=roadmap&markers=color:red|40.7580,-73.9855&key=YOUR_API_KEY ``` Then use the generated URL in your HTML: ```html ``` ## Supported URL Formats The extension automatically parses various Google Maps URL formats: ### Coordinate Format (@lat,lng,zoom) ``` https://www.google.com/maps/@40.7580,-73.9855,15z ``` ### Query Parameter (q=lat,lng or q=place) ``` https://www.google.com/maps?q=40.7580,-73.9855 https://www.google.com/maps?q=Empire+State+Building ``` ### LL Parameter (ll=lat,lng) ``` https://maps.google.com?ll=40.7580,-73.9855 ``` ### Short URLs ``` https://goo.gl/maps/example ``` ## Features - **Free interactive maps** - Uses Google Maps iframe embed (no API key needed) - **Static previews** - Shows thumbnail image before loading interactive map - **Smooth transitions** - Fades from static to interactive (1s ease) - **Pulsing animation** - Loading indicator while iframe loads - **Responsive sizing** - Maps adapt to lightbox size (16:9 aspect ratio, max 800px width) - **Full map features** - All Google Maps functionality (zoom, pan, street view, etc.) - **UI integration** - Automatically disables download and zoom buttons ## How It Works 1. **Initial display**: Shows thumbnail image (from `` tag or auto-generated with API key) 2. **On open**: Loads Google Maps iframe embed in background 3. **Transition**: Fades from static image to interactive map when loaded 4. **Interaction**: Full Google Maps functionality available ## Mixing Content Types You can mix images and Google Maps in the same gallery: ```html ``` ## Bundle Size - **ESM:** ~3.5 KB (minified) - **UMD:** ~12 KB (minified) No external dependencies - the extension uses native iframe embeds. ## API Key Setup (Optional) **Only needed if you want auto-generated thumbnails.** 1. Go to [Google Cloud Console](https://console.cloud.google.com/) 2. Create or select a project 3. Enable **Maps Static API** 4. Create an API key 5. Restrict the key: - **Application restrictions**: HTTP referrers (your domain) - **API restrictions**: Maps Static API only ## Pricing - **Interactive maps (iframe)**: **FREE** - unlimited usage - **Static thumbnails (when auto-generated)**: Subject to [Google Maps Static API pricing](https://mapsplatform.google.com/pricing/) - Free tier: 28,000 static map loads/month - After free tier: $2.00 per 1,000 loads 💡 **Tip**: Use your own thumbnail images to avoid Static API costs entirely. ## Example: Travel Photo Gallery ```html ``` ## Troubleshooting ### Map not opening - Verify the URL is a valid Google Maps URL - Check browser console for errors ### Static thumbnail not showing (with API key) - Ensure Maps Static API is enabled in Google Cloud Console - Verify API key is correct - Check API key restrictions aren't blocking requests - Check browser console for error messages ### No thumbnail showing (without API key, without ``) This is expected behavior. Either: - Add `` tags with your own thumbnails (recommended) - Provide an API key to auto-generate thumbnails ## Related Extensions - [Mapbox](/extensions/mapbox) - Mapbox GL JS maps - [OpenStreetMap](/extensions/openstreetmap) - OpenStreetMap embeds - [YouTube Video](/extensions/youtube-video) - Embed YouTube videos --- # Logger Extension Debug extension that logs all lifecycle events Path: /extensions/logger The Logger extension is a development tool that logs all lifecycle events to the browser console. It's useful for debugging and understanding the extension system. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { logger } from 'vistaview/extensions/logger'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [logger()], }); ``` ### UMD (CDN) ```html ``` ## Features - **Lifecycle logging** - Logs all extension lifecycle events - **Image initialization** - Logs when images are initialized - **Navigation tracking** - Logs image view events - **Open/close tracking** - Logs lightbox open and close events - **Console output** - All logs use `console.debug()` for easy filtering ## What Gets Logged The logger uses `console.debug()` for all output. Each hook logs a label string followed by the raw data object on a second line. ### onInitializeImage Logged once per image during setup: ``` Logger: VistaView initialized with params: VistaImageParams { elm: {...}, pos: 0, index: 0, ... } ``` ### onOpen Logged when the lightbox opens: ``` Logger: VistaView opened VistaView { state: {...}, options: {...}, ... } ``` ### onImageView Logged when navigating to an image: ``` Logger: Image viewed VistaData { index: { from: 0, to: 1 }, via: { next: true, prev: false }, ... } ``` ### onContentChange Logged when image content changes (pan, zoom, etc.): ``` Logger: Content changed VistaImageClone { config: {...}, state: { transform: {...} }, ... } ``` ### onClose Logged when the lightbox closes: ``` Logger: VistaView closed VistaView { state: {...}, options: {...}, ... } ``` ## Usage Example ```javascript import { vistaView } from 'vistaview'; import { logger } from 'vistaview/extensions/logger'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [logger()], onOpen: () => { console.log('App: Gallery opened'); }, }); ``` Open your browser's developer console and interact with the lightbox to see the logs. ## Filtering Logs The logger uses `console.debug()`, so you can filter logs in your browser's developer console: ### Chrome/Edge 1. Open DevTools (F12) 2. Go to Console tab 3. Select log levels and choose "Verbose" or "Debug" ### Firefox 1. Open Developer Tools (F12) 2. Go to Console tab 3. Click the filter icon and enable "Debug" ### Safari 1. Open Web Inspector (Cmd+Option+I) 2. Go to Console tab 3. Click the filter icon and enable "Debug" ## Bundle Size - **ESM:** 0.61 KB (0.23 KB gzip) - **UMD:** 0.76 KB (0.37 KB gzip) ## Use Cases ### Debugging Custom Extensions ```javascript import { logger } from 'vistaview/extensions/logger'; import { myCustomExtension } from './my-extension'; vistaView({ elements: '#gallery > a', extensions: [ logger(), // Log all events myCustomExtension(), // Your extension ], }); ``` ### Understanding Event Order Use the logger to understand the order of lifecycle events: ```javascript vistaView({ elements: '#gallery > a', extensions: [logger()], }); ``` Then interact with the lightbox and observe the console: ``` Logger: VistaView opened Logger: VistaView initialized with params: Logger: Image viewed Logger: Image viewed Logger: VistaView closed ``` ### Development vs Production Only include the logger in development: ```javascript const extensions = []; if (process.env.NODE_ENV === 'development') { const { logger } = await import('vistaview/extensions/logger'); extensions.push(logger()); } vistaView({ elements: '#gallery > a', extensions, }); ``` ## Next Steps - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) - See [events and lifecycle](/core/configuration/events) --- # Vimeo Video Extension Embed Vimeo videos in the lightbox Path: /extensions/vimeo-video The Vimeo Video extension allows you to embed Vimeo videos in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { vimeoVideo } from 'vistaview/extensions/vimeo-video'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [vimeoVideo()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links pointing to Vimeo video URLs: ```html ``` ## Automatic Thumbnail Generation The extension provides helper functions to generate Vimeo thumbnail URLs from video URLs: ```javascript import { getVimeoThumbnail, parseVimeoVideoId } from 'vistaview/extensions/vimeo-video'; // Generate thumbnail URL from video URL const thumbnailUrl = getVimeoThumbnail('https://vimeo.com/123456789'); // Returns: "https://vumbnail.com/123456789.jpg" // Or extract just the video ID const videoId = parseVimeoVideoId('https://vimeo.com/123456789'); // Returns: "123456789" ``` :::tip[Vimeo Thumbnail Note] Vimeo doesn't provide direct thumbnail URLs without API authentication. The `getVimeoThumbnail()` function uses vumbnail.com as a workaround. For production use, consider using [Vimeo's oEmbed API](https://developer.vimeo.com/api/oembed) for more reliable thumbnails. ::: ## Complete Example ```html ``` ## Supported URL Formats The extension automatically detects and parses these Vimeo URL formats: - `https://vimeo.com/VIDEO_ID` - `https://player.vimeo.com/video/VIDEO_ID` - `https://www.vimeo.com/VIDEO_ID` ## Features - **Autoplay** - Videos automatically start playing when opened - **Responsive sizing** - Videos maintain 16:9 aspect ratio - **Full controls** - All Vimeo player controls available - **High quality** - Videos play at the best available quality ## Mixing Images and Videos You can mix images and Vimeo videos in the same gallery: ```html ``` ## Video Size The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Bundle Size - **ESM:** 2.65 KB (1.24 KB gzip) - **UMD:** 13.69 KB (4.19 KB gzip) ## Privacy Considerations This extension embeds Vimeo videos using the standard Vimeo player. The player may use cookies and track user interactions according to Vimeo's privacy policy. ## Limitations - **No zoom controls** - Videos cannot be zoomed like images - **Requires internet connection** - Videos stream from Vimeo - **Vimeo Terms of Service** - Ensure compliance with Vimeo's ToS - **Private videos** - Requires proper authentication/permissions ## Example with Multiple Extensions ```javascript import { vistaView } from 'vistaview'; import { youtubeVideo } from 'vistaview/extensions/youtube-video'; import { vimeoVideo } from 'vistaview/extensions/vimeo-video'; vistaView({ elements: '#gallery > a', extensions: [youtubeVideo(), vimeoVideo()], }); ``` ## Next Steps - Try other video extensions: [YouTube](/extensions/youtube-video), [Dailymotion](/extensions/dailymotion-video) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # YouTube Video Extension Embed YouTube videos in the lightbox Path: /extensions/youtube-video The YouTube Video extension allows you to embed YouTube videos in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { youtubeVideo } from 'vistaview/extensions/youtube-video'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [youtubeVideo()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links pointing to YouTube video URLs: ```html ``` ## Automatic Thumbnail Generation The extension provides a helper function to generate YouTube thumbnail URLs from video URLs: ```javascript import { getYouTubeThumbnail } from 'vistaview/extensions/youtube-video'; // Generate thumbnail URL from video URL const thumbnailUrl = getYouTubeThumbnail('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); // Returns: "https://img.youtube.com/vi/dQw4w9WgXcQ/hqdefault.jpg" // Use in your gallery dynamically const videoUrl = 'https://youtu.be/dQw4w9WgXcQ'; const link = document.createElement('a'); link.href = videoUrl; const img = document.createElement('img'); img.src = getYouTubeThumbnail(videoUrl); img.alt = 'Video thumbnail'; link.appendChild(img); document.getElementById('gallery').appendChild(link); ``` You can also extract just the video ID: ```javascript import { parseYouTubeVideoId } from 'vistaview/extensions/youtube-video'; const videoId = parseYouTubeVideoId('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); // Returns: "dQw4w9WgXcQ" ``` ## Complete Example ```html ``` ## Supported URL Formats The extension automatically detects and parses these YouTube URL formats: - `https://www.youtube.com/watch?v=VIDEO_ID` - `https://youtu.be/VIDEO_ID` - `https://www.youtube.com/embed/VIDEO_ID` - `https://m.youtube.com/watch?v=VIDEO_ID` ## Features - **Autoplay** - Videos automatically start playing when opened - **Responsive sizing** - Videos maintain 16:9 aspect ratio - **Full controls** - All YouTube player controls available - **No related videos from other channels** - `rel=0` parameter set by default ## Mixing Images and Videos You can mix images and YouTube videos in the same gallery: ```html ``` ## Video Size The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Customization ### Custom Video Size Extend the extension to customize video dimensions: ```javascript import { youtubeVideo } from 'vistaview/extensions/youtube-video'; // The extension uses fixed sizing, but you can create a custom version // See the Extensions Authoring Guide for details ``` ### Styling The video iframe uses the class `vvw-img-hi` and can be styled: ```css .vvw-img-hi { border-radius: 8px; box-shadow: 0 0 40px rgba(0, 0, 0, 0.5); } ``` ## Bundle Size - **ESM:** 3.10 KB (1.42 KB gzip) - **UMD:** 14.07 KB (4.36 KB gzip) ## Privacy Considerations This extension embeds YouTube videos using the standard `youtube.com` domain. For enhanced privacy, you may want to create a custom extension using `youtube-nocookie.com` domain. ## Limitations - **No zoom controls** - Videos cannot be zoomed like images - **Requires internet connection** - Videos stream from YouTube - **YouTube Terms of Service** - Ensure compliance with YouTube's ToS ## Example with Multiple Extensions ```javascript import { vistaView } from 'vistaview'; import { youtubeVideo } from 'vistaview/extensions/youtube-video'; import { vimeoVideo } from 'vistaview/extensions/vimeo-video'; import { download } from 'vistaview/extensions/download'; vistaView({ elements: '#gallery > a', extensions: [ youtubeVideo(), vimeoVideo(), download(), // Works for images, not videos ], }); ``` ## Next Steps - Try other video extensions: [Vimeo](/extensions/vimeo-video), [Dailymotion](/extensions/dailymotion-video) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # Wistia Video Extension Embed Wistia videos in the lightbox Path: /extensions/wistia-video The Wistia Video extension allows you to embed Wistia videos in the VistaView lightbox instead of images. ## Installation ### ESM (Module Bundlers) ```javascript import { vistaView } from 'vistaview'; import { wistiaVideo } from 'vistaview/extensions/wistia-video'; import 'vistaview/style.css'; vistaView({ elements: '#gallery > a', extensions: [wistiaVideo()], }); ``` ### UMD (CDN) ```html ``` ## Usage Create links pointing to Wistia video URLs: ```html ``` ## Automatic Thumbnail Generation The extension provides helper functions to work with Wistia video URLs: ```javascript import { getWistiaThumbnail, parseWistiaVideoId } from 'vistaview/extensions/wistia-video'; // Extract video ID const videoId = parseWistiaVideoId('https://fast.wistia.net/embed/iframe/abc123def'); // Returns: "abc123def" // Get thumbnail URL (async - fetches from Wistia's oEmbed API) const thumbnailUrl = await getWistiaThumbnail('https://fast.wistia.net/embed/iframe/abc123def'); // Returns: URL to the video thumbnail ``` :::tip[Wistia Thumbnail Note] The `getWistiaThumbnail()` function is **async** because it fetches thumbnail information from Wistia's oEmbed API. Make sure to use `await` or handle the Promise appropriately. ::: ## Complete Example ```html ``` ## Supported URL Formats The extension automatically detects and parses Wistia video URLs containing video IDs. ## Features - **Autoplay** - Videos automatically start playing when opened - **Responsive sizing** - Videos maintain 16:9 aspect ratio - **Full controls** - All Wistia player controls available - **High quality** - Videos play at the best available quality ## Video Size The extension creates videos with a maximum width of 800px (or window width, whichever is smaller) while maintaining a 16:9 aspect ratio. ## Bundle Size - **ESM:** 2.93 KB (1.35 KB gzip) - **UMD:** 13.92 KB (4.28 KB gzip) ## Limitations - **No zoom controls** - Videos cannot be zoomed like images - **Requires internet connection** - Videos stream from Wistia - **Wistia account required** - Videos must be hosted on Wistia ## Next Steps - Try other video extensions: [YouTube](/extensions/youtube-video), [Vimeo](/extensions/vimeo-video) - Learn about [creating custom extensions](/extensions/authoring) - Explore other [extensions](/extensions/overview) --- # Behavior Extensions Create extensions that add functionality without visible UI Path: /extensions/authoring/behavior-extensions Behavior extensions add functionality through lifecycle hooks without adding visible controls. They're perfect for logging, analytics, keyboard shortcuts, and other non-visual features. ## Basic Behavior Extension ```typescript import type { VistaExtension } from 'vistaview'; export function simpleLogger(): VistaExtension { return { name: 'simpleLogger', onOpen: () => console.log('Opened'), onClose: () => console.log('Closed'), }; } ``` ## Complete Example: Logger A comprehensive logging extension: ```typescript import type { VistaData, VistaExtension, VistaImageClone, VistaImageParams } from 'vistaview'; import type { VistaView } from 'vistaview'; export function logger(): VistaExtension { return { name: 'logger', onInitializeImage: (params: VistaImageParams) => { console.debug('Logger: VistaView initialized with params:'); console.debug(params); }, onContentChange: (_content: VistaImageClone, _v: VistaView) => { console.debug('Logger: Content changed'); console.debug(_content); }, onImageView: async (vistaData: VistaData, _v: VistaView) => { console.debug('Logger: Image viewed'); console.debug(vistaData); }, onOpen: async (_vistaView: VistaView) => { console.debug('Logger: VistaView opened'); console.debug(_vistaView); }, onClose: (_vistaView: VistaView) => { console.debug('Logger: VistaView closed'); console.debug(_vistaView); }, }; } ``` ## Analytics Extension Track user interactions: ```typescript import type { VistaData, VistaExtension, VistaView } from 'vistaview'; export function analytics({ trackEvent, }: { trackEvent: (event: string, data: any) => void; }): VistaExtension { let openTime: number; let viewCount = 0; return { name: 'analytics', onOpen: (vistaView: VistaView) => { openTime = Date.now(); viewCount = 0; trackEvent('lightbox_open', { totalImages: vistaView.state.elmLength, }); }, onImageView: (vistaData: VistaData, _v: VistaView) => { viewCount++; trackEvent('image_view', { index: vistaData.index.to, viewNumber: viewCount, }); }, onClose: (_v: VistaView) => { const duration = Date.now() - openTime; trackEvent('lightbox_close', { duration, imagesViewed: viewCount, averageTimePerImage: duration / viewCount, }); }, }; } ``` Usage: ```typescript vistaView({ elements: '#gallery > a', extensions: [ analytics({ trackEvent: (event, data) => { // Send to your analytics service gtag('event', event, data); }, }), ], }); ``` ## Keyboard Shortcuts Extension Add custom keyboard shortcuts: ```typescript import type { VistaExtension, VistaView } from 'vistaview'; export function keyboardShortcuts(): VistaExtension { let vistaView: VistaView | null = null; const handleKeyDown = (e: KeyboardEvent) => { if (!vistaView) return; switch (e.key) { case 'f': // Toggle fullscreen if (document.fullscreenElement) { document.exitFullscreen(); } else { document.documentElement.requestFullscreen(); } break; case 'd': // Download current image // Trigger download logic break; case 'i': // Show image info console.log(vistaView.state); break; } }; return { name: 'keyboardShortcuts', onOpen: (view: VistaView) => { vistaView = view; document.addEventListener('keydown', handleKeyDown); }, onClose: () => { document.removeEventListener('keydown', handleKeyDown); vistaView = null; }, }; } ``` ## Preload Adjacent Images **Note:** VistaView already handles image preloading internally. This example is provided for educational purposes to demonstrate behavior extension patterns. ```typescript import type { VistaData, VistaExtension } from 'vistaview'; export function preloadAdjacent(): VistaExtension { const preloadCache = new Map(); const preload = (src: string) => { if (preloadCache.has(src)) return; const img = new Image(); img.src = src; preloadCache.set(src, img); }; return { name: 'preloadAdjacent', onImageView: (vistaData: VistaData, vistaView: VistaView) => { const currentIndex = vistaData.index.to ?? 0; const total = vistaView.state.elmLength; // Preload next image const nextIndex = (currentIndex + 1) % total; const nextImage = vistaView.state.children.images[nextIndex]; if (nextImage?.config.src) { preload(nextImage.config.src); } // Preload previous image const prevIndex = (currentIndex - 1 + total) % total; const prevImage = vistaView.state.children.images[prevIndex]; if (prevImage?.config.src) { preload(prevImage.config.src); } }, onClose: () => { preloadCache.clear(); }, }; } ``` ## Auto-Play Slideshow Automatic image rotation: ```typescript import type { VistaExtension, VistaView } from 'vistaview'; export function autoPlay({ interval = 3000, }: { interval?: number; } = {}): VistaExtension { let intervalId: number | null = null; let vistaView: VistaView | null = null; const startAutoPlay = () => { if (intervalId) return; intervalId = window.setInterval(() => { if (!vistaView) return; const currentIndex = vistaView.state.currentIndex; const total = vistaView.state.elmLength; const nextIndex = (currentIndex + 1) % total; vistaView.view(nextIndex); }, interval); }; const stopAutoPlay = () => { if (intervalId !== null) { clearInterval(intervalId); intervalId = null; } }; return { name: 'autoPlay', onOpen: (view: VistaView) => { vistaView = view; startAutoPlay(); }, onImageView: () => { // Reset timer on manual navigation stopAutoPlay(); startAutoPlay(); }, onClose: () => { stopAutoPlay(); vistaView = null; }, }; } ``` ## Image Counter Display Show current position without adding a control: ```typescript import type { VistaData, VistaExtension, VistaView } from 'vistaview'; export function imageCounter(): VistaExtension { let counterElement: HTMLDivElement | null = null; return { name: 'imageCounter', onOpen: (vistaView: VistaView) => { counterElement = document.createElement('div'); counterElement.className = 'vvw-counter'; counterElement.style.cssText = ` position: absolute; top: 20px; left: 50%; transform: translateX(-50%); background: var(--vvw-ui-bg-color); color: var(--vvw-ui-text-color); padding: 8px 16px; border-radius: var(--vvw-ui-border-radius); font-size: 14px; `; vistaView.qs('.vvw-container')?.appendChild(counterElement); }, onImageView: (vistaData: VistaData, vistaView: VistaView) => { const current = (vistaData.index.to ?? 0) + 1; const total = vistaView.state.elmLength; if (counterElement) { counterElement.textContent = `${current} / ${total}`; } }, onClose: () => { counterElement?.remove(); counterElement = null; }, }; } ``` ## Key Concepts ### Lifecycle Hooks Behavior extensions use lifecycle hooks to react to events: - `onOpen` - Lightbox opened, set up state - `onImageView` - Image changed, update based on new image - `onClose` - Lightbox closed, clean up resources ### State Persistence Use closure variables to maintain state: ```typescript export function statefulExtension(): VistaExtension { let count = 0; let cache = new Map(); return { name: 'statefulExtension', onImageView: () => { count++; // Persists between calls }, }; } ``` ### Cleanup Always clean up resources: ```typescript onClose: () => { clearInterval(intervalId); document.removeEventListener('keydown', handler); cache.clear(); vistaView = null; }; ``` ## Next Steps - [Content Extensions](/extensions/authoring/content-extensions) - [Built-in Extensions](/extensions/overview) --- # UI Extensions Create extensions that add visible controls to the lightbox Path: /extensions/authoring/ui-extensions UI extensions add visible controls to the lightbox interface. They provide the `control` method that returns an HTML element to be added to the UI. ## Basic UI Extension ```typescript import type { VistaExtension } from 'vistaview'; export function myButton(): VistaExtension { return { name: 'myButton', control: () => { const button = document.createElement('button'); button.setAttribute('aria-label', 'My Button'); button.textContent = '✨'; button.addEventListener('click', () => { console.log('Button clicked!'); }); return button; }, }; } ``` ## Complete Example: Download Button A fully-featured download button with state management: ```typescript import type { VistaData, VistaExtension, VistaView } from 'vistaview'; const downloadIcon = ``; export function download(): VistaExtension { let currentImage: string | null = null; let currentAlt: string | null = null; let button: HTMLButtonElement | null = null; return { name: 'download', control: () => { button = document.createElement('button'); button.setAttribute('aria-label', 'Download'); button.innerHTML = downloadIcon; button.addEventListener('click', async () => { if (!currentImage) return; if (button?.classList.contains('vvw--pulsing')) return; // prevent multiple clicks button?.classList.add('vvw--pulsing'); let response: Response | null = await fetch(currentImage); let blob: Blob | null = await response.blob(); const finalUrl = response.url; // This is the redirected URL const alt = currentAlt; const extension = finalUrl.split('?')[0].split('#')[0].split('.').pop(); const fileName = alt ? `${alt}.${extension}` : finalUrl.split('?')[0].split('#')[0].split('/').pop() || 'download.' + extension; const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = fileName; document.body.appendChild(link); link.click(); document.body.removeChild(link); blob = null; response = null; button?.classList.remove('vvw--pulsing'); }); return button; }, onImageView: (vistaData: VistaData, _v: VistaView) => { const centerImage = vistaData.images.to ? vistaData.images.to[Math.floor(vistaData.images.to.length / 2)] : null; if (!centerImage) { currentImage = null; currentAlt = null; return; } const { parsedSrcSet, config } = centerImage; // get the biggest image || the current image currentImage = parsedSrcSet && parsedSrcSet.length > 0 ? parsedSrcSet[parsedSrcSet.length - 1].src : config.src || null; currentAlt = config.alt || null; }, onDeactivateUi: (names: string[], _requestBy, _v: VistaView) => { if (names.includes('download') && button) { button.setAttribute('disabled', 'true'); } }, onReactivateUi: (names: string[], _requestBy, _v: VistaView) => { if (names.includes('download') && button) { button.removeAttribute('disabled'); } }, onClose: (_v: VistaView) => { button?.remove(); button = null; currentImage = null; currentAlt = null; }, }; } ``` ## Adding the Control to UI Specify where your control appears using the `controls` config: ```typescript vistaView({ elements: '#gallery > a', controls: { topRight: ['zoomIn', 'zoomOut', 'download', 'close'], }, extensions: [download()], }); ``` Available positions: - `topLeft` - `topRight` - `bottomLeft` - `bottomRight` ## UI Extension with SVG Icons ```typescript export function fullscreen(): VistaExtension { const enterIcon = ` `; const exitIcon = ` `; let button: HTMLButtonElement | null = null; let isFullscreen = false; return { name: 'fullscreen', control: () => { button = document.createElement('button'); button.setAttribute('aria-label', 'Toggle fullscreen'); button.innerHTML = enterIcon; button.addEventListener('click', async () => { if (!isFullscreen) { await document.documentElement.requestFullscreen(); button!.innerHTML = exitIcon; } else { await document.exitFullscreen(); button!.innerHTML = enterIcon; } isFullscreen = !isFullscreen; }); return button; }, onClose: () => { if (isFullscreen) { document.exitFullscreen(); } button?.remove(); button = null; isFullscreen = false; }, }; } ``` ## Styling UI Extensions Use CSS variables for consistent styling: ```css .vvw-ui button[aria-label='Download'] { background: var(--vvw-ui-bg-color); color: var(--vvw-ui-text-color); border-radius: var(--vvw-ui-border-radius); padding: 8px; border: none; cursor: pointer; } .vvw-ui button[aria-label='Download']:hover { background: var(--vvw-ui-hover-bg-color); } .vvw-ui button[aria-label='Download']:disabled { opacity: 0.5; cursor: not-allowed; } ``` ## Key Concepts ### State Management Use closure variables to persist state: ```typescript export function myExtension(): VistaExtension { let button: HTMLButtonElement | null = null; let currentState = 'idle'; return { name: 'myExtension', control: () => { button = document.createElement('button'); // Use button and currentState throughout lifecycle return button; }, }; } ``` ### Cleanup Always clean up in `onClose`: ```typescript onClose: () => { button?.removeEventListener('click', handleClick); button?.remove(); button = null; currentImage = null; }; ``` ### UI State Handle disable/enable states. Your Extensions might not be known to other extensions. If you want your extensions to have the same state as the zoomIn, zoomOut, and download extension, check for 'zoomIn', 'zoomOut', or 'download'. For example, Video extensions disable the download button by default, so your extensions might want to listen to the download 'button' as well: ```typescript onDeactivateUi: (names) => { if ((names.includes('myExtension') || names.includes('download')) && button) { button.setAttribute('disabled', 'true'); button.classList.add('disabled'); } }, onReactivateUi: (names) => { if ((names.includes('myExtension') || names.includes('download')) && button) { button.removeAttribute('disabled'); button.classList.remove('disabled'); } } ``` ## Next Steps - [Behavior Extensions](/extensions/authoring/behavior-extensions) - [Built-in Extensions](/extensions/overview) --- # Extensions Authoring Guide Learn how to create custom extensions for VistaView Path: /extensions/authoring Extensions are objects that implement the `VistaExtension` interface and hook into the lightbox lifecycle. You pass them in the `extensions` array when initializing VistaView, and they can add UI controls, respond to navigation events, replace image rendering with custom content, and more. ## The VistaExtension Interface ```typescript import type { VistaExtension, VistaImageParams, VistaData, VistaImageClone, VistaView, VistaBox, } from 'vistaview'; const myExtension: VistaExtension = { // Required: unique name used to reference this extension in controls config name: 'myExtension', // Optional: shown in aria-label when the extension provides a control description: 'My custom extension', // Optional: return an HTMLElement to add to the UI toolbar control: () => { /* ... */ return button; }, // Optional: intercept image initialization — return a VistaBox to replace default image onInitializeImage: (params: VistaImageParams) => { /* ... */ }, // Optional: called when the lightbox opens onOpen: (vistaView: VistaView) => { /* ... */ }, // Optional: called when navigating to an image onImageView: (data: VistaData, vistaView: VistaView) => { /* ... */ }, // Optional: called when image content changes (pan, zoom, etc.) onContentChange: (content: VistaImageClone, vistaView: VistaView) => { /* ... */ }, // Optional: called when UI controls are disabled (e.g. video is shown) onDeactivateUi: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => { /* ... */ }, // Optional: called when UI controls are re-enabled onReactivateUi: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => { /* ... */ }, // Optional: called when the lightbox closes onClose: (vistaView: VistaView) => { /* ... */ }, }; ``` ## Quick Start The minimal extension — just a name and one hook: ```typescript import type { VistaExtension } from 'vistaview'; import { vistaView } from 'vistaview'; export function myExtension(): VistaExtension { return { name: 'myExtension', onOpen: (v) => { console.log('Lightbox opened, total images:', v.state.elmLength); }, }; } vistaView({ elements: '#gallery > a', extensions: [myExtension()], }); ``` ## Extension Types There are three patterns, each covered in its own guide: ### UI Extensions Add a button or other control element to the toolbar. The `control()` method returns the element; you register it in the `controls` config by the extension's `name`. Use `onDeactivateUi` / `onReactivateUi` to respond when other extensions disable controls (for example, video extensions disable zoom and download). → [UI Extensions guide](/extensions/authoring/ui-extensions) ### Behavior Extensions React to lifecycle events without any visible UI — logging, analytics, keyboard shortcuts, auto-play, etc. These only use the `on*` hooks. → [Behavior Extensions guide](/extensions/authoring/behavior-extensions) ### Content Extensions Intercept `onInitializeImage` and return a custom `VistaBox` subclass to replace the default image renderer. Used for videos, maps, iframes, or any non-image content. → [Content Extensions guide](/extensions/authoring/content-extensions) ## Lifecycle Event Order ### On open 1. `onOpen` (all extensions) 2. `onInitializeImage` (per image, for preloaded images) 3. `onImageView` (for the initial image) ### On navigate 1. `onInitializeImage` (for newly preloaded images) 2. `onImageView` ### On close 1. `onClose` (all extensions) ## Using Extensions with Controls If your extension provides a `control()`, register it by name in the `controls` configuration: ```typescript vistaView({ elements: '#gallery > a', extensions: [myExtension()], controls: { topRight: ['zoomIn', 'zoomOut', 'myExtension', 'close'], }, }); ``` The extension name and the string in the controls array must match exactly. ## Next Steps - [UI Extensions](/extensions/authoring/ui-extensions) — add buttons and toolbar elements - [Behavior Extensions](/extensions/authoring/behavior-extensions) — hook into events without UI - [Content Extensions](/extensions/authoring/content-extensions) — render custom content types - [Built-in Extensions](/extensions/overview) — see real examples --- # Content Extensions Support custom content types by extending VistaBox Path: /extensions/authoring/content-extensions Content extensions allow VistaView to display custom content types beyond images. They implement `onInitializeImage` to return custom `VistaBox` instances. ## VistaBox Overview `VistaBox` is the base class that handles content display, sizing, and transitions. To support custom content: 1. Extend `VistaBox` 2. Set `this.element` to your custom DIV element 3. Define dimensions (`fullW`, `fullH`, `minW`, `maxW`) 4. Override methods as needed :::tip[VistaBox Source Code] For a complete understanding of `VistaBox` properties and methods, check the [source code on GitHub](https://github.com/juji/vistaview/blob/main/src/lib/vista-box.ts). ::: ## Basic Content Extension ```typescript import type { VistaExtension, VistaImageParams } from 'vistaview'; import { VistaBox } from 'vistaview'; class VistaCustomContent extends VistaBox { element: HTMLDivElement; constructor(par: VistaImageParams) { super(par); // Always call super first // Create your custom element this.element = document.createElement('div'); this.element.classList.add('vvw-img-hi'); this.element.textContent = 'Custom Content'; // Set dimensions const { width: fullWidth, height: fullHeight } = this.getFullSizeDim(); this.fullH = fullHeight; this.fullW = fullWidth; this.minW = this.fullW * 0.5; // Required: tells VistaView when to close (size threshold) this.maxW = this.fullW; this.element.style.width = `${fullWidth}px`; this.element.style.height = `${fullHeight}px`; // Initialize sizes this.setSizes({ stableSize: false, initDimension: true }); // Mark as loaded this.isLoadedResolved!(true); } protected getFullSizeDim(): { width: number; height: number } { return { width: 800, height: 600 }; } } export function customContent(): VistaExtension { return { name: 'customContent', onInitializeImage: (params: VistaImageParams) => { // Check if this element should use custom content if (params.elm.config.src.includes('custom')) { return new VistaCustomContent(params); } }, }; } ``` ## Video Extension Example Complete YouTube video extension: ```typescript import type { VistaData, VistaExtension, VistaImageParams } from 'vistaview'; import { VistaBox } from 'vistaview'; import type { VistaView } from 'vistaview'; export function parseYouTubeVideoId(url: string): string | null { if (!url) return null; const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/, /youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/, /youtube\.com\/v\/([a-zA-Z0-9_-]{11})/, /youtube\.com\/live\/([a-zA-Z0-9_-]{11})/, /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/, ]; for (const pattern of patterns) { const match = url.match(pattern); if (match?.[1]) return match[1]; } return null; } export function getYouTubeThumbnail(videoUrl: string): string { const videoId = parseYouTubeVideoId(videoUrl); if (!videoId) throw new Error('Invalid YouTube video URL'); return `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`; } export class VistaYoutubeVideo extends VistaBox { element: HTMLDivElement; url: string; constructor(par: VistaImageParams) { super(par); const url = par.elm.config.src; this.url = url; // Create container with thumbnail const div = document.createElement('div'); div.style.position = 'relative'; // youtube thumbnail view // for initial iframe loading const image = document.createElement('img'); div.appendChild(image); // Get thumbnail source from: // 1. Origin image (if lightbox opened from thumbnail click) // 2. data-thumbnail attribute // 3. Generated YouTube thumbnail URL image.src = this.origin?.image.src || par.elm.elm.dataset.thumbnail || getYouTubeThumbnail(url); image.style.width = '100%'; image.style.height = '100%'; image.style.objectFit = 'cover'; image.classList.add('vvw--pulsing'); // add vvw-img-hi clas to the div // so the animation will run this.element = div; this.element.classList.add('vvw-img-hi'); // Set dimensions const { width: fullWidth, height: fullHeight } = this.getFullSizeDim(); this.fullH = fullHeight; this.fullW = fullWidth; this.minW = this.fullW * 0.5; // Required: tells VistaView when to close (size threshold) this.maxW = this.fullW; this.element.style.width = `${fullWidth}px`; this.element.style.height = `${fullHeight}px`; // Initialize sizes // always do this this.setSizes({ stableSize: false, initDimension: true }); // Load iframe when in center position if (this.pos === 0) { const iframe = document.createElement('iframe'); iframe.frameBorder = '0'; iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share'; iframe.allowFullscreen = true; iframe.width = '100%'; iframe.height = '100%'; iframe.style.position = 'absolute'; iframe.style.top = '0'; iframe.style.left = '0'; iframe.style.backgroundColor = 'transparent'; iframe.style.opacity = '0'; iframe.style.transition = 'opacity 1s ease'; iframe.src = `https://www.youtube.com/embed/${parseYouTubeVideoId(url)}?autoplay=1&rel=0`; div.appendChild(iframe); iframe.onload = () => { iframe.style.opacity = '1'; image.classList.remove('vvw--pulsing'); }; } // set as loaded this.isLoadedResolved!(true); } // for videos, the full size have a max width // so we extend this function protected getFullSizeDim(): { width: number; height: number } { const maxWidth = Math.min(window.innerWidth, 800); return { width: maxWidth, height: (maxWidth * 9) / 16, }; } // final transform should not propagate events, // since we don't need it for videos setFinalTransform() { return super.setFinalTransform({ propagateEvent: false }); } } export function youtubeVideo(): VistaExtension { return { name: 'ytVideo', onInitializeImage: (params: VistaImageParams) => { const url = params.elm.config.src; const videoId = parseYouTubeVideoId(url); if (!videoId) return; return new VistaYoutubeVideo(params); }, onImageView: async (data: VistaData, v: VistaView) => { const mainData = data.images.to![Math.floor(data.images.to!.length / 2)]; if (mainData instanceof VistaYoutubeVideo) { // deactivate these on display v.deactivateUi(['download', 'zoomIn', 'zoomOut'], mainData); } }, }; } ``` Usage: ```html Video ``` ```typescript vistaView({ elements: '#gallery > a', extensions: [youtubeVideo()], }); ``` ## Key Points ### Constructor Requirements ```typescript constructor(par: VistaImageParams) { super(par); // ALWAYS call first // Create your element this.element = document.createElement('div'); this.element.classList.add('vvw-img-hi'); // Get dimensions const { width: fullWidth, height: fullHeight } = this.getFullSizeDim(); // Set dimensions this.fullW = fullWidth; this.fullH = fullHeight; this.minW = fullWidth * 0.5; this.maxW = fullWidth; // Set element size this.element.style.width = `${fullWidth}px`; this.element.style.height = `${fullHeight}px`; // Initialize this.setSizes({ stableSize: false, initDimension: true }); // Handle loading this.isLoadedResolved!(true); // or wait for async load } ``` ### Override Methods ```typescript // Required: Return full dimensions protected getFullSizeDim(): { width: number; height: number } { const maxWidth = Math.min(window.innerWidth, 800); return { width: maxWidth, height: (maxWidth * 9) / 16, }; } // Optional: Custom transform behavior setFinalTransform() { return super.setFinalTransform({ propagateEvent: false }); } ``` ```typescript constructor(par: VistaImageParams) { super(par); // ALWAYS call first // Create your element this.element = document.createElement('div'); // Set dimensions this.fullW = 800; this.fullH = 600; this.minW = 400; this.maxW = 1200; // Initialize this.setSizes({ stableSize: false, initDimension: true }); // Handle loading this.isLoadedResolved!(true); // or wait for async load } ``` **Key Points:** - `element` must be set in constructor - Call `getFullSizeDim()` to get dimensions, then apply to `element.style` - Must call `isLoadedResolved!(true)` when ready - Can call `isLoadedRejected!(error)` on failure ## Handling Content Detection Check attributes or URL patterns in `onInitializeImage`: ```typescript export function myPdfContent(): VistaExtension { return { name: 'myPdfContent', onInitializeImage: (par: VistaImageParams) => { const url = par.elm.config.src; const type = par.elm.elm.getAttribute('data-type'); // Check by URL pattern (includes yourpdfsite.com and ends with .pdf) if (/yourpdfsite\.com.*\.pdf$/i.test(url)) { return new MyVistaPDF(par); } }, }; } ``` ## Next Steps - [Built-in Video Extensions](/extensions/overview) --- ## Styling & Theming --- # CSS Variables Customize VistaView appearance with CSS custom properties Path: /styling/css-variables VistaView uses CSS custom properties (CSS variables) for easy customization without modifying the source code. ## Basic Usage Import the base CSS file: ```javascript import 'vistaview/style.css'; ``` Then override variables in your own CSS: ```css /* The following are default values */ :root { --vvw-bg-color: #000000; --vvw-text-color: #ffffff; --vvw-bg-blur: 10px; --vvw-bg-opacity: 0.8; --vvw-anim-dur: 333; --vvw-init-z: 1; --vvw-dest-z: 2147483647; --vvw-ui-outline-color: hsl(from var(--vvw-bg-color) h s calc(l + 30)); --vvw-ui-text-color: var(--vvw-text-color); --vvw-ui-bg-color: var(--vvw-bg-color); --vvw-ui-hover-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 20)); --vvw-ui-active-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 40)); --vvw-ui-border-radius: 0px; --vvw-ui-border-width: 0px; } ``` ## Available Variables ### Core Colors ```css :root { --vvw-bg-color: #000000; --vvw-text-color: #ffffff; --vvw-bg-blur: 10px; --vvw-bg-opacity: 0.8; } ``` ### Animation ```css :root { /* Duration in milliseconds */ --vvw-anim-dur: 333; } ``` ### Z-Index ```css :root { /* Initial z-index (set via initialZIndex config) */ --vvw-init-z: 1; /* Maximum z-index when lightbox is open */ --vvw-dest-z: 2147483647; } ``` ### UI Theme Colors These are derived from the core colors: ```css :root { --vvw-ui-outline-color: hsl(from var(--vvw-bg-color) h s calc(l + 30)); --vvw-ui-bg-color: var(--vvw-bg-color); --vvw-ui-text-color: var(--vvw-text-color); --vvw-ui-hover-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 20)); --vvw-ui-active-bg-color: hsl(from var(--vvw-bg-color) h s calc(l + 40)); --vvw-ui-border-radius: 0px; --vvw-ui-border-width: 1px; } ``` ## Best Practices 1. **Only override what you need** - Most variables have sensible defaults 2. **Test with different themes** for pre-built options before customizing 3. **Use semantic colors** - The UI colors derive from `--vvw-bg-color` automatically 4. **Consider accessibility** - Ensure adequate contrast ratios ## Next Steps - Explore [pre-built themes](/styling/themes) - Learn about [custom styling](/styling/custom) - See [configuration options](/core/configuration/complete) --- # Custom Styling Create custom styles and themes for VistaView Path: /styling/custom There are two ways to customize the appearance of VistaView: 1. **Update CSS variables** - Quick customization using existing variables 2. **Create a custom CSS file** - Full theme with custom styling ## Method 1: Update CSS Variables The simplest way to customize VistaView is by overriding CSS variables in your own stylesheet. ```css /* custom.css */ :root { /* Colors */ --vvw-bg-color: #1a1a2e; --vvw-text-color: #eee; --vvw-bg-opacity: 0.95; --vvw-bg-blur: 10px; /* UI Colors */ --vvw-ui-outline-color: #333; --vvw-ui-bg-color: #16213e; --vvw-ui-text-color: #fff; --vvw-ui-hover-bg-color: #0f3460; --vvw-ui-active-bg-color: #e94560; /* UI Styling */ --vvw-ui-border-radius: 12px; --vvw-ui-border-width: 1px; } ``` Import after the base styles: ```javascript import 'vistaview/style.css'; import './custom.css'; ``` See the [CSS Variables](/styling/css-variables) reference for all available variables. ## Method 2: Create a Custom Theme For more control, create a complete custom theme file that includes both variable overrides and custom styling. ```css /* my-theme.css */ /* Override variables */ :root { --vvw-bg-color: #1a1a2e; --vvw-text-color: #eee; --vvw-ui-bg-color: #16213e; --vvw-ui-hover-bg-color: #0f3460; --vvw-ui-border-radius: 12px; } /* Custom component styling */ .vvw-ui { &.vvw-prev, &.vvw-next { button { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); &:hover { transform: scale(1.1); } } } } .vvw-bottom-bar, .vvw-top-bar { button { transition: all 200ms ease; &:hover { box-shadow: 0 0 12px var(--vvw-ui-hover-bg-color); } } } ``` Import after the base styles: ```javascript import 'vistaview/style.css'; import './my-theme.css'; ``` ## Accessibility Features ### Automatic Reduced Motion Support VistaView detects the browser's `prefers-reduced-motion` setting and automatically disables slide transitions. This happens at runtime - no CSS configuration needed. ### High Contrast Mode ```css @media (prefers-contrast: high) { :root { --vvw-bg-color: #000; --vvw-text-color: #fff; --vvw-ui-bg-color: #000; --vvw-ui-text-color: #fff; --vvw-ui-hover-bg-color: #333; --vvw-ui-border-width: 2px; } } ``` ## Next Steps - Review [CSS variables](/styling/css-variables) reference - Explore [pre-built themes](/styling/themes) - Check out [configuration options](/core/configuration/complete) --- # Themes Pre-built themes for VistaView Path: /styling/themes import ThemePreviewButton from '../../../components/ThemePreviewButton.astro'; VistaView includes 17 pre-built themes that you can use out of the box. Each theme is a separate CSS file that can be imported alongside the base styles. ## Using Themes ```javascript import 'vistaview/style.css'; // Base styles (required) import 'vistaview/styles/dark-rounded.css'; // Theme (optional) ``` ## Available Themes ### Dark Themes #### dark-rounded Modern dark theme with rounded corners and animated navigation buttons. ```javascript import 'vistaview/styles/dark-rounded.css'; ``` #### midnight-ocean Deep navy blues with cyan accents. ```javascript import 'vistaview/styles/midnight-ocean.css'; ``` #### midnight-gold Elegant black background with gold accents. ```javascript import 'vistaview/styles/midnight-gold.css'; ``` #### ember-glow Dark theme with orange glow effects. ```javascript import 'vistaview/styles/ember-glow.css'; ``` #### neon-nights Cyberpunk-inspired magenta and cyan with glowing effects. ```javascript import 'vistaview/styles/neon-nights.css'; ``` ### Light Themes #### paper-light Light theme with subtle shadows and paper-like appearance. ```javascript import 'vistaview/styles/paper-light.css'; ``` #### ice-crystal Cool light blue palette with crisp styling. ```javascript import 'vistaview/styles/ice-crystal.css'; ``` ### Color Themes #### autumn-amber Warm oranges and browns with earthy tones. ```javascript import 'vistaview/styles/autumn-amber.css'; ``` #### cotton-candy Playful pastel pink with soft styling. ```javascript import 'vistaview/styles/cotton-candy.css'; ``` #### forest-moss Earthy greens inspired by nature. ```javascript import 'vistaview/styles/forest-moss.css'; ``` #### green-lake Calming teal and green palette with smooth transitions. ```javascript import 'vistaview/styles/green-lake.css'; ``` #### lavender-fields Soft purple palette with gentle animations. ```javascript import 'vistaview/styles/lavender-fields.css'; ``` #### mint-chocolate Brown and mint green combination. ```javascript import 'vistaview/styles/mint-chocolate.css'; ``` #### soft-neutral Warm beige and cream tones with maximum roundness. ```javascript import 'vistaview/styles/soft-neutral.css'; ``` #### strawberry Vibrant pink and red gradient theme. ```javascript import 'vistaview/styles/strawberry.css'; ``` ### Special Themes #### stark-minimal Pure black and white, zero border radius, minimalist design. ```javascript import 'vistaview/styles/stark-minimal.css'; ``` #### retro-arcade Bold primary colors with classic arcade aesthetics. ```javascript import 'vistaview/styles/retro-arcade.css'; ``` ## Theme Sizes All themes are lightweight: - **Smallest:** dark-rounded (0.69 KB, 0.26 KB gzip) - **Largest:** retro-arcade (1.14 KB, 0.38 KB gzip) - **Average:** ~0.83 KB (~0.30 KB gzip) ## Creating Custom Themes See the [Custom Styling](/styling/custom) guide to create your own theme based on these examples. ## Next Steps - Learn about [CSS variables](/styling/css-variables) - Create [custom styling](/styling/custom) - Explore [configuration options](/core/configuration/complete) --- ## API Reference --- # Extensions Extension system types and interfaces Path: /api-reference/extensions Extensions allow you to add custom functionality, content types, and UI controls to VistaView. **Extension Types:** See [Types](/api-reference/types) for: - [VistaExtension](/api-reference/types#vistaextension) - Extension interface - [VistaDefaultCtrl](/api-reference/types#vistadefaultctrl) - Built-in control names - [VistaImageParams](/api-reference/types#vistaimageparams) - Parameters for `onInitializeImage` ## Creating Extensions Extensions implement the [VistaExtension](/api-reference/types#vistaextension) interface with optional hooks: - `name` (required) - Unique identifier - `description` (optional) - Human-readable description - `control()` (optional) - Returns custom UI control element - `onInitializeImage()` (optional) - Replace default image creation - `onImageView()` (optional) - Triggered on navigation - `onContentChange()` (optional) - Triggered on content/zoom changes - `onDeactivateUi()` / `onReactivateUi()` (optional) - UI control state - `onOpen()` / `onClose()` (optional) - Lightbox lifecycle ## Extension Example Simple logger extension: ```typescript import type { VistaExtension, VistaData } from 'vistaview'; import type { VistaView } from 'vistaview'; export function logger(): VistaExtension { return { name: 'logger', description: 'Logs all lightbox events', onOpen: (vistaView) => { console.log('[Logger] Opened'); }, onClose: (vistaView) => { console.log('[Logger] Closed'); }, onImageView: (data, vistaView) => { console.log('[Logger] Image view:', data.index.to); }, onContentChange: (content, vistaView) => { console.log('[Logger] Content changed, scale:', content.scale); }, }; } // Usage vistaView({ elements: '#gallery > a', extensions: [logger()], }); ``` ## Control Configuration **Example:** ```typescript vistaView({ elements: '#gallery > a', controls: { topRight: ['close'], bottomCenter: ['indexDisplay'], bottomRight: ['zoomIn', 'zoomOut'], }, }); ``` See [VistaDefaultCtrl](/api-reference/types#vistadefaultctrl) for built-in control names. ## Advanced Classes These classes are exported for advanced use cases: ### VistaBox Base class for content containers. Extend this to create custom content types. ```typescript import { VistaBox } from 'vistaview'; import type { VistaImageParams } from 'vistaview'; export class CustomContentBox extends VistaBox { element: HTMLDivElement; constructor(params: VistaImageParams) { super(params); // Create custom element this.element = document.createElement('div'); this.element.innerHTML = '

Custom content

'; // Setup required this.element.classList.add('vvw-img-hi'); this.fullW = 800; this.fullH = 600; this.minW = 400; this.maxW = 800; this.element.style.width = `${this.fullW}px`; this.element.style.height = `${this.fullH}px`; this.setSizes({ stableSize: false, initDimension: true }); this.isLoadedResolved!(true); } } ``` ### Other Classes - [**VistaView**](/api-reference/classes/vistaview) - Main view controller class (available in all callbacks) - [**VistaState**](/api-reference/classes/vistastate) - State management (accessible via `vistaView.state`) - [**VistaBox**](/api-reference/classes/vistabox) - Base class for content containers - [**VistaImage**](/api-reference/classes/vistaimage) - Individual image instance (extends VistaBox) - [**VistaPointers**](/api-reference/classes/vistapointers) - Multi-pointer tracking system (see [VistaPointer](/api-reference/types#vistapointer)) - [**VistaImageEvent**](/api-reference/classes/vistaimageevent) - Event handling system - [**VistaHiresTransition**](/api-reference/classes/vistahirestransition) - High-resolution image transition manager ## Utility Functions ### parseElement Parses a DOM element or image config into parsed element data. ```typescript import { parseElement } from 'vistaview/lib/utils'; const parsed = parseElement(element, index); ``` ## Complete Extension Example Custom download button extension: ```typescript import type { VistaExtension, VistaData } from 'vistaview'; import type { VistaView } from 'vistaview'; export function downloadButton(): VistaExtension { let downloadBtn: HTMLButtonElement | null = null; return { name: 'downloadButton', description: 'Adds a download button', control: () => { downloadBtn = document.createElement('button'); downloadBtn.innerHTML = '⬇️ Download'; downloadBtn.className = 'vvw-download-btn'; downloadBtn.style.cssText = ` padding: 8px 16px; background: rgba(0, 0, 0, 0.7); color: white; border: none; border-radius: 4px; cursor: pointer; `; downloadBtn.addEventListener('click', (e) => { e.stopPropagation(); // Download logic here }); return downloadBtn; }, onImageView: (data, vistaView) => { if (downloadBtn) { const mainImage = data.images.to![Math.floor(data.images.to!.length / 2)]; const src = mainImage.origin?.elm.querySelector('img')?.src || ''; // Update download URL downloadBtn.onclick = (e) => { e.stopPropagation(); const link = document.createElement('a'); link.href = src; link.download = `image-${data.index.to! + 1}.jpg`; link.click(); }; } }, }; } // Usage vistaView({ elements: '#gallery > a', extensions: [downloadButton()], controls: { bottomRight: ['downloadButton'], }, }); ``` ## Related - [Main Function](/api-reference/main-function) - [Event Callbacks](/api-reference/events) - [Types](/api-reference/types) - [Extensions Authoring Guide](/extensions/authoring) - [Built-in Extensions](/extensions/overview) --- # Event Callbacks Event callback functions and data types Path: /api-reference/events Event callbacks allow you to hook into different stages of the lightbox lifecycle. ## Event Callback Types ### onOpen Triggered when the lightbox opens. ```typescript onOpen?: (vistaView: VistaView) => void; ``` **Parameters:** - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance **Example:** ```typescript vistaView({ elements: '#gallery > a', onOpen: (vistaView) => { console.log('Lightbox opened'); console.log('Total images:', vistaView.state.elmLength); }, }); ``` ### onClose Triggered when the lightbox closes. ```typescript onClose?: (vistaView: VistaView) => void; ``` **Parameters:** - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance **Example:** ```typescript vistaView({ elements: '#gallery > a', onClose: (vistaView) => { console.log('Lightbox closed'); console.log('Last viewed index:', vistaView.state.currentIndex); }, }); ``` ### onImageView Triggered when navigating between images or when opening at a specific image. ```typescript onImageView?: (data: VistaData, vistaView: VistaView) => void; ``` **Parameters:** - `data:` [VistaData](/api-reference/types#vistadata) - Navigation data with from/to information - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance **Example:** ```typescript vistaView({ elements: '#gallery > a', onImageView: (data, vistaView) => { console.log(`Viewing image ${data.index.to! + 1} of ${vistaView.state.elmLength}`); if (data.via.next) console.log('→ Next'); if (data.via.prev) console.log('← Previous'); }, }); ``` ### onContentChange Triggered when content changes (including zoom operations). ```typescript onContentChange?: (content: VistaImageClone, vistaView: VistaView) => void; ``` **Parameters:** - `content:` [VistaImageClone](/api-reference/types#vistaimageclone) - The changed content - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance **Example:** ```typescript vistaView({ elements: '#gallery > a', onContentChange: (content, vistaView) => { console.log('Zoom level:', content.state.transform.scale.toFixed(2) + 'x'); }, }); ``` **Event Data Types:** See [Types](/api-reference/types) for: - [VistaData](/api-reference/types#vistadata) - Navigation and transition data - [VistaImageClone](/api-reference/types#vistaimageclone) - Current image state - [VistaParsedElm](/api-reference/types#vistaparsedelm) - Parsed element information - [VistaImgOrigin](/api-reference/types#vistaimgorigin) - Origin element properties ## Related - [Main Function](/api-reference/main-function) - [Lifecycle Functions](/api-reference/lifecycle) - [Types](/api-reference/types) - [Events Configuration Guide](/core/configuration/events) --- # Lifecycle Functions Custom lifecycle functions for overriding default behavior Path: /api-reference/lifecycle Lifecycle functions allow you to override VistaView's default behavior at key stages. **Lifecycle Function Types:** See [Types](/api-reference/types) for: - [VistaInitFn](/api-reference/types#vistainitfn) - Custom initialization function - [VistaImageSetupFn](/api-reference/types#vistaimagesetupfn) - Custom setup function - [VistaTransitionFn](/api-reference/types#vistatransitionfn) - Custom transition function - [VistaOpenFn](/api-reference/types#vistaopenfn) - Custom open function - [VistaCloseFn](/api-reference/types#vistaclosefn) - Custom close function ## Usage Examples ### Custom Initialization ```typescript import { vistaView, init } from 'vistaview'; vistaView({ elements: '#gallery > a', initFunction: (vistaView) => { // Call default initialization init(vistaView); // Add custom initialization console.log('Custom initialization'); console.log('Total images:', vistaView.state.elmLength); }, }); ``` ### Custom Image Setup ```typescript import { vistaView, imageSetup } from 'vistaview'; vistaView({ elements: '#gallery > a', imageSetupFunction: (data, vistaView) => { // Call default setup imageSetup(data, vistaView); // Custom setup logic console.log('Setting up image:', data.index.to); }, }); ``` ### Custom Transition ```typescript import { vistaView, transition } from 'vistaview'; vistaView({ elements: '#gallery > a', transitionFunction: (data, abortSignal, vistaView) => { // Use default transition return transition(data, abortSignal, vistaView); }, }); ``` **Custom fade transition:** ```typescript vistaView({ elements: '#gallery > a', transitionFunction: (data, abortSignal, vistaView) => { const elements = data.htmlElements; if (elements.from && elements.to) { const fromElms = elements.from; const toElms = elements.to; // Fade out old images fromElms.forEach((elm) => { elm.style.transition = 'opacity 300ms ease'; elm.style.opacity = '0'; }); // Fade in new images toElms.forEach((elm) => { elm.style.opacity = '0'; elm.style.transition = 'opacity 300ms ease'; setTimeout(() => (elm.style.opacity = '1'), 50); }); const transitionEnded = new Promise((resolve) => { setTimeout(resolve, 350); }); return { cleanup: () => {}, transitionEnded, }; } }, }); ``` ### Custom Close ```typescript import { vistaView, close } from 'vistaview'; vistaView({ elements: '#gallery > a', closeFunction: (vistaView) => { console.log('Custom close logic'); // Call default close close(vistaView); }, }); ``` ## Default Behavior Functions These functions implement the default behavior and can be imported for use in custom function overrides: ### init Default initialization function. ```typescript import { init } from 'vistaview'; vistaView({ elements: '#gallery > a', initFunction: (vistaView) => { init(vistaView); // Add custom logic after default init }, }); ``` ### open Default open function. ```typescript import { open } from 'vistaview'; ``` ### close Default close function. ```typescript import { close } from 'vistaview'; vistaView({ elements: '#gallery > a', closeFunction: (vistaView) => { // Custom logic before close console.log('Closing lightbox'); // Call default close close(vistaView); }, }); ``` ### transition Default transition animation function. ```typescript import { transition } from 'vistaview'; vistaView({ elements: '#gallery > a', transitionFunction: (data, abortSignal, vistaView) => { return transition(data, abortSignal, vistaView); }, }); ``` ### imageSetup Default image setup function. ```typescript import { imageSetup } from 'vistaview'; vistaView({ elements: '#gallery > a', imageSetupFunction: (data, vistaView) => { imageSetup(data, vistaView); // Add custom setup logic }, }); ``` ### DefaultOptions Default configuration options object. See [VistaOpt](/api-reference/types#vistaopt) for all configuration options. ```typescript import { DefaultOptions } from 'vistaview'; const DefaultOptions: VistaOpt = { animationDurationBase: 333, maxZoomLevel: 2, preloads: 1, keyboardListeners: true, arrowOnSmallScreens: false, rapidLimit: 222, controls: { topLeft: ['indexDisplay'], topRight: ['zoomIn', 'zoomOut', 'close'], bottomLeft: ['description'], }, }; ``` ## Related - [Main Function](/api-reference/main-function) - [Event Callbacks](/api-reference/events) - [Types](/api-reference/types) - [Lifecycle Configuration Guide](/core/configuration/lifecycle) --- # Types TypeScript type definitions and interfaces Path: /api-reference/types Complete TypeScript type definitions for VistaView. ## Core Types ### VistaParams Main configuration interface including the `elements` property. ```typescript interface VistaParams extends VistaOpt { elements: string | VistaImgConfig[]; } ``` **Properties:** - `elements` (required): CSS selector string or array of [VistaImgConfig](#vistaimgconfig) configurations - Extends [VistaOpt](#vistaopt) with all configuration options ### VistaOpt Base configuration options interface. ```typescript interface VistaOpt { // Animation animationDurationBase?: number; // Zoom maxZoomLevel?: number; // Preloading preloads?: number; // Interaction keyboardListeners?: boolean; arrowOnSmallScreens?: boolean; rapidLimit?: number; // Styling initialZIndex?: number; // Controls controls?: { topLeft?: (VistaDefaultCtrl | string)[]; topRight?: (VistaDefaultCtrl | string)[]; topCenter?: (VistaDefaultCtrl | string)[]; bottomCenter?: (VistaDefaultCtrl | string)[]; bottomLeft?: (VistaDefaultCtrl | string)[]; bottomRight?: (VistaDefaultCtrl | string)[]; }; // Extensions extensions?: VistaExtension[]; // Event Callbacks onOpen?: (vistaView: VistaView) => void; onClose?: (vistaView: VistaView) => void; onImageView?: (data: VistaData, vistaView: VistaView) => void; onContentChange?: (content: VistaImageClone, vistaView: VistaView) => void; // Lifecycle Functions initFunction?: VistaInitFn; imageSetupFunction?: VistaImageSetupFn; transitionFunction?: VistaTransitionFn; openFunction?: VistaOpenFn; closeFunction?: VistaCloseFn; } ``` **Related Types:** - [VistaDefaultCtrl](#vistadefaultctrl) - Control names - [VistaExtension](#vistaextension) - Extension system - [VistaData](#vistadata), [VistaImageClone](#vistaimageclone) - Event data - [VistaInitFn](#vistainitfn), [VistaImageSetupFn](#vistaimagesetupfn), [VistaTransitionFn](#vistatransitionfn), [VistaOpenFn](#vistaopenfn), [VistaCloseFn](#vistaclosefn) - Lifecycle functions ### VistaInterface Instance interface with control methods returned by `vistaView()`. ```typescript interface VistaInterface { open(index?: number): void; close(): Promise; view(index: number): void; next(): void; prev(): void; reset(): void; zoomIn(): void; zoomOut(): void; getCurrentIndex(): number; destroy(): void; } ``` **Methods:** - `open(index?)` - Opens lightbox at specified index - `close()` - Closes lightbox (returns Promise) - `view(index)` - Navigate to specific image - `next()` - Navigate to next image - `prev()` - Navigate to previous image - `reset()` - Recalculate elements and re-attach event listeners (useful after DOM changes) - `zoomIn()` - Zoom in - `zoomOut()` - Zoom out - `getCurrentIndex()` - Get current image index - `destroy()` - Destroy instance and cleanup ### VistaImgConfig Image configuration object. ```typescript interface VistaImgConfig { src: string; alt?: string; srcSet?: string; } ``` **Properties:** - `src` (required): Image URL - `alt` (optional): Alt text for accessibility - `srcSet` (optional): Responsive image sources ## Event Data Types ### VistaData Data passed to event callbacks and transition functions. ```typescript interface VistaData { htmlElements: { from: HTMLElement[] | null; to: HTMLElement[] | null; }; images: { from: VistaBox[] | null; to: VistaBox[] | null; }; index: { from: number | null; to: number | null; }; via: { next: boolean; prev: boolean; }; } ``` **Properties:** - `htmlElements.from` - Previous HTML elements - `htmlElements.to` - New HTML elements - `images.from` - Previous image objects - `images.to` - New image objects - `index.from` - Previous image index (null on initial open) - `index.to` - New image index - `via.next` - True if navigated via next - `via.prev` - True if navigated via previous ### VistaImageClone Current image state passed to `onContentChange` callback. ```typescript interface VistaImageClone { config: { src: string; alt?: string; srcSet?: string; }; origin: { src: string; srcSet: string; borderRadius: string; objectFit: string; } | null; parsedSrcSet?: { src: string; width: number }[]; element: string; thumb?: string; index: number; pos: number; state: { width: number; height: number; transform: { x: number; y: number; scale: number; }; translate: { x: number; y: number; }; }; } ``` **Properties:** - `config` - Image configuration (src, alt, srcSet) - `origin` - Original element properties (null for non-image content) - `parsedSrcSet` - Parsed srcSet attribute - `element` - HTML string of the content - `thumb` - Thumbnail URL (if applicable) - `index` - Current image index - `pos` - Position in the view - `state.width` - Current width - `state.height` - Current height - `state.transform` - Transform state (x, y, scale) - `state.translate` - Translation offsets (x, y) ### VistaParsedElm Parsed element information passed to extensions. ```typescript interface VistaParsedElm { config: VistaImgConfig; parsedSrcSet?: { src: string; width: number }[]; origin?: VistaImgOrigin; } ``` **Properties:** - `config` - Image configuration ([VistaImgConfig](#vistaimgconfig)) - `parsedSrcSet` - Parsed srcSet attribute with sources and widths - `origin` - Origin element properties ([VistaImgOrigin](#vistaimgorigin)) ### VistaImgOrigin Origin element properties for animations. ```typescript interface VistaImgOrigin { anchor?: HTMLAnchorElement; image: HTMLImageElement; src: string; srcSet: string; borderRadius: string; objectFit: string; } ``` **Properties:** - `anchor` - The original anchor element (if exists) - `image` - The original image element - `src` - Original image source - `srcSet` - Original srcSet attribute - `borderRadius` - Original border radius style - `objectFit` - Original object-fit style ## Lifecycle Function Types ### VistaInitFn Type for custom initialization function. ```typescript type VistaInitFn = (vistaView: VistaView) => void; ``` **Parameters:** - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance ### VistaImageSetupFn Type for custom setup function when navigating between images. ```typescript type VistaImageSetupFn = (data: VistaData, vistaView: VistaView) => void; ``` **Parameters:** - `data:` [VistaData](#vistadata) - Navigation data - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance ### VistaTransitionFn Type for custom transition animation function. ```typescript type VistaTransitionFn = ( data: VistaData, abortSignal: AbortSignal, vistaView: VistaView ) => { cleanup: () => void; transitionEnded: Promise } | void; ``` **Parameters:** - `data:` [VistaData](#vistadata) - Navigation data - `abortSignal: AbortSignal` - Signal to abort the transition - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance **Returns:** Object with cleanup function and promise, or void ### VistaOpenFn Type for custom open function. ```typescript type VistaOpenFn = (vistaView: VistaView) => void; ``` **Parameters:** - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance ### VistaCloseFn Type for custom close function. ```typescript type VistaCloseFn = (vistaView: VistaView) => void; ``` **Parameters:** - `vistaView:` [VistaView](/api-reference/classes/vistaview) - The VistaView instance ## Extension Types ### VistaExtension Interface for creating extensions. ```typescript interface VistaExtension { name: string; description?: string; control?: () => HTMLElement | null; onInitializeImage?: (parsed: VistaImageParams) => VistaBox | void | null | undefined; onImageView?: (data: VistaData, vistaView: VistaView) => void; onContentChange?: (content: VistaImageClone, vistaView: VistaView) => void; onDeactivateUi?: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => void; onReactivateUi?: (names: string[], requestBy: VistaBox | null, vistaView: VistaView) => void; onOpen?: (vistaView: VistaView) => void; onClose?: (vistaView: VistaView) => void; } ``` **Properties:** - `name` (required) - Unique identifier for the extension - `description` (optional) - Human-readable description - `control` (optional) - Returns a custom UI control element - `onInitializeImage` (optional) - Hook to replace default image creation - `onImageView` (optional) - Triggered when navigating between images - `onContentChange` (optional) - Triggered when content changes - `onDeactivateUi` (optional) - Triggered when UI controls are deactivated - `onReactivateUi` (optional) - Triggered when UI controls are reactivated - `onOpen` (optional) - Triggered when lightbox opens - `onClose` (optional) - Triggered when lightbox closes **Type References:** - [VistaImageParams](#vistaimageparams) - Used in `onInitializeImage` - [VistaData](#vistadata) - Used in `onImageView` - [VistaImageClone](#vistaimageclone) - Used in `onContentChange` ## Control Types ### VistaDefaultCtrl Built-in control names. ```typescript type VistaDefaultCtrl = 'indexDisplay' | 'zoomIn' | 'zoomOut' | 'close' | 'description'; ``` ## Advanced Types ### VistaImageParams Parameters passed to extension `onInitializeImage` hook. ```typescript interface VistaImageParams { elm: VistaParsedElm; pos: number; index: number; maxZoomLevel: number; onScale: (par: { vistaImage: VistaBox; scale: number; isMax: boolean; isMin: boolean }) => void; vistaView: VistaView; transitionState?: VistaHiresTransitionOpt; transitionShouldWait?: () => boolean; } ``` **Properties:** - `elm` - Parsed element ([VistaParsedElm](#vistaparsedelm)) - `pos` - Position in the view - `index` - Image index - `maxZoomLevel` - Maximum zoom level - `onScale` - Callback for scale changes - `vistaView` - [VistaView](/api-reference/classes/vistaview) instance - `transitionState` - Optional transition state - `transitionShouldWait` - Optional transition wait function ## Pointer Event Types ### VistaPointer Represents a single pointer (mouse, touch, or pen) position and movement. ```typescript type VistaPointer = { x: number; y: number; movementX: number; movementY: number; id: number | string; }; ``` **Properties:** - `x` - Current X coordinate - `y` - Current Y coordinate - `movementX` - Movement delta on X axis since last event - `movementY` - Movement delta on Y axis since last event - `id` - Unique identifier for this pointer ### VistaPointerListenerArgs Arguments passed to internal pointer listeners used by `VistaPointers`. ```typescript type VistaPointerListenerArgs = { event: 'down' | 'move' | 'up' | 'cancel'; pointer: VistaPointer; pointers: VistaPointer[]; lastPointerLen: number; }; ``` **Properties:** - `event` - Type of pointer event - `pointer` - Current [VistaPointer](#vistapointer) data - `pointers` - Array of all active [VistaPointer](#vistapointer) instances - `lastPointerLen` - Previous number of active pointers (for detecting pointer count changes) ### VistaPointerListener A listener function passed to `VistaPointers` via `VistaPointerArgs.listeners` or `addEventListener()`. ```typescript type VistaPointerListener = (args: VistaPointerListenerArgs) => void; ``` **Parameters:** - `args` - [VistaPointerListenerArgs](#vistapointerlistenerargs) event data ### VistaExternalPointerListenerArgs Arguments passed to external pointer listeners registered via [`registerPointerListener()`](/api-reference/classes/vistaview#registerpointerlistener). ```typescript type VistaExternalPointerListenerArgs = { event: 'down' | 'move' | 'up' | 'cancel'; pointer: VistaPointer; pointers: VistaPointer[]; lastPointerLen: number; state: VistaState; hasInternalExecution: boolean; abortController: AbortController | null; }; ``` **Properties:** - `event` - Type of pointer event - `pointer` - Current [VistaPointer](#vistapointer) data - `pointers` - Array of all active [VistaPointer](#vistapointer) instances - `lastPointerLen` - Previous number of pointers (for detecting changes) - `state` - [VistaState](/api-reference/classes/vistastate) instance - `hasInternalExecution` - Whether VistaView handled this event internally - `abortController` - Controller for canceling operations ## Related - [Main Function](/api-reference/main-function) - [Event Callbacks](/api-reference/events) - [Lifecycle Functions](/api-reference/lifecycle) - [Extensions](/api-reference/extensions) --- # Main Function vistaView() function, configuration, and instance methods Path: /api-reference/main-function ## vistaView() Creates and initializes a lightbox instance. This function is the primary entry point that instantiates the [VistaView](/api-reference/classes/vistaview) class. ```typescript function vistaView(params: VistaParams): VistaInterface | null; ``` **Parameters:** - `params:` [VistaParams](/api-reference/types#vistaparams) - Configuration object **Returns:** [VistaInterface](/api-reference/types#vistainterface) or `null` if no valid elements are found or input is invalid **Example:** ```typescript import { vistaView } from 'vistaview'; import 'vistaview/style.css'; const gallery = vistaView({ elements: '#gallery > a', maxZoomLevel: 3, preloads: 2, }); ``` :::note The `vistaView()` function (lowercase 'v') is the factory function, while [VistaView](/api-reference/classes/vistaview) (capital 'V') is the underlying class. For most use cases, use the `vistaView()` function. Direct access to the VistaView class is useful for TypeScript type imports and advanced extensions. ::: **Configuration:** See [Types](/api-reference/types) for: - [VistaParams](/api-reference/types#vistaparams) - Main configuration interface - [VistaOpt](/api-reference/types#vistaopt) - All configuration options - [VistaImgConfig](/api-reference/types#vistaimgconfig) - Image configuration object ## Instance Methods The `vistaView()` function returns a [VistaInterface](/api-reference/types#vistainterface) object with the following methods: ### open(index?) Opens the lightbox at the specified index (0-based). ```typescript open(index?: number): void; ``` **Parameters:** - `index` (optional): Image index to open at (default: 0) **Example:** ```typescript const gallery = vistaView({ elements: '#gallery > a' }); gallery.open(); // Open at first image gallery.open(0); // Open at first image gallery.open(2); // Open at third image ``` ### close() Closes the lightbox. ```typescript close(): Promise; ``` **Returns:** Promise that resolves when close animation completes **Example:** ```typescript await gallery.close(); console.log('Gallery closed'); ``` ### view(index) Navigates to a specific image while the lightbox is open. ```typescript view(index: number): void; ``` **Parameters:** - `index` (required): Image index to navigate to (0-based) **Example:** ```typescript gallery.view(2); // Go to third image ``` ### next() Navigates to the next image. Wraps to first image when at the end. ```typescript next(): void; ``` **Example:** ```typescript gallery.next(); ``` ### prev() Navigates to the previous image. Wraps to last image when at the beginning. ```typescript prev(): void; ``` **Example:** ```typescript gallery.prev(); ``` ### reset() Recalculates elements and re-attaches event listeners. Useful after DOM changes. ```typescript reset(): void; ``` **Example:** ```typescript // After adding new images to the DOM document.querySelector('#gallery')!.innerHTML += ` New Photo `; // Refresh the gallery gallery.reset(); ``` ### zoomIn() Zooms in on the current image. ```typescript zoomIn(): void; ``` **Example:** ```typescript gallery.zoomIn(); ``` ### zoomOut() Zooms out on the current image. ```typescript zoomOut(): void; ``` **Example:** ```typescript gallery.zoomOut(); ``` ### getCurrentIndex() Returns the current image index (0-based). ```typescript getCurrentIndex(): number; ``` **Returns:** Current image index **Example:** ```typescript const currentIndex = gallery.getCurrentIndex(); console.log(`Viewing image ${currentIndex + 1}`); ``` ### destroy() Destroys the lightbox instance and removes all event listeners. ```typescript destroy(): void; ``` **Example:** ```typescript gallery.destroy(); ``` ## Related - [Event Callbacks](/api-reference/events) - [Lifecycle Functions](/api-reference/lifecycle) - [Complete Configuration Guide](/core/configuration/complete) --- # VistaBox Class Base class for image and custom content containers Path: /api-reference/classes/vistabox The `VistaBox` class is an abstract base class for all content types in VistaView. Extend this class to create custom content types like videos, maps, or interactive elements. ## Overview `VistaBox` handles: - Image sizing and scaling - Zoom and pan transformations - Lifecycle management (init, load, destroy) - State management for width, height, and transformations **Use Case:** Create custom content extensions by extending VistaBox. See [Extensions](/api-reference/extensions) for examples. ## Public Properties ### element ```typescript abstract element: HTMLImageElement | HTMLDivElement ``` The DOM element containing the content. Must be implemented by subclasses. ### state ```typescript state: VistaImageState; ``` Current state of the image including dimensions and transformations. Contains internal properties prefixed with `_` (e.g., `_width`, `_height`, `_transform`). ### pos ```typescript pos: number; ``` Position relative to the current image (`0` = center, `-1` = left, `1` = right). ### index ```typescript index: number; ``` Zero-based index in the gallery. ### config ```typescript config: VistaImgConfig; ``` Image configuration containing `src`, `alt`, and `srcSet`. ### origin ```typescript origin: VistaImgOrigin | undefined; ``` Information about the origin element (thumbnail) in the DOM. ### isReady ```typescript isReady: boolean; ``` Whether the content has finished loading. ### thumb ```typescript thumb: HTMLDivElement | null; ``` Thumbnail element used during transitions. ## Public Methods ### constructor() ```typescript constructor(par: VistaImageParams) ``` Creates a new VistaBox instance. Called by [VistaView](/api-reference/classes/vistaview) during initialization. ### init() ```typescript async init(): Promise ``` Initializes the content. Override this to implement custom loading logic. ### setSizes() ```typescript setSizes(par?: { stableSize?: boolean; initDimension?: boolean }): void ``` Calculates and sets dimensions based on viewport and content size. **Parameters:** - `par.stableSize` - Use cached dimensions without recalculation - `par.initDimension` - Calculate initial dimensions from origin element ### prepareClose() ```typescript prepareClose(): void ``` Prepares the element for closing transition. Called before the lightbox closes. ### cancelPendingLoad() ```typescript cancelPendingLoad(): void ``` Cancels any in-progress image loading operations. ### destroy() ```typescript destroy(): void ``` Cleans up resources and removes event listeners. Called when the element is no longer needed. ### cloneStyleFrom() ```typescript cloneStyleFrom(img: VistaBox, state?: VistaHiresTransitionOpt): void ``` Copies style and state from another VistaBox instance. Used during transitions to maintain visual continuity. ### toObject() ```typescript toObject(): VistaImageClone ``` Returns a serializable representation of the current state. Used for the `onContentChange` event. ### setInitialCenter() ```typescript setInitialCenter(center: { x: number; y: number }): void ``` Sets the center point for zoom and pan operations. ### onImageReady() ```typescript onImageReady(): void ``` Override this method to perform actions when the content is ready. ### animateZoom() ```typescript animateZoom(scaleFactor: number, center?: { x: number; y: number }): void ``` Override to implement custom zoom animation logic. ### scaleMove() ```typescript scaleMove(scaleFactor: number, center?: { x: number; y: number }, animate?: boolean): void ``` Override to implement custom scale and movement logic. ### theThrow() ```typescript theThrow(par: { x: number; y: number }): () => void ``` Override to implement momentum scrolling after a swipe gesture. ## Protected Properties The following protected properties are available when extending VistaBox: ### initH ```typescript protected initH: number = 0 ``` Initial height of the content based on thumbnail dimensions. ### initW ```typescript protected initW: number = 0 ``` Initial width of the content based on thumbnail dimensions. ### fullH ```typescript protected fullH: number = 0 ``` Full height of the content when displayed in the lightbox. ### fullW ```typescript protected fullW: number = 0 ``` Full width of the content when displayed in the lightbox. ### maxW ```typescript protected maxW: number = 0 ``` Maximum allowed width for the content. ### minW ```typescript protected minW: number = 0 ``` Minimum allowed width for the content. ### defaultWH ```typescript protected defaultWH: number = 200 ``` Default width/height fallback value. ### isZoomedIn ```typescript protected isZoomedIn: boolean = false ``` Whether the content is currently zoomed in. ### isCancelled ```typescript protected isCancelled: boolean = false ``` Whether the loading operation has been cancelled. ### isLoadedResolved ```typescript protected isLoadedResolved: ((val: boolean | PromiseLike) => void) | null = null ``` Resolver function for the `isLoaded` promise. ### isLoadedRejected ```typescript protected isLoadedRejected: ((reason?: any) => void) | null = null ``` Rejection function for the `isLoaded` promise. ### isLoaded ```typescript protected isLoaded: Promise ``` Promise that resolves when the content has finished loading. ### replacement ```typescript protected replacement: HTMLImageElement | null = null ``` Placeholder element that replaces the original thumbnail in the DOM. ### originalParent ```typescript protected originalParent: HTMLElement | null = null ``` Reference to the original parent element of the thumbnail. ### originalNextSibling ```typescript protected originalNextSibling: ChildNode | null = null ``` Reference to the next sibling of the original thumbnail for proper reinsertion. ### originalStyle ```typescript protected originalStyle = '' ``` Original CSS text of the thumbnail element. ### thumbImage ```typescript protected thumbImage: HTMLImageElement | null = null ``` Reference to the original thumbnail image element. ### originRect ```typescript protected originRect: { width: number; height: number; top: number; left: number } ``` Bounding rectangle of the origin element. ### fittedSize ```typescript protected fittedSize: { width: number; height: number } | null = null ``` Calculated fitted size of the thumbnail image. ### maxZoomLevel ```typescript protected maxZoomLevel: number ``` Maximum zoom level allowed for this content. ### vistaView ```typescript protected vistaView: VistaView ``` Reference to the parent VistaView instance. ### transitionState ```typescript protected transitionState: VistaHiresTransitionOpt | null = null ``` State object for high-resolution transitions. ### transitionShouldWait ```typescript protected transitionShouldWait: () => boolean = () => false ``` Function that determines if transition should wait before starting. ### initPointerCenter ```typescript protected initPointerCenter = { x: 0, y: 0 } ``` Initial center point for pointer interactions. ### onScale ```typescript protected onScale: (par: { vistaImage: VistaBox; scale: number; isMax: boolean; isMin: boolean; }) => void ``` Callback function invoked when content is scaled. ## Protected Methods The following protected methods are available when extending VistaBox: ### createState() ```typescript protected createState(): VistaImageState ``` Creates and returns a new state object with getters/setters that trigger DOM updates. Called in the constructor. ### onLessThanMinWidthChange() ```typescript protected onLessThanMinWidthChange(value: boolean): void ``` Called when content width falls below minimum. Sets opacity to 0.5 when true. ### onTranslateChange() ```typescript protected onTranslateChange(value: { x: number; y: number }): void ``` Updates the CSS translate property when state.translate changes. ### onTransformChange() ```typescript protected onTransformChange(value: { x: number; y: number; scale: number }): void ``` Updates the CSS transform property when state.transform changes. ### onWidthChange() ```typescript protected onWidthChange(value: number): void ``` Updates the CSS width property when state.width changes. ### onHeightChange() ```typescript protected onHeightChange(value: number): void ``` Updates the CSS height property when state.height changes. ### getFullSizeDim() ```typescript protected getFullSizeDim(): { width: number; height: number } ``` Calculates the full size dimensions based on thumbnail aspect ratio and viewport size. **Returns:** Object containing calculated width and height. ### normalize() ```typescript protected normalize(): void ``` Resets content to its default state with no zoom or translation. Sets transform and translate to zero, and dimensions to full size. ### getFromParsedSrcSet() ```typescript protected getFromParsedSrcSet(targetWidth: number): string | null ``` Selects the most appropriate source from the parsed srcSet based on target width and device pixel ratio. **Parameters:** - `targetWidth` - The desired width in pixels **Returns:** The selected source URL, or null if no srcSet is available. ### setFinalTransform() ```typescript setFinalTransform(par?: { propagateEvent?: boolean }): { close: boolean; cancel: () => void } ``` Finalizes the current transform state by converting temporary transforms into permanent translate and size values. Called at the end of pan/zoom operations. **Parameters:** - `par.propagateEvent` - Whether to trigger onContentChange events (default: true) **Returns:** Object with close flag and cancel function. ## Related - [VistaImage](/api-reference/classes/vistaimage) - Image implementation extending VistaBox - [Extensions](/api-reference/extensions) - Creating custom content types - [VistaImageParams](/api-reference/types#vistaimageparams) - Constructor parameters --- # VistaHiresTransition Class High-resolution image transition manager Path: /api-reference/classes/vistahirestransition The `VistaHiresTransition` class manages smooth animated transitions when images are loaded or when dimensions/positions change. ## Overview `VistaHiresTransition` provides: - Smooth easing animations for size and position changes - Concurrent animation management - Frame-by-frame state interpolation - Animation cancellation **Use Case:** Used internally by [VistaImage](/api-reference/classes/vistaimage) to animate dimension and transform changes. Typically not used directly by applications. ## Public Properties None - all properties and map are private/static. ## Public Static Methods ### start() ```typescript static start(options: { vistaImage: VistaBox; onComplete: () => void; shouldWait: () => boolean; target: { width?: number; height?: number; transform?: { x?: number; y?: number; scale?: number }; translate?: { x?: number; y?: number }; }; }): void ``` Starts an animated transition for a VistaBox instance. **Parameters:** - `vistaImage` - The [VistaBox](/api-reference/classes/vistabox) instance to animate - `onComplete` - Callback when animation completes - `shouldWait` - Function returning `true` to pause animation - `target` - Target dimensions and transformations to animate to **Example:** ```typescript import { VistaHiresTransition } from 'vistaview'; VistaHiresTransition.start({ vistaImage: image, onComplete: () => console.log('Animation complete'), shouldWait: () => false, target: { width: 800, height: 600, transform: { scale: 1.5, x: 0, y: 0 }, }, }); ``` ### stop() ```typescript static stop(vistaImage: VistaBox): VistaHiresTransitionOpt | undefined ``` Stops an active animation for a VistaBox instance. **Parameters:** - `vistaImage` - The [VistaBox](/api-reference/classes/vistabox) instance **Returns:** The animation state at the time of stopping, or `undefined` if no animation was running **Example:** ```typescript const state = VistaHiresTransition.stop(image); if (state) { console.log('Stopped at:', state.current); } ``` ## Animation Behavior - Uses **easing function** (20% of remaining distance per frame) for smooth motion - Stops when values are within threshold (1px for position, 0.005 for scale) - Handles multiple concurrent animations per instance - Respects `shouldWait` callback to pause during rapid navigation ## Related - [VistaBox](/api-reference/classes/vistabox) - Container class that uses transitions - [VistaImage](/api-reference/classes/vistaimage) - Image class that triggers transitions - [VistaView](/api-reference/classes/vistaview) - Main controller --- # VistaImage Class Image implementation extending VistaBox Path: /api-reference/classes/vistaimage The `VistaImage` class extends [VistaBox](/api-reference/classes/vistabox) and implements image-specific functionality including responsive images, hi-res loading, and zoom/pan controls. ## Overview `VistaImage` is the default content type used by VistaView for displaying images. It automatically handles: - Progressive image loading with thumbnails - Responsive images with `srcset` support - Zoom and pan interactions - Hi-resolution image transitions ## Usage Typically, you don't instantiate `VistaImage` directly - [VistaView](/api-reference/classes/vistaview) creates instances automatically. However, you can reference it when creating custom extensions. ```typescript import { VistaImage } from 'vistaview'; // Used internally by VistaView const image = new VistaImage(params); ``` ## Public Properties Inherits all properties from [VistaBox](/api-reference/classes/vistabox): - `element` - HTMLImageElement containing the image - `state` - Current dimensions and transformations - `pos` - Position relative to current image - `index` - Gallery index - `config` - Image configuration - `origin` - Origin element information - `isReady` - Whether image has loaded - `thumb` - Thumbnail element ## Public Methods ### constructor() ```typescript constructor(par: VistaImageParams) ``` Creates a new VistaImage instance with automatic image loading. ### Inherited Methods All public methods from [VistaBox](/api-reference/classes/vistabox) are available: - `init()` - Initialize the image - `setSizes()` - Calculate dimensions - `prepareClose()` - Prepare for closing - `cancelPendingLoad()` - Cancel loading - `destroy()` - Clean up resources - `cloneStyleFrom()` - Copy style from another instance - `toObject()` - Serialize current state - `setInitialCenter()` - Set zoom center point ## Related - [VistaBox](/api-reference/classes/vistabox) - Base class - [VistaView](/api-reference/classes/vistaview) - Main controller - [Extensions](/api-reference/extensions) - Creating custom content types --- # VistaImageEvent Class Event handling system for pointer interactions Path: /api-reference/classes/vistaimageevent The `VistaImageEvent` class manages pointer events and translates them into image manipulation actions like zooming, panning, and navigation. ## Overview `VistaImageEvent` coordinates: - Single and multi-touch gestures - Pinch-to-zoom detection - Pan/drag interactions when zoomed - Momentum scrolling - External pointer event listeners **Use Case:** Created internally by [VistaView](/api-reference/classes/vistaview). Extensions can register listeners through [`registerPointerListener()`](/api-reference/classes/vistaview#registerpointerlistener). ## Public Properties None - all properties are private. ## Public Methods ### constructor() ```typescript constructor(vvw: VistaView) ``` Creates a new event handling system for a [VistaView](/api-reference/classes/vistaview) instance. ### registerPointerListener() ```typescript registerPointerListener(listener: (e: VistaExternalPointerListenerArgs) => void): void ``` Registers an external pointer event listener. Same as calling [`viewer.registerPointerListener()`](/api-reference/classes/vistaview#registerpointerlistener). **Parameters:** - `listener` - Function receiving [pointer event data](/api-reference/types#vistaexternalpointerlistenerargs) **Example:** ```typescript const eventSystem = new VistaImageEvent(viewer); eventSystem.registerPointerListener((e) => { console.log('Event:', e.event); console.log('Pointers:', e.pointers.length); console.log('State:', e.state.zoomedIn); }); ``` ### start() ```typescript start(imageContainer: HTMLElement): void ``` Starts listening to pointer events on the specified container. Called automatically by [VistaView](/api-reference/classes/vistaview) when opening. **Parameters:** - `imageContainer` - The element to attach event listeners to ### stop() ```typescript stop(): void ``` Removes all event listeners and cleans up resources. Called automatically by [VistaView](/api-reference/classes/vistaview) when closing. ## Related - [VistaView](/api-reference/classes/vistaview) - Main controller that uses VistaImageEvent - [VistaPointers](/api-reference/classes/vistapointers) - Underlying pointer tracking system - [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) - Event data type --- # VistaView Class The core VistaView class - the main controller for the lightbox viewer Path: /api-reference/classes/vistaview The `VistaView` class is the core controller that manages the entire lifecycle of the lightbox viewer. Each instance represents a lightbox that can be opened, navigated, and controlled programmatically. ## Overview `VistaView` orchestrates all aspects of the lightbox experience: - **Instance Management**: Ensures only one lightbox is active at a time via `GlobalVistaState` - **Image Navigation**: Handles next/prev navigation with smooth transitions and rapid-swap optimization - **UI Controls**: Manages zoom, close, and navigation buttons - **Event Coordination**: Integrates pointer events, keyboard shortcuts, and extension hooks - **State Management**: Tracks current index, zoom level, and UI activation state - **Extension Integration**: Calls extension lifecycle hooks at key moments ## Constructor ```typescript new VistaView(elements: string | VistaImgConfig[], options?: VistaOpt) ``` Creates a new VistaView instance. **Parameters:** - `elements`: Either a CSS selector string or an array of [image configurations](/api-reference/types#vistaimgconfig) - `options`: Optional configuration object (see [VistaOpt](/api-reference/types#vistaopt)) **Example:** ```typescript // Using CSS selector const viewer = new VistaView('.gallery-item', { maxZoomLevel: 3, preloads: 2, }); // Using configuration array const viewer = new VistaView([ { src: 'image1.jpg', alt: 'First image' }, { src: 'image2.jpg', alt: 'Second image' }, ]); ``` ## Public Properties ### options ```typescript options: VistaOpt; ``` The merged configuration options for this instance. Combines user-provided options with [DefaultOptions](/api-reference/lifecycle#defaultoptions). See [VistaOpt](/api-reference/types#vistaopt) for complete type definition. ### state ```typescript state: VistaState; ``` The current state manager containing: - `currentIndex`: Current image index - `elmLength`: Total number of images - `zoomedIn`: Whether the current image is zoomed - `extensions`: Set of registered extensions - `children`: Current DOM elements and VistaBox instances - `abortController`: For canceling transitions See [VistaState](/api-reference/classes/vistastate) for complete documentation. ### imageContainer ```typescript imageContainer: HTMLElement | null; ``` Reference to the DOM element containing the image elements. `null` when the lightbox is closed. ### externalPointerListener ```typescript externalPointerListener: ((e: VistaExternalPointerListenerArgs) => void)[] ``` Array of external pointer event listeners registered via `registerPointerListener()`. Used by extensions to hook into pointer events. See [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) for the event argument type. ## Public Methods ### open() ```typescript open(startIndex?: number): void ``` Opens the lightbox at the specified image index. **Parameters:** - `startIndex`: The index of the image to display first (default: `0`) **Behavior:** - Prevents opening if another VistaView instance is already open - Prevents body scrolling - Creates and injects the lightbox DOM structure - Sets up event handlers and keyboard listeners - Calls `onOpen` event callback and extension hooks - Supports negative indices and values beyond the array length (wraps around) **Example:** ```typescript const viewer = new VistaView('.gallery-item'); viewer.open(2); // Opens at the third image ``` ### close() ```typescript close(animate?: boolean): Promise ``` Closes the lightbox and cleans up resources. **Parameters:** - `animate`: Whether to animate the close transition (default: `true`) **Behavior:** - Waits for close animation to complete (if `animate` is `true`) - Removes DOM elements and event handlers - Destroys all VistaBox instances - Restores body scrolling - Calls `onClose` event callback and extension hooks - Resets `GlobalVistaState` **Example:** ```typescript // Close with animation await viewer.close(); // Close immediately without animation await viewer.close(false); ``` ### destroy() ```typescript destroy(): void ``` Completely destroys the VistaView instance and removes all event listeners. **Behavior:** - Closes the lightbox without animation - Removes click listeners from trigger elements - Clears external pointer listeners - Cannot be reopened after destruction **Example:** ```typescript viewer.destroy(); // viewer is now unusable ``` ### next() ```typescript next(): void ``` Navigates to the next image in the sequence. **Behavior:** - Wraps around to the first image after the last one - Triggers transition animation - Calls `onImageView` event callback **Example:** ```typescript viewer.next(); ``` ### prev() ```typescript prev(): void ``` Navigates to the previous image in the sequence. **Behavior:** - Wraps around to the last image when at the first one - Triggers transition animation - Calls `onImageView` event callback **Example:** ```typescript viewer.prev(); ``` ### view() ```typescript view(index: number, via?: { next: boolean; prev: boolean }): void ``` Jumps to a specific image by index. **Parameters:** - `index`: The target image index - `via`: Optional object indicating navigation direction (used internally) **Behavior:** - Supports negative indices and values beyond array length (wraps around) - Aborts any in-progress transition - Calls `onImageView` event callback - Handles rapid navigation with optimized transitions **Example:** ```typescript viewer.view(5); // Jump to 6th image viewer.view(-1); // Jump to last image ``` ### zoomIn() ```typescript zoomIn(): void ``` Zooms in on the current image by a factor of 1.68x. **Behavior:** - Respects `maxZoomLevel` option - Throttled to prevent excessive calls (222ms) - Disables zoom-in button when at maximum zoom - Can be disabled via `deactivateUi(['zoomIn'])` **Example:** ```typescript viewer.zoomIn(); ``` ### zoomOut() ```typescript zoomOut(): void ``` Zooms out of the current image by a factor of 0.68x. **Behavior:** - Returns to minimum zoom (fit to viewport) - Throttled to prevent excessive calls (222ms) - Disables zoom-out button when at minimum zoom - Can be disabled via `deactivateUi(['zoomOut'])` **Example:** ```typescript viewer.zoomOut(); ``` ### getCurrentIndex() ```typescript getCurrentIndex(): number ``` Returns the current image index. **Returns:** The zero-based index of the currently displayed image, or `-1` if closed. **Example:** ```typescript const index = viewer.getCurrentIndex(); console.log(`Viewing image ${index + 1}`); ``` ### reset() ```typescript reset(): void ``` Recalculates the image list and reattaches click listeners. **Behavior:** - Queries the DOM for elements matching the selector (if using string selector) - Updates `state.elmLength` - Removes and re-adds click event listeners **Use Case:** Call this if the DOM has changed (elements added/removed) and you need to update the gallery. **Example:** ```typescript // After dynamically adding more images to the page document.querySelector('.gallery').innerHTML += 'New'; viewer.reset(); ``` ### qs() ```typescript qs(selector: string): T | null ``` Queries for an element within the lightbox root element. **Parameters:** - `selector`: CSS selector string **Returns:** The first matching element or `null` **Example:** ```typescript const closeButton = viewer.qs('.vvw-close'); ``` ### qsOrigin() ```typescript qsOrigin>(selector: string): T ``` Queries for elements in the document (not limited to lightbox root). **Parameters:** - `selector`: CSS selector string **Returns:** NodeList of matching elements **Example:** ```typescript const galleryItems = viewer.qsOrigin>('.gallery-item'); ``` ### registerPointerListener() ```typescript registerPointerListener(listener: (e: VistaExternalPointerListenerArgs) => void): void ``` Registers an external pointer event listener. **Parameters:** - `listener`: Function that receives [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) pointer event data **Use Case:** Extensions can use this to respond to pointer events without directly managing event handlers. **Example:** ```typescript viewer.registerPointerListener((e) => { console.log('Pointer event:', e.event, e.pointer); console.log('Active pointers:', e.pointers.length); }); ``` ### deactivateUi() ```typescript deactivateUi(names: string[], requestBy?: VistaBox): void ``` Temporarily disables UI controls. **Parameters:** - `names`: Array of control names to disable (e.g., `['zoomIn', 'zoomOut']`) - `requestBy`: Optional VistaBox instance making the request **Behavior:** - Sets `disabled` attribute on specified buttons - Notifies extensions via `onDeactivateUi` hook - Automatically reactivated before navigation or transitions **Example:** ```typescript // Disable zoom during a custom animation viewer.deactivateUi(['zoomIn', 'zoomOut']); ``` ## Related - [Main Function](/api-reference/main-function) - The `vistaView()` function that creates [VistaView](/api-reference/classes/vistaview) instances - [VistaOpt](/api-reference/types#vistaopt) - Configuration options type - [Event Callbacks](/api-reference/events) - Events fired during lifecycle - [Lifecycle Functions](/api-reference/lifecycle) - Customizable lifecycle hooks :::tip Use the [`vistaView()`](/api-reference/main-function) function (lowercase 'v') for creating instances. The `VistaView` class (capital 'V') is primarily used for TypeScript type imports in extensions and callbacks. ::: --- # VistaState Class Internal state management class for VistaView Path: /api-reference/classes/vistastate The `VistaState` class manages the internal state of a [VistaView](/api-reference/classes/vistaview) instance. It tracks the current state of the lightbox, including open/close status, current image, zoom level, and registered extensions. ## Overview `VistaState` is automatically instantiated by [VistaView](/api-reference/classes/vistaview) and accessible via the [`state`](/api-reference/classes/vistaview#state) property. It provides a centralized location for all runtime state information. **Access:** ```typescript const viewer = new VistaView('.gallery-item'); viewer.open(); console.log(viewer.state.currentIndex); // Current image index console.log(viewer.state.zoomedIn); // Zoom state console.log(viewer.state.elmLength); // Total images ``` ## Properties ### open ```typescript open: boolean; ``` Whether the lightbox is currently open. `true` when the lightbox is visible, `false` when closed. ### settled ```typescript settled: boolean; ``` Whether the open transition animation has completed. Useful for determining if the lightbox is fully settled after opening. ### closing ```typescript closing: boolean; ``` Whether the lightbox is currently in the process of closing. `true` during the close transition animation. ### zoomedIn ```typescript zoomedIn: boolean; ``` Whether the current image is zoomed beyond its minimum scale. `false` when the image is at fit-to-viewport scale, `true` when zoomed in. ### children ```typescript children: { htmls: HTMLElement[]; images: VistaBox[]; } ``` Current DOM elements and image instances in the view. **Properties:** - `htmls` - Array of HTML container elements (`.vvw-item` divs) - `images` - Array of [VistaBox](/api-reference/classes/vistabox) instances (images or custom content) The arrays include the current image plus preloaded images based on the `preloads` configuration option. **Example:** ```typescript const viewer = new VistaView('.gallery-item', { preloads: 2 }); viewer.open(5); // With preloads: 2, children includes images at indices 3, 4, 5, 6, 7 console.log(viewer.state.children.images.length); // 5 console.log(viewer.state.children.images[2].index); // 5 (center image) ``` ### currentIndex ```typescript currentIndex: number; ``` Zero-based index of the currently displayed image. `-1` when the lightbox is closed. **Example:** ```typescript console.log(viewer.state.currentIndex); // 3 (viewing 4th image) ``` ### elmLength ```typescript elmLength: number; ``` Total number of images in the gallery. Updated automatically when `reset()` is called. **Example:** ```typescript const viewer = new VistaView('.gallery-item'); console.log(viewer.state.elmLength); // 10 (total images) ``` ### abortController ```typescript abortController: AbortController; ``` Controller for canceling in-progress transitions. Automatically reset before each navigation to abort the previous transition. **Use Case:** Extensions can listen to the abort signal to cancel long-running operations when the user navigates quickly. **Example:** ```typescript const signal = viewer.state.abortController.signal; signal.addEventListener('abort', () => { console.log('Transition was canceled'); }); ``` ### isReducedMotion ```typescript isReducedMotion: boolean; ``` Whether the user has requested reduced motion via system preferences. Detected from the `prefers-reduced-motion` media query. **Example:** ```typescript if (viewer.state.isReducedMotion) { console.log('User prefers reduced motion'); } ``` ### extensions ```typescript extensions: Set; ``` Set of registered [extension](/api-reference/extensions) instances. Populated from the `extensions` configuration option. **Example:** ```typescript import { logger } from 'vistaview/extensions/logger'; const viewer = new VistaView('.gallery-item', { extensions: [logger()], }); console.log(viewer.state.extensions.size); // 1 ``` ## Related - [VistaView Class](/api-reference/classes/vistaview) - Main controller class that uses VistaState - [VistaExtension](/api-reference/types#vistaextension) - Extension interface type - [Extensions](/api-reference/extensions) - Extension system documentation --- # VistaPointers Class Multi-pointer tracking system for touch and mouse interactions Path: /api-reference/classes/vistapointers The `VistaPointers` class provides a unified interface for tracking mouse and touch pointer events. It normalizes pointer data across different input types and manages multi-touch gestures. ## Overview `VistaPointers` handles: - Mouse, touch, and pen input tracking - Multi-pointer gestures (pinch, pan) - Pointer movement calculations - Event normalization across input types **Use Case:** Primarily used internally by [VistaView](/api-reference/classes/vistaview) for handling interactions. Extensions can access pointer data through event listeners. ## Public Properties None - all properties are private. ## Public Methods ### constructor() ```typescript constructor(args: VistaPointerArgs) ``` Creates a new pointer tracking system. **Parameters:** - `args.elm` - Element to attach listeners to (defaults to `document`) - `args.listeners` - Array of [pointer listeners](/api-reference/types#vistapointerlistener) **Example:** ```typescript import { VistaPointers } from 'vistaview'; const pointers = new VistaPointers({ elm: element, listeners: [ (e) => { console.log('Pointer event:', e.event, e.pointers.length); }, ], }); ``` ### startListeners() ```typescript startListeners(): void ``` Starts listening to pointer events. Called automatically by constructor. ### removeListeners() ```typescript removeListeners(): void ``` Removes all pointer event listeners. Call this when cleaning up. **Example:** ```typescript pointers.removeListeners(); ``` ### addEventListener() ```typescript addEventListener(listener: VistaPointerListener): void ``` Adds a pointer event listener. **Example:** ```typescript pointers.addEventListener((e) => { if (e.event === 'down') { console.log('Pointer down at:', e.pointer.x, e.pointer.y); } }); ``` ### removeEventListener() ```typescript removeEventListener(listener: VistaPointerListener): void ``` Removes a specific pointer event listener. ### getPointerDistance() ```typescript getPointerDistance(p1: VistaPointer, p2: VistaPointer): number ``` Calculates the distance between two pointers. Useful for pinch-to-zoom gestures. **Parameters:** - `p1` - First [pointer](/api-reference/types#vistapointer) - `p2` - Second [pointer](/api-reference/types#vistapointer) **Returns:** Distance in pixels **Example:** ```typescript pointers.addEventListener((e) => { if (e.pointers.length >= 2) { const distance = pointers.getPointerDistance(e.pointers[0], e.pointers[1]); console.log('Pinch distance:', distance); } }); ``` ### getCentroid() ```typescript getCentroid(): { x: number; y: number } | null ``` Calculates the center point of all active pointers. Returns `null` if no pointers are active. **Returns:** Center coordinates or `null` **Example:** ```typescript const center = pointers.getCentroid(); if (center) { console.log('Center point:', center.x, center.y); } ``` ## Related - [VistaPointer](/api-reference/types#vistapointer) - Pointer data type - [VistaPointerListener](/api-reference/types#vistapointerlistener) - Listener function type - [VistaExternalPointerListenerArgs](/api-reference/types#vistaexternalpointerlistenerargs) - Event arguments --- ## AI Integration --- # AI Integration Agent-ready tooling — MCP Server, Markdown for Agents, and LLMs.txt Path: /ai-integration VistaView's documentation is built for AI consumption. Agents and LLMs can access docs via three complementary mechanisms: ## LLMs.txt (via Context7) A curated summary of all documentation in a single file. Ideal for LLM context windows. - [`/llms.txt`](/llms.txt) — Concise overviews of each section - [`/llms-full.txt`](/llms-full.txt) — Complete documentation in one file - [Context7](https://context7.com/llmstxt/vistaview_jujiplay_llms_txt) — Preprocessed for common AI tools ## Markdown for Agents Set the `Accept: text/markdown` header on any documentation URL to receive the page content as plain Markdown instead of HTML. ```sh curl -H "Accept: text/markdown" https://vistaview.jujiplay.com/core/installation/ ``` The response contains only the page's main content — no navigation, sidebars, or chrome. ## MCP Server A JSON-RPC MCP server is available at [`POST /mcp`](/mcp) for programmatic access from AI agents and tools. **Tools:** | Tool | Description | |---|---| | `get_package_info` | Fetch npm package metadata for vistaview (or any package) | | `get_build_status` | Get latest GitHub Actions build status | | `search_docs` | Search across all documentation | ### Claude Desktop Add to your `claude_desktop_config.json`: ```json { "mcpServers": { "vistaview": { "url": "https://vistaview.jujiplay.com/mcp" } } } ``` ### Any MCP Client Configure with the endpoint URL: ``` https://vistaview.jujiplay.com/mcp ``` Protocol: JSON-RPC 2.0 over HTTP POST. ## Why Agent-Ready? When building with VistaView, AI assistants can: - Look up configuration options without leaving the IDE - Verify the latest package version and compatibility - Check build status when reporting issues - Search documentation for specific features or APIs