import { useCallback, useEffect, useState } from "react";
interface Options {
rootMargin?: string;
threshold?: number;
}
import { useCallback, useEffect, useRef, useState } from 'react';
export function usePaginatedFetch(fetchPage, { pageSize = 20 } = {}) {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
import { useMemo } from "react";
export type SortDir = "asc" | "desc";
export interface SortConfig<T> {
key: keyof T;
dir: SortDir;
export interface Todo {
id: string;
title: string;
done: boolean;
pending: boolean;
}
export interface CartItem {
sku: string;
name: string;
unitPrice: number; // cents
qty: number;
}
export const required = (msg = 'This field is required') => (value) =>
value && value.trim() !== '' ? '' : msg;
export const minLength = (n, msg) => (value) =>
value && value.length >= n ? '' : msg || `Must be at least ${n} characters`;
import { useState, useRef, useEffect, useCallback } from 'react';
export function useOnScreen(options = {}) {
const [node, setNode] = useState(null);
const [isIntersecting, setIsIntersecting] = useState(false);
import { useEffect, useState } from "react";
export function useDebouncedValue<T>(value: T, delay = 300): T {
const [debounced, setDebounced] = useState<T>(value);
useEffect(() => {