@liberfi.io/hooks 0.1.86 → 0.1.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -8,7 +8,7 @@ declare global {
8
8
  };
9
9
  }
10
10
  }
11
- declare const _default: "0.1.86";
11
+ declare const _default: "0.1.87";
12
12
 
13
13
  type UseBooleanReturn = [
14
14
  /** current state */
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ declare global {
8
8
  };
9
9
  }
10
10
  }
11
- declare const _default: "0.1.86";
11
+ declare const _default: "0.1.87";
12
12
 
13
13
  type UseBooleanReturn = [
14
14
  /** current state */
package/dist/index.js CHANGED
@@ -10,9 +10,9 @@ var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
10
10
  // src/version.ts
11
11
  if (typeof window !== "undefined") {
12
12
  window.__LIBERFI_VERSION__ = window.__LIBERFI_VERSION__ || {};
13
- window.__LIBERFI_VERSION__["@liberfi.io/hooks"] = "0.1.86";
13
+ window.__LIBERFI_VERSION__["@liberfi.io/hooks"] = "0.1.87";
14
14
  }
15
- var version_default = "0.1.86";
15
+ var version_default = "0.1.87";
16
16
  var useBoolean = (initialValue = false) => {
17
17
  const [value, setValue] = react.useState(initialValue);
18
18
  const setTrue = react.useCallback(() => setValue(true), []);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts","../src/useBoolean.ts","../src/useSafeLayoutEffect.ts","../src/useCallbackRef.ts","../src/useClipboardRead.ts","../src/useIsMounted.ts","../src/useResizeObserver.ts","../src/useTick.ts","../src/useTickAge.ts","../src/useValueRef.ts","../src/internal/throttle.ts","../src/useThrottledResizeObserver.ts","../src/internal/di/container.ts","../src/internal/di/getGlobalObject.ts","../src/internal/di/simpleDI.ts","../src/useEventEmitter.ts","../src/useScrollCollapse.ts"],"names":["useState","useCallback","useLayoutEffect","useEffect","useRef","useMemo","EventEmitter"],"mappings":"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","file":"index.js","sourcesContent":["declare global {\n interface Window {\n __LIBERFI_VERSION__?: {\n [key: string]: string;\n };\n }\n}\nif (typeof window !== \"undefined\") {\n window.__LIBERFI_VERSION__ = window.__LIBERFI_VERSION__ || {};\n window.__LIBERFI_VERSION__[\"@liberfi.io/hooks\"] = \"0.1.86\";\n}\n\nexport default \"0.1.86\";\n","import { useCallback, useState } from \"react\";\n\nexport type UseBooleanReturn = [\n /** current state */\n boolean,\n {\n /** set state to true */\n setTrue: () => void;\n /** set state to false */\n setFalse: () => void;\n /** toggle state */\n toggle: () => void;\n },\n];\n\n/**\n * Hook to manage a boolean state\n * @param initialValue Initial value of the boolean\n * @returns\n */\nexport const useBoolean = (initialValue = false): UseBooleanReturn => {\n const [value, setValue] = useState(initialValue);\n const setTrue = useCallback(() => setValue(true), []);\n const setFalse = useCallback(() => setValue(false), []);\n const toggle = useCallback(() => setValue((v) => !v), []);\n return [value, { setTrue, setFalse, toggle }];\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\nexport const useSafeLayoutEffect = globalThis?.document\n ? useLayoutEffect\n : useEffect;\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Part of this code is taken from @chakra-ui/system ❤️\n */\nimport { useCallback, useRef } from \"react\";\nimport { useSafeLayoutEffect } from \"./useSafeLayoutEffect\";\n\n/**\n * React hook to persist any value between renders,\n * but keeps it up-to-date if it changes.\n * @param fn the function to persist\n * @param deps the function dependency list\n */\nexport function useCallbackRef<T extends (...args: any[]) => any>(\n fn: T | undefined,\n deps: React.DependencyList = [],\n): T {\n const ref = useRef(fn);\n\n useSafeLayoutEffect(() => {\n ref.current = fn;\n });\n\n return useCallback(((...args) => ref.current?.(...args)) as T, deps);\n}\n","import { useCallback } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\n/**\n * Hook that returns a stable async function to read text from the clipboard.\n * Silently ignores errors (e.g. permission denied, empty clipboard).\n *\n * @param onRead Called with the clipboard text when read succeeds and is non-empty\n */\nexport function useClipboardRead(onRead?: (text: string) => void) {\n const onReadRef = useCallbackRef(onRead);\n\n return useCallback(async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) onReadRef(text);\n } catch {\n // Clipboard access denied — silently ignore\n }\n }, [onReadRef]);\n}\n","import { useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Custom hook that determines if the component is currently mounted.\n * @example\n * ```tsx\n * const isComponentMounted = useIsMounted();\n * // Use isComponentMounted() to check if the component is currently mounted before performing certain actions.\n * ```\n */\nexport function useIsMounted(): () => boolean {\n const isMounted = useRef(false);\n\n useEffect(() => {\n isMounted.current = true;\n\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n return useCallback(() => isMounted.current, []);\n}\n","import type { RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useIsMounted } from \"./useIsMounted\";\n\n/** The size of the observed element. */\nexport type Size = {\n /** The width of the observed element. */\n width: number | undefined;\n /** The height of the observed element. */\n height: number | undefined;\n};\n\n/** The options for the ResizeObserver. */\nexport type UseResizeObserverOptions<T extends HTMLElement = HTMLElement> = {\n /** The ref of the element to observe. */\n ref: RefObject<T | null>;\n /**\n * When using `onResize`, the hook doesn't re-render on element size changes; it delegates handling to the provided callback.\n * @default undefined\n */\n onResize?: (size: Size) => void;\n /**\n * The box model to use for the ResizeObserver.\n * @default 'content-box'\n */\n box?: \"border-box\" | \"content-box\" | \"device-pixel-content-box\";\n};\n\nconst initialSize: Size = {\n width: undefined,\n height: undefined,\n};\n\n/**\n * Custom hook that observes the size of an element using the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n * @template T - The type of the element to observe.\n * @see [Documentation](https://usehooks-ts.com/react-hook/use-resize-observer)\n * @example\n * ```tsx\n * const myRef = useRef(null);\n * const { width = 0, height = 0 } = useResizeObserver({\n * ref: myRef,\n * box: 'content-box',\n * });\n *\n * <div ref={myRef}>Hello, world!</div>\n * ```\n */\nexport function useResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseResizeObserverOptions<T>,\n): Size {\n const { ref, box = \"content-box\" } = options;\n const [{ width, height }, setSize] = useState<Size>(initialSize);\n const isMounted = useIsMounted();\n const previousSize = useRef<Size>({ ...initialSize });\n const onResize = useRef<((size: Size) => void) | undefined>(undefined);\n onResize.current = options.onResize;\n\n useEffect(() => {\n if (!ref.current) return;\n\n if (typeof window === \"undefined\" || !(\"ResizeObserver\" in window)) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const boxProp =\n box === \"border-box\"\n ? \"borderBoxSize\"\n : box === \"device-pixel-content-box\"\n ? \"devicePixelContentBoxSize\"\n : \"contentBoxSize\";\n\n const newWidth = extractSize(entry, boxProp, \"inlineSize\");\n const newHeight = extractSize(entry, boxProp, \"blockSize\");\n\n const hasChanged =\n previousSize.current.width !== newWidth ||\n previousSize.current.height !== newHeight;\n\n if (hasChanged) {\n const newSize: Size = { width: newWidth, height: newHeight };\n previousSize.current.width = newWidth;\n previousSize.current.height = newHeight;\n\n if (onResize.current) {\n onResize.current(newSize);\n } else {\n if (isMounted()) {\n setSize(newSize);\n }\n }\n }\n });\n\n observer.observe(ref.current, { box });\n\n return () => {\n observer.disconnect();\n };\n }, [box, ref, isMounted]);\n\n return { width, height };\n}\n\ntype BoxSizesKey = keyof Pick<\n ResizeObserverEntry,\n \"borderBoxSize\" | \"contentBoxSize\" | \"devicePixelContentBoxSize\"\n>;\n\nfunction extractSize(\n entry: ResizeObserverEntry,\n box: BoxSizesKey,\n sizeType: keyof ResizeObserverSize,\n): number | undefined {\n if (!entry[box]) {\n if (box === \"contentBoxSize\") {\n return entry.contentRect[sizeType === \"inlineSize\" ? \"width\" : \"height\"];\n }\n return undefined;\n }\n const boxSize = (\n Array.isArray(entry[box]) ? entry[box][0] : entry[box]\n ) as ResizeObserverSize;\n return boxSize[sizeType];\n}\n","import { useEffect } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\nexport type TickEvent = {\n /** delta time in milliseconds since last tick */\n delta: number;\n /** current timestamp in milliseconds */\n now: number;\n};\n\nexport type TickCallback = (event: TickEvent) => void;\n\ntype UnsubscribeTick = () => void;\n\ntype TickSubscription = {\n /** interval in milliseconds to execute the callback */\n interval: number;\n /** last executed timestamp in milliseconds */\n lastExecuted: number;\n};\n\n/**\n * Global timer singleton using setTimeout for better performance\n */\nclass GlobalTimer {\n /** singleton instance */\n private static instance: GlobalTimer;\n\n /** setTimeout id */\n private timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n /** subscription map */\n private subscribers: Map<TickCallback, TickSubscription> = new Map();\n\n /** is timer running */\n private isRunning = false;\n\n /** internal update interval for smoothness */\n private readonly internalInterval = 200;\n\n /**\n * Get the singleton instance of the timer\n * @returns Timer instance\n */\n static getInstance(): GlobalTimer {\n if (!GlobalTimer.instance) {\n GlobalTimer.instance = new GlobalTimer();\n }\n return GlobalTimer.instance;\n }\n\n /**\n * Subscribe to the timer\n * @param callback tick callback\n * @param interval interval in milliseconds to execute the callback\n * @returns unsubscribe function\n */\n subscribe(callback: TickCallback, interval: number = 1000): UnsubscribeTick {\n this.subscribers.set(callback, {\n interval,\n lastExecuted: Date.now(),\n });\n\n // start timer if this is the first subscriber\n if (!this.isRunning) {\n this.start();\n }\n\n // return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n // stop timer if no more subscribers\n if (this.subscribers.size === 0) {\n this.stop();\n }\n };\n }\n\n private start(): void {\n if (this.isRunning) return;\n this.isRunning = true;\n this.scheduleNext();\n }\n\n private scheduleNext(): void {\n this.timeoutId = setTimeout(() => {\n const now = Date.now();\n\n // check each subscriber and execute if their interval has passed\n this.subscribers.forEach((config, callback) => {\n if (now - config.lastExecuted >= config.interval) {\n callback({ delta: now - config.lastExecuted, now });\n config.lastExecuted = now;\n }\n });\n\n // schedule next tick if still running\n if (this.isRunning) {\n this.scheduleNext();\n }\n }, this.internalInterval);\n }\n\n private stop(): void {\n this.isRunning = false;\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n}\n\n/**\n * Hook to call a callback at specified interval\n * @param callback Function to call at specified interval\n * @param interval Interval in milliseconds (default: 1000ms)\n * @returns\n */\nexport function useTick(callback: TickCallback, interval: number = 1000) {\n const callbackRef = useCallbackRef(callback);\n useEffect(\n () => GlobalTimer.getInstance().subscribe(callbackRef, interval),\n [interval],\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { TickEvent, useTick } from \"./useTick\";\n\n/**\n * Hook to get the age in milliseconds since birthday in every tick\n * @param birthday Timestamp in milliseconds or Date object (default: now)\n * @param interval Tick interval in milliseconds (default: 1000ms)\n * @returns age in milliseconds since birthday\n */\nexport function useTickAge(\n birthday: number | Date = Date.now(),\n interval: number = 1000,\n) {\n const birthdayRef = useRef(\n birthday instanceof Date ? birthday.getTime() : birthday,\n );\n // keep ref updated\n birthdayRef.current =\n birthday instanceof Date ? birthday.getTime() : birthday;\n\n const [age, setAge] = useState(Math.max(0, Date.now() - birthdayRef.current));\n\n const tickAge = useCallback(\n ({ now }: TickEvent) => setAge(Math.max(0, now - birthdayRef.current)),\n [],\n );\n\n useTick(tickAge, interval);\n\n return age;\n}\n","import { RefObject, useRef } from \"react\";\n\n/**\n * Returns an always updated ref to value\n */\nexport function useValueRef<T>(value: T): RefObject<T> {\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n return valueRef;\n}\n","/**\n * Minimal throttle with leading + trailing execution.\n * Replaces lodash-es/throttle for the single call-site in this package.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(\n fn: T,\n wait: number,\n): T {\n let lastCallTime = 0;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let lastArgs: Parameters<T> | null = null;\n\n const throttled = (...args: Parameters<T>) => {\n const now = Date.now();\n const remaining = wait - (now - lastCallTime);\n\n if (remaining <= 0) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastCallTime = now;\n fn(...args);\n } else {\n lastArgs = args;\n if (timeoutId === null) {\n timeoutId = setTimeout(() => {\n lastCallTime = Date.now();\n timeoutId = null;\n if (lastArgs) {\n fn(...lastArgs);\n lastArgs = null;\n }\n }, remaining);\n }\n }\n };\n\n return throttled as T;\n}\n","import { useMemo, useState } from \"react\";\nimport { throttle } from \"./internal/throttle\";\nimport { useResizeObserver } from \"./useResizeObserver\";\nimport type { Size, UseResizeObserverOptions } from \"./useResizeObserver\";\n\nexport type UseThrottledResizeObserverOptions<\n T extends HTMLElement = HTMLElement,\n> = Pick<UseResizeObserverOptions<T>, \"ref\" | \"box\"> & {\n throttleMs?: number;\n};\n\nexport function useThrottledResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseThrottledResizeObserverOptions<T>,\n): Size {\n const { ref, box, throttleMs = 50 } = options;\n\n const [size, setSize] = useState<Size>({\n width: undefined,\n height: undefined,\n });\n\n const onResize = useMemo(\n () => throttle(setSize, throttleMs),\n [throttleMs, setSize],\n );\n\n useResizeObserver({ ref, box, onResize });\n\n return size;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class Container {\n public constructor(private services: { [name: string]: any } = {}) {}\n\n register(...serviceClasses: any[]): void {\n serviceClasses.forEach((serviceClass) => {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.add(service);\n });\n }\n\n registerByName(name: string, serviceClass: any): void {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.addByName(name, service);\n }\n\n get<T = any>(name: string): T {\n return this.services[name];\n }\n\n getAll(): { [name: string]: any } {\n return Object.assign({}, this.services);\n }\n\n private add(service: any): any {\n return this.addByName(service.constructor.name, service);\n }\n\n /**\n * Stores the service under three keys — original, lowercase, and uppercase —\n * so that callers can retrieve it case-insensitively (e.g. \"EE\", \"ee\", \"Ee\"\n * all resolve to the same instance).\n */\n private addByName(name: string, service: any): any {\n this.services[name] = service;\n this.services[name.toLowerCase()] = service;\n this.services[name.toUpperCase()] = service;\n return this.get(name);\n }\n}\n","export const getGlobalObject = () => {\n if (typeof globalThis !== \"undefined\") {\n return globalThis;\n }\n if (typeof self !== \"undefined\") {\n return self;\n }\n if (typeof window !== \"undefined\") {\n return window;\n }\n // @ts-ignore\n if (typeof global !== \"undefined\") {\n // @ts-ignore\n return global;\n }\n throw new Error(\"cannot find the global object\");\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Container } from \"./container\";\nimport { getGlobalObject } from \"./getGlobalObject\";\n\n/**\n * Global Dependency Injection Container\n */\nexport class SimpleDI {\n private static KEY = \"__LIBERFI_CONTAINER__\";\n private static container: Container =\n (getGlobalObject() as any)[SimpleDI.KEY] || null;\n\n private static getContainer(): Container {\n if (!SimpleDI.container) {\n (getGlobalObject() as any)[SimpleDI.KEY] = SimpleDI.container =\n new Container();\n }\n return SimpleDI.container;\n }\n\n static register(...serviceClasses: any[]): void {\n SimpleDI.getContainer().register(...serviceClasses);\n }\n\n static registerByName(name: string, serviceClass: any): void {\n SimpleDI.getContainer().registerByName(name, serviceClass);\n }\n\n static get<T = any>(name: string): T {\n return SimpleDI.getContainer().get<T>(name);\n }\n\n static getOr<T = any>(name: string, instance: T): T {\n const s = SimpleDI.getContainer().get<T>(name);\n if (!s) {\n SimpleDI.registerByName(name, instance);\n }\n return instance;\n }\n\n static getAll(): { [name: string]: any } {\n return SimpleDI.getContainer().getAll();\n }\n\n /**\n * Reset the global container, removing all registered services.\n * Primarily used in test teardown to ensure isolation between suites.\n */\n static reset(): void {\n if (SimpleDI.container) {\n SimpleDI.container = null!;\n delete (getGlobalObject() as any)[SimpleDI.KEY];\n }\n }\n\n private constructor() {}\n}\n","import { useRef } from \"react\";\nimport EventEmitter from \"eventemitter3\";\nimport { SimpleDI } from \"./internal/di\";\n\nexport const useEventEmitter = () => {\n const ref = useRef<EventEmitter | null>(null);\n if (ref.current === null) {\n let ee = SimpleDI.get<EventEmitter>(\"EE\");\n if (!ee) {\n ee = new EventEmitter();\n SimpleDI.registerByName(\"EE\", ee);\n }\n ref.current = ee;\n }\n return ref.current;\n};\n","import { useState, useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseScrollCollapseOptions {\n /**\n * The CSS `top` offset (px) of the sticky element. Used to compute the exact\n * scroll position at which the element starts sticking.\n * @default 0\n */\n stickyTop?: number;\n}\n\nexport interface UseScrollCollapseReturn {\n /** Attach to the sticky element that should collapse when it becomes stuck. */\n ref: RefObject<HTMLDivElement | null>;\n /** True when the scroll position is past the element's natural position. */\n isCollapsed: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction findScrollParent(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el.parentElement;\n while (cur && cur !== document.documentElement) {\n const oy = window.getComputedStyle(cur).overflowY;\n if (oy === \"auto\" || oy === \"scroll\" || oy === \"overlay\") return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Detects when a `position: sticky` element becomes stuck and returns\n * `isCollapsed: true`.\n *\n * Attach `ref` to the sticky element. At mount the hook snapshots the\n * element's natural scroll position as the collapse threshold, then listens\n * to the nearest scroll parent (or `window`) and compares `scrollTop` to that\n * threshold on every scroll event.\n *\n * The expand threshold is derived automatically from the element's actual\n * height change (measured via ResizeObserver). When the element collapses and\n * shrinks, the expand threshold shifts down by exactly the height reduction\n * — enough to absorb the scrollTop clamp the browser applies after the layout\n * shift, preventing an immediate re-expand feedback loop.\n *\n * ```tsx\n * const { ref, isCollapsed } = useScrollCollapse();\n *\n * <div ref={ref} className=\"sticky top-0\">\n * {isCollapsed ? <CompactHeader /> : <ExpandedHeader />}\n * </div>\n * ```\n */\nexport function useScrollCollapse({\n stickyTop = 0,\n}: UseScrollCollapseOptions = {}): UseScrollCollapseReturn {\n const [isCollapsed, setIsCollapsed] = useState(false);\n const ref = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const scrollParent = findScrollParent(el);\n const getScrollTop = () =>\n scrollParent ? scrollParent.scrollTop : window.scrollY;\n\n // Compute the collapse threshold: the scrollTop value at which the element\n // would reach `stickyTop` in the viewport and start sticking.\n //\n // rect.top – element's current top edge relative to the viewport\n // containerTop – scroll container's top edge relative to the viewport\n // rect.top - containerTop – element's offset from the container's visible top\n //\n // Adding getScrollTop() converts that viewport-relative offset into an\n // absolute position within the scrollable content. This is necessary because\n // rect.top changes as the user scrolls (it's viewport-relative), while\n // collapseAt must remain a fixed scroll position captured once at mount.\n // When the component mounts mid-scroll (e.g. SPA navigation with scroll\n // restoration, or a pre-scrolled container), getScrollTop() is non-zero and\n // the correction keeps collapseAt accurate.\n const rect = el.getBoundingClientRect();\n const containerTop = scrollParent\n ? scrollParent.getBoundingClientRect().top\n : 0;\n const collapseAt = rect.top - containerTop + getScrollTop() - stickyTop;\n\n // Track the element's current height via ResizeObserver.\n // expandedHeight is the height at mount (fully expanded state).\n // currentHeight is updated in real time as the element resizes.\n const expandedHeight = el.offsetHeight;\n let currentHeight = expandedHeight;\n\n const resizeObserver = new ResizeObserver(([entry]) => {\n currentHeight =\n entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n });\n resizeObserver.observe(el);\n\n // Local variable that mirrors React state.\n // The scroll handler is a closure captured once at mount; reading\n // `isCollapsed` (the React state) inside it would always return the\n // initial value (stale closure). This local var is mutated in-place and\n // is always current.\n let isCollapsedLocal = false;\n\n // Tracks the pending requestAnimationFrame id so we can cancel it when a\n // new scroll event arrives before the frame fires.\n let rafId = 0;\n\n const handleScroll = () => {\n // RAF-based throttle: scroll events can fire 5–10× per frame on smooth\n // scrolling devices. Cancelling the previous scheduled frame and\n // re-scheduling ensures the threshold check runs at most once per\n // animation frame (~16 ms / 60 fps), regardless of event frequency.\n cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n const scrollTop = getScrollTop();\n\n // Asymmetric expand threshold.\n //\n // When the header collapses it shrinks by Δh (e.g. 80 px → 40 px,\n // Δh = 40 px). The browser immediately clamps scrollTop downward by\n // ~Δh to prevent the viewport from jumping. If expandAt == collapseAt,\n // the clamped scrollTop would be below expandAt, triggering an instant\n // re-expand — a feedback loop.\n //\n // Fix: shift expandAt down by Δh (the measured height reduction).\n // The user then has to scroll back up by at least Δh before the header\n // reopens, exactly absorbing the clamp.\n const heightDelta = Math.max(0, expandedHeight - currentHeight);\n const expandAt = Math.max(0, collapseAt - heightDelta);\n\n if (!isCollapsedLocal && scrollTop >= collapseAt) {\n isCollapsedLocal = true;\n setIsCollapsed(true);\n } else if (isCollapsedLocal && scrollTop <= expandAt) {\n isCollapsedLocal = false;\n setIsCollapsed(false);\n }\n });\n };\n\n const target: EventTarget = scrollParent ?? window;\n target.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n target.removeEventListener(\"scroll\", handleScroll);\n resizeObserver.disconnect();\n cancelAnimationFrame(rafId);\n };\n }, [stickyTop]);\n\n return { ref, isCollapsed };\n}\n"]}
1
+ {"version":3,"sources":["../src/version.ts","../src/useBoolean.ts","../src/useSafeLayoutEffect.ts","../src/useCallbackRef.ts","../src/useClipboardRead.ts","../src/useIsMounted.ts","../src/useResizeObserver.ts","../src/useTick.ts","../src/useTickAge.ts","../src/useValueRef.ts","../src/internal/throttle.ts","../src/useThrottledResizeObserver.ts","../src/internal/di/container.ts","../src/internal/di/getGlobalObject.ts","../src/internal/di/simpleDI.ts","../src/useEventEmitter.ts","../src/useScrollCollapse.ts"],"names":["useState","useCallback","useLayoutEffect","useEffect","useRef","useMemo","EventEmitter"],"mappings":"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","file":"index.js","sourcesContent":["declare global {\n interface Window {\n __LIBERFI_VERSION__?: {\n [key: string]: string;\n };\n }\n}\nif (typeof window !== \"undefined\") {\n window.__LIBERFI_VERSION__ = window.__LIBERFI_VERSION__ || {};\n window.__LIBERFI_VERSION__[\"@liberfi.io/hooks\"] = \"0.1.87\";\n}\n\nexport default \"0.1.87\";\n","import { useCallback, useState } from \"react\";\n\nexport type UseBooleanReturn = [\n /** current state */\n boolean,\n {\n /** set state to true */\n setTrue: () => void;\n /** set state to false */\n setFalse: () => void;\n /** toggle state */\n toggle: () => void;\n },\n];\n\n/**\n * Hook to manage a boolean state\n * @param initialValue Initial value of the boolean\n * @returns\n */\nexport const useBoolean = (initialValue = false): UseBooleanReturn => {\n const [value, setValue] = useState(initialValue);\n const setTrue = useCallback(() => setValue(true), []);\n const setFalse = useCallback(() => setValue(false), []);\n const toggle = useCallback(() => setValue((v) => !v), []);\n return [value, { setTrue, setFalse, toggle }];\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\nexport const useSafeLayoutEffect = globalThis?.document\n ? useLayoutEffect\n : useEffect;\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Part of this code is taken from @chakra-ui/system ❤️\n */\nimport { useCallback, useRef } from \"react\";\nimport { useSafeLayoutEffect } from \"./useSafeLayoutEffect\";\n\n/**\n * React hook to persist any value between renders,\n * but keeps it up-to-date if it changes.\n * @param fn the function to persist\n * @param deps the function dependency list\n */\nexport function useCallbackRef<T extends (...args: any[]) => any>(\n fn: T | undefined,\n deps: React.DependencyList = [],\n): T {\n const ref = useRef(fn);\n\n useSafeLayoutEffect(() => {\n ref.current = fn;\n });\n\n return useCallback(((...args) => ref.current?.(...args)) as T, deps);\n}\n","import { useCallback } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\n/**\n * Hook that returns a stable async function to read text from the clipboard.\n * Silently ignores errors (e.g. permission denied, empty clipboard).\n *\n * @param onRead Called with the clipboard text when read succeeds and is non-empty\n */\nexport function useClipboardRead(onRead?: (text: string) => void) {\n const onReadRef = useCallbackRef(onRead);\n\n return useCallback(async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) onReadRef(text);\n } catch {\n // Clipboard access denied — silently ignore\n }\n }, [onReadRef]);\n}\n","import { useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Custom hook that determines if the component is currently mounted.\n * @example\n * ```tsx\n * const isComponentMounted = useIsMounted();\n * // Use isComponentMounted() to check if the component is currently mounted before performing certain actions.\n * ```\n */\nexport function useIsMounted(): () => boolean {\n const isMounted = useRef(false);\n\n useEffect(() => {\n isMounted.current = true;\n\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n return useCallback(() => isMounted.current, []);\n}\n","import type { RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useIsMounted } from \"./useIsMounted\";\n\n/** The size of the observed element. */\nexport type Size = {\n /** The width of the observed element. */\n width: number | undefined;\n /** The height of the observed element. */\n height: number | undefined;\n};\n\n/** The options for the ResizeObserver. */\nexport type UseResizeObserverOptions<T extends HTMLElement = HTMLElement> = {\n /** The ref of the element to observe. */\n ref: RefObject<T | null>;\n /**\n * When using `onResize`, the hook doesn't re-render on element size changes; it delegates handling to the provided callback.\n * @default undefined\n */\n onResize?: (size: Size) => void;\n /**\n * The box model to use for the ResizeObserver.\n * @default 'content-box'\n */\n box?: \"border-box\" | \"content-box\" | \"device-pixel-content-box\";\n};\n\nconst initialSize: Size = {\n width: undefined,\n height: undefined,\n};\n\n/**\n * Custom hook that observes the size of an element using the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n * @template T - The type of the element to observe.\n * @see [Documentation](https://usehooks-ts.com/react-hook/use-resize-observer)\n * @example\n * ```tsx\n * const myRef = useRef(null);\n * const { width = 0, height = 0 } = useResizeObserver({\n * ref: myRef,\n * box: 'content-box',\n * });\n *\n * <div ref={myRef}>Hello, world!</div>\n * ```\n */\nexport function useResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseResizeObserverOptions<T>,\n): Size {\n const { ref, box = \"content-box\" } = options;\n const [{ width, height }, setSize] = useState<Size>(initialSize);\n const isMounted = useIsMounted();\n const previousSize = useRef<Size>({ ...initialSize });\n const onResize = useRef<((size: Size) => void) | undefined>(undefined);\n onResize.current = options.onResize;\n\n useEffect(() => {\n if (!ref.current) return;\n\n if (typeof window === \"undefined\" || !(\"ResizeObserver\" in window)) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const boxProp =\n box === \"border-box\"\n ? \"borderBoxSize\"\n : box === \"device-pixel-content-box\"\n ? \"devicePixelContentBoxSize\"\n : \"contentBoxSize\";\n\n const newWidth = extractSize(entry, boxProp, \"inlineSize\");\n const newHeight = extractSize(entry, boxProp, \"blockSize\");\n\n const hasChanged =\n previousSize.current.width !== newWidth ||\n previousSize.current.height !== newHeight;\n\n if (hasChanged) {\n const newSize: Size = { width: newWidth, height: newHeight };\n previousSize.current.width = newWidth;\n previousSize.current.height = newHeight;\n\n if (onResize.current) {\n onResize.current(newSize);\n } else {\n if (isMounted()) {\n setSize(newSize);\n }\n }\n }\n });\n\n observer.observe(ref.current, { box });\n\n return () => {\n observer.disconnect();\n };\n }, [box, ref, isMounted]);\n\n return { width, height };\n}\n\ntype BoxSizesKey = keyof Pick<\n ResizeObserverEntry,\n \"borderBoxSize\" | \"contentBoxSize\" | \"devicePixelContentBoxSize\"\n>;\n\nfunction extractSize(\n entry: ResizeObserverEntry,\n box: BoxSizesKey,\n sizeType: keyof ResizeObserverSize,\n): number | undefined {\n if (!entry[box]) {\n if (box === \"contentBoxSize\") {\n return entry.contentRect[sizeType === \"inlineSize\" ? \"width\" : \"height\"];\n }\n return undefined;\n }\n const boxSize = (\n Array.isArray(entry[box]) ? entry[box][0] : entry[box]\n ) as ResizeObserverSize;\n return boxSize[sizeType];\n}\n","import { useEffect } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\nexport type TickEvent = {\n /** delta time in milliseconds since last tick */\n delta: number;\n /** current timestamp in milliseconds */\n now: number;\n};\n\nexport type TickCallback = (event: TickEvent) => void;\n\ntype UnsubscribeTick = () => void;\n\ntype TickSubscription = {\n /** interval in milliseconds to execute the callback */\n interval: number;\n /** last executed timestamp in milliseconds */\n lastExecuted: number;\n};\n\n/**\n * Global timer singleton using setTimeout for better performance\n */\nclass GlobalTimer {\n /** singleton instance */\n private static instance: GlobalTimer;\n\n /** setTimeout id */\n private timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n /** subscription map */\n private subscribers: Map<TickCallback, TickSubscription> = new Map();\n\n /** is timer running */\n private isRunning = false;\n\n /** internal update interval for smoothness */\n private readonly internalInterval = 200;\n\n /**\n * Get the singleton instance of the timer\n * @returns Timer instance\n */\n static getInstance(): GlobalTimer {\n if (!GlobalTimer.instance) {\n GlobalTimer.instance = new GlobalTimer();\n }\n return GlobalTimer.instance;\n }\n\n /**\n * Subscribe to the timer\n * @param callback tick callback\n * @param interval interval in milliseconds to execute the callback\n * @returns unsubscribe function\n */\n subscribe(callback: TickCallback, interval: number = 1000): UnsubscribeTick {\n this.subscribers.set(callback, {\n interval,\n lastExecuted: Date.now(),\n });\n\n // start timer if this is the first subscriber\n if (!this.isRunning) {\n this.start();\n }\n\n // return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n // stop timer if no more subscribers\n if (this.subscribers.size === 0) {\n this.stop();\n }\n };\n }\n\n private start(): void {\n if (this.isRunning) return;\n this.isRunning = true;\n this.scheduleNext();\n }\n\n private scheduleNext(): void {\n this.timeoutId = setTimeout(() => {\n const now = Date.now();\n\n // check each subscriber and execute if their interval has passed\n this.subscribers.forEach((config, callback) => {\n if (now - config.lastExecuted >= config.interval) {\n callback({ delta: now - config.lastExecuted, now });\n config.lastExecuted = now;\n }\n });\n\n // schedule next tick if still running\n if (this.isRunning) {\n this.scheduleNext();\n }\n }, this.internalInterval);\n }\n\n private stop(): void {\n this.isRunning = false;\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n}\n\n/**\n * Hook to call a callback at specified interval\n * @param callback Function to call at specified interval\n * @param interval Interval in milliseconds (default: 1000ms)\n * @returns\n */\nexport function useTick(callback: TickCallback, interval: number = 1000) {\n const callbackRef = useCallbackRef(callback);\n useEffect(\n () => GlobalTimer.getInstance().subscribe(callbackRef, interval),\n [interval],\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { TickEvent, useTick } from \"./useTick\";\n\n/**\n * Hook to get the age in milliseconds since birthday in every tick\n * @param birthday Timestamp in milliseconds or Date object (default: now)\n * @param interval Tick interval in milliseconds (default: 1000ms)\n * @returns age in milliseconds since birthday\n */\nexport function useTickAge(\n birthday: number | Date = Date.now(),\n interval: number = 1000,\n) {\n const birthdayRef = useRef(\n birthday instanceof Date ? birthday.getTime() : birthday,\n );\n // keep ref updated\n birthdayRef.current =\n birthday instanceof Date ? birthday.getTime() : birthday;\n\n const [age, setAge] = useState(Math.max(0, Date.now() - birthdayRef.current));\n\n const tickAge = useCallback(\n ({ now }: TickEvent) => setAge(Math.max(0, now - birthdayRef.current)),\n [],\n );\n\n useTick(tickAge, interval);\n\n return age;\n}\n","import { RefObject, useRef } from \"react\";\n\n/**\n * Returns an always updated ref to value\n */\nexport function useValueRef<T>(value: T): RefObject<T> {\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n return valueRef;\n}\n","/**\n * Minimal throttle with leading + trailing execution.\n * Replaces lodash-es/throttle for the single call-site in this package.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(\n fn: T,\n wait: number,\n): T {\n let lastCallTime = 0;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let lastArgs: Parameters<T> | null = null;\n\n const throttled = (...args: Parameters<T>) => {\n const now = Date.now();\n const remaining = wait - (now - lastCallTime);\n\n if (remaining <= 0) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastCallTime = now;\n fn(...args);\n } else {\n lastArgs = args;\n if (timeoutId === null) {\n timeoutId = setTimeout(() => {\n lastCallTime = Date.now();\n timeoutId = null;\n if (lastArgs) {\n fn(...lastArgs);\n lastArgs = null;\n }\n }, remaining);\n }\n }\n };\n\n return throttled as T;\n}\n","import { useMemo, useState } from \"react\";\nimport { throttle } from \"./internal/throttle\";\nimport { useResizeObserver } from \"./useResizeObserver\";\nimport type { Size, UseResizeObserverOptions } from \"./useResizeObserver\";\n\nexport type UseThrottledResizeObserverOptions<\n T extends HTMLElement = HTMLElement,\n> = Pick<UseResizeObserverOptions<T>, \"ref\" | \"box\"> & {\n throttleMs?: number;\n};\n\nexport function useThrottledResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseThrottledResizeObserverOptions<T>,\n): Size {\n const { ref, box, throttleMs = 50 } = options;\n\n const [size, setSize] = useState<Size>({\n width: undefined,\n height: undefined,\n });\n\n const onResize = useMemo(\n () => throttle(setSize, throttleMs),\n [throttleMs, setSize],\n );\n\n useResizeObserver({ ref, box, onResize });\n\n return size;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class Container {\n public constructor(private services: { [name: string]: any } = {}) {}\n\n register(...serviceClasses: any[]): void {\n serviceClasses.forEach((serviceClass) => {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.add(service);\n });\n }\n\n registerByName(name: string, serviceClass: any): void {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.addByName(name, service);\n }\n\n get<T = any>(name: string): T {\n return this.services[name];\n }\n\n getAll(): { [name: string]: any } {\n return Object.assign({}, this.services);\n }\n\n private add(service: any): any {\n return this.addByName(service.constructor.name, service);\n }\n\n /**\n * Stores the service under three keys — original, lowercase, and uppercase —\n * so that callers can retrieve it case-insensitively (e.g. \"EE\", \"ee\", \"Ee\"\n * all resolve to the same instance).\n */\n private addByName(name: string, service: any): any {\n this.services[name] = service;\n this.services[name.toLowerCase()] = service;\n this.services[name.toUpperCase()] = service;\n return this.get(name);\n }\n}\n","export const getGlobalObject = () => {\n if (typeof globalThis !== \"undefined\") {\n return globalThis;\n }\n if (typeof self !== \"undefined\") {\n return self;\n }\n if (typeof window !== \"undefined\") {\n return window;\n }\n // @ts-ignore\n if (typeof global !== \"undefined\") {\n // @ts-ignore\n return global;\n }\n throw new Error(\"cannot find the global object\");\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Container } from \"./container\";\nimport { getGlobalObject } from \"./getGlobalObject\";\n\n/**\n * Global Dependency Injection Container\n */\nexport class SimpleDI {\n private static KEY = \"__LIBERFI_CONTAINER__\";\n private static container: Container =\n (getGlobalObject() as any)[SimpleDI.KEY] || null;\n\n private static getContainer(): Container {\n if (!SimpleDI.container) {\n (getGlobalObject() as any)[SimpleDI.KEY] = SimpleDI.container =\n new Container();\n }\n return SimpleDI.container;\n }\n\n static register(...serviceClasses: any[]): void {\n SimpleDI.getContainer().register(...serviceClasses);\n }\n\n static registerByName(name: string, serviceClass: any): void {\n SimpleDI.getContainer().registerByName(name, serviceClass);\n }\n\n static get<T = any>(name: string): T {\n return SimpleDI.getContainer().get<T>(name);\n }\n\n static getOr<T = any>(name: string, instance: T): T {\n const s = SimpleDI.getContainer().get<T>(name);\n if (!s) {\n SimpleDI.registerByName(name, instance);\n }\n return instance;\n }\n\n static getAll(): { [name: string]: any } {\n return SimpleDI.getContainer().getAll();\n }\n\n /**\n * Reset the global container, removing all registered services.\n * Primarily used in test teardown to ensure isolation between suites.\n */\n static reset(): void {\n if (SimpleDI.container) {\n SimpleDI.container = null!;\n delete (getGlobalObject() as any)[SimpleDI.KEY];\n }\n }\n\n private constructor() {}\n}\n","import { useRef } from \"react\";\nimport EventEmitter from \"eventemitter3\";\nimport { SimpleDI } from \"./internal/di\";\n\nexport const useEventEmitter = () => {\n const ref = useRef<EventEmitter | null>(null);\n if (ref.current === null) {\n let ee = SimpleDI.get<EventEmitter>(\"EE\");\n if (!ee) {\n ee = new EventEmitter();\n SimpleDI.registerByName(\"EE\", ee);\n }\n ref.current = ee;\n }\n return ref.current;\n};\n","import { useState, useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseScrollCollapseOptions {\n /**\n * The CSS `top` offset (px) of the sticky element. Used to compute the exact\n * scroll position at which the element starts sticking.\n * @default 0\n */\n stickyTop?: number;\n}\n\nexport interface UseScrollCollapseReturn {\n /** Attach to the sticky element that should collapse when it becomes stuck. */\n ref: RefObject<HTMLDivElement | null>;\n /** True when the scroll position is past the element's natural position. */\n isCollapsed: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction findScrollParent(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el.parentElement;\n while (cur && cur !== document.documentElement) {\n const oy = window.getComputedStyle(cur).overflowY;\n if (oy === \"auto\" || oy === \"scroll\" || oy === \"overlay\") return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Detects when a `position: sticky` element becomes stuck and returns\n * `isCollapsed: true`.\n *\n * Attach `ref` to the sticky element. At mount the hook snapshots the\n * element's natural scroll position as the collapse threshold, then listens\n * to the nearest scroll parent (or `window`) and compares `scrollTop` to that\n * threshold on every scroll event.\n *\n * The expand threshold is derived automatically from the element's actual\n * height change (measured via ResizeObserver). When the element collapses and\n * shrinks, the expand threshold shifts down by exactly the height reduction\n * — enough to absorb the scrollTop clamp the browser applies after the layout\n * shift, preventing an immediate re-expand feedback loop.\n *\n * ```tsx\n * const { ref, isCollapsed } = useScrollCollapse();\n *\n * <div ref={ref} className=\"sticky top-0\">\n * {isCollapsed ? <CompactHeader /> : <ExpandedHeader />}\n * </div>\n * ```\n */\nexport function useScrollCollapse({\n stickyTop = 0,\n}: UseScrollCollapseOptions = {}): UseScrollCollapseReturn {\n const [isCollapsed, setIsCollapsed] = useState(false);\n const ref = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const scrollParent = findScrollParent(el);\n const getScrollTop = () =>\n scrollParent ? scrollParent.scrollTop : window.scrollY;\n\n // Compute the collapse threshold: the scrollTop value at which the element\n // would reach `stickyTop` in the viewport and start sticking.\n //\n // rect.top – element's current top edge relative to the viewport\n // containerTop – scroll container's top edge relative to the viewport\n // rect.top - containerTop – element's offset from the container's visible top\n //\n // Adding getScrollTop() converts that viewport-relative offset into an\n // absolute position within the scrollable content. This is necessary because\n // rect.top changes as the user scrolls (it's viewport-relative), while\n // collapseAt must remain a fixed scroll position captured once at mount.\n // When the component mounts mid-scroll (e.g. SPA navigation with scroll\n // restoration, or a pre-scrolled container), getScrollTop() is non-zero and\n // the correction keeps collapseAt accurate.\n const rect = el.getBoundingClientRect();\n const containerTop = scrollParent\n ? scrollParent.getBoundingClientRect().top\n : 0;\n const collapseAt = rect.top - containerTop + getScrollTop() - stickyTop;\n\n // Track the element's current height via ResizeObserver.\n // expandedHeight is the height at mount (fully expanded state).\n // currentHeight is updated in real time as the element resizes.\n const expandedHeight = el.offsetHeight;\n let currentHeight = expandedHeight;\n\n const resizeObserver = new ResizeObserver(([entry]) => {\n currentHeight =\n entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n });\n resizeObserver.observe(el);\n\n // Local variable that mirrors React state.\n // The scroll handler is a closure captured once at mount; reading\n // `isCollapsed` (the React state) inside it would always return the\n // initial value (stale closure). This local var is mutated in-place and\n // is always current.\n let isCollapsedLocal = false;\n\n // Tracks the pending requestAnimationFrame id so we can cancel it when a\n // new scroll event arrives before the frame fires.\n let rafId = 0;\n\n const handleScroll = () => {\n // RAF-based throttle: scroll events can fire 5–10× per frame on smooth\n // scrolling devices. Cancelling the previous scheduled frame and\n // re-scheduling ensures the threshold check runs at most once per\n // animation frame (~16 ms / 60 fps), regardless of event frequency.\n cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n const scrollTop = getScrollTop();\n\n // Asymmetric expand threshold.\n //\n // When the header collapses it shrinks by Δh (e.g. 80 px → 40 px,\n // Δh = 40 px). The browser immediately clamps scrollTop downward by\n // ~Δh to prevent the viewport from jumping. If expandAt == collapseAt,\n // the clamped scrollTop would be below expandAt, triggering an instant\n // re-expand — a feedback loop.\n //\n // Fix: shift expandAt down by Δh (the measured height reduction).\n // The user then has to scroll back up by at least Δh before the header\n // reopens, exactly absorbing the clamp.\n const heightDelta = Math.max(0, expandedHeight - currentHeight);\n const expandAt = Math.max(0, collapseAt - heightDelta);\n\n if (!isCollapsedLocal && scrollTop >= collapseAt) {\n isCollapsedLocal = true;\n setIsCollapsed(true);\n } else if (isCollapsedLocal && scrollTop <= expandAt) {\n isCollapsedLocal = false;\n setIsCollapsed(false);\n }\n });\n };\n\n const target: EventTarget = scrollParent ?? window;\n target.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n target.removeEventListener(\"scroll\", handleScroll);\n resizeObserver.disconnect();\n cancelAnimationFrame(rafId);\n };\n }, [stickyTop]);\n\n return { ref, isCollapsed };\n}\n"]}
package/dist/index.mjs CHANGED
@@ -4,9 +4,9 @@ import EventEmitter from 'eventemitter3';
4
4
  // src/version.ts
5
5
  if (typeof window !== "undefined") {
6
6
  window.__LIBERFI_VERSION__ = window.__LIBERFI_VERSION__ || {};
7
- window.__LIBERFI_VERSION__["@liberfi.io/hooks"] = "0.1.86";
7
+ window.__LIBERFI_VERSION__["@liberfi.io/hooks"] = "0.1.87";
8
8
  }
9
- var version_default = "0.1.86";
9
+ var version_default = "0.1.87";
10
10
  var useBoolean = (initialValue = false) => {
11
11
  const [value, setValue] = useState(initialValue);
12
12
  const setTrue = useCallback(() => setValue(true), []);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts","../src/useBoolean.ts","../src/useSafeLayoutEffect.ts","../src/useCallbackRef.ts","../src/useClipboardRead.ts","../src/useIsMounted.ts","../src/useResizeObserver.ts","../src/useTick.ts","../src/useTickAge.ts","../src/useValueRef.ts","../src/internal/throttle.ts","../src/useThrottledResizeObserver.ts","../src/internal/di/container.ts","../src/internal/di/getGlobalObject.ts","../src/internal/di/simpleDI.ts","../src/useEventEmitter.ts","../src/useScrollCollapse.ts"],"names":["useCallback","useRef","useEffect","useState"],"mappings":"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","file":"index.mjs","sourcesContent":["declare global {\n interface Window {\n __LIBERFI_VERSION__?: {\n [key: string]: string;\n };\n }\n}\nif (typeof window !== \"undefined\") {\n window.__LIBERFI_VERSION__ = window.__LIBERFI_VERSION__ || {};\n window.__LIBERFI_VERSION__[\"@liberfi.io/hooks\"] = \"0.1.86\";\n}\n\nexport default \"0.1.86\";\n","import { useCallback, useState } from \"react\";\n\nexport type UseBooleanReturn = [\n /** current state */\n boolean,\n {\n /** set state to true */\n setTrue: () => void;\n /** set state to false */\n setFalse: () => void;\n /** toggle state */\n toggle: () => void;\n },\n];\n\n/**\n * Hook to manage a boolean state\n * @param initialValue Initial value of the boolean\n * @returns\n */\nexport const useBoolean = (initialValue = false): UseBooleanReturn => {\n const [value, setValue] = useState(initialValue);\n const setTrue = useCallback(() => setValue(true), []);\n const setFalse = useCallback(() => setValue(false), []);\n const toggle = useCallback(() => setValue((v) => !v), []);\n return [value, { setTrue, setFalse, toggle }];\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\nexport const useSafeLayoutEffect = globalThis?.document\n ? useLayoutEffect\n : useEffect;\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Part of this code is taken from @chakra-ui/system ❤️\n */\nimport { useCallback, useRef } from \"react\";\nimport { useSafeLayoutEffect } from \"./useSafeLayoutEffect\";\n\n/**\n * React hook to persist any value between renders,\n * but keeps it up-to-date if it changes.\n * @param fn the function to persist\n * @param deps the function dependency list\n */\nexport function useCallbackRef<T extends (...args: any[]) => any>(\n fn: T | undefined,\n deps: React.DependencyList = [],\n): T {\n const ref = useRef(fn);\n\n useSafeLayoutEffect(() => {\n ref.current = fn;\n });\n\n return useCallback(((...args) => ref.current?.(...args)) as T, deps);\n}\n","import { useCallback } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\n/**\n * Hook that returns a stable async function to read text from the clipboard.\n * Silently ignores errors (e.g. permission denied, empty clipboard).\n *\n * @param onRead Called with the clipboard text when read succeeds and is non-empty\n */\nexport function useClipboardRead(onRead?: (text: string) => void) {\n const onReadRef = useCallbackRef(onRead);\n\n return useCallback(async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) onReadRef(text);\n } catch {\n // Clipboard access denied — silently ignore\n }\n }, [onReadRef]);\n}\n","import { useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Custom hook that determines if the component is currently mounted.\n * @example\n * ```tsx\n * const isComponentMounted = useIsMounted();\n * // Use isComponentMounted() to check if the component is currently mounted before performing certain actions.\n * ```\n */\nexport function useIsMounted(): () => boolean {\n const isMounted = useRef(false);\n\n useEffect(() => {\n isMounted.current = true;\n\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n return useCallback(() => isMounted.current, []);\n}\n","import type { RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useIsMounted } from \"./useIsMounted\";\n\n/** The size of the observed element. */\nexport type Size = {\n /** The width of the observed element. */\n width: number | undefined;\n /** The height of the observed element. */\n height: number | undefined;\n};\n\n/** The options for the ResizeObserver. */\nexport type UseResizeObserverOptions<T extends HTMLElement = HTMLElement> = {\n /** The ref of the element to observe. */\n ref: RefObject<T | null>;\n /**\n * When using `onResize`, the hook doesn't re-render on element size changes; it delegates handling to the provided callback.\n * @default undefined\n */\n onResize?: (size: Size) => void;\n /**\n * The box model to use for the ResizeObserver.\n * @default 'content-box'\n */\n box?: \"border-box\" | \"content-box\" | \"device-pixel-content-box\";\n};\n\nconst initialSize: Size = {\n width: undefined,\n height: undefined,\n};\n\n/**\n * Custom hook that observes the size of an element using the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n * @template T - The type of the element to observe.\n * @see [Documentation](https://usehooks-ts.com/react-hook/use-resize-observer)\n * @example\n * ```tsx\n * const myRef = useRef(null);\n * const { width = 0, height = 0 } = useResizeObserver({\n * ref: myRef,\n * box: 'content-box',\n * });\n *\n * <div ref={myRef}>Hello, world!</div>\n * ```\n */\nexport function useResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseResizeObserverOptions<T>,\n): Size {\n const { ref, box = \"content-box\" } = options;\n const [{ width, height }, setSize] = useState<Size>(initialSize);\n const isMounted = useIsMounted();\n const previousSize = useRef<Size>({ ...initialSize });\n const onResize = useRef<((size: Size) => void) | undefined>(undefined);\n onResize.current = options.onResize;\n\n useEffect(() => {\n if (!ref.current) return;\n\n if (typeof window === \"undefined\" || !(\"ResizeObserver\" in window)) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const boxProp =\n box === \"border-box\"\n ? \"borderBoxSize\"\n : box === \"device-pixel-content-box\"\n ? \"devicePixelContentBoxSize\"\n : \"contentBoxSize\";\n\n const newWidth = extractSize(entry, boxProp, \"inlineSize\");\n const newHeight = extractSize(entry, boxProp, \"blockSize\");\n\n const hasChanged =\n previousSize.current.width !== newWidth ||\n previousSize.current.height !== newHeight;\n\n if (hasChanged) {\n const newSize: Size = { width: newWidth, height: newHeight };\n previousSize.current.width = newWidth;\n previousSize.current.height = newHeight;\n\n if (onResize.current) {\n onResize.current(newSize);\n } else {\n if (isMounted()) {\n setSize(newSize);\n }\n }\n }\n });\n\n observer.observe(ref.current, { box });\n\n return () => {\n observer.disconnect();\n };\n }, [box, ref, isMounted]);\n\n return { width, height };\n}\n\ntype BoxSizesKey = keyof Pick<\n ResizeObserverEntry,\n \"borderBoxSize\" | \"contentBoxSize\" | \"devicePixelContentBoxSize\"\n>;\n\nfunction extractSize(\n entry: ResizeObserverEntry,\n box: BoxSizesKey,\n sizeType: keyof ResizeObserverSize,\n): number | undefined {\n if (!entry[box]) {\n if (box === \"contentBoxSize\") {\n return entry.contentRect[sizeType === \"inlineSize\" ? \"width\" : \"height\"];\n }\n return undefined;\n }\n const boxSize = (\n Array.isArray(entry[box]) ? entry[box][0] : entry[box]\n ) as ResizeObserverSize;\n return boxSize[sizeType];\n}\n","import { useEffect } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\nexport type TickEvent = {\n /** delta time in milliseconds since last tick */\n delta: number;\n /** current timestamp in milliseconds */\n now: number;\n};\n\nexport type TickCallback = (event: TickEvent) => void;\n\ntype UnsubscribeTick = () => void;\n\ntype TickSubscription = {\n /** interval in milliseconds to execute the callback */\n interval: number;\n /** last executed timestamp in milliseconds */\n lastExecuted: number;\n};\n\n/**\n * Global timer singleton using setTimeout for better performance\n */\nclass GlobalTimer {\n /** singleton instance */\n private static instance: GlobalTimer;\n\n /** setTimeout id */\n private timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n /** subscription map */\n private subscribers: Map<TickCallback, TickSubscription> = new Map();\n\n /** is timer running */\n private isRunning = false;\n\n /** internal update interval for smoothness */\n private readonly internalInterval = 200;\n\n /**\n * Get the singleton instance of the timer\n * @returns Timer instance\n */\n static getInstance(): GlobalTimer {\n if (!GlobalTimer.instance) {\n GlobalTimer.instance = new GlobalTimer();\n }\n return GlobalTimer.instance;\n }\n\n /**\n * Subscribe to the timer\n * @param callback tick callback\n * @param interval interval in milliseconds to execute the callback\n * @returns unsubscribe function\n */\n subscribe(callback: TickCallback, interval: number = 1000): UnsubscribeTick {\n this.subscribers.set(callback, {\n interval,\n lastExecuted: Date.now(),\n });\n\n // start timer if this is the first subscriber\n if (!this.isRunning) {\n this.start();\n }\n\n // return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n // stop timer if no more subscribers\n if (this.subscribers.size === 0) {\n this.stop();\n }\n };\n }\n\n private start(): void {\n if (this.isRunning) return;\n this.isRunning = true;\n this.scheduleNext();\n }\n\n private scheduleNext(): void {\n this.timeoutId = setTimeout(() => {\n const now = Date.now();\n\n // check each subscriber and execute if their interval has passed\n this.subscribers.forEach((config, callback) => {\n if (now - config.lastExecuted >= config.interval) {\n callback({ delta: now - config.lastExecuted, now });\n config.lastExecuted = now;\n }\n });\n\n // schedule next tick if still running\n if (this.isRunning) {\n this.scheduleNext();\n }\n }, this.internalInterval);\n }\n\n private stop(): void {\n this.isRunning = false;\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n}\n\n/**\n * Hook to call a callback at specified interval\n * @param callback Function to call at specified interval\n * @param interval Interval in milliseconds (default: 1000ms)\n * @returns\n */\nexport function useTick(callback: TickCallback, interval: number = 1000) {\n const callbackRef = useCallbackRef(callback);\n useEffect(\n () => GlobalTimer.getInstance().subscribe(callbackRef, interval),\n [interval],\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { TickEvent, useTick } from \"./useTick\";\n\n/**\n * Hook to get the age in milliseconds since birthday in every tick\n * @param birthday Timestamp in milliseconds or Date object (default: now)\n * @param interval Tick interval in milliseconds (default: 1000ms)\n * @returns age in milliseconds since birthday\n */\nexport function useTickAge(\n birthday: number | Date = Date.now(),\n interval: number = 1000,\n) {\n const birthdayRef = useRef(\n birthday instanceof Date ? birthday.getTime() : birthday,\n );\n // keep ref updated\n birthdayRef.current =\n birthday instanceof Date ? birthday.getTime() : birthday;\n\n const [age, setAge] = useState(Math.max(0, Date.now() - birthdayRef.current));\n\n const tickAge = useCallback(\n ({ now }: TickEvent) => setAge(Math.max(0, now - birthdayRef.current)),\n [],\n );\n\n useTick(tickAge, interval);\n\n return age;\n}\n","import { RefObject, useRef } from \"react\";\n\n/**\n * Returns an always updated ref to value\n */\nexport function useValueRef<T>(value: T): RefObject<T> {\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n return valueRef;\n}\n","/**\n * Minimal throttle with leading + trailing execution.\n * Replaces lodash-es/throttle for the single call-site in this package.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(\n fn: T,\n wait: number,\n): T {\n let lastCallTime = 0;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let lastArgs: Parameters<T> | null = null;\n\n const throttled = (...args: Parameters<T>) => {\n const now = Date.now();\n const remaining = wait - (now - lastCallTime);\n\n if (remaining <= 0) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastCallTime = now;\n fn(...args);\n } else {\n lastArgs = args;\n if (timeoutId === null) {\n timeoutId = setTimeout(() => {\n lastCallTime = Date.now();\n timeoutId = null;\n if (lastArgs) {\n fn(...lastArgs);\n lastArgs = null;\n }\n }, remaining);\n }\n }\n };\n\n return throttled as T;\n}\n","import { useMemo, useState } from \"react\";\nimport { throttle } from \"./internal/throttle\";\nimport { useResizeObserver } from \"./useResizeObserver\";\nimport type { Size, UseResizeObserverOptions } from \"./useResizeObserver\";\n\nexport type UseThrottledResizeObserverOptions<\n T extends HTMLElement = HTMLElement,\n> = Pick<UseResizeObserverOptions<T>, \"ref\" | \"box\"> & {\n throttleMs?: number;\n};\n\nexport function useThrottledResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseThrottledResizeObserverOptions<T>,\n): Size {\n const { ref, box, throttleMs = 50 } = options;\n\n const [size, setSize] = useState<Size>({\n width: undefined,\n height: undefined,\n });\n\n const onResize = useMemo(\n () => throttle(setSize, throttleMs),\n [throttleMs, setSize],\n );\n\n useResizeObserver({ ref, box, onResize });\n\n return size;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class Container {\n public constructor(private services: { [name: string]: any } = {}) {}\n\n register(...serviceClasses: any[]): void {\n serviceClasses.forEach((serviceClass) => {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.add(service);\n });\n }\n\n registerByName(name: string, serviceClass: any): void {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.addByName(name, service);\n }\n\n get<T = any>(name: string): T {\n return this.services[name];\n }\n\n getAll(): { [name: string]: any } {\n return Object.assign({}, this.services);\n }\n\n private add(service: any): any {\n return this.addByName(service.constructor.name, service);\n }\n\n /**\n * Stores the service under three keys — original, lowercase, and uppercase —\n * so that callers can retrieve it case-insensitively (e.g. \"EE\", \"ee\", \"Ee\"\n * all resolve to the same instance).\n */\n private addByName(name: string, service: any): any {\n this.services[name] = service;\n this.services[name.toLowerCase()] = service;\n this.services[name.toUpperCase()] = service;\n return this.get(name);\n }\n}\n","export const getGlobalObject = () => {\n if (typeof globalThis !== \"undefined\") {\n return globalThis;\n }\n if (typeof self !== \"undefined\") {\n return self;\n }\n if (typeof window !== \"undefined\") {\n return window;\n }\n // @ts-ignore\n if (typeof global !== \"undefined\") {\n // @ts-ignore\n return global;\n }\n throw new Error(\"cannot find the global object\");\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Container } from \"./container\";\nimport { getGlobalObject } from \"./getGlobalObject\";\n\n/**\n * Global Dependency Injection Container\n */\nexport class SimpleDI {\n private static KEY = \"__LIBERFI_CONTAINER__\";\n private static container: Container =\n (getGlobalObject() as any)[SimpleDI.KEY] || null;\n\n private static getContainer(): Container {\n if (!SimpleDI.container) {\n (getGlobalObject() as any)[SimpleDI.KEY] = SimpleDI.container =\n new Container();\n }\n return SimpleDI.container;\n }\n\n static register(...serviceClasses: any[]): void {\n SimpleDI.getContainer().register(...serviceClasses);\n }\n\n static registerByName(name: string, serviceClass: any): void {\n SimpleDI.getContainer().registerByName(name, serviceClass);\n }\n\n static get<T = any>(name: string): T {\n return SimpleDI.getContainer().get<T>(name);\n }\n\n static getOr<T = any>(name: string, instance: T): T {\n const s = SimpleDI.getContainer().get<T>(name);\n if (!s) {\n SimpleDI.registerByName(name, instance);\n }\n return instance;\n }\n\n static getAll(): { [name: string]: any } {\n return SimpleDI.getContainer().getAll();\n }\n\n /**\n * Reset the global container, removing all registered services.\n * Primarily used in test teardown to ensure isolation between suites.\n */\n static reset(): void {\n if (SimpleDI.container) {\n SimpleDI.container = null!;\n delete (getGlobalObject() as any)[SimpleDI.KEY];\n }\n }\n\n private constructor() {}\n}\n","import { useRef } from \"react\";\nimport EventEmitter from \"eventemitter3\";\nimport { SimpleDI } from \"./internal/di\";\n\nexport const useEventEmitter = () => {\n const ref = useRef<EventEmitter | null>(null);\n if (ref.current === null) {\n let ee = SimpleDI.get<EventEmitter>(\"EE\");\n if (!ee) {\n ee = new EventEmitter();\n SimpleDI.registerByName(\"EE\", ee);\n }\n ref.current = ee;\n }\n return ref.current;\n};\n","import { useState, useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseScrollCollapseOptions {\n /**\n * The CSS `top` offset (px) of the sticky element. Used to compute the exact\n * scroll position at which the element starts sticking.\n * @default 0\n */\n stickyTop?: number;\n}\n\nexport interface UseScrollCollapseReturn {\n /** Attach to the sticky element that should collapse when it becomes stuck. */\n ref: RefObject<HTMLDivElement | null>;\n /** True when the scroll position is past the element's natural position. */\n isCollapsed: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction findScrollParent(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el.parentElement;\n while (cur && cur !== document.documentElement) {\n const oy = window.getComputedStyle(cur).overflowY;\n if (oy === \"auto\" || oy === \"scroll\" || oy === \"overlay\") return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Detects when a `position: sticky` element becomes stuck and returns\n * `isCollapsed: true`.\n *\n * Attach `ref` to the sticky element. At mount the hook snapshots the\n * element's natural scroll position as the collapse threshold, then listens\n * to the nearest scroll parent (or `window`) and compares `scrollTop` to that\n * threshold on every scroll event.\n *\n * The expand threshold is derived automatically from the element's actual\n * height change (measured via ResizeObserver). When the element collapses and\n * shrinks, the expand threshold shifts down by exactly the height reduction\n * — enough to absorb the scrollTop clamp the browser applies after the layout\n * shift, preventing an immediate re-expand feedback loop.\n *\n * ```tsx\n * const { ref, isCollapsed } = useScrollCollapse();\n *\n * <div ref={ref} className=\"sticky top-0\">\n * {isCollapsed ? <CompactHeader /> : <ExpandedHeader />}\n * </div>\n * ```\n */\nexport function useScrollCollapse({\n stickyTop = 0,\n}: UseScrollCollapseOptions = {}): UseScrollCollapseReturn {\n const [isCollapsed, setIsCollapsed] = useState(false);\n const ref = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const scrollParent = findScrollParent(el);\n const getScrollTop = () =>\n scrollParent ? scrollParent.scrollTop : window.scrollY;\n\n // Compute the collapse threshold: the scrollTop value at which the element\n // would reach `stickyTop` in the viewport and start sticking.\n //\n // rect.top – element's current top edge relative to the viewport\n // containerTop – scroll container's top edge relative to the viewport\n // rect.top - containerTop – element's offset from the container's visible top\n //\n // Adding getScrollTop() converts that viewport-relative offset into an\n // absolute position within the scrollable content. This is necessary because\n // rect.top changes as the user scrolls (it's viewport-relative), while\n // collapseAt must remain a fixed scroll position captured once at mount.\n // When the component mounts mid-scroll (e.g. SPA navigation with scroll\n // restoration, or a pre-scrolled container), getScrollTop() is non-zero and\n // the correction keeps collapseAt accurate.\n const rect = el.getBoundingClientRect();\n const containerTop = scrollParent\n ? scrollParent.getBoundingClientRect().top\n : 0;\n const collapseAt = rect.top - containerTop + getScrollTop() - stickyTop;\n\n // Track the element's current height via ResizeObserver.\n // expandedHeight is the height at mount (fully expanded state).\n // currentHeight is updated in real time as the element resizes.\n const expandedHeight = el.offsetHeight;\n let currentHeight = expandedHeight;\n\n const resizeObserver = new ResizeObserver(([entry]) => {\n currentHeight =\n entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n });\n resizeObserver.observe(el);\n\n // Local variable that mirrors React state.\n // The scroll handler is a closure captured once at mount; reading\n // `isCollapsed` (the React state) inside it would always return the\n // initial value (stale closure). This local var is mutated in-place and\n // is always current.\n let isCollapsedLocal = false;\n\n // Tracks the pending requestAnimationFrame id so we can cancel it when a\n // new scroll event arrives before the frame fires.\n let rafId = 0;\n\n const handleScroll = () => {\n // RAF-based throttle: scroll events can fire 5–10× per frame on smooth\n // scrolling devices. Cancelling the previous scheduled frame and\n // re-scheduling ensures the threshold check runs at most once per\n // animation frame (~16 ms / 60 fps), regardless of event frequency.\n cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n const scrollTop = getScrollTop();\n\n // Asymmetric expand threshold.\n //\n // When the header collapses it shrinks by Δh (e.g. 80 px → 40 px,\n // Δh = 40 px). The browser immediately clamps scrollTop downward by\n // ~Δh to prevent the viewport from jumping. If expandAt == collapseAt,\n // the clamped scrollTop would be below expandAt, triggering an instant\n // re-expand — a feedback loop.\n //\n // Fix: shift expandAt down by Δh (the measured height reduction).\n // The user then has to scroll back up by at least Δh before the header\n // reopens, exactly absorbing the clamp.\n const heightDelta = Math.max(0, expandedHeight - currentHeight);\n const expandAt = Math.max(0, collapseAt - heightDelta);\n\n if (!isCollapsedLocal && scrollTop >= collapseAt) {\n isCollapsedLocal = true;\n setIsCollapsed(true);\n } else if (isCollapsedLocal && scrollTop <= expandAt) {\n isCollapsedLocal = false;\n setIsCollapsed(false);\n }\n });\n };\n\n const target: EventTarget = scrollParent ?? window;\n target.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n target.removeEventListener(\"scroll\", handleScroll);\n resizeObserver.disconnect();\n cancelAnimationFrame(rafId);\n };\n }, [stickyTop]);\n\n return { ref, isCollapsed };\n}\n"]}
1
+ {"version":3,"sources":["../src/version.ts","../src/useBoolean.ts","../src/useSafeLayoutEffect.ts","../src/useCallbackRef.ts","../src/useClipboardRead.ts","../src/useIsMounted.ts","../src/useResizeObserver.ts","../src/useTick.ts","../src/useTickAge.ts","../src/useValueRef.ts","../src/internal/throttle.ts","../src/useThrottledResizeObserver.ts","../src/internal/di/container.ts","../src/internal/di/getGlobalObject.ts","../src/internal/di/simpleDI.ts","../src/useEventEmitter.ts","../src/useScrollCollapse.ts"],"names":["useCallback","useRef","useEffect","useState"],"mappings":"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","file":"index.mjs","sourcesContent":["declare global {\n interface Window {\n __LIBERFI_VERSION__?: {\n [key: string]: string;\n };\n }\n}\nif (typeof window !== \"undefined\") {\n window.__LIBERFI_VERSION__ = window.__LIBERFI_VERSION__ || {};\n window.__LIBERFI_VERSION__[\"@liberfi.io/hooks\"] = \"0.1.87\";\n}\n\nexport default \"0.1.87\";\n","import { useCallback, useState } from \"react\";\n\nexport type UseBooleanReturn = [\n /** current state */\n boolean,\n {\n /** set state to true */\n setTrue: () => void;\n /** set state to false */\n setFalse: () => void;\n /** toggle state */\n toggle: () => void;\n },\n];\n\n/**\n * Hook to manage a boolean state\n * @param initialValue Initial value of the boolean\n * @returns\n */\nexport const useBoolean = (initialValue = false): UseBooleanReturn => {\n const [value, setValue] = useState(initialValue);\n const setTrue = useCallback(() => setValue(true), []);\n const setFalse = useCallback(() => setValue(false), []);\n const toggle = useCallback(() => setValue((v) => !v), []);\n return [value, { setTrue, setFalse, toggle }];\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\nexport const useSafeLayoutEffect = globalThis?.document\n ? useLayoutEffect\n : useEffect;\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Part of this code is taken from @chakra-ui/system ❤️\n */\nimport { useCallback, useRef } from \"react\";\nimport { useSafeLayoutEffect } from \"./useSafeLayoutEffect\";\n\n/**\n * React hook to persist any value between renders,\n * but keeps it up-to-date if it changes.\n * @param fn the function to persist\n * @param deps the function dependency list\n */\nexport function useCallbackRef<T extends (...args: any[]) => any>(\n fn: T | undefined,\n deps: React.DependencyList = [],\n): T {\n const ref = useRef(fn);\n\n useSafeLayoutEffect(() => {\n ref.current = fn;\n });\n\n return useCallback(((...args) => ref.current?.(...args)) as T, deps);\n}\n","import { useCallback } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\n/**\n * Hook that returns a stable async function to read text from the clipboard.\n * Silently ignores errors (e.g. permission denied, empty clipboard).\n *\n * @param onRead Called with the clipboard text when read succeeds and is non-empty\n */\nexport function useClipboardRead(onRead?: (text: string) => void) {\n const onReadRef = useCallbackRef(onRead);\n\n return useCallback(async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) onReadRef(text);\n } catch {\n // Clipboard access denied — silently ignore\n }\n }, [onReadRef]);\n}\n","import { useCallback, useEffect, useRef } from \"react\";\n\n/**\n * Custom hook that determines if the component is currently mounted.\n * @example\n * ```tsx\n * const isComponentMounted = useIsMounted();\n * // Use isComponentMounted() to check if the component is currently mounted before performing certain actions.\n * ```\n */\nexport function useIsMounted(): () => boolean {\n const isMounted = useRef(false);\n\n useEffect(() => {\n isMounted.current = true;\n\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n return useCallback(() => isMounted.current, []);\n}\n","import type { RefObject } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { useIsMounted } from \"./useIsMounted\";\n\n/** The size of the observed element. */\nexport type Size = {\n /** The width of the observed element. */\n width: number | undefined;\n /** The height of the observed element. */\n height: number | undefined;\n};\n\n/** The options for the ResizeObserver. */\nexport type UseResizeObserverOptions<T extends HTMLElement = HTMLElement> = {\n /** The ref of the element to observe. */\n ref: RefObject<T | null>;\n /**\n * When using `onResize`, the hook doesn't re-render on element size changes; it delegates handling to the provided callback.\n * @default undefined\n */\n onResize?: (size: Size) => void;\n /**\n * The box model to use for the ResizeObserver.\n * @default 'content-box'\n */\n box?: \"border-box\" | \"content-box\" | \"device-pixel-content-box\";\n};\n\nconst initialSize: Size = {\n width: undefined,\n height: undefined,\n};\n\n/**\n * Custom hook that observes the size of an element using the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n * @template T - The type of the element to observe.\n * @see [Documentation](https://usehooks-ts.com/react-hook/use-resize-observer)\n * @example\n * ```tsx\n * const myRef = useRef(null);\n * const { width = 0, height = 0 } = useResizeObserver({\n * ref: myRef,\n * box: 'content-box',\n * });\n *\n * <div ref={myRef}>Hello, world!</div>\n * ```\n */\nexport function useResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseResizeObserverOptions<T>,\n): Size {\n const { ref, box = \"content-box\" } = options;\n const [{ width, height }, setSize] = useState<Size>(initialSize);\n const isMounted = useIsMounted();\n const previousSize = useRef<Size>({ ...initialSize });\n const onResize = useRef<((size: Size) => void) | undefined>(undefined);\n onResize.current = options.onResize;\n\n useEffect(() => {\n if (!ref.current) return;\n\n if (typeof window === \"undefined\" || !(\"ResizeObserver\" in window)) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const boxProp =\n box === \"border-box\"\n ? \"borderBoxSize\"\n : box === \"device-pixel-content-box\"\n ? \"devicePixelContentBoxSize\"\n : \"contentBoxSize\";\n\n const newWidth = extractSize(entry, boxProp, \"inlineSize\");\n const newHeight = extractSize(entry, boxProp, \"blockSize\");\n\n const hasChanged =\n previousSize.current.width !== newWidth ||\n previousSize.current.height !== newHeight;\n\n if (hasChanged) {\n const newSize: Size = { width: newWidth, height: newHeight };\n previousSize.current.width = newWidth;\n previousSize.current.height = newHeight;\n\n if (onResize.current) {\n onResize.current(newSize);\n } else {\n if (isMounted()) {\n setSize(newSize);\n }\n }\n }\n });\n\n observer.observe(ref.current, { box });\n\n return () => {\n observer.disconnect();\n };\n }, [box, ref, isMounted]);\n\n return { width, height };\n}\n\ntype BoxSizesKey = keyof Pick<\n ResizeObserverEntry,\n \"borderBoxSize\" | \"contentBoxSize\" | \"devicePixelContentBoxSize\"\n>;\n\nfunction extractSize(\n entry: ResizeObserverEntry,\n box: BoxSizesKey,\n sizeType: keyof ResizeObserverSize,\n): number | undefined {\n if (!entry[box]) {\n if (box === \"contentBoxSize\") {\n return entry.contentRect[sizeType === \"inlineSize\" ? \"width\" : \"height\"];\n }\n return undefined;\n }\n const boxSize = (\n Array.isArray(entry[box]) ? entry[box][0] : entry[box]\n ) as ResizeObserverSize;\n return boxSize[sizeType];\n}\n","import { useEffect } from \"react\";\nimport { useCallbackRef } from \"./useCallbackRef\";\n\nexport type TickEvent = {\n /** delta time in milliseconds since last tick */\n delta: number;\n /** current timestamp in milliseconds */\n now: number;\n};\n\nexport type TickCallback = (event: TickEvent) => void;\n\ntype UnsubscribeTick = () => void;\n\ntype TickSubscription = {\n /** interval in milliseconds to execute the callback */\n interval: number;\n /** last executed timestamp in milliseconds */\n lastExecuted: number;\n};\n\n/**\n * Global timer singleton using setTimeout for better performance\n */\nclass GlobalTimer {\n /** singleton instance */\n private static instance: GlobalTimer;\n\n /** setTimeout id */\n private timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n /** subscription map */\n private subscribers: Map<TickCallback, TickSubscription> = new Map();\n\n /** is timer running */\n private isRunning = false;\n\n /** internal update interval for smoothness */\n private readonly internalInterval = 200;\n\n /**\n * Get the singleton instance of the timer\n * @returns Timer instance\n */\n static getInstance(): GlobalTimer {\n if (!GlobalTimer.instance) {\n GlobalTimer.instance = new GlobalTimer();\n }\n return GlobalTimer.instance;\n }\n\n /**\n * Subscribe to the timer\n * @param callback tick callback\n * @param interval interval in milliseconds to execute the callback\n * @returns unsubscribe function\n */\n subscribe(callback: TickCallback, interval: number = 1000): UnsubscribeTick {\n this.subscribers.set(callback, {\n interval,\n lastExecuted: Date.now(),\n });\n\n // start timer if this is the first subscriber\n if (!this.isRunning) {\n this.start();\n }\n\n // return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n // stop timer if no more subscribers\n if (this.subscribers.size === 0) {\n this.stop();\n }\n };\n }\n\n private start(): void {\n if (this.isRunning) return;\n this.isRunning = true;\n this.scheduleNext();\n }\n\n private scheduleNext(): void {\n this.timeoutId = setTimeout(() => {\n const now = Date.now();\n\n // check each subscriber and execute if their interval has passed\n this.subscribers.forEach((config, callback) => {\n if (now - config.lastExecuted >= config.interval) {\n callback({ delta: now - config.lastExecuted, now });\n config.lastExecuted = now;\n }\n });\n\n // schedule next tick if still running\n if (this.isRunning) {\n this.scheduleNext();\n }\n }, this.internalInterval);\n }\n\n private stop(): void {\n this.isRunning = false;\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n}\n\n/**\n * Hook to call a callback at specified interval\n * @param callback Function to call at specified interval\n * @param interval Interval in milliseconds (default: 1000ms)\n * @returns\n */\nexport function useTick(callback: TickCallback, interval: number = 1000) {\n const callbackRef = useCallbackRef(callback);\n useEffect(\n () => GlobalTimer.getInstance().subscribe(callbackRef, interval),\n [interval],\n );\n}\n","import { useCallback, useRef, useState } from \"react\";\nimport { TickEvent, useTick } from \"./useTick\";\n\n/**\n * Hook to get the age in milliseconds since birthday in every tick\n * @param birthday Timestamp in milliseconds or Date object (default: now)\n * @param interval Tick interval in milliseconds (default: 1000ms)\n * @returns age in milliseconds since birthday\n */\nexport function useTickAge(\n birthday: number | Date = Date.now(),\n interval: number = 1000,\n) {\n const birthdayRef = useRef(\n birthday instanceof Date ? birthday.getTime() : birthday,\n );\n // keep ref updated\n birthdayRef.current =\n birthday instanceof Date ? birthday.getTime() : birthday;\n\n const [age, setAge] = useState(Math.max(0, Date.now() - birthdayRef.current));\n\n const tickAge = useCallback(\n ({ now }: TickEvent) => setAge(Math.max(0, now - birthdayRef.current)),\n [],\n );\n\n useTick(tickAge, interval);\n\n return age;\n}\n","import { RefObject, useRef } from \"react\";\n\n/**\n * Returns an always updated ref to value\n */\nexport function useValueRef<T>(value: T): RefObject<T> {\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n return valueRef;\n}\n","/**\n * Minimal throttle with leading + trailing execution.\n * Replaces lodash-es/throttle for the single call-site in this package.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function throttle<T extends (...args: any[]) => void>(\n fn: T,\n wait: number,\n): T {\n let lastCallTime = 0;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let lastArgs: Parameters<T> | null = null;\n\n const throttled = (...args: Parameters<T>) => {\n const now = Date.now();\n const remaining = wait - (now - lastCallTime);\n\n if (remaining <= 0) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n lastCallTime = now;\n fn(...args);\n } else {\n lastArgs = args;\n if (timeoutId === null) {\n timeoutId = setTimeout(() => {\n lastCallTime = Date.now();\n timeoutId = null;\n if (lastArgs) {\n fn(...lastArgs);\n lastArgs = null;\n }\n }, remaining);\n }\n }\n };\n\n return throttled as T;\n}\n","import { useMemo, useState } from \"react\";\nimport { throttle } from \"./internal/throttle\";\nimport { useResizeObserver } from \"./useResizeObserver\";\nimport type { Size, UseResizeObserverOptions } from \"./useResizeObserver\";\n\nexport type UseThrottledResizeObserverOptions<\n T extends HTMLElement = HTMLElement,\n> = Pick<UseResizeObserverOptions<T>, \"ref\" | \"box\"> & {\n throttleMs?: number;\n};\n\nexport function useThrottledResizeObserver<T extends HTMLElement = HTMLElement>(\n options: UseThrottledResizeObserverOptions<T>,\n): Size {\n const { ref, box, throttleMs = 50 } = options;\n\n const [size, setSize] = useState<Size>({\n width: undefined,\n height: undefined,\n });\n\n const onResize = useMemo(\n () => throttle(setSize, throttleMs),\n [throttleMs, setSize],\n );\n\n useResizeObserver({ ref, box, onResize });\n\n return size;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class Container {\n public constructor(private services: { [name: string]: any } = {}) {}\n\n register(...serviceClasses: any[]): void {\n serviceClasses.forEach((serviceClass) => {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.add(service);\n });\n }\n\n registerByName(name: string, serviceClass: any): void {\n let service = serviceClass;\n if (service instanceof Function) {\n service = new serviceClass();\n }\n this.addByName(name, service);\n }\n\n get<T = any>(name: string): T {\n return this.services[name];\n }\n\n getAll(): { [name: string]: any } {\n return Object.assign({}, this.services);\n }\n\n private add(service: any): any {\n return this.addByName(service.constructor.name, service);\n }\n\n /**\n * Stores the service under three keys — original, lowercase, and uppercase —\n * so that callers can retrieve it case-insensitively (e.g. \"EE\", \"ee\", \"Ee\"\n * all resolve to the same instance).\n */\n private addByName(name: string, service: any): any {\n this.services[name] = service;\n this.services[name.toLowerCase()] = service;\n this.services[name.toUpperCase()] = service;\n return this.get(name);\n }\n}\n","export const getGlobalObject = () => {\n if (typeof globalThis !== \"undefined\") {\n return globalThis;\n }\n if (typeof self !== \"undefined\") {\n return self;\n }\n if (typeof window !== \"undefined\") {\n return window;\n }\n // @ts-ignore\n if (typeof global !== \"undefined\") {\n // @ts-ignore\n return global;\n }\n throw new Error(\"cannot find the global object\");\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Container } from \"./container\";\nimport { getGlobalObject } from \"./getGlobalObject\";\n\n/**\n * Global Dependency Injection Container\n */\nexport class SimpleDI {\n private static KEY = \"__LIBERFI_CONTAINER__\";\n private static container: Container =\n (getGlobalObject() as any)[SimpleDI.KEY] || null;\n\n private static getContainer(): Container {\n if (!SimpleDI.container) {\n (getGlobalObject() as any)[SimpleDI.KEY] = SimpleDI.container =\n new Container();\n }\n return SimpleDI.container;\n }\n\n static register(...serviceClasses: any[]): void {\n SimpleDI.getContainer().register(...serviceClasses);\n }\n\n static registerByName(name: string, serviceClass: any): void {\n SimpleDI.getContainer().registerByName(name, serviceClass);\n }\n\n static get<T = any>(name: string): T {\n return SimpleDI.getContainer().get<T>(name);\n }\n\n static getOr<T = any>(name: string, instance: T): T {\n const s = SimpleDI.getContainer().get<T>(name);\n if (!s) {\n SimpleDI.registerByName(name, instance);\n }\n return instance;\n }\n\n static getAll(): { [name: string]: any } {\n return SimpleDI.getContainer().getAll();\n }\n\n /**\n * Reset the global container, removing all registered services.\n * Primarily used in test teardown to ensure isolation between suites.\n */\n static reset(): void {\n if (SimpleDI.container) {\n SimpleDI.container = null!;\n delete (getGlobalObject() as any)[SimpleDI.KEY];\n }\n }\n\n private constructor() {}\n}\n","import { useRef } from \"react\";\nimport EventEmitter from \"eventemitter3\";\nimport { SimpleDI } from \"./internal/di\";\n\nexport const useEventEmitter = () => {\n const ref = useRef<EventEmitter | null>(null);\n if (ref.current === null) {\n let ee = SimpleDI.get<EventEmitter>(\"EE\");\n if (!ee) {\n ee = new EventEmitter();\n SimpleDI.registerByName(\"EE\", ee);\n }\n ref.current = ee;\n }\n return ref.current;\n};\n","import { useState, useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface UseScrollCollapseOptions {\n /**\n * The CSS `top` offset (px) of the sticky element. Used to compute the exact\n * scroll position at which the element starts sticking.\n * @default 0\n */\n stickyTop?: number;\n}\n\nexport interface UseScrollCollapseReturn {\n /** Attach to the sticky element that should collapse when it becomes stuck. */\n ref: RefObject<HTMLDivElement | null>;\n /** True when the scroll position is past the element's natural position. */\n isCollapsed: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction findScrollParent(el: HTMLElement): HTMLElement | null {\n let cur: HTMLElement | null = el.parentElement;\n while (cur && cur !== document.documentElement) {\n const oy = window.getComputedStyle(cur).overflowY;\n if (oy === \"auto\" || oy === \"scroll\" || oy === \"overlay\") return cur;\n cur = cur.parentElement;\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Detects when a `position: sticky` element becomes stuck and returns\n * `isCollapsed: true`.\n *\n * Attach `ref` to the sticky element. At mount the hook snapshots the\n * element's natural scroll position as the collapse threshold, then listens\n * to the nearest scroll parent (or `window`) and compares `scrollTop` to that\n * threshold on every scroll event.\n *\n * The expand threshold is derived automatically from the element's actual\n * height change (measured via ResizeObserver). When the element collapses and\n * shrinks, the expand threshold shifts down by exactly the height reduction\n * — enough to absorb the scrollTop clamp the browser applies after the layout\n * shift, preventing an immediate re-expand feedback loop.\n *\n * ```tsx\n * const { ref, isCollapsed } = useScrollCollapse();\n *\n * <div ref={ref} className=\"sticky top-0\">\n * {isCollapsed ? <CompactHeader /> : <ExpandedHeader />}\n * </div>\n * ```\n */\nexport function useScrollCollapse({\n stickyTop = 0,\n}: UseScrollCollapseOptions = {}): UseScrollCollapseReturn {\n const [isCollapsed, setIsCollapsed] = useState(false);\n const ref = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const scrollParent = findScrollParent(el);\n const getScrollTop = () =>\n scrollParent ? scrollParent.scrollTop : window.scrollY;\n\n // Compute the collapse threshold: the scrollTop value at which the element\n // would reach `stickyTop` in the viewport and start sticking.\n //\n // rect.top – element's current top edge relative to the viewport\n // containerTop – scroll container's top edge relative to the viewport\n // rect.top - containerTop – element's offset from the container's visible top\n //\n // Adding getScrollTop() converts that viewport-relative offset into an\n // absolute position within the scrollable content. This is necessary because\n // rect.top changes as the user scrolls (it's viewport-relative), while\n // collapseAt must remain a fixed scroll position captured once at mount.\n // When the component mounts mid-scroll (e.g. SPA navigation with scroll\n // restoration, or a pre-scrolled container), getScrollTop() is non-zero and\n // the correction keeps collapseAt accurate.\n const rect = el.getBoundingClientRect();\n const containerTop = scrollParent\n ? scrollParent.getBoundingClientRect().top\n : 0;\n const collapseAt = rect.top - containerTop + getScrollTop() - stickyTop;\n\n // Track the element's current height via ResizeObserver.\n // expandedHeight is the height at mount (fully expanded state).\n // currentHeight is updated in real time as the element resizes.\n const expandedHeight = el.offsetHeight;\n let currentHeight = expandedHeight;\n\n const resizeObserver = new ResizeObserver(([entry]) => {\n currentHeight =\n entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n });\n resizeObserver.observe(el);\n\n // Local variable that mirrors React state.\n // The scroll handler is a closure captured once at mount; reading\n // `isCollapsed` (the React state) inside it would always return the\n // initial value (stale closure). This local var is mutated in-place and\n // is always current.\n let isCollapsedLocal = false;\n\n // Tracks the pending requestAnimationFrame id so we can cancel it when a\n // new scroll event arrives before the frame fires.\n let rafId = 0;\n\n const handleScroll = () => {\n // RAF-based throttle: scroll events can fire 5–10× per frame on smooth\n // scrolling devices. Cancelling the previous scheduled frame and\n // re-scheduling ensures the threshold check runs at most once per\n // animation frame (~16 ms / 60 fps), regardless of event frequency.\n cancelAnimationFrame(rafId);\n rafId = requestAnimationFrame(() => {\n const scrollTop = getScrollTop();\n\n // Asymmetric expand threshold.\n //\n // When the header collapses it shrinks by Δh (e.g. 80 px → 40 px,\n // Δh = 40 px). The browser immediately clamps scrollTop downward by\n // ~Δh to prevent the viewport from jumping. If expandAt == collapseAt,\n // the clamped scrollTop would be below expandAt, triggering an instant\n // re-expand — a feedback loop.\n //\n // Fix: shift expandAt down by Δh (the measured height reduction).\n // The user then has to scroll back up by at least Δh before the header\n // reopens, exactly absorbing the clamp.\n const heightDelta = Math.max(0, expandedHeight - currentHeight);\n const expandAt = Math.max(0, collapseAt - heightDelta);\n\n if (!isCollapsedLocal && scrollTop >= collapseAt) {\n isCollapsedLocal = true;\n setIsCollapsed(true);\n } else if (isCollapsedLocal && scrollTop <= expandAt) {\n isCollapsedLocal = false;\n setIsCollapsed(false);\n }\n });\n };\n\n const target: EventTarget = scrollParent ?? window;\n target.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n target.removeEventListener(\"scroll\", handleScroll);\n resizeObserver.disconnect();\n cancelAnimationFrame(rafId);\n };\n }, [stickyTop]);\n\n return { ref, isCollapsed };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liberfi.io/hooks",
3
- "version": "0.1.86",
3
+ "version": "0.1.87",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -40,7 +40,7 @@
40
40
  "ts-jest": "^29.4.6",
41
41
  "tsup": "^8.5.0",
42
42
  "typescript": "^5.9.2",
43
- "tsconfig": "0.1.77"
43
+ "tsconfig": "0.1.78"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"