or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-operations.mddata-structures.mddom-interactions.mdeffects.mdindex.mdperformance.mdspecialized-hooks.mdstate-management.mdstorage.mdtimers.md
tile.json

specialized-hooks.mddocs/

Specialized Hooks

Advanced and specialized hooks for complex use cases including table management, virtual lists, WebSocket connections, browser APIs, drag & drop, and developer tools.

Capabilities

Table Management

useAntdTable

Comprehensive table management for Ant Design with forms, pagination, and search functionality.

/**
 * Manages Ant Design Table with forms and pagination
 * @param service - Async function that returns table data
 * @param options - Configuration options for table behavior
 * @returns Object with table props, search controls, and request state
 */
function useAntdTable<TData extends Data, TParams extends Params>(
  service: Service<TData, TParams>,
  options?: AntdTableOptions<TData, TParams>
): AntdTableResult<TData, TParams>;

// Data structure for paginated results
interface Data {
  list: any[];
  total: number;
}

type Params = [any, any]; // [pagination, formData]

// Service function type
type Service<TData extends Data, TParams extends Params> = (...args: TParams) => Promise<TData>;

// Result interface
interface AntdTableResult<TData extends Data, TParams extends Params> {
  // Table props for Ant Design Table component
  tableProps: {
    dataSource: TData['list'];
    loading: boolean;
    onChange: (pagination: any, filters?: any, sorter?: any) => void;
    pagination: any;
  };
  
  // Search functionality
  search: {
    type: 'simple' | 'advance';
    changeType: () => void;
    submit: () => void;
    reset: () => void;
  };
  
  // Request controls (inherited from useRequest)
  loading: boolean;
  data?: TData;
  error?: Error;
  params?: TParams;
  run: (...params: TParams) => void;
  runAsync: (...params: TParams) => Promise<TData>;
  refresh: () => void;
  refreshAsync: () => Promise<TData>;
  cancel: () => void;
  mutate: (data?: TData) => void;
}

interface AntdTableOptions<TData extends Data, TParams extends Params> {
  // Pagination
  defaultPageSize?: number;
  
  // Form integration
  form?: any; // Ant Design Form instance
  defaultType?: 'simple' | 'advance';
  
  // Search behavior
  manual?: boolean;
  refreshDeps?: any[];
  
  // Data processing
  formatResult?: (data: any) => TData;
  
  // Callbacks
  onSuccess?: (data: TData, params: TParams) => void;
  onError?: (error: Error, params: TParams) => void;
}

Usage Example:

import { useAntdTable } from 'ahooks';
import { Table, Form, Input, Button, Card } from 'antd';
import { useState } from 'react';

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
  createdAt: string;
}

interface UserSearchParams {
  name?: string;
  email?: string;
  role?: string;
}

function UserTable() {
  const [form] = Form.useForm();
  
  // Service function that returns paginated data
  const getUserList = async (
    { current, pageSize }: { current: number; pageSize: number },
    formData: UserSearchParams
  ) => {
    const params = new URLSearchParams({
      page: current.toString(),
      size: pageSize.toString(),
      ...formData
    });
    
    const response = await fetch(`/api/users?${params}`);
    const data = await response.json();
    
    return {
      list: data.users,
      total: data.total
    };
  };
  
  const { tableProps, search } = useAntdTable(getUserList, {
    defaultPageSize: 10,
    form,
    formatResult: (data) => ({
      list: data.users || [],
      total: data.total || 0
    }),
    onSuccess: (data, params) => {
      console.log('Table data loaded:', data.list.length, 'items');
    }
  });
  
  const columns = [
    {
      title: 'Name',
      dataIndex: 'name',
      sorter: true
    },
    {
      title: 'Email',
      dataIndex: 'email'
    },
    {
      title: 'Role',
      dataIndex: 'role',
      filters: [
        { text: 'Admin', value: 'admin' },
        { text: 'User', value: 'user' },
        { text: 'Moderator', value: 'moderator' }
      ]
    },
    {
      title: 'Created',
      dataIndex: 'createdAt',
      sorter: true,
      render: (date: string) => new Date(date).toLocaleDateString()
    },
    {
      title: 'Actions',
      render: (_, user: User) => (
        <div>
          <Button size="small" onClick={() => editUser(user.id)}>Edit</Button>
          <Button size="small" danger onClick={() => deleteUser(user.id)}>Delete</Button>
        </div>
      )
    }
  ];
  
  const editUser = (id: number) => {
    console.log('Edit user:', id);
  };
  
  const deleteUser = (id: number) => {
    console.log('Delete user:', id);
    // Refresh table after deletion
    search.submit();
  };
  
  return (
    <div>
      <Card>
        <Form form={form} onFinish={search.submit}>
          <div style={{ display: 'flex', gap: '16px', marginBottom: '16px' }}>
            <Form.Item name="name" style={{ margin: 0 }}>
              <Input placeholder="Search by name" />
            </Form.Item>
            
            <Form.Item name="email" style={{ margin: 0 }}>
              <Input placeholder="Search by email" />
            </Form.Item>
            
            {search.type === 'advance' && (
              <Form.Item name="role" style={{ margin: 0 }}>
                <Input placeholder="Search by role" />
              </Form.Item>
            )}
            
            <Button type="primary" htmlType="submit">
              Search
            </Button>
            <Button onClick={search.reset}>Reset</Button>
            <Button type="link" onClick={search.changeType}>
              {search.type === 'simple' ? 'Advanced' : 'Simple'} Search
            </Button>
          </div>
        </Form>
      </Card>
      
      <Table
        {...tableProps}
        columns={columns}
        rowKey="id"
        style={{ marginTop: '16px' }}
      />
    </div>
  );
}

useFusionTable

Fusion Design table management hook built on top of useAntdTable, providing integration with Fusion Design Form and Table components.

/**
 * Manages Fusion Design Table with forms and pagination
 * @param service - Async function that returns table data
 * @param options - Configuration options including field instance
 * @returns Object with table props, pagination props, and search controls
 */
function useFusionTable<TData extends Data, TParams extends Params>(
  service: Service<TData, TParams>,
  options?: FusionTableOptions<TData, TParams>
): FusionTableResult<TData, TParams>;

// Fusion-specific field interface
interface Field {
  getFieldInstance?: (name: string) => Record<string, any>;
  setValues: (value: Record<string, any>) => void;
  getValues: (...args: any) => Record<string, any>;
  reset: (...args: any) => void;
  validate: (fields: any, callback: (errors, values) => void) => void;
  [key: string]: any;
}

// Result interface for Fusion Table
interface FusionTableResult<TData extends Data, TParams extends Params> {
  // Pagination props for Fusion Pagination component
  paginationProps: {
    onChange: (current: number) => void;
    onPageSizeChange: (size: number) => void;
    current: number;
    pageSize: number;
    total: number;
  };
  
  // Table props for Fusion Table component
  tableProps: {
    dataSource: TData['list'];
    loading: boolean;
    onSort: (dataIndex: string, order: string) => void;
    onFilter: (filterParams: any) => void;
  };
  
  // Search functionality
  search: {
    type: 'simple' | 'advance';
    changeType: () => void;
    submit: () => void;
    reset: () => void;
  };
  
  // Request controls (inherited from useRequest)
  loading: boolean;
  data?: TData;
  error?: Error;
  params?: TParams;
  run: (...params: TParams) => void;
  runAsync: (...params: TParams) => Promise<TData>;
  refresh: () => void;
  refreshAsync: () => Promise<TData>;
  cancel: () => void;
  mutate: (data?: TData) => void;
}

interface FusionTableOptions<TData extends Data, TParams extends Params> {
  // Fusion Form field instance
  field?: Field;
  
  // Default form type
  defaultType?: 'simple' | 'advance';
  
  // Pagination
  defaultPageSize?: number;
  
  // Default parameters [pagination, formData]
  defaultParams?: TParams;
  
  // Search behavior
  manual?: boolean;
  refreshDeps?: any[];
  
  // Request options (inherited from useRequest)
  onSuccess?: (data: TData, params: TParams) => void;
  onError?: (error: Error, params: TParams) => void;
}

Usage Example:

import { useFusionTable } from 'ahooks';
import { Table, Form, Field, Input, Button, Pagination } from '@alifd/next';

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
}

interface UserTableData {
  list: User[];
  total: number;
}

function FusionUserTable() {
  const field = Field.useField();
  
  // Service function that returns paginated data
  const getUserList = async ([pagination, formData]: [any, any]): Promise<UserTableData> => {
    const response = await fetch('/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        current: pagination.current,
        pageSize: pagination.pageSize,
        ...formData
      })
    });
    return response.json();
  };
  
  const { tableProps, paginationProps, search, loading } = useFusionTable(getUserList, {
    field,
    defaultPageSize: 10,
    defaultType: 'simple'
  });
  
  const columns = [
    {
      title: 'Name',
      dataIndex: 'name',
      sortable: true
    },
    {
      title: 'Email',
      dataIndex: 'email'
    },
    {
      title: 'Role',
      dataIndex: 'role',
      filters: [
        { text: 'Admin', value: 'admin' },
        { text: 'User', value: 'user' }
      ]
    }
  ];
  
  return (
    <div>
      <Form field={field} onSubmit={search.submit}>
        <Form.Item>
          <Input name="name" placeholder="Search by name" />
        </Form.Item>
        
        <Form.Item>
          <Button type="primary" htmlType="submit">Search</Button>
          <Button onClick={search.reset}>Reset</Button>
          <Button onClick={search.changeType}>
            Switch to {search.type === 'simple' ? 'Advanced' : 'Simple'}
          </Button>
        </Form.Item>
      </Form>
      
      <Table
        {...tableProps}
        columns={columns}
        primaryKey="id"
      />
      
      <Pagination {...paginationProps} />
    </div>
  );
}

usePagination

Generic pagination management for any data source.

/**
 * Generic pagination management
 * @param service - Async function that returns paginated data
 * @param options - Configuration options
 * @returns Object with pagination state and controls
 */
function usePagination<TData extends Data, TParams extends Params>(
  service: Service<TData, TParams>,
  options?: PaginationOptions<TData, TParams>
): PaginationResult<TData, TParams>;

interface PaginationResult<TData extends Data, TParams extends Params> {
  data: TData | undefined;
  loading: boolean;
  pagination: {
    current: number;
    pageSize: number;
    total: number;
    totalPage: number;
    onChange: (current: number, pageSize: number) => void;
    changeCurrent: (current: number) => void;
    changePageSize: (pageSize: number) => void;
  };
  
  // Standard request controls
  error?: Error;
  params?: TParams;
  run: (...params: TParams) => void;
  runAsync: (...params: TParams) => Promise<TData>;
  refresh: () => void;
  refreshAsync: () => Promise<TData>;
  cancel: () => void;
  mutate: (data?: TData) => void;
}

useInfiniteScroll

Manages infinite scrolling for loading more data as user scrolls.

/**
 * Manages infinite scrolling for loading more data
 * @param service - Async function that returns data for next page
 * @param options - Configuration options
 * @returns Object with data, loading states, and load more controls
 */
function useInfiniteScroll<TData extends Data>(
  service: Service<TData>,
  options?: InfiniteScrollOptions<TData>
): InfiniteScrollResult<TData>;

interface InfiniteScrollResult<TData extends Data> {
  /** Accumulated data from all loaded pages */
  data: TData;
  /** Loading state for initial load */
  loading: boolean;
  /** Loading state for loading more data */
  loadingMore: boolean;
  /** Error object if any request failed */
  error?: Error;
  /** Whether there's no more data to load */
  noMore: boolean;
  /** Load next page of data */
  loadMore: () => void;
  /** Load next page and return promise */
  loadMoreAsync: () => Promise<TData>;
  /** Reload from first page */
  reload: () => void;
  /** Reload from first page and return promise */
  reloadAsync: () => Promise<TData>;
  /** Cancel ongoing request */
  cancel: () => void;
  /** Update data without request */
  mutate: (data?: TData) => void;
}

Virtual Lists

useVirtualList

Renders large lists efficiently by only rendering visible items.

/**
 * Renders large lists efficiently using virtualization
 * @param list - Array of data items to virtualize
 * @param options - Configuration options for virtualization
 * @returns Object with visible items and scroll control
 */
function useVirtualList<T = any>(list: T[], options: Options<T>): VirtualListReturn<T>;

interface Options<T> {
  /** Container element reference */
  containerTarget: BasicTarget;
  /** Wrapper element reference (scrollable container) */
  wrapperTarget: BasicTarget;
  /** Height of each item (number or function) */
  itemHeight: number | ((index: number, data: T) => number);
  /** Number of items to render outside visible area (default: 5) */
  overscan?: number;
}

interface VirtualListReturn<T> {
  /** Array of visible items with their data and original index */
  list: Array<{ data: T; index: number }>;
  /** Function to scroll to specific item index */
  scrollTo: (index: number) => void;
}

type BasicTarget = Element | (() => Element | null) | React.MutableRefObject<Element | null>;

Usage Example:

import { useVirtualList } from 'ahooks';
import { useRef, useMemo } from 'react';

function LargeList() {
  const containerRef = useRef<HTMLDivElement>(null);
  const wrapperRef = useRef<HTMLDivElement>(null);
  
  // Generate large dataset
  const largeData = useMemo(() => 
    Array.from({ length: 100000 }, (_, index) => ({
      id: index,
      name: `Item ${index}`,
      description: `Description for item ${index}`,
      value: Math.floor(Math.random() * 1000)
    }))
  , []);
  
  const { list, scrollTo } = useVirtualList(largeData, {
    containerTarget: containerRef,
    wrapperTarget: wrapperRef,
    itemHeight: 60, // Fixed height for each item
    overscan: 10 // Render 10 extra items outside visible area
  });
  
  const jumpToItem = (index: number) => {
    scrollTo(index);
  };
  
  return (
    <div>
      <h2>Virtual List (100,000 items)</h2>
      
      <div style={{ marginBottom: '10px' }}>
        <button onClick={() => jumpToItem(0)}>Jump to Start</button>
        <button onClick={() => jumpToItem(50000)}>Jump to Middle</button>
        <button onClick={() => jumpToItem(99999)}>Jump to End</button>
        <button onClick={() => jumpToItem(Math.floor(Math.random() * largeData.length))}>
          Jump to Random
        </button>
      </div>
      
      <div
        ref={wrapperRef}
        style={{
          height: '400px',
          overflow: 'auto',
          border: '1px solid #ccc'
        }}
      >
        <div ref={containerRef}>
          {list.map(({ data, index }) => (
            <div
              key={index}
              style={{
                height: '60px',
                padding: '10px',
                borderBottom: '1px solid #eee',
                display: 'flex',
                alignItems: 'center',
                backgroundColor: index % 2 === 0 ? '#f9f9f9' : 'white'
              }}
            >
              <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 'bold' }}>{data.name}</div>
                <div style={{ fontSize: '12px', color: '#666' }}>
                  {data.description}
                </div>
              </div>
              <div style={{ textAlign: 'right' }}>
                <div>Index: {index}</div>
                <div>Value: {data.value}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
      
      <p>Only rendering visible items. Scroll to see more!</p>
    </div>
  );
}

WebSocket

useWebSocket

Manages WebSocket connections with automatic reconnection and comprehensive event handling.

/**
 * Manages WebSocket connections with reconnection
 * @param socketUrl - WebSocket URL to connect to
 * @param options - Configuration options
 * @returns Object with connection state and control methods
 */
function useWebSocket(socketUrl: string, options?: Options): Result;

interface Options {
  /** Maximum reconnection attempts (default: 3) */
  reconnectLimit?: number;
  /** Interval between reconnection attempts in ms (default: 3000) */
  reconnectInterval?: number;
  /** Don't connect automatically on mount */
  manual?: boolean;
  /** WebSocket protocols */
  protocols?: string | string[];
  
  // Event callbacks
  onOpen?: (event: WebSocketEventMap['open'], instance: WebSocket) => void;
  onClose?: (event: WebSocketEventMap['close'], instance: WebSocket) => void;
  onMessage?: (message: WebSocketEventMap['message'], instance: WebSocket) => void;
  onError?: (event: WebSocketEventMap['error'], instance: WebSocket) => void;
}

interface Result {
  /** Latest received message */
  latestMessage?: WebSocketEventMap['message'];
  /** Send message function */
  sendMessage: WebSocket['send'];
  /** Disconnect WebSocket */
  disconnect: () => void;
  /** Connect WebSocket */
  connect: () => void;
  /** Current connection state */
  readyState: ReadyState;
  /** WebSocket instance */
  webSocketIns?: WebSocket;
}

enum ReadyState {
  Connecting = 0,
  Open = 1,
  Closing = 2,
  Closed = 3,
}

Usage Example:

import { useWebSocket, ReadyState } from 'ahooks';
import { useState, useCallback } from 'react';

interface ChatMessage {
  id: string;
  user: string;
  message: string;
  timestamp: number;
}

function ChatApp() {
  const [messageHistory, setMessageHistory] = useState<ChatMessage[]>([]);
  const [currentMessage, setCurrentMessage] = useState('');
  const [username, setUsername] = useState('User' + Math.floor(Math.random() * 1000));
  
  const {
    sendMessage,
    latestMessage,
    readyState,
    connect,
    disconnect
  } = useWebSocket('ws://localhost:8080/chat', {
    onOpen: () => {
      console.log('Connected to chat server');
      setMessageHistory(prev => [...prev, {
        id: Date.now().toString(),
        user: 'System',
        message: 'Connected to chat',
        timestamp: Date.now()
      }]);
    },
    onClose: () => {
      console.log('Disconnected from chat server');
    },
    onError: (event) => {
      console.error('WebSocket error:', event);
    },
    reconnectLimit: 5,
    reconnectInterval: 3000
  });
  
  // Handle incoming messages
  const handleMessage = useCallback(() => {
    if (latestMessage?.data) {
      try {
        const message: ChatMessage = JSON.parse(latestMessage.data);
        setMessageHistory(prev => [...prev, message]);
      } catch (error) {
        console.error('Failed to parse message:', error);
      }
    }
  }, [latestMessage]);
  
  // Effect to handle new messages
  useEffect(() => {
    handleMessage();
  }, [handleMessage]);
  
  const sendChatMessage = () => {
    if (currentMessage.trim() && readyState === ReadyState.Open) {
      const message: ChatMessage = {
        id: Date.now().toString(),
        user: username,
        message: currentMessage.trim(),
        timestamp: Date.now()
      };
      
      sendMessage(JSON.stringify(message));
      setCurrentMessage('');
    }
  };
  
  const connectionStatus = {
    [ReadyState.Connecting]: 'Connecting',
    [ReadyState.Open]: 'Connected',
    [ReadyState.Closing]: 'Closing',
    [ReadyState.Closed]: 'Disconnected',
  }[readyState];
  
  return (
    <div style={{ maxWidth: '600px', margin: '0 auto' }}>
      <h2>WebSocket Chat</h2>
      
      <div style={{ marginBottom: '20px' }}>
        <div>Status: <strong>{connectionStatus}</strong></div>
        <div>
          <input
            value={username}
            onChange={(e) => setUsername(e.target.value)}
            placeholder="Username"
            style={{ marginRight: '10px' }}
          />
          <button onClick={connect} disabled={readyState === ReadyState.Open}>
            Connect
          </button>
          <button onClick={disconnect} disabled={readyState !== ReadyState.Open}>
            Disconnect
          </button>
        </div>
      </div>
      
      <div
        style={{
          height: '300px',
          border: '1px solid #ccc',
          padding: '10px',
          overflowY: 'auto',
          marginBottom: '10px',
          backgroundColor: '#f9f9f9'
        }}
      >
        {messageHistory.map((msg) => (
          <div key={msg.id} style={{ marginBottom: '8px' }}>
            <strong>{msg.user}:</strong> {msg.message}
            <span style={{ fontSize: '12px', color: '#666', marginLeft: '10px' }}>
              {new Date(msg.timestamp).toLocaleTimeString()}
            </span>
          </div>
        ))}
      </div>
      
      <div style={{ display: 'flex' }}>
        <input
          value={currentMessage}
          onChange={(e) => setCurrentMessage(e.target.value)}
          placeholder="Type a message..."
          style={{ flex: 1, marginRight: '10px' }}
          onKeyPress={(e) => e.key === 'Enter' && sendChatMessage()}
          disabled={readyState !== ReadyState.Open}
        />
        <button 
          onClick={sendChatMessage}
          disabled={readyState !== ReadyState.Open || !currentMessage.trim()}
        >
          Send
        </button>
      </div>
    </div>
  );
}

Browser APIs

useNetwork

Tracks network connection status and connection quality information.

/**
 * Tracks network connection status and quality
 * @returns Object with network state information
 */
function useNetwork(): NetworkState;

interface NetworkState {
  /** Date when connection status last changed */
  since?: Date;
  /** Whether browser is online */
  online?: boolean;
  /** Round-trip time estimate in ms */
  rtt?: number;
  /** Connection type (4g, 3g, etc.) */
  type?: string;
  /** Downlink speed estimate in Mbps */
  downlink?: number;
  /** Whether user has data saver enabled */
  saveData?: boolean;
  /** Maximum downlink speed in Mbps */
  downlinkMax?: number;
  /** Effective connection type (slow-2g, 2g, 3g, 4g) */
  effectiveType?: string;
}

useResponsive

Manages responsive breakpoints and screen size detection.

/**
 * Manages responsive breakpoints
 * @returns Object with boolean flags for each breakpoint
 */
function useResponsive(): ResponsiveInfo;

type ResponsiveInfo = Record<string, boolean>;

/**
 * Configures custom breakpoints for useResponsive
 * @param config - Object with breakpoint names and pixel values
 */
function configResponsive(config: ResponsiveConfig): void;

type ResponsiveConfig = Record<string, number>;

useDocumentVisibility

Tracks document visibility state (visible, hidden, prerender).

/**
 * Tracks document visibility state
 * @returns Current visibility state
 */
function useDocumentVisibility(): VisibilityState;

type VisibilityState = 'hidden' | 'visible' | 'prerender' | undefined;

useTitle

Manages document title with optional restoration on unmount.

/**
 * Manages document title
 * @param title - New document title
 * @param restoreOnUnmount - Whether to restore original title on unmount
 */
function useTitle(title: string, restoreOnUnmount?: boolean): void;

useFavicon

Manages document favicon.

/**
 * Manages document favicon
 * @param href - URL or data URI for favicon
 */
function useFavicon(href: string): void;

Drag & Drop

useDrag

Handles drag operations with customizable drag data and visual feedback.

/**
 * Handles drag operations
 * @param data - Data to transfer during drag
 * @param target - Element to make draggable
 * @param options - Drag configuration options
 */
function useDrag<T>(data: T, target: BasicTarget, options?: Options): void;

interface Options {
  onDragStart?: (event: React.DragEvent) => void;
  onDragEnd?: (event: React.DragEvent) => void;
  dragImage?: {
    image: string | Element;
    offsetX?: number;
    offsetY?: number;
  };
}

useDrop

Handles drop operations with support for files, text, and custom data.

/**
 * Handles drop operations
 * @param target - Element to make a drop target
 * @param options - Drop configuration options
 */
function useDrop(target: BasicTarget, options?: Options): void;

interface Options {
  onFiles?: (files: File[], event?: React.DragEvent) => void;
  onUri?: (url: string, event?: React.DragEvent) => void;
  onDom?: (content: any, event?: React.DragEvent) => void;
  onText?: (text: string, event?: React.ClipboardEvent) => void;
  onDragEnter?: (event?: React.DragEvent) => void;
  onDragOver?: (event?: React.DragEvent) => void;
  onDragLeave?: (event?: React.DragEvent) => void;
  onDrop?: (event?: React.DragEvent) => void;
  onPaste?: (event?: React.ClipboardEvent) => void;
}

Developer Tools

useWhyDidYouUpdate

Tracks prop changes that cause component re-renders for debugging performance issues.

/**
 * Tracks prop changes that cause re-renders
 * @param name - Component name for logging
 * @param props - Object with props to track
 */
function useWhyDidYouUpdate(name: string, props: Record<string, any>): void;

useUpdate

Forces component re-render, useful for debugging or manual updates.

/**
 * Forces component re-render
 * @returns Function to trigger re-render
 */
function useUpdate(): () => void;

useUnmountedRef

Returns ref indicating whether component has been unmounted.

/**
 * Returns ref indicating if component is unmounted
 * @returns Ref object with current boolean indicating unmount status
 */
function useUnmountedRef(): MutableRefObject<boolean>;

External Resources

useExternal

Loads external JavaScript and CSS resources dynamically.

/**
 * Loads external JavaScript and CSS resources
 * @param path - URL of external resource
 * @param options - Loading options
 * @returns Loading status
 */
function useExternal(path?: string, options?: Options): Status;

type Status = 'unset' | 'loading' | 'ready' | 'error';

type Options = JsOptions | CssOptions | DefaultOptions;

interface JsOptions {
  type: 'js';
  js?: Partial<HTMLScriptElement>;
  keepWhenUnused?: boolean;
}

interface CssOptions {
  type: 'css';
  css?: Partial<HTMLStyleElement>;
  keepWhenUnused?: boolean;
}

Form Helpers

useEventTarget

Manages form input state with convenient change handler.

/**
 * Manages form input state
 * @param options - Configuration options
 * @returns Array with current value and actions
 */
function useEventTarget<T, U = T>(options?: Options<T, U>): [T | undefined, EventTargetActions];

interface Options<T, U> {
  initialValue?: T;
  transformer?: (value: U) => T;
}

interface EventTargetActions {
  onChange: (e: { target: { value: any } }) => void;
  reset: () => void;
}

Theme Management

useTheme

Manages application theme state.

/**
 * Manages theme state
 * @returns Array with current theme and setter function
 */
function useTheme(): [string | undefined, (theme: string) => void];

Event Communication

useEventEmitter

Creates event emitter for component-to-component communication.

/**
 * Creates event emitter for component communication
 * @returns EventEmitter instance
 */
function useEventEmitter<T = void>(): EventEmitter<T>;

class EventEmitter<T> {
  /** Emit event with data */
  emit: (val: T) => void;
  /** Subscribe to events */
  useSubscription: (callback: (val: T) => void) => void;
}

Common Types

// Basic target element type
type BasicTarget<T = Element> = (() => T | null) | T | null | React.MutableRefObject<T>;

// React ref type
type MutableRefObject<T> = React.MutableRefObject<T>;

// Data structure for paginated results
interface Data {
  list: any[];
  total: number;
}

// Network connection state
interface NetworkState {
  since?: Date;
  online?: boolean;
  rtt?: number;
  type?: string;
  downlink?: number;
  saveData?: boolean;
  downlinkMax?: number;
  effectiveType?: string;
}

// WebSocket ready states
enum ReadyState {
  Connecting = 0,
  Open = 1,
  Closing = 2,
  Closed = 3,
}