···11+/**
22+ * Error Tooltips — structured descriptions for spreadsheet formula errors.
33+ *
44+ * Each error type gets a title, description, and actionable hint.
55+ * Used by the grid renderer to show rich tooltips on hover and
66+ * to apply the `cell-error` CSS class for visual treatment.
77+ */
88+99+export interface ErrorInfo {
1010+ title: string;
1111+ description: string;
1212+ hint: string;
1313+}
1414+1515+export const ERROR_DESCRIPTIONS: Record<string, ErrorInfo> = {
1616+ '#DIV/0!': {
1717+ title: 'Division by Zero',
1818+ description: 'A formula is trying to divide by zero or an empty cell.',
1919+ hint: 'Check the divisor in your formula. Use IF() to handle zero values.',
2020+ },
2121+ '#REF!': {
2222+ title: 'Invalid Reference',
2323+ description: 'A formula refers to a cell that has been deleted or is out of range.',
2424+ hint: 'Check if referenced cells were deleted or moved.',
2525+ },
2626+ '#VALUE!': {
2727+ title: 'Wrong Value Type',
2828+ description: 'A formula has the wrong type of argument (e.g., text instead of number).',
2929+ hint: 'Ensure arguments match the expected types. Use VALUE() to convert text.',
3030+ },
3131+ '#NAME?': {
3232+ title: 'Unrecognized Name',
3333+ description: 'The formula contains a name that is not recognized.',
3434+ hint: 'Check for typos in function names or named ranges.',
3535+ },
3636+ '#NULL!': {
3737+ title: 'Null Intersection',
3838+ description: 'Two ranges do not intersect.',
3939+ hint: 'Check the range references in your formula.',
4040+ },
4141+ '#N/A': {
4242+ title: 'Value Not Available',
4343+ description: 'A lookup function could not find a matching value.',
4444+ hint: 'Check the lookup value and range. Use IFERROR() to handle missing values.',
4545+ },
4646+ '#ERROR!': {
4747+ title: 'Formula Error',
4848+ description: 'The formula could not be evaluated.',
4949+ hint: 'Check the formula syntax and references.',
5050+ },
5151+ '#CIRCULAR!': {
5252+ title: 'Circular Reference',
5353+ description: 'The formula refers to its own cell, directly or indirectly.',
5454+ hint: 'Remove the self-reference or restructure the formula.',
5555+ },
5656+ '#NUM!': {
5757+ title: 'Invalid Number',
5858+ description: 'A formula produced a number that is too large, too small, or invalid.',
5959+ hint: 'Check for operations that produce infinity or invalid results.',
6060+ },
6161+};
6262+6363+/**
6464+ * Check whether a display value is a formula error.
6565+ * Errors start with `#` and end with `!` or `?`.
6666+ */
6767+export function isErrorValue(value: string): boolean {
6868+ if (typeof value !== 'string') return false;
6969+ if (!value.startsWith('#')) return false;
7070+ // Match known patterns: ends with ! or ? (possibly with extra info like "#NAME? (foo)")
7171+ return value.endsWith('!') || value.includes('?') || value === '#N/A';
7272+}
7373+7474+/**
7575+ * Look up structured error info for a given error value.
7676+ * Returns null for unrecognized errors.
7777+ */
7878+export function getErrorInfo(value: string): ErrorInfo | null {
7979+ if (typeof value !== 'string') return null;
8080+ // Direct match first
8181+ if (ERROR_DESCRIPTIONS[value]) return ERROR_DESCRIPTIONS[value];
8282+ // Prefix match for errors with extra info (e.g. "#NAME? (UNKNOWNFUNC)")
8383+ for (const key of Object.keys(ERROR_DESCRIPTIONS)) {
8484+ if (value.startsWith(key)) return ERROR_DESCRIPTIONS[key];
8585+ }
8686+ return null;
8787+}
8888+8989+/**
9090+ * Format error info into a plain-text tooltip string.
9191+ * Used as fallback for `title` attributes and accessibility.
9292+ */
9393+export function formatErrorTooltip(info: ErrorInfo): string {
9494+ return `${info.title}: ${info.description}\nHint: ${info.hint}`;
9595+}