UNPKG

@tempots/ui

Version:

Provides a higher level of renderables to help fast development with Tempo.

141 lines (140 loc) 4.39 kB
import { Signal, TNode, Renderable } from '@tempots/dom'; /** * Represents the mode for determining if an element is in the viewport. * * - `partial`: Indicates that the element is considered in the viewport if any part of it is visible. * - `full`: Indicates that the element is considered in the viewport only if it is fully visible. * * @public */ export type InViewportMode = 'partial' | 'full'; export type InViewportOptions = { mode?: InViewportMode; once?: boolean; }; /** * Creates a component that tracks whether an element is visible in the viewport. * * This component uses the Intersection Observer API to efficiently detect when an element * enters or exits the viewport. It's perfect for implementing lazy loading, infinite scrolling, * animations on scroll, and other viewport-based interactions. * * @example * ```typescript * // Basic viewport detection * InViewport( * { mode: 'partial' }, * (isVisible) => html.div( * attr.class(isVisible.map(v => v ? 'visible' : 'hidden')), * 'This element changes class when visible' * ) * ) * ``` * * @example * ```typescript * // Lazy load images * const imageUrl = 'https://example.com/large-image.jpg' * * InViewport( * { mode: 'partial', once: true }, * (isVisible) => isVisible.value * ? html.img(attr.src(imageUrl), attr.alt('Lazy loaded image')) * : html.div(attr.class('placeholder'), 'Loading...') * ) * ``` * * @example * ```typescript * // Infinite scrolling trigger * const loadMore = () => { * // Load more data * console.log('Loading more items...') * } * * html.div( * ForEach(items, item => ItemComponent(item)), * InViewport( * { mode: 'partial' }, * (isVisible) => { * // Trigger load more when sentinel comes into view * isVisible.on(visible => { * if (visible) loadMore() * }) * return html.div(attr.class('loading-sentinel'), 'Loading more...') * } * ) * ) * ``` * * @example * ```typescript * // Animation on scroll * InViewport( * { mode: 'full' }, // Only trigger when fully visible * (isVisible) => html.div( * attr.class(isVisible.map(v => * v ? 'animate-fade-in' : 'opacity-0' * )), * 'This animates when fully in view' * ) * ) * ``` * * @param options - Configuration options for viewport detection * @param options.mode - 'partial' (any part visible) or 'full' (completely visible) * @param options.once - If true, stops observing after first intersection * @param fn - Function that receives the visibility signal and returns content to render * @returns A renderable component that tracks viewport visibility * @public */ export declare const InViewport: ({ mode, once }: InViewportOptions, fn: (value: Signal<boolean>) => TNode) => Renderable; /** * Conditionally renders content based on whether an element is in the viewport. * * This is a convenience wrapper around `InViewport` that provides a simpler API * for cases where you just want to show/hide content based on viewport visibility. * It's perfect for simple lazy loading or reveal animations. * * @example * ```typescript * // Simple lazy loading * WhenInViewport( * { mode: 'partial', once: true }, * () => html.img( * attr.src('https://example.com/image.jpg'), * attr.alt('Lazy loaded image') * ), * () => html.div(attr.class('skeleton'), 'Loading...') * ) * ``` * * @example * ```typescript * // Reveal animation * WhenInViewport( * { mode: 'full' }, * () => html.div( * attr.class('animate-slide-up'), * 'This content slides up when visible' * ) * ) * ``` * * @example * ```typescript * // Load expensive component only when needed * WhenInViewport( * { mode: 'partial', once: true }, * () => ExpensiveChart({ data: chartData }), * () => html.div('Chart will load when visible') * ) * ``` * * @param options - Configuration options for viewport detection * @param then - Function that returns content to render when element is in viewport * @param otherwise - Optional function that returns content when element is not in viewport * @returns A renderable component that conditionally shows content based on viewport visibility * @public */ export declare const WhenInViewport: (options: InViewportOptions, then: () => TNode, otherwise?: () => TNode) => Renderable;