/** * Type-safe default configuration for React Buoy DevTools. * * This module provides a simple, type-safe way for teams to configure * which tools are enabled by default in the floating menu and dial menu. * * @example * ```tsx * import { FloatingDevTools } from '@react-buoy/core'; * * // Simple: Enable specific tools by default * * ``` */ /** * All known tool IDs that can appear in the floating menu or dial menu. * This is a union type of all auto-discovered tool IDs. */ export type BuiltInToolId = | 'env' // Environment variables tool (@react-buoy/env) | 'network' // Network request logger (@react-buoy/network) | 'storage' // AsyncStorage/MMKV browser (@react-buoy/storage) | 'query' // React Query devtools (@react-buoy/react-query) | 'query-wifi-toggle' // WiFi toggle for React Query (@react-buoy/react-query) | 'route-events' // Navigation tracking (@react-buoy/route-events) | 'debug-borders' // Visual debug borders (@react-buoy/debug-borders) | 'highlight-updates' // Highlight re-renders toggle (@react-buoy/highlight-updates) | 'highlight-updates-modal' // Render count analysis modal (@react-buoy/highlight-updates) | 'benchmark'; // Performance benchmarking (@react-buoy/benchmark) /** * Special floating-only tool IDs that only appear in the floating bubble row. */ export type FloatingOnlyToolId = 'environment'; // Environment badge indicator /** * All tool IDs that can appear in the floating menu (bubble row). * Includes all built-in tools plus floating-only tools. */ export type FloatingToolId = BuiltInToolId | FloatingOnlyToolId; /** * Tool IDs that can appear in the dial menu. * Same as BuiltInToolId (environment badge is floating-only). */ export type DialToolId = BuiltInToolId; /** * Maximum number of tools allowed in the dial menu. */ export const MAX_DIAL_TOOLS = 6; /** * Configuration for default floating menu tools. * Pass an array of tool IDs to enable by default. * * @example * ```tsx * const floatingDefaults: DefaultFloatingConfig = ['env', 'environment', 'network']; * ``` */ export type DefaultFloatingConfig = FloatingToolId[]; /** * Configuration for default dial menu tools. * Pass an array of 1-6 tool IDs to enable by default. * * @example * ```tsx * const dialDefaults: DefaultDialConfig = ['env', 'network', 'storage', 'query']; * ``` */ export type DefaultDialConfig = DialToolId[]; /** * Validates that a dial configuration doesn't exceed the maximum allowed tools. * Throws an error with helpful message if validation fails. * * @param tools - Array of dial tool IDs to validate * @throws Error if more than MAX_DIAL_TOOLS are provided * * @example * ```tsx * // This is valid * validateDialConfig(['env', 'network', 'storage']); * * // This throws an error * validateDialConfig(['env', 'network', 'storage', 'query', 'route-events', 'debug-borders', 'benchmark']); * // Error: "Dial menu default configuration has 7 tools, but maximum is 6..." * ``` */ export function validateDialConfig(tools: DefaultDialConfig): void { if (tools.length > MAX_DIAL_TOOLS) { const toolList = tools.map((t) => `"${t}"`).join(', '); throw new Error( `Dial menu default configuration has ${tools.length} tools, but maximum is ${MAX_DIAL_TOOLS}. ` + `Tools provided: [${toolList}]. ` + `Please remove ${tools.length - MAX_DIAL_TOOLS} tool(s) from defaultDialTools.` ); } } /** * Helper to create a type-safe default configuration. * Provides autocomplete and validation at compile time. * * @example * ```tsx * import { createDefaultConfig } from '@react-buoy/core'; * * const config = createDefaultConfig({ * floating: ['env', 'environment', 'network', 'query-wifi-toggle'], * dial: ['env', 'network', 'storage', 'query', 'route-events', 'debug-borders'], * }); * * * ``` */ export function createDefaultConfig< F extends FloatingToolId[], D extends DialToolId[] >(config: { floating?: F; dial?: D; }): { floating: F | undefined; dial: D | undefined; } { // Runtime validation for dial tools if (config.dial) { validateDialConfig(config.dial); } return { floating: config.floating, dial: config.dial, }; } /** * Type guard to check if a string is a valid FloatingToolId. */ export function isFloatingToolId(id: string): id is FloatingToolId { const validIds: FloatingToolId[] = [ 'env', 'network', 'storage', 'query', 'query-wifi-toggle', 'route-events', 'debug-borders', 'highlight-updates', 'highlight-updates-modal', 'benchmark', 'environment', ]; return validIds.includes(id as FloatingToolId); } /** * Type guard to check if a string is a valid DialToolId. */ export function isDialToolId(id: string): id is DialToolId { const validIds: DialToolId[] = [ 'env', 'network', 'storage', 'query', 'query-wifi-toggle', 'route-events', 'debug-borders', 'highlight-updates', 'highlight-updates-modal', 'benchmark', ]; return validIds.includes(id as DialToolId); } /** * Converts an array of tool IDs into a settings record. * Used internally to convert default config to DevToolsSettings format. * * @internal */ export function toolIdsToRecord( ids: T[], allPossibleIds: T[] ): Record { const record: Record = {}; const enabledSet = new Set(ids); for (const id of allPossibleIds) { record[id] = enabledSet.has(id); } return record; }