UNPKG

extended-dynamic-forms

Version:

Extended React JSON Schema Form (RJSF) v6 with custom components, widgets, templates, layouts, and form events

497 lines (495 loc) 16.5 kB
import { WidgetProps } from '@rjsf/utils'; /** * Presentation modes for the Choice Widget */ export declare enum PresentationMode { /** Dropdown/Select presentation */ DROPDOWN = "dropdown", /** Radio button presentation */ RADIO = "radio", /** Checkbox presentation (multi-select) */ CHECKBOX = "checkbox" } /** * Loading states for async data operations */ export interface LoadingState { /** Whether the widget is currently loading */ isLoading: boolean; /** Loading message to display to users */ message?: string; /** Progress percentage (0-100) for long operations */ progress?: number; } /** * Error states for data operations */ export interface ErrorState { /** Whether an error has occurred */ hasError: boolean; /** Error message to display to users */ message: string; /** Error code for programmatic handling */ code?: string | number; /** Stack trace for debugging (development only) */ stack?: string; /** Whether the error is recoverable */ recoverable?: boolean; /** Timestamp when the error occurred */ timestamp?: number; } /** * Represents a single choice option */ export interface ChoiceOption { /** Display text for the option */ label: string; /** Value to be stored when selected */ value: string | number | boolean; /** Whether this option is disabled */ disabled?: boolean; /** Additional metadata for the option */ metadata?: { /** Optional description or help text */ description?: string; /** CSS class names for styling */ className?: string; /** Icon identifier for display */ icon?: string; /** Group or category identifier for organizing options */ group?: string; /** Display order for sorting */ order?: number; /** Additional data attributes */ data?: Record<string, unknown>; /** Accessibility attributes */ a11y?: { /** ARIA label for screen readers */ ariaLabel?: string; /** ARIA description */ ariaDescription?: string; /** Whether this option has a popup */ ariaHasPopup?: boolean; }; /** Internal properties for system use */ _index?: number; _active?: boolean; _originalData?: any; }; } /** * Configuration for static data sources */ export interface StaticDataSourceConfig { /** Type identifier for static data source */ type: 'static'; /** Array of choice options */ options: ChoiceOption[]; } /** * HTTP method types for API requests */ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH'; /** * Response mapper function to transform API data into ChoiceOption[] */ export type ResponseMapper = (data: unknown) => ChoiceOption[]; /** * Built-in response mapper configurations */ export interface ResponseMapperConfig { /** Type of built-in mapper */ type: 'simple' | 'nested' | 'custom'; /** Configuration for simple mapper */ simple?: { /** Path to the array in response (e.g., 'data.items') */ arrayPath?: string; /** Field name for label (default: 'label') */ labelField?: string; /** Field name for value (default: 'value') */ valueField?: string; /** Field name for disabled state (default: 'disabled') */ disabledField?: string; }; /** Configuration for nested mapper */ nested?: { /** Path to the array in response */ arrayPath: string; /** Nested paths for extracting data */ paths: { label: string; value: string; disabled?: string; description?: string; }; }; /** Custom mapper function */ custom?: ResponseMapper; } /** * Cache configuration for API responses */ export interface CacheConfig { /** Cache duration in milliseconds (default: 300000 = 5 minutes) */ ttl?: number; /** Cache key for storage (auto-generated if not provided) */ key?: string; /** Whether to use browser storage for persistence */ persistent?: boolean; /** Cache storage type */ storageType?: 'memory' | 'sessionStorage' | 'localStorage'; } /** * Configuration for API data sources */ export interface ApiDataSourceConfig { /** Type identifier for API data source */ type: 'api'; /** API endpoint URL */ url: string; /** HTTP method (default: 'GET') */ method?: HttpMethod; /** Request headers */ headers?: Record<string, string>; /** Request body for POST/PUT/PATCH */ body?: unknown; /** Query parameters */ params?: Record<string, string | number | boolean>; /** Response mapper configuration */ responseMapper: ResponseMapperConfig; /** Cache configuration */ cache?: CacheConfig; /** Request timeout in milliseconds (default: 30000) */ timeout?: number; /** Number of retry attempts on failure (default: 0) */ retries?: number; /** Authentication configuration */ auth?: { /** Authentication type */ type: 'bearer' | 'basic' | 'apiKey'; /** Token or credentials */ credentials: string | { username: string; password: string; }; /** Header name for API key auth */ headerName?: string; }; } /** * WebSocket message types for real-time communication */ export type WebSocketMessageType = 'options-update' | 'options-add' | 'options-remove' | 'options-patch' | 'search-request' | 'search-response' | 'connection-ready' | 'error' | 'heartbeat'; /** * WebSocket message structure */ export interface WebSocketMessage<T = unknown> { /** Message type identifier */ type: WebSocketMessageType; /** Message payload */ data?: T; /** Unique message ID for correlation */ messageId?: string; /** Timestamp when message was created */ timestamp?: number; /** Error details for error messages */ error?: { code: string; message: string; details?: unknown; }; } /** * Configuration for WebSocket data sources */ export interface WebSocketDataSourceConfig { /** Type identifier for WebSocket data source */ type: 'websocket'; /** WebSocket server URL */ url: string; /** WebSocket protocols */ protocols?: string | string[]; /** Authentication configuration */ auth?: { /** Authentication type */ type: 'bearer' | 'query' | 'header'; /** Token or credentials */ credentials: string; /** Parameter/header name for auth */ paramName?: string; }; /** Connection configuration */ connection?: { /** Connection timeout in milliseconds (default: 30000) */ connectTimeout?: number; /** Auto-reconnect on connection loss (default: true) */ autoReconnect?: boolean; /** Max reconnection attempts (default: 5) */ maxReconnectAttempts?: number; /** Reconnection delay in milliseconds (default: 1000) */ reconnectDelay?: number; /** Heartbeat interval in milliseconds (default: 30000) */ heartbeatInterval?: number; /** Response timeout for requests in milliseconds (default: 10000) */ responseTimeout?: number; }; /** Message handling configuration */ messageHandling?: { /** Whether to request initial options on connect (default: true) */ requestInitialOptions?: boolean; /** Initial message to send after connection */ initialMessage?: WebSocketMessage; /** Whether to enable real-time search (default: false) */ enableRealtimeSearch?: boolean; /** Search debounce delay in milliseconds (default: 300) */ searchDebounceMs?: number; }; /** Response transformation */ responseMapper?: ResponseMapperConfig; /** Cache configuration (for offline support) */ cache?: CacheConfig; } /** * Union type for all data source configurations */ export type DataSourceConfig = StaticDataSourceConfig | ApiDataSourceConfig | WebSocketDataSourceConfig; /** * Validation configuration for selected values */ export interface ValidationConfig { /** Custom validation function */ validator?: (value: unknown, options: ChoiceOption[]) => string | null; /** Whether to validate on change (default: true) */ validateOnChange?: boolean; /** Whether to validate on blur (default: true) */ validateOnBlur?: boolean; /** Custom error messages */ messages?: { required?: string; invalid?: string; custom?: string; }; } /** * Search and filtering configuration */ export interface SearchConfig { /** Whether search is enabled */ enabled: boolean; /** Search placeholder text */ placeholder?: string; /** Minimum characters before search activates */ minLength?: number; /** Search debounce delay in milliseconds */ debounceMs?: number; /** Whether search is case-sensitive */ caseSensitive?: boolean; /** Fields to search in */ searchFields?: ('label' | 'value' | 'description')[]; /** Custom search function */ customFilter?: (option: ChoiceOption, searchTerm: string) => boolean; } /** * Accessibility configuration */ export interface AccessibilityConfig { /** ARIA label for the widget */ ariaLabel?: string; /** ARIA description */ ariaDescription?: string; /** Whether to announce changes to screen readers */ announceChanges?: boolean; /** Custom ARIA attributes */ ariaAttributes?: Record<string, string>; /** Keyboard navigation configuration */ keyboard?: { /** Whether to enable arrow key navigation */ arrowKeys?: boolean; /** Whether to enable type-ahead search */ typeAhead?: boolean; /** Whether to enable home/end keys */ homeEnd?: boolean; }; } /** * Main configuration interface for the Choice Widget */ export interface ChoiceWidgetConfig { /** Presentation mode for the widget */ presentationMode?: PresentationMode; /** Data source configuration */ dataSource?: DataSourceConfig; /** Whether multiple selections are allowed */ multiple?: boolean; /** Whether to allow clearing the selection */ allowClear?: boolean; /** Placeholder text when no option is selected */ placeholder?: string; /** Whether the widget is disabled */ disabled?: boolean; /** Whether the widget is read-only */ readonly?: boolean; /** Maximum number of selections (for multiple mode) */ maxSelections?: number; /** Minimum number of selections (for multiple mode) */ minSelections?: number; /** Search and filtering configuration */ search?: SearchConfig; /** Validation configuration */ validation?: ValidationConfig; /** Accessibility configuration */ accessibility?: AccessibilityConfig; /** Custom CSS class names */ className?: string; /** Custom inline styles */ style?: React.CSSProperties; /** Size variant for Ant Design components */ size?: 'small' | 'middle' | 'large'; /** Whether to show option counts in multi-select */ showOptionCount?: boolean; /** Custom loading component */ loadingComponent?: React.ComponentType<LoadingState>; /** Custom error component */ errorComponent?: React.ComponentType<ErrorState>; /** Custom empty state component */ emptyComponent?: React.ComponentType<{ message?: string; }>; } /** * Internal state interface for the Choice Widget */ export interface ChoiceWidgetState { /** Available options */ options: ChoiceOption[]; /** Currently selected values */ selectedValues: (string | number | boolean)[]; /** Loading state */ loading: LoadingState; /** Error state */ error: ErrorState; /** Search term */ searchTerm: string; /** Filtered options based on search */ filteredOptions: ChoiceOption[]; /** Whether the dropdown/menu is open */ isOpen: boolean; /** Focused option index for keyboard navigation */ focusedOptionIndex: number; } /** * Event handlers for the Choice Widget */ export interface ChoiceWidgetEventHandlers { /** Called when selection changes */ onSelectionChange?: (values: (string | number | boolean)[], options: ChoiceOption[]) => void; /** Called when search term changes */ onSearchChange?: (searchTerm: string) => void; /** Called when widget receives focus */ onFocus?: (event: React.FocusEvent) => void; /** Called when widget loses focus */ onBlur?: (event: React.FocusEvent) => void; /** Called when dropdown opens */ onOpen?: () => void; /** Called when dropdown closes */ onClose?: () => void; /** Called when data loading starts */ onLoadingStart?: () => void; /** Called when data loading completes */ onLoadingComplete?: (options: ChoiceOption[]) => void; /** Called when an error occurs */ onError?: (error: ErrorState) => void; /** Called when error is cleared */ onErrorClear?: () => void; } /** * Props interface for the Choice Widget component * Extends RJSF WidgetProps and adds Choice Widget specific properties */ export interface ChoiceWidgetProps extends WidgetProps { /** Choice Widget configuration from ui:options */ options: WidgetProps['options'] & { /** Choice Widget specific configuration */ choiceConfig?: ChoiceWidgetConfig; /** Legacy support for enum options */ enumOptions?: { label: string; value: unknown; }[]; }; /** Event handlers */ eventHandlers?: ChoiceWidgetEventHandlers; /** Current widget state (for controlled usage) */ state?: Partial<ChoiceWidgetState>; /** State change handler (for controlled usage) */ onStateChange?: (state: Partial<ChoiceWidgetState>) => void; } /** * Data provider interface for abstracting data sources */ export interface ChoiceDataProvider { /** Fetch options from the data source */ fetchOptions(): Promise<ChoiceOption[]>; /** Whether this provider supports caching */ supportsCaching: boolean; /** Whether this provider supports real-time updates */ supportsRealTime: boolean; /** Cleanup resources */ cleanup(): void; } /** * Cache interface for storing fetched data */ export interface ChoiceCache { /** Get cached data */ get(key: string): ChoiceOption[] | null; /** Set cached data */ set(key: string, data: ChoiceOption[], ttl?: number): void; /** Clear specific cache entry */ clear(key: string): void; /** Clear all cache entries */ clearAll(): void; /** Check if cache entry exists and is valid */ has(key: string): boolean; } /** * Strategy interface for different presentation modes */ export interface PresentationStrategy { /** Render the widget */ render(props: ChoiceWidgetProps, state: ChoiceWidgetState): React.ReactElement; /** Handle selection change */ handleSelectionChange(value: unknown, props: ChoiceWidgetProps, state: ChoiceWidgetState): (string | number | boolean)[]; /** Get default props for this presentation mode */ getDefaultProps(): Partial<ChoiceWidgetConfig>; /** Validate props for this presentation mode */ validateProps(config: ChoiceWidgetConfig): string[] | null; } /** * Type guard to check if a data source is static */ export declare function isStaticDataSource(dataSource: DataSourceConfig): dataSource is StaticDataSourceConfig; /** * Type guard to check if a data source is API-based */ export declare function isApiDataSource(dataSource: DataSourceConfig): dataSource is ApiDataSourceConfig; /** * Type guard to check if a data source is WebSocket-based */ export declare function isWebSocketDataSource(dataSource: DataSourceConfig): dataSource is WebSocketDataSourceConfig; /** * Type guard to check if widget supports multiple selections */ export declare function supportsMultipleSelections(mode: PresentationMode): boolean; /** * Default configuration values */ export declare const DEFAULT_CHOICE_CONFIG: Partial<ChoiceWidgetConfig>; /** * Default cache configuration */ export declare const DEFAULT_CACHE_CONFIG: CacheConfig; /** * Default response mapper for simple API responses */ export declare const DEFAULT_RESPONSE_MAPPER: ResponseMapperConfig;