UNPKG

html-squircle

Version:

Utilities for generating superellipse squircles in the form of SVG strings, to be used in clip-path and background inline styles.

92 lines (79 loc) 2.97 kB
import { useMemo } from "react" import { eitherSquircleObj } from "../core/eitherSquircle.js" import { sortAndSerialize } from "../utils/sortAndSerialize.js" import { useCache } from "./CacheContext.js" import { useResizeObserver } from "./useResizeObserver.js" import type { RefObject } from "react" import type { SquircleOptionsBackground, SquircleOptionsBackgroundReact, SquircleOptionsClipReact, } from "../types.js" /** * Pass a ref for the observed element and options for the squircle computation * function. The returned type will depend on the options used. * * Note this will NOT work properly if you apply the style to an element your * component manages which may leave the DOM without your component unmounting. * Apply it only to elements which will be rendered unconditionally with your * component. */ export function useSquircle( ref: RefObject<Element | null>, options?: SquircleOptionsClipReact, ): { clipPath: `path('${string}')` } /** * Pass a ref for the observed element and options for the squircle computation * function. The returned type will depend on the options used. * * Note this will NOT work properly if you apply the style to an element your * component manages which may leave the DOM without your component unmounting. * Apply it only to elements which will be rendered unconditionally with your * component. */ export function useSquircle( ref: RefObject<Element | null>, options?: SquircleOptionsBackgroundReact, ): { background: `url("data:image/svg+xml,${string}") left top no-repeat` } /** * Pass a ref for the observed element and options for the squircle computation * function. The returned type will depend on the options used. * * Note this will NOT work properly if you apply the style to an element your * component manages which may leave the DOM without your component unmounting. * Apply it only to elements which will be rendered unconditionally with your * component. */ export function useSquircle( ref: RefObject<Element | null>, options?: SquircleOptionsClipReact | SquircleOptionsBackgroundReact, ): | { clipPath: `path('${string}')` } | { background: `url("data:image/svg+xml,${string}") left top no-repeat` } { // Observe the size const size = useResizeObserver(ref) // Get the cache if provided const cache = useCache() // Memoize the result const squircle = useMemo(() => { // Add observed size to the size-less props const config: SquircleOptionsBackground = { ...options, ...size, } // If no cache provided, just compute result if (!cache) { return eitherSquircleObj(config) } // Compute cache key const cacheKey = sortAndSerialize(config) // Get from cache const cached = cache.get(cacheKey) ?? eitherSquircleObj(config) // Set in cache if (!cache.has(cacheKey)) { cache.set(cacheKey, cached) } return cached }, [cache, options, size]) return squircle }