@opencorestack/opengridx 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +4 -1
  3. package/dist/ai.cjs +1 -0
  4. package/dist/ai.cjs.map +1 -0
  5. package/dist/ai.d.ts +166 -0
  6. package/dist/ai.es.js +1 -0
  7. package/dist/ai.es.js.map +1 -0
  8. package/dist/index.d.ts +148 -2
  9. package/dist/opengridx.css +1 -1
  10. package/dist/opengridx.es.js +6084 -5523
  11. package/dist/opengridx.es.js.map +1 -1
  12. package/dist/opengridx.umd.js +17 -15
  13. package/dist/opengridx.umd.js.map +1 -1
  14. package/docs/API_REFERENCE.md +98 -1
  15. package/docs/README.md +3 -1
  16. package/docs/architecture/datagrid-orchestration.md +10 -1
  17. package/docs/customization/theming.md +9 -0
  18. package/docs/features/ai-toolkit.md +119 -0
  19. package/docs/features/clipboard.md +88 -0
  20. package/docs/features/editing-reordering.md +50 -0
  21. package/docs/features/keyboard-navigation.md +11 -0
  22. package/docs/features/undo-redo.md +79 -0
  23. package/docs/roadmap.md +1 -1
  24. package/lib/ai/coerce.ts +90 -0
  25. package/lib/ai/columns.ts +90 -0
  26. package/lib/ai/index.ts +16 -0
  27. package/lib/ai/schema.ts +214 -0
  28. package/lib/ai/types.ts +88 -0
  29. package/lib/ai/validate.ts +286 -0
  30. package/lib/components/Cell/Cell.css +5 -0
  31. package/lib/components/Cell/GridEditInputCell.css +12 -4
  32. package/lib/components/Cell/GridEditInputCell.tsx +19 -12
  33. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +14 -0
  34. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +3 -2
  35. package/lib/components/DataGrid/DataGrid.tsx +62 -2
  36. package/lib/components/FilterPanel/FilterPanel.css +14 -0
  37. package/lib/components/FilterPanel/FilterPanel.tsx +3 -2
  38. package/lib/components/ListView/ListView.css +2 -4
  39. package/lib/components/ListView/ListViewRow.tsx +2 -2
  40. package/lib/components/Toolbar/GlobalSearch.css +16 -0
  41. package/lib/components/Toolbar/GlobalSearch.tsx +3 -2
  42. package/lib/components/ui/Checkbox.tsx +16 -5
  43. package/lib/components/ui/Input.css +43 -0
  44. package/lib/components/ui/Input.tsx +24 -5
  45. package/lib/hooks/core/gridApiPlaceholder.ts +8 -1
  46. package/lib/hooks/core/useDataGrid.ts +27 -0
  47. package/lib/hooks/core/useGridCellSelection.ts +30 -2
  48. package/lib/hooks/core/useGridClipboardPaste.ts +283 -0
  49. package/lib/hooks/core/useGridUndoRedo.ts +220 -0
  50. package/lib/hooks/features/useGridBatchEdit.ts +217 -0
  51. package/lib/hooks/features/useGridEditing.ts +24 -45
  52. package/lib/index.ts +7 -0
  53. package/lib/styles/opengridx.css +2 -1
  54. package/lib/types/index.ts +124 -0
  55. package/lib/utils/editing/commit.ts +69 -0
  56. package/lib/utils/editing/targets.ts +109 -0
  57. package/lib/utils/parsing.ts +252 -0
  58. package/llms.txt +55 -1
  59. package/package.json +8 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.es.js","sources":["../lib/utils/values.ts","../lib/utils/filtering/index.ts","../lib/ai/columns.ts","../lib/ai/schema.ts","../lib/utils/parsing.ts","../lib/ai/coerce.ts","../lib/ai/validate.ts"],"sourcesContent":["import type { GridColDef, GridRowModel } from '../types';\n\nconst warnedCallbacks = new Set<string>();\n\n/**\n * Warn once per key (callback kind and column), in development only, that a consumer callback\n * threw and the grid fell back to a default instead of crashing.\n */\nexport function warnCallbackFailure(key: string, message: string, error: unknown): void {\n if (process.env.NODE_ENV === 'production' || warnedCallbacks.has(key)) return;\n warnedCallbacks.add(key);\n console.warn(`[OpenGridX] ${message}.`, error);\n}\n\n/**\n * Call a consumer callback; when it throws, warn once per `key` (dev only) and return `fallback`.\n * Used for callbacks whose failure has an obvious default (a detail-panel height, a group label).\n */\nexport function callSafely<T>(fn: () => T, fallback: T, key: string, message: string): T {\n try {\n return fn();\n } catch (error) {\n warnCallbackFailure(key, message, error);\n return fallback;\n }\n}\n\ntype ValueGetterColumn<R extends GridRowModel> = Pick<GridColDef<R>, 'valueGetter'>;\n\n/**\n * Read a cell through the column's `valueGetter` (or `row[field]`), returning a throw as `error`\n * instead of swallowing it. The row renderer uses this to show the error in that one cell.\n */\nexport function tryGetCellValue<R extends GridRowModel>(\n row: R,\n field: string,\n colDef?: ValueGetterColumn<R>\n): { value: unknown; error?: unknown } {\n const raw = row[field];\n if (!colDef?.valueGetter) return { value: raw };\n try {\n return { value: colDef.valueGetter({ row, field, value: raw }) };\n } catch (error) {\n return { value: undefined, error: error ?? new Error('valueGetter failed') };\n }\n}\n\n/**\n * The value a cell holds before formatting: the column's `valueGetter` result when it has one,\n * otherwise `row[field]`. Filtering, sorting, the quick filter, aggregation, row grouping, pivot,\n * list view, clipboard and editing all read cells through this, so a computed column behaves the\n * same everywhere. A `valueGetter` that throws reads as `undefined` (with a one-time dev warning\n * per column), so one bad record cannot take the whole grid down.\n */\nexport function getCellValue<R extends GridRowModel>(row: R, field: string, colDef?: ValueGetterColumn<R>): unknown {\n const { value, error } = tryGetCellValue(row, field, colDef);\n if (error !== undefined) {\n warnCallbackFailure(`valueGetter:${field}`, `valueGetter for column \"${field}\" threw; the value is read as undefined`, error);\n }\n return value;\n}\n\n/**\n * The column's `valueFormatter` text for `value`, or undefined when the column has no formatter\n * or the formatter throws (with a one-time dev warning per column).\n */\nexport function getFormattedValue<R extends GridRowModel>(\n row: R,\n field: string,\n value: unknown,\n colDef?: Pick<GridColDef<R>, 'valueFormatter'>\n): string | undefined {\n const formatter = colDef?.valueFormatter;\n if (!formatter) return undefined;\n return callSafely(\n () => formatter({ value, row, field }),\n undefined,\n `valueFormatter:${field}`,\n `valueFormatter for column \"${field}\" threw; the value is shown unformatted`,\n );\n}\n\n/**\n * Coerce a cell or filter value to a number. Returns null for null/undefined, blank strings,\n * NaN and anything that does not parse, so an empty cell is never read as 0.\n */\nexport function toNumber(value: unknown): number | null {\n if (value == null) return null;\n if (typeof value === 'number') return Number.isNaN(value) ? null : value;\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n const n = Number(trimmed);\n return Number.isNaN(n) ? null : n;\n }\n if (typeof value === 'boolean') return null;\n if (value instanceof Date) {\n const t = value.getTime();\n return Number.isNaN(t) ? null : t;\n }\n if (typeof value === 'bigint') return Number(value);\n return null;\n}\n\nconst DATE_ONLY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Parse a Date object, epoch milliseconds or a date string. A plain `YYYY-MM-DD` string is read\n * as a local calendar date: `new Date('2024-01-10')` is UTC midnight, which is the previous day\n * west of UTC. Returns null for empty, unparsable or invalid values.\n */\nexport function toDate(value: unknown): Date | null {\n if (value == null) return null;\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'number') {\n date = new Date(value);\n } else if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') return null;\n const match = DATE_ONLY.exec(trimmed);\n if (match) {\n const year = Number(match[1]);\n const month = Number(match[2]) - 1;\n const day = Number(match[3]);\n date = new Date(year, month, day);\n // Reject roll-overs such as 2024-02-31.\n if (date.getMonth() !== month || date.getDate() !== day) return null;\n } else {\n date = new Date(trimmed);\n }\n } else {\n return null;\n }\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\n/** A sortable integer for the local calendar day of a date (YYYYMMDD), or null when unparsable. */\nexport function toLocalDayKey(value: unknown): number | null {\n const date = toDate(value);\n if (!date) return null;\n return date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate();\n}\n\n/** The local calendar day of a date as `YYYY-MM-DD`, or '' when unparsable. */\nexport function toLocalDateString(value: unknown): string {\n const date = toDate(value);\n if (!date) return '';\n const y = String(date.getFullYear()).padStart(4, '0');\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\nlet localDateFormat: Intl.DateTimeFormat | null = null;\n\n/**\n * `date.toLocaleDateString()` (the default locale's numeric date), with the formatter created\n * once: building a new one per call is several times slower on large grids.\n */\nexport function formatLocalDate(date: Date): string {\n localDateFormat ??= new Intl.DateTimeFormat();\n return localDateFormat.format(date);\n}\n\ntype ValueOption = string | number | { value: unknown; label: string };\n\n/** The label of the `valueOptions` entry for `value`, or undefined when no option matches. */\nexport function getValueOptionLabel(options: readonly ValueOption[] | undefined, value: unknown): string | undefined {\n if (!options) return undefined;\n const optionValue = (option: ValueOption): unknown => (typeof option === 'object' ? option.value : option);\n const optionLabel = (option: ValueOption): string => (typeof option === 'object' ? option.label : String(option));\n // Exact match first; then by text, so a numeric option still labels a value read back as a string.\n const match = options.find(option => Object.is(optionValue(option), value))\n ?? options.find(option => String(optionValue(option)) === String(value));\n return match === undefined ? undefined : optionLabel(match);\n}\n\n/**\n * Default display text for a cell whose column has no `valueFormatter`, by column `type`:\n * - `date`: the local calendar date (`toLocaleDateString()`) of a Date, timestamp or date string;\n * text that does not parse as a date is shown as is.\n * - `boolean`: `Yes` / `No` for `true` / `false`.\n * - `singleSelect`: the matching `valueOptions` label; a value with no option is shown as is.\n * - anything else (and `image`, whose cell renders an image of this URL): `String(value)`.\n * null and undefined are ''. The grid cells and the text exporters (CSV, print, PDF) use this, so\n * a file shows what the grid shows.\n */\nexport function formatValueByType(value: unknown, colDef: Pick<GridColDef, 'type' | 'valueOptions'> | undefined): string {\n if (value === null || value === undefined) return '';\n switch (colDef?.type) {\n case 'date': {\n const date = toDate(value);\n return date ? formatLocalDate(date) : String(value);\n }\n case 'boolean':\n if (value === true) return 'Yes';\n if (value === false) return 'No';\n return String(value);\n case 'singleSelect':\n return getValueOptionLabel(colDef.valueOptions, value) ?? String(value);\n default:\n return String(value);\n }\n}\n","\nimport type { GridRowModel, GridFilterItem, GridFilterModel, GridFilterGroup, GridFilterOperator, GridColDef } from '../../types';\nimport type { GridColumnLookup } from '../columnLookup';\nimport { getCellValue, getFormattedValue, toLocalDateString, toLocalDayKey, toNumber } from '../values';\n\n/** Compares a cell value with the filter item's value. */\nexport type GridFilterOperatorFn = (value: unknown, filterValue?: unknown) => boolean;\n\ntype RowPredicate = (row: GridRowModel) => boolean;\n\n/** Operators that take no value. Every other operator ignores an item whose value is empty. */\nexport const NO_VALUE_OPERATORS: ReadonlySet<string> = new Set<GridFilterOperator>(['isEmpty', 'isNotEmpty']);\n\n/**\n * True for a filter value that means \"nothing entered yet\": undefined, null, a blank string or an\n * empty array. Items with such a value (other than isEmpty / isNotEmpty) do not filter.\n */\nexport function isEmptyFilterValue(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'string') return value.trim() === '';\n if (Array.isArray(value)) return value.length === 0;\n return false;\n}\n\nfunction isBlankCell(value: unknown): boolean {\n if (value == null) return true;\n if (typeof value === 'number') return Number.isNaN(value);\n return typeof value === 'string' && value.trim() === '';\n}\n\nconst numeric = (compare: (a: number, b: number) => boolean): GridFilterOperatorFn => (value, filterValue) => {\n const a = toNumber(value);\n const b = toNumber(filterValue);\n if (a === null || b === null) return false;\n return compare(a, b);\n};\n\nconst byDay = (compare: (a: number, b: number) => boolean): GridFilterOperatorFn => (value, filterValue) => {\n const a = toLocalDayKey(value);\n const b = toLocalDayKey(filterValue);\n if (a === null || b === null) return false;\n return compare(a, b);\n};\n\n/** Same local calendar day. Accepts Date objects, epoch milliseconds and date strings on both sides. */\nconst dateIs: GridFilterOperatorFn = byDay((a, b) => a === b);\n\n/** A different local calendar day. Empty or unparsable cells count as \"not that day\". */\nconst dateNot: GridFilterOperatorFn = (value, filterValue) => {\n const a = toLocalDayKey(value);\n const b = toLocalDayKey(filterValue);\n if (a === null || b === null) return true;\n return a !== b;\n};\n\nexport const FILTER_OPERATORS: Record<GridFilterOperator, GridFilterOperatorFn> = {\n contains: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().includes(String(filterValue).toLowerCase());\n },\n\n equals: (value, filterValue) => {\n if (value == null && filterValue == null) return true;\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase() === String(filterValue).toLowerCase();\n },\n\n startsWith: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().startsWith(String(filterValue).toLowerCase());\n },\n\n endsWith: (value, filterValue) => {\n if (value == null || filterValue == null) return false;\n return String(value).toLowerCase().endsWith(String(filterValue).toLowerCase());\n },\n\n isEmpty: (value) => {\n return value == null || String(value).trim() === '';\n },\n\n isNotEmpty: (value) => {\n return value != null && String(value).trim() !== '';\n },\n\n // Numeric operators: blank cells and non-numeric values never match (a blank cell is not 0).\n '=': numeric((a, b) => a === b),\n '>': numeric((a, b) => a > b),\n '>=': numeric((a, b) => a >= b),\n '<': numeric((a, b) => a < b),\n '<=': numeric((a, b) => a <= b),\n\n '!=': (value, filterValue) => {\n if (isEmptyFilterValue(filterValue)) return true;\n const a = toNumber(value);\n const b = toNumber(filterValue);\n if (a !== null && b !== null) return a !== b;\n // An empty cell is \"not equal\" to every value, whatever that value is.\n if (isBlankCell(value)) return true;\n return String(value).toLowerCase() !== String(filterValue).toLowerCase();\n },\n\n // A scalar value is treated as a one-element list, so a typed \"Active\" works like [\"Active\"].\n isAnyOf: (value, filterValue) => {\n if (value == null) return false;\n const options = Array.isArray(filterValue) ? filterValue : [filterValue];\n const cell = String(value).toLowerCase();\n return options.some(option => option != null && String(option).toLowerCase() === cell);\n },\n\n // Used by boolean and singleSelect (case-insensitive string comparison), and by dates.\n not: (value, filterValue) => {\n if (value instanceof Date) return dateNot(value, filterValue);\n if (value == null && filterValue == null) return false;\n if (value == null || filterValue == null) return true;\n return String(value).toLowerCase() !== String(filterValue).toLowerCase();\n },\n\n is: (value, filterValue) => {\n if (filterValue == null || filterValue === '') return true;\n if (value instanceof Date) return dateIs(value, filterValue);\n return String(value).toLowerCase() === String(filterValue).toLowerCase();\n },\n\n // Date operators compare local calendar days.\n after: byDay((a, b) => a > b),\n onOrAfter: byDay((a, b) => a >= b),\n before: byDay((a, b) => a < b),\n onOrBefore: byDay((a, b) => a <= b),\n};\n\n/** Date columns compare `is` / `not` by calendar day, so ISO strings and Date objects match the typed day. */\nconst DATE_COLUMN_OPERATORS: Partial<Record<GridFilterOperator, GridFilterOperatorFn>> = {\n is: dateIs,\n not: dateNot,\n};\n\nfunction resolveOperator(operator: string, colDef: GridColDef | undefined): GridFilterOperatorFn | undefined {\n if (!Object.prototype.hasOwnProperty.call(FILTER_OPERATORS, operator)) return undefined;\n const op = operator as GridFilterOperator;\n if (colDef?.type === 'date') {\n const dateFn = DATE_COLUMN_OPERATORS[op];\n if (dateFn) return dateFn;\n }\n return FILTER_OPERATORS[op];\n}\n\nfunction isFilterGroup(item: GridFilterItem | GridFilterGroup): item is GridFilterGroup {\n return 'items' in item && Array.isArray(item.items);\n}\n\ninterface CompileContext {\n columns?: GridColumnLookup;\n /** Unknown operators already reported in this pass, so the warning fires once per pass, not per row. */\n warned: Set<string>;\n}\n\nfunction compileItem(item: GridFilterItem, ctx: CompileContext): RowPredicate | null {\n const { field, operator, value } = item;\n // An item whose value has not been entered yet (or was cleared) does not filter.\n if (!NO_VALUE_OPERATORS.has(operator) && isEmptyFilterValue(value)) return null;\n\n const colDef = ctx.columns?.byField.get(field);\n const operatorFn = resolveOperator(operator, colDef);\n if (!operatorFn) {\n if (!ctx.warned.has(operator)) {\n ctx.warned.add(operator);\n console.warn(`Unknown filter operator: ${operator}`);\n }\n return null;\n }\n return (row) => operatorFn(getCellValue(row, field, colDef), value);\n}\n\nfunction compileGroup(\n items: (GridFilterItem | GridFilterGroup)[],\n logicOperator: 'and' | 'or',\n ctx: CompileContext\n): RowPredicate | null {\n const predicates: RowPredicate[] = [];\n for (const item of items) {\n const predicate = isFilterGroup(item)\n ? compileGroup(item.items, item.logicOperator, ctx)\n : compileItem(item, ctx);\n if (predicate) predicates.push(predicate);\n }\n if (predicates.length === 0) return null;\n if (predicates.length === 1) return predicates[0];\n return logicOperator === 'or'\n ? (row) => predicates.some(p => p(row))\n : (row) => predicates.every(p => p(row));\n}\n\nfunction pushSearchText(out: string[], value: unknown): void {\n if (value == null) return;\n switch (typeof value) {\n case 'string':\n out.push(value.toLowerCase());\n return;\n case 'number':\n if (!Number.isNaN(value)) out.push(String(value));\n return;\n case 'boolean':\n case 'bigint':\n out.push(String(value));\n return;\n default:\n break;\n }\n if (value instanceof Date) {\n // Search the calendar day, not Date.toString()'s \"Wed Jan 10 2024 ... GMT+0000\".\n const day = toLocalDateString(value);\n if (day) out.push(day);\n return;\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (entry == null || typeof entry !== 'object') pushSearchText(out, entry);\n }\n }\n // Other objects have no meaningful text (\"[object Object]\") and are skipped.\n}\n\nfunction getQuickFilterTexts(row: GridRowModel, columns: GridColumnLookup | undefined): string[] {\n const texts: string[] = [];\n if (!columns) {\n for (const value of Object.values(row)) pushSearchText(texts, value);\n return texts;\n }\n for (const col of columns.quickFilterColumns) {\n const value = getCellValue(row, col.field, col);\n const formatted = getFormattedValue(row, col.field, value, col);\n if (formatted != null && formatted !== '') texts.push(String(formatted).toLowerCase());\n pushSearchText(texts, value);\n }\n return texts;\n}\n\n// Search texts per column lookup and row object. The grid keeps one lookup while the columns and\n// hidden columns stay the same, so typing in the quick filter reads every cell once, not per keystroke.\nconst quickFilterTextCache = new WeakMap<GridColumnLookup, WeakMap<GridRowModel, string[]>>();\n\nfunction getCachedQuickFilterTexts(row: GridRowModel, columns: GridColumnLookup | undefined): string[] {\n if (!columns) return getQuickFilterTexts(row, columns);\n let byRow = quickFilterTextCache.get(columns);\n if (!byRow) {\n byRow = new WeakMap();\n quickFilterTextCache.set(columns, byRow);\n }\n let texts = byRow.get(row);\n if (!texts) {\n texts = getQuickFilterTexts(row, columns);\n byRow.set(row, texts);\n }\n return texts;\n}\n\nfunction compileQuickFilter(values: readonly string[] | undefined, columns: GridColumnLookup | undefined): RowPredicate | null {\n const terms = (values ?? [])\n .map(value => String(value ?? '').trim().toLowerCase())\n .filter(term => term !== '');\n if (terms.length === 0) return null;\n return (row) => {\n const texts = getCachedQuickFilterTexts(row, columns);\n return terms.every(term => texts.some(text => text.includes(term)));\n };\n}\n\n/**\n * Compile a filter model into a row predicate. Returns null when the model filters nothing\n * (no items with a value and no quick-filter terms), so callers can skip the pass entirely.\n *\n * Pass `columns` so that cells are read through `valueGetter`, date columns use calendar-day\n * comparison and the quick filter searches only visible, filterable columns (including their\n * `valueFormatter` text). Without it, `row[field]` is read and the quick filter searches every\n * primitive value in the row.\n */\nexport function createRowFilter(\n filterModel: GridFilterModel | GridFilterGroup | null | undefined,\n columns?: GridColumnLookup\n): RowPredicate | null {\n if (!filterModel) return null;\n const ctx: CompileContext = { columns, warned: new Set() };\n const quickFilterValues = 'quickFilterValues' in filterModel ? filterModel.quickFilterValues : undefined;\n const quick = compileQuickFilter(quickFilterValues, columns);\n const itemsPredicate = compileGroup(filterModel.items ?? [], filterModel.logicOperator ?? 'and', ctx);\n if (quick && itemsPredicate) return (row) => quick(row) && itemsPredicate(row);\n return quick ?? itemsPredicate;\n}\n\n/**\n * Apply a single filter item to a row\n */\nexport function applyFilterItem<R extends GridRowModel>(\n row: R,\n filterItem: GridFilterItem,\n colDef?: GridColDef\n): boolean {\n const columns: GridColumnLookup | undefined = colDef\n ? { byField: new Map([[filterItem.field, colDef]]), quickFilterColumns: [] }\n : undefined;\n const predicate = compileItem(filterItem, { columns, warned: new Set() });\n return predicate ? predicate(row) : true;\n}\n\n/**\n * Apply the quick filter (global search). Every term must be found in at least one searched value.\n */\nexport function applyQuickFilter<R extends GridRowModel>(\n row: R,\n quickFilterValues: string[],\n columns?: GridColumnLookup\n): boolean {\n const predicate = compileQuickFilter(quickFilterValues, columns);\n return predicate ? predicate(row) : true;\n}\n\n/**\n * Check if a row matches the filter model. Compiles the model on every call: to test many rows,\n * build a predicate once with createRowFilter.\n */\nexport function isRowMatchingFilter<R extends GridRowModel>(\n row: R,\n filterModel: GridFilterModel | GridFilterGroup,\n columns?: GridColumnLookup\n): boolean {\n const predicate = createRowFilter(filterModel, columns);\n return predicate ? predicate(row) : true;\n}\n\nexport function filterRows<R extends GridRowModel>(\n rows: R[],\n filterModel: GridFilterModel,\n columns?: GridColumnLookup\n): R[] {\n const predicate = createRowFilter(filterModel, columns);\n if (!predicate) return rows;\n return rows.filter(row => predicate(row));\n}\n\nexport function getDefaultOperator(type?: string): GridFilterOperator {\n switch (type) {\n case 'number':\n return '=';\n case 'date':\n return 'is';\n case 'boolean':\n return 'is';\n case 'singleSelect':\n return 'isAnyOf';\n default:\n return 'contains';\n }\n}\n\nexport function getOperatorsForType(type?: string): GridFilterOperator[] {\n switch (type) {\n case 'number':\n return ['=', '!=', '>', '>=', '<', '<=', 'isEmpty', 'isNotEmpty'];\n case 'date':\n return ['is', 'not', 'after', 'onOrAfter', 'before', 'onOrBefore', 'isEmpty', 'isNotEmpty'];\n case 'boolean':\n return ['is'];\n case 'singleSelect':\n return ['isAnyOf', 'is', 'not'];\n default:\n return ['contains', 'equals', 'startsWith', 'endsWith', 'isEmpty', 'isNotEmpty'];\n }\n}\n","// Which columns may take part in each part of the state. The schema and the validator both read\n// these, so the model is never offered a field the validator would drop.\nimport { getOperatorsForType } from '../utils/filtering';\nimport type { GridFilterOperator, GridPivotAggFn } from '../types';\nimport type { GridAiColumn, GridAiPart, GridAiPartOptions } from './types';\n\n/** The built-in aggregation functions (`AGGREGATION_FUNCTIONS` in lib/utils/aggregation). */\nexport const AGGREGATION_FNS: readonly string[] = ['sum', 'avg', 'count', 'min', 'max', 'unique'];\n/** The functions a pivot value field takes (`GridPivotAggFn`). */\nexport const PIVOT_FNS: readonly GridPivotAggFn[] = ['sum', 'avg', 'count', 'min', 'max'];\n/** Operators without a value. */\nexport const NO_VALUE_OPS: readonly string[] = ['isEmpty', 'isNotEmpty'];\n/** Deepest nesting of filter groups. */\nexport const MAX_FILTER_DEPTH = 3;\n\nexport const ALL_PARTS: readonly GridAiPart[] = ['filter', 'sort', 'grouping', 'aggregation', 'pivot', 'columnVisibility'];\n\n/** State key of each part, in output order. */\nexport const PART_KEYS: Record<GridAiPart, string> = {\n filter: 'filterModel',\n sort: 'sortModel',\n grouping: 'rowGroupingModel',\n aggregation: 'aggregationModel',\n pivot: 'pivotModel',\n columnVisibility: 'columnVisibilityModel',\n};\n\nexport function hasOwn(obj: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function selectedParts(options: GridAiPartOptions | undefined): GridAiPart[] {\n const include = Array.isArray(options?.include) ? options.include : ALL_PARTS;\n const exclude = Array.isArray(options?.exclude) ? options.exclude : [];\n return ALL_PARTS.filter((part) => include.includes(part) && !exclude.includes(part));\n}\n\n/**\n * The usable columns, first one per field. System columns (`__check__`, `__group__`, …), spacers\n * and fields that are not plain strings are skipped.\n */\nexport function usableColumns(columns: readonly GridAiColumn[] | unknown): GridAiColumn[] {\n if (!Array.isArray(columns)) return [];\n const seen = new Set<string>();\n const out: GridAiColumn[] = [];\n for (const col of columns as unknown[]) {\n if (!isPlainObject(col)) continue;\n const field = col.field;\n if (typeof field !== 'string' || field === '' || field.startsWith('__') || col.isSpacer === true || seen.has(field)) continue;\n seen.add(field);\n out.push(col as unknown as GridAiColumn);\n }\n return out;\n}\n\nexport function operatorsOf(col: GridAiColumn): GridFilterOperator[] {\n return getOperatorsForType(col.type);\n}\n\nexport const isFilterable = (col: GridAiColumn): boolean => col.filterable !== false;\nexport const isSortable = (col: GridAiColumn): boolean => col.sortable !== false;\nexport const isGroupable = (col: GridAiColumn): boolean => col.groupable !== false;\nexport const isHideable = (col: GridAiColumn): boolean => col.hideable !== false;\n\n/**\n * Aggregation functions for a column, as the Summaries panel offers them: every built-in function\n * for number columns (or `aggregable: true`), `count` for the others, never with `aggregable: false`,\n * and limited by `availableAggregationFunctions`.\n */\nexport function aggregationFnsOf(col: GridAiColumn, fns: readonly string[] = AGGREGATION_FNS): string[] {\n if (col.aggregable === false) return [];\n const base = col.type === 'number' || col.aggregable === true ? fns : fns.filter((fn) => fn === 'count');\n const allowed = col.availableAggregationFunctions;\n return Array.isArray(allowed) ? base.filter((fn) => allowed.includes(fn)) : [...base];\n}\n\n/** JSON-safe option values of a singleSelect column, in order, without duplicates. */\nexport function optionValues(col: GridAiColumn): (string | number)[] {\n const out: (string | number)[] = [];\n if (!Array.isArray(col.valueOptions)) return out;\n for (const option of col.valueOptions) {\n const value: unknown = option !== null && typeof option === 'object' ? option.value : option;\n if ((typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value))) && !out.includes(value)) out.push(value);\n }\n return out;\n}\n","// getGridAiSchema: a JSON Schema (draft 2020-12) of the grid state a model may produce. Built from\n// the column definitions only; no row data is read. Same columns and options, same schema.\nimport {\n MAX_FILTER_DEPTH,\n NO_VALUE_OPS,\n PART_KEYS,\n PIVOT_FNS,\n aggregationFnsOf,\n isFilterable,\n isGroupable,\n isHideable,\n isSortable,\n operatorsOf,\n optionValues,\n selectedParts,\n usableColumns,\n} from './columns';\nimport type { GridAiColumn, GridAiJsonSchema, GridAiPart, GridAiSchema, GridAiSchemaOptions } from './types';\n\n/** Title of every schema. Also the marker `check-bundle` uses to keep this code out of the core bundle. */\nexport const GRID_AI_SCHEMA_TITLE = 'OpenGridX grid state';\n\nconst MAX_EXAMPLES = 10;\n\ninterface Ctx {\n descriptions: boolean;\n examples: boolean;\n}\n\nfunction label(col: GridAiColumn): string {\n const header = typeof col.headerName === 'string' && col.headerName !== '' ? col.headerName : col.field;\n const desc = typeof col.description === 'string' && col.description !== '' ? ` (${col.description})` : '';\n return `${header}${desc}`;\n}\n\nfunction describe(node: GridAiJsonSchema, text: string, ctx: Ctx): GridAiJsonSchema {\n return ctx.descriptions ? { ...node, description: text } : node;\n}\n\nfunction examplesOf(col: GridAiColumn, ctx: Ctx): unknown[] {\n if (!ctx.examples || !Array.isArray(col.aiExamples)) return [];\n return col.aiExamples\n .filter((v) => typeof v === 'string' || typeof v === 'boolean' || (typeof v === 'number' && Number.isFinite(v)))\n .slice(0, MAX_EXAMPLES);\n}\n\n/** Schema of one filter value for the column's type. */\nfunction valueSchema(col: GridAiColumn, ctx: Ctx): GridAiJsonSchema {\n let node: GridAiJsonSchema;\n switch (col.type) {\n case 'number':\n node = { type: 'number' };\n break;\n case 'date':\n node = { type: 'string', format: 'date' };\n break;\n case 'boolean':\n node = { type: 'boolean' };\n break;\n case 'singleSelect': {\n const values = optionValues(col);\n const one: GridAiJsonSchema = values.length > 0 ? { enum: values } : { type: 'string' };\n node = { anyOf: [one, { type: 'array', items: one }] };\n break;\n }\n default:\n node = { type: 'string' };\n }\n const examples = examplesOf(col, ctx);\n return examples.length > 0 ? { ...node, examples } : node;\n}\n\nfunction filterItemSchema(col: GridAiColumn, ctx: Ctx): GridAiJsonSchema {\n const operators = operatorsOf(col);\n const noValue = operators.filter((op) => NO_VALUE_OPS.includes(op));\n const hint = col.type === 'singleSelect' ? '; isAnyOf takes an array' : '';\n const ops = noValue.length > 0 ? `${noValue.join(' and ')} take no value${hint}` : hint.slice(2);\n return describe(\n {\n type: 'object',\n properties: {\n field: { const: col.field },\n operator: { enum: operators },\n value: valueSchema(col, ctx),\n },\n required: ['field', 'operator'],\n additionalProperties: false,\n },\n ops ? `${label(col)}: ${ops}` : label(col),\n ctx,\n );\n}\n\nfunction filterSchema(cols: GridAiColumn[], ctx: Ctx, defs: Record<string, GridAiJsonSchema>): GridAiJsonSchema | null {\n const filterable = cols.filter(isFilterable);\n const properties: Record<string, GridAiJsonSchema> = {};\n const logic = { enum: ['and', 'or'] };\n if (filterable.length > 0) {\n defs.filterItem = { oneOf: filterable.map((col) => filterItemSchema(col, ctx)) };\n // Groups are unrolled to MAX_FILTER_DEPTH levels: the deepest one holds items only.\n for (let depth = MAX_FILTER_DEPTH; depth >= 1; depth--) {\n const child = depth === MAX_FILTER_DEPTH ? { $ref: '#/$defs/filterItem' } : { anyOf: [{ $ref: '#/$defs/filterItem' }, { $ref: `#/$defs/filterGroup${depth + 1}` }] };\n defs[`filterGroup${depth}`] = {\n type: 'object',\n properties: { logicOperator: logic, items: { type: 'array', items: child } },\n required: ['logicOperator', 'items'],\n additionalProperties: false,\n };\n }\n properties.items = { type: 'array', items: { anyOf: [{ $ref: '#/$defs/filterItem' }, { $ref: '#/$defs/filterGroup1' }] } };\n properties.logicOperator = logic;\n }\n properties.quickFilterValues = describe({ type: 'array', items: { type: 'string' } }, 'Words a row must contain, in any column', ctx);\n return { type: 'object', properties, additionalProperties: false };\n}\n\nfunction fieldEnum(cols: GridAiColumn[]): GridAiJsonSchema {\n return { enum: cols.map((c) => c.field) };\n}\n\nfunction partSchema(part: GridAiPart, cols: GridAiColumn[], ctx: Ctx, defs: Record<string, GridAiJsonSchema>): GridAiJsonSchema | null {\n switch (part) {\n case 'filter':\n return filterSchema(cols, ctx, defs);\n case 'sort': {\n const sortable = cols.filter(isSortable);\n if (sortable.length === 0) return null;\n return describe(\n {\n type: 'array',\n items: {\n type: 'object',\n properties: { field: fieldEnum(sortable), sort: { enum: ['asc', 'desc'] } },\n required: ['field', 'sort'],\n additionalProperties: false,\n },\n },\n 'Most significant first',\n ctx,\n );\n }\n case 'grouping': {\n const groupable = cols.filter(isGroupable);\n if (groupable.length === 0) return null;\n return describe({ type: 'array', items: fieldEnum(groupable), uniqueItems: true }, 'Outermost first', ctx);\n }\n case 'aggregation': {\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const col of cols) {\n const fns = aggregationFnsOf(col);\n if (fns.length > 0) properties[col.field] = describe({ enum: fns }, label(col), ctx);\n }\n if (Object.keys(properties).length === 0) return null;\n return { type: 'object', properties, additionalProperties: false };\n }\n case 'pivot': {\n const dims = cols.filter(isGroupable);\n const values = cols\n .map((col) => ({ col, fns: aggregationFnsOf(col, PIVOT_FNS) }))\n .filter((v) => v.fns.length > 0)\n .map(({ col, fns }) => describe({\n type: 'object',\n properties: { field: { const: col.field }, aggFn: { enum: fns } },\n required: ['field', 'aggFn'],\n additionalProperties: false,\n }, label(col), ctx));\n if (dims.length === 0 || values.length === 0) return null;\n const dimArray = { type: 'array', items: fieldEnum(dims), uniqueItems: true };\n return {\n type: 'object',\n properties: { rowFields: dimArray, columnFields: dimArray, valueFields: { type: 'array', items: { oneOf: values } } },\n required: ['rowFields', 'columnFields', 'valueFields'],\n additionalProperties: false,\n };\n }\n case 'columnVisibility': {\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const col of cols.filter(isHideable)) properties[col.field] = describe({ type: 'boolean' }, label(col), ctx);\n if (Object.keys(properties).length === 0) return null;\n return describe({ type: 'object', properties, additionalProperties: false }, 'false hides a column', ctx);\n }\n }\n}\n\n/**\n * A JSON Schema (draft 2020-12) of the grid state a model may return for these columns: filter,\n * sort, grouping, aggregation, pivot and column visibility, each limited to the fields, operators\n * and functions the columns allow. Send it with the user's prompt to a model with structured\n * output, then pass the reply to `validateGridAiState`. Reads column definitions only, never rows.\n * @since v3.4\n */\nexport function getGridAiSchema<C extends GridAiColumn>(columns: readonly C[], options: GridAiSchemaOptions = {}): GridAiSchema {\n const ctx: Ctx = { descriptions: options.descriptions !== false, examples: options.examples !== false };\n const cols = usableColumns(columns);\n const defs: Record<string, GridAiJsonSchema> = {};\n const properties: Record<string, GridAiJsonSchema> = {};\n for (const part of selectedParts(options)) {\n const node = partSchema(part, cols, ctx, defs);\n if (node) properties[PART_KEYS[part]] = node;\n }\n const schema: GridAiSchema = {\n $schema: 'https://json-schema.org/draft/2020-12/schema',\n schemaVersion: 1,\n title: GRID_AI_SCHEMA_TITLE,\n type: 'object',\n properties,\n additionalProperties: false,\n };\n if (ctx.descriptions) {\n schema.description = 'Grid state to apply. Include only the parts the user asked to change.';\n }\n if (Object.keys(defs).length > 0) schema.$defs = defs;\n return schema;\n}\n","import type { GridColDef, GridValidRowModel } from '../types';\nimport { toDate } from './values';\n\n/**\n * Text → typed values: the TSV reader clipboard paste uses, and the per-column-type parsers paste,\n * `GridColDef.valueParser` defaults and the `/ai` validator share. Pure and React-free.\n *\n * Every pattern here is linear (CodeQL scans every push): no adjacent quantifiers that can match the\n * same characters.\n */\n\n/** A parsed value, or `{ ok: false }` when the text does not fit the column type. */\nexport type GridParsedValue = { ok: true; value: unknown } | { ok: false };\n\nconst INVALID: GridParsedValue = { ok: false };\nconst valid = (value: unknown): GridParsedValue => ({ ok: true, value });\n\n/**\n * Splits tab-separated text the way Excel, Google Sheets and LibreOffice write it: tabs between\n * columns, `\\r\\n`, `\\n` or `\\r` between rows. A field that starts with a double quote is quoted: it\n * may hold tabs, line breaks and doubled quotes (`\"\"` → `\"`), the reverse of `escapeTsvField`. A\n * quote inside an unquoted field is kept as is. A trailing empty line is ignored, so `\"a\\tb\\n\"` is one\n * row. Empty text gives no rows.\n */\nexport function parseTsv(text: string): string[][] {\n const rows: string[][] = [];\n if (text === '') return rows;\n let row: string[] = [];\n let field = '';\n let i = 0;\n const n = text.length;\n let fieldStart = true;\n while (i < n) {\n const ch = text[i];\n if (fieldStart && ch === '\"') {\n // A quoted field: read to the closing quote, `\"\"` being one quote.\n let j = i + 1;\n let value = '';\n let closed = false;\n while (j < n) {\n const q = text[j];\n if (q === '\"') {\n if (text[j + 1] === '\"') {\n value += '\"';\n j += 2;\n continue;\n }\n closed = true;\n j += 1;\n break;\n }\n value += q;\n j += 1;\n }\n if (!closed) {\n // No closing quote: not a quoted field after all, read the quote as text.\n field += ch;\n i += 1;\n fieldStart = false;\n continue;\n }\n field += value;\n i = j;\n fieldStart = false;\n continue;\n }\n fieldStart = false;\n if (ch === '\\t') {\n row.push(field);\n field = '';\n fieldStart = true;\n i += 1;\n } else if (ch === '\\n' || ch === '\\r') {\n row.push(field);\n rows.push(row);\n row = [];\n field = '';\n fieldStart = true;\n i += ch === '\\r' && text[i + 1] === '\\n' ? 2 : 1;\n } else {\n field += ch;\n i += 1;\n }\n }\n // The last line, unless the text ended with a line break (Excel always adds one).\n if (!fieldStart || row.length > 0 || field !== '') {\n row.push(field);\n rows.push(row);\n }\n return rows;\n}\n\nconst PLAIN_NUMBER = /^\\d+(?:\\.\\d*)?(?:e[+-]?\\d+)?$/i;\nconst LEADING_DOT_NUMBER = /^\\.\\d+(?:e[+-]?\\d+)?$/i;\nconst GROUPED_NUMBER = /^\\d{1,3}(?:,\\d{3})+(?:\\.\\d*)?$/;\n// Currency symbols (Unicode Sc) and every kind of space, including the no-break spaces Excel uses\n// as a thousands separator.\nconst STRIPPED_CHARS = /[\\p{Sc}\\s]/gu;\n\n/**\n * A number as spreadsheets copy it: `1234.5`, `1,234.5` (comma thousands groups only), `-12`,\n * `(12)` (accounting negative), `12%` (→ 0.12), `1e3`, with currency symbols and spaces stripped.\n * Empty text is `null`. `1,5` is not accepted (it is ambiguous): use a `valueParser` for\n * decimal-comma locales.\n */\nexport function parseNumberText(text: string): GridParsedValue {\n let s = text.replace(STRIPPED_CHARS, '');\n if (s === '') return text.trim() === '' ? valid(null) : INVALID;\n let negative = false;\n if (s.startsWith('(') && s.endsWith(')')) {\n negative = true;\n s = s.slice(1, -1);\n }\n if (s.startsWith('-') || s.startsWith('+') || s.startsWith('−')) {\n if (s[0] !== '+') negative = !negative;\n s = s.slice(1);\n }\n let percent = false;\n if (s.endsWith('%')) {\n percent = true;\n s = s.slice(0, -1);\n }\n if (GROUPED_NUMBER.test(s)) s = s.split(',').join('');\n else if (!PLAIN_NUMBER.test(s) && !LEADING_DOT_NUMBER.test(s)) return INVALID;\n let value = Number(s);\n if (!Number.isFinite(value)) return INVALID;\n if (percent) value /= 100;\n if (negative) value = -value;\n return valid(value);\n}\n\nconst ISO_DATE_PREFIX = /^(\\d{4}-\\d{2}-\\d{2})/;\nconst pad2 = (n: number) => String(n).padStart(2, '0');\nconst localDay = (date: Date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;\n\n/**\n * A date: ISO `2026-10-07` (read as that local calendar day) or anything `Date.parse` accepts. Empty\n * text is `null`. The result takes the kind of `current` (the value the cell holds now), as the date\n * editor does: a timestamp stays a timestamp, a date string stays a `YYYY-MM-DD` string (an ISO\n * date-time string keeps its time part); otherwise it is a `Date`.\n */\nexport function parseDateText(text: string, current?: unknown): GridParsedValue {\n const trimmed = text.trim();\n if (trimmed === '') return valid(null);\n const date = toDate(trimmed);\n if (!date) return INVALID;\n if (typeof current === 'number') return valid(date.getTime());\n if (typeof current === 'string') {\n const day = localDay(date);\n return valid(ISO_DATE_PREFIX.test(current) && current.length > 10 ? day + current.slice(10) : day);\n }\n return valid(date);\n}\n\n/** Text read as `true` / `false`, besides the grid's own `Yes` / `No` cell labels. Lower case. */\nconst TRUE_WORDS = new Set(['true', 'yes', '1']);\nconst FALSE_WORDS = new Set(['false', 'no', '0']);\n\nexport interface GridBooleanLabels {\n /** Text shown for `true` (the grid shows `Yes`). */\n trueLabel?: string;\n /** Text shown for `false` (the grid shows `No`). */\n falseLabel?: string;\n}\n\n/**\n * A boolean: `true`/`false`, `yes`/`no` (the grid's own `Yes` / `No` cell labels), `1`/`0` and any\n * `labels` given, case-insensitive. Empty text is `null`.\n */\nexport function parseBooleanText(text: string, labels?: GridBooleanLabels): GridParsedValue {\n const s = text.trim().toLowerCase();\n if (s === '') return valid(null);\n if (labels?.trueLabel !== undefined && s === labels.trueLabel.trim().toLowerCase()) return valid(true);\n if (labels?.falseLabel !== undefined && s === labels.falseLabel.trim().toLowerCase()) return valid(false);\n if (TRUE_WORDS.has(s)) return valid(true);\n if (FALSE_WORDS.has(s)) return valid(false);\n return INVALID;\n}\n\ntype ValueOption = NonNullable<GridColDef['valueOptions']>[number];\n\n/**\n * A `singleSelect` value: the option whose value or label matches the text, case-insensitive (values\n * first). Returns the option's own value, so a numeric option stays a number. Empty text is `null`.\n */\nexport function parseSingleSelectText(text: string, options: readonly ValueOption[] | undefined): GridParsedValue {\n const s = text.trim();\n if (s === '') return valid(null);\n if (!options || options.length === 0) return INVALID;\n const lower = s.toLowerCase();\n for (const option of options) {\n const value = typeof option === 'object' ? option.value : option;\n if (String(value).toLowerCase() === lower) return valid(value);\n }\n for (const option of options) {\n if (typeof option === 'object' && option.label.toLowerCase() === lower) return valid(option.value);\n }\n return INVALID;\n}\n\ntype ParserColumn = Pick<GridColDef, 'type' | 'valueOptions'>;\n\nexport interface GridParseTextOptions {\n /** The value the cell holds now: a parsed date takes its kind (see `parseDateText`). */\n current?: unknown;\n /** Extra boolean labels, besides `Yes` / `No`. */\n booleanLabels?: GridBooleanLabels;\n}\n\n/**\n * Parses cell text by the column `type`, without `valueParser`:\n *\n * | type | accepted |\n * | :--- | :--- |\n * | `string` (default), `image` | the text as is (an empty cell is `''`) |\n * | `number` | `parseNumberText` |\n * | `date` | `parseDateText` |\n * | `boolean` | `parseBooleanText` |\n * | `singleSelect` | `parseSingleSelectText` |\n *\n * An empty cell is `null` for every type but `string` / `image`.\n */\nexport function parseValueByType(text: string, colDef: ParserColumn | undefined, options?: GridParseTextOptions): GridParsedValue {\n switch (colDef?.type) {\n case 'number': return parseNumberText(text);\n case 'date': return parseDateText(text, options?.current);\n case 'boolean': return parseBooleanText(text, options?.booleanLabels);\n case 'singleSelect': return parseSingleSelectText(text, colDef.valueOptions);\n default: return valid(text);\n }\n}\n\n/**\n * Parses the text pasted into one cell: the column's `valueParser` when it has one (a throw, or a\n * returned `undefined`, rejects the text), otherwise `parseValueByType`.\n */\nexport function parseCellText<R extends GridValidRowModel>(\n text: string,\n colDef: GridColDef<R>,\n row: R,\n options?: GridParseTextOptions,\n): GridParsedValue {\n const { valueParser } = colDef;\n if (!valueParser) return parseValueByType(text, colDef as unknown as ParserColumn, options);\n let value: unknown;\n try {\n value = valueParser(text, { row, field: colDef.field, colDef });\n } catch {\n return INVALID;\n }\n return value === undefined ? INVALID : valid(value);\n}\n","// Value coercion for the AI validator. Text goes through the same parsers as clipboard paste\n// (`lib/utils/parsing.ts`), so a value the grid accepts from Excel is accepted from a model and the\n// other way round. Model output is JSON, so typed values (a number, a boolean, a Date) are taken as\n// they are. Empty input is valid: null, or '' for text columns.\nimport {\n parseBooleanText,\n parseDateText,\n parseNumberText,\n parseSingleSelectText,\n type GridParsedValue,\n} from '../utils/parsing';\n\nexport type CoerceResult<T = unknown> = { ok: true; value: T } | { ok: false; reason: 'invalidValue' };\n\n/** The column properties coercion reads. */\nexport interface CoerceColumn {\n type?: string;\n valueOptions?: readonly (string | number | { value: unknown; label: string })[];\n}\n\nconst ok = <T>(value: T): CoerceResult<T> => ({ ok: true, value });\nconst INVALID: CoerceResult<never> = { ok: false, reason: 'invalidValue' };\n\nconst fromParsed = <T>(parsed: GridParsedValue): CoerceResult<T> =>\n parsed.ok ? ok(parsed.value as T) : INVALID;\n\nfunction isBlank(text: unknown): boolean {\n return text == null || (typeof text === 'string' && text.trim() === '');\n}\n\n/** `string` and `image` columns: text as is. Numbers and booleans become their text. */\nexport function coerceString(text: unknown): CoerceResult<string> {\n if (text == null) return ok('');\n if (typeof text === 'string') return ok(text);\n if (typeof text === 'number' || typeof text === 'boolean') return ok(String(text));\n return INVALID;\n}\n\n/** `number` columns: a finite number, or text in the paste format (`1,234.5`, `12%`, `$40`). */\nexport function coerceNumber(text: unknown): CoerceResult<number | null> {\n if (isBlank(text)) return ok(null);\n if (typeof text === 'number') return Number.isFinite(text) ? ok(text) : INVALID;\n if (typeof text !== 'string') return INVALID;\n return fromParsed(parseNumberText(text));\n}\n\n/** `date` columns: a Date, epoch milliseconds, or text in the paste format (ISO `2026-10-07` …). */\nexport function coerceDate(text: unknown): CoerceResult<Date | null> {\n if (isBlank(text)) return ok(null);\n if (text instanceof Date) return Number.isNaN(text.getTime()) ? INVALID : ok(text);\n if (typeof text === 'number') return Number.isFinite(text) ? ok(new Date(text)) : INVALID;\n if (typeof text !== 'string') return INVALID;\n return fromParsed(parseDateText(text));\n}\n\n/** `boolean` columns: a boolean, or `true`/`false`, `yes`/`no`, `1`/`0` (case-insensitive). */\nexport function coerceBoolean(text: unknown): CoerceResult<boolean | null> {\n if (isBlank(text)) return ok(null);\n if (typeof text === 'boolean') return ok(text);\n if (typeof text !== 'string' && typeof text !== 'number') return INVALID;\n return fromParsed(parseBooleanText(String(text)));\n}\n\n/**\n * `singleSelect` columns: an option value or label, case-insensitive; returns the option's value.\n * Without `valueOptions` the model has nothing to choose from, so any scalar is kept as it is.\n */\nexport function coerceSingleSelect(text: unknown, colDef: CoerceColumn): CoerceResult<unknown> {\n if (isBlank(text)) return ok(null);\n if (typeof text !== 'string' && typeof text !== 'number' && typeof text !== 'boolean') return INVALID;\n const options = colDef.valueOptions;\n if (!options || options.length === 0) return ok(text);\n return fromParsed(parseSingleSelectText(String(text), options));\n}\n\n/** Coerces `text` for the column's `type`. */\nexport function coerceValue(text: unknown, colDef: CoerceColumn): CoerceResult<unknown> {\n switch (colDef.type) {\n case 'number':\n return coerceNumber(text);\n case 'date':\n return coerceDate(text);\n case 'boolean':\n return coerceBoolean(text);\n case 'singleSelect':\n return coerceSingleSelect(text, colDef);\n default:\n return coerceString(text);\n }\n}\n","// validateGridAiState: the safety layer between a model's reply and the grid. Anything the columns\n// do not allow is dropped with an error; values are coerced to the column type. Never throws.\n// Only own keys of the input are read (never `__proto__`), and every key written to the output is a\n// column field, so nothing in the reply can reach Object.prototype or the output's prototype.\nimport type {\n GridAggregationModel,\n GridColumnVisibilityModel,\n GridFilterGroup,\n GridFilterItem,\n GridFilterModel,\n GridFilterOperator,\n GridPivotModel,\n GridPivotValueField,\n GridSortItem,\n} from '../types';\nimport { toLocalDateString } from '../utils/values';\nimport { coerceBoolean, coerceValue } from './coerce';\nimport {\n ALL_PARTS,\n MAX_FILTER_DEPTH,\n NO_VALUE_OPS,\n PART_KEYS,\n PIVOT_FNS,\n aggregationFnsOf,\n hasOwn,\n isFilterable,\n isGroupable,\n isHideable,\n isPlainObject,\n isSortable,\n operatorsOf,\n selectedParts,\n usableColumns,\n} from './columns';\nimport type { GridAiColumn, GridAiPart, GridAiState, GridAiValidateOptions, GridAiValidationError, GridAiValidationResult } from './types';\n\n/** Longest list read from the model output; the rest is dropped with one error. */\nconst MAX_LIST = 200;\n/** Errors past this many are not listed, so a reply full of junk still gives a readable list. */\nconst MAX_ERRORS = 100;\n\ntype Allowed = (col: GridAiColumn) => boolean;\ntype FilterNode = GridFilterItem | GridFilterGroup;\n\ninterface Ctx {\n errors: GridAiValidationError[];\n byField: Map<string, GridAiColumn>;\n}\n\nfunction fail(ctx: Ctx, path: string, message: string): null {\n if (ctx.errors.length < MAX_ERRORS) ctx.errors.push({ path, message });\n return null;\n}\n\n/** A short, safe rendering of a value for an error message. */\nfunction show(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.slice(0, 60));\n return value === null || typeof value !== 'object' ? String(value) : Array.isArray(value) ? 'a list' : 'an object';\n}\n\nfunction lower(value: unknown): string | null {\n return typeof value === 'string' ? value.trim().toLowerCase() : null;\n}\n\n/** Own enumerable keys of the input, without `__proto__`. */\nfunction keysOf(obj: Record<string, unknown>): string[] {\n return Object.keys(obj).filter((key) => key !== '__proto__');\n}\n\nfunction column(ctx: Ctx, value: unknown, path: string, allowed: Allowed, what: string): GridAiColumn | null {\n const col = typeof value === 'string' ? ctx.byField.get(value) : undefined;\n if (!col) return fail(ctx, path, `Unknown field ${show(value)}`);\n return allowed(col) ? col : fail(ctx, path, `Field ${show(value)} cannot be ${what}`);\n}\n\n/** The first MAX_LIST entries of an array; a single value is read as a one-entry list. */\nfunction list(ctx: Ctx, value: unknown, path: string): unknown[] {\n if (value == null) return [];\n const items = Array.isArray(value) ? value : [value];\n if (items.length > MAX_LIST) fail(ctx, path, `Only the first ${MAX_LIST} entries are read`);\n return items.slice(0, MAX_LIST);\n}\n\n/** The choice `value` names, case-insensitively, in the choice's own spelling. */\nfunction oneOf(ctx: Ctx, value: unknown, path: string, choices: readonly string[]): string | null {\n const v = lower(value);\n return choices.find((c) => c.toLowerCase() === v) ?? fail(ctx, path, `${show(value)} is not one of ${choices.join(', ')}`);\n}\n\n/** One filter value, coerced; dates become `YYYY-MM-DD` as the filter panel writes them. */\nfunction filterValue(ctx: Ctx, raw: unknown, col: GridAiColumn, path: string): { v: unknown } | null {\n const result = coerceValue(raw, col);\n if (!result.ok) return fail(ctx, path, `${show(raw)} is not a valid ${col.type ?? 'string'} value`);\n const v = result.value instanceof Date ? toLocalDateString(result.value) : result.value;\n return v == null || v === '' ? fail(ctx, path, 'Missing value') : { v };\n}\n\nfunction filterItem(ctx: Ctx, raw: Record<string, unknown>, path: string): GridFilterItem | null {\n const col = column(ctx, raw.field, `${path}.field`, isFilterable, 'filtered');\n if (!col) return null;\n const operator = oneOf(ctx, raw.operator, `${path}.operator`, operatorsOf(col));\n if (operator === null) return null;\n const item: GridFilterItem = { field: col.field, operator: operator as GridFilterOperator };\n if (NO_VALUE_OPS.includes(item.operator)) return item;\n const rawValue = hasOwn(raw, 'value') ? raw.value : undefined;\n if (item.operator === 'isAnyOf') {\n const values: unknown[] = [];\n list(ctx, rawValue, `${path}.value`).forEach((entry, i) => {\n const r = filterValue(ctx, entry, col, `${path}.value[${i}]`);\n if (r && !values.includes(r.v)) values.push(r.v);\n });\n if (values.length === 0) return fail(ctx, `${path}.value`, 'No valid values');\n item.value = values;\n return item;\n }\n if (Array.isArray(rawValue)) return fail(ctx, `${path}.value`, 'Expected one value, not a list');\n const r = filterValue(ctx, rawValue, col, `${path}.value`);\n if (!r) return null;\n item.value = r.v;\n return item;\n}\n\nfunction logic(ctx: Ctx, raw: unknown, path: string): 'and' | 'or' | null {\n return raw === undefined ? null : (oneOf(ctx, raw, path, ['and', 'or']) as 'and' | 'or' | null);\n}\n\nfunction filterItems(ctx: Ctx, raw: unknown, path: string, depth: number): FilterNode[] {\n const out: FilterNode[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const at = `${path}[${i}]`;\n if (!isPlainObject(entry)) {\n fail(ctx, at, `Expected a filter, got ${show(entry)}`);\n } else if (hasOwn(entry, 'items') || hasOwn(entry, 'logicOperator')) {\n if (depth >= MAX_FILTER_DEPTH) {\n fail(ctx, at, `Groups nest at most ${MAX_FILTER_DEPTH} levels`);\n return;\n }\n const items = filterItems(ctx, entry.items, `${at}.items`, depth + 1);\n if (items.length === 0) fail(ctx, at, 'Empty group removed');\n else out.push({ logicOperator: logic(ctx, entry.logicOperator, `${at}.logicOperator`) ?? 'and', items });\n } else {\n const item = filterItem(ctx, entry, at);\n if (item) out.push(item);\n }\n });\n return out;\n}\n\nfunction filterModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridFilterModel {\n const model: GridFilterModel = {};\n if (hasOwn(raw, 'items')) model.items = filterItems(ctx, raw.items, `${path}.items`, 0);\n const op = logic(ctx, raw.logicOperator, `${path}.logicOperator`);\n if (op) model.logicOperator = op;\n if (hasOwn(raw, 'quickFilterValues')) {\n model.quickFilterValues = [];\n list(ctx, raw.quickFilterValues, `${path}.quickFilterValues`).forEach((entry, i) => {\n const word = typeof entry === 'string' || typeof entry === 'number' ? String(entry).trim() : null;\n if (word === null) fail(ctx, `${path}.quickFilterValues[${i}]`, `Expected text, got ${show(entry)}`);\n else if (word !== '') model.quickFilterValues?.push(word);\n });\n }\n return model;\n}\n\nfunction sortModel(ctx: Ctx, raw: unknown, path: string): GridSortItem[] {\n const out: GridSortItem[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const at = `${path}[${i}]`;\n if (!isPlainObject(entry)) return fail(ctx, at, `Expected { field, sort }, got ${show(entry)}`);\n const col = column(ctx, entry.field, `${at}.field`, isSortable, 'sorted');\n const sort = col && oneOf(ctx, entry.sort, `${at}.sort`, ['asc', 'desc']);\n if (!col || !sort) return;\n if (out.some((s) => s.field === col.field)) fail(ctx, at, `${show(col.field)} is sorted twice`);\n else out.push({ field: col.field, sort: sort as 'asc' | 'desc' });\n });\n return out;\n}\n\nfunction fieldList(ctx: Ctx, raw: unknown, path: string, allowed: Allowed, what: string): string[] {\n const out: string[] = [];\n list(ctx, raw, path).forEach((entry, i) => {\n const col = column(ctx, entry, `${path}[${i}]`, allowed, what);\n if (col && !out.includes(col.field)) out.push(col.field);\n });\n return out;\n}\n\nconst canAggregate: Allowed = (col) => aggregationFnsOf(col).length > 0;\nconst canPivot: Allowed = (col) => aggregationFnsOf(col, PIVOT_FNS).length > 0;\n\nfunction aggregationModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridAggregationModel {\n const model: GridAggregationModel = {};\n for (const key of keysOf(raw)) {\n // 'none' is how the grid spells \"no aggregation\": nothing to set.\n if (lower(raw[key]) === 'none') continue;\n const col = column(ctx, key, `${path}.${key}`, canAggregate, 'aggregated');\n const fn = col && oneOf(ctx, raw[key], `${path}.${key}`, aggregationFnsOf(col));\n if (col && fn) model[col.field] = fn;\n }\n return model;\n}\n\nfunction pivotModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridPivotModel {\n const valueFields: GridPivotValueField[] = [];\n list(ctx, raw.valueFields, `${path}.valueFields`).forEach((entry, i) => {\n const at = `${path}.valueFields[${i}]`;\n if (!isPlainObject(entry)) return fail(ctx, at, `Expected { field, aggFn }, got ${show(entry)}`);\n const col = column(ctx, entry.field, `${at}.field`, canPivot, 'a pivot value');\n const aggFn = col && (oneOf(ctx, entry.aggFn, `${at}.aggFn`, aggregationFnsOf(col, PIVOT_FNS)) as GridPivotValueField['aggFn'] | null);\n if (col && aggFn && !valueFields.some((v) => v.field === col.field && v.aggFn === aggFn)) valueFields.push({ field: col.field, aggFn });\n });\n return {\n rowFields: fieldList(ctx, raw.rowFields, `${path}.rowFields`, isGroupable, 'a pivot label'),\n columnFields: fieldList(ctx, raw.columnFields, `${path}.columnFields`, isGroupable, 'a pivot label'),\n valueFields,\n };\n}\n\nfunction visibilityModel(ctx: Ctx, raw: Record<string, unknown>, path: string): GridColumnVisibilityModel {\n const model: GridColumnVisibilityModel = {};\n for (const key of keysOf(raw)) {\n const col = column(ctx, key, `${path}.${key}`, isHideable, 'hidden');\n const visible = coerceBoolean(raw[key]);\n if (!col) continue;\n if (visible.ok && visible.value !== null) model[col.field] = visible.value;\n else fail(ctx, `${path}.${key}`, `Expected true or false, got ${show(raw[key])}`);\n }\n return model;\n}\n\nfunction readPart(ctx: Ctx, part: GridAiPart, raw: unknown, path: string, state: GridAiState): void {\n if (part === 'sort') state.sortModel = sortModel(ctx, raw, path);\n else if (part === 'grouping') state.rowGroupingModel = fieldList(ctx, raw, path, isGroupable, 'grouped');\n else if (!isPlainObject(raw)) fail(ctx, path, `Expected an object, got ${show(raw)}`);\n else if (part === 'filter') state.filterModel = filterModel(ctx, raw, path);\n else if (part === 'aggregation') state.aggregationModel = aggregationModel(ctx, raw, path);\n else if (part === 'pivot') state.pivotModel = pivotModel(ctx, raw, path);\n else state.columnVisibilityModel = visibilityModel(ctx, raw, path);\n}\n\n/**\n * Checks a model's reply against the columns and returns the state that is safe to apply.\n * `json` is an object or a JSON string (bad JSON gives one error and an empty state). Unknown\n * parts, fields, operators and enum values are dropped, each with an error; values are coerced to\n * the column type (`\"1,200\"` → 1200, a date → `\"YYYY-MM-DD\"`); filter groups left empty are\n * removed. Never throws, and never returns a field the columns do not allow.\n * @since v3.4\n */\nexport function validateGridAiState<C extends GridAiColumn>(\n json: unknown,\n columns: readonly C[],\n options: GridAiValidateOptions = {},\n): GridAiValidationResult {\n const ctx: Ctx = { errors: [], byField: new Map() };\n const state: GridAiState = {};\n try {\n for (const col of usableColumns(columns)) ctx.byField.set(col.field, col);\n let input = json;\n if (typeof json === 'string') {\n try {\n input = JSON.parse(json) as unknown;\n } catch {\n fail(ctx, '', 'Not valid JSON');\n return { state, errors: ctx.errors };\n }\n }\n if (!isPlainObject(input)) {\n fail(ctx, '', `Expected an object, got ${show(input)}`);\n return { state, errors: ctx.errors };\n }\n const allowed = selectedParts(options);\n for (const key of keysOf(input)) {\n const part = ALL_PARTS.find((p) => PART_KEYS[p] === key);\n if (key === 'schemaVersion') {\n if (input[key] !== 1) fail(ctx, key, `Unsupported schemaVersion ${show(input[key])}`);\n } else if (!part) fail(ctx, key, 'Unknown part');\n else if (!allowed.includes(part)) fail(ctx, key, 'Part not allowed');\n else readPart(ctx, part, input[key], key, state);\n }\n } catch {\n // Defensive only: a getter on a hand-built input object could throw.\n fail(ctx, '', 'Could not read the input');\n return { state: {}, errors: ctx.errors };\n }\n return { state, errors: ctx.errors };\n}\n"],"names":["DATE_ONLY","toDate","value","date","trimmed","match","year","month","day","toLocalDateString","y","m","d","getOperatorsForType","type","AGGREGATION_FNS","PIVOT_FNS","NO_VALUE_OPS","MAX_FILTER_DEPTH","ALL_PARTS","PART_KEYS","hasOwn","obj","key","isPlainObject","selectedParts","options","include","exclude","part","usableColumns","columns","seen","out","col","field","operatorsOf","isFilterable","isSortable","isGroupable","isHideable","aggregationFnsOf","fns","base","fn","allowed","optionValues","option","GRID_AI_SCHEMA_TITLE","MAX_EXAMPLES","label","header","desc","describe","node","text","ctx","examplesOf","v","valueSchema","values","one","examples","filterItemSchema","operators","noValue","op","hint","ops","filterSchema","cols","defs","filterable","properties","logic","depth","child","fieldEnum","c","partSchema","sortable","groupable","dims","dimArray","getGridAiSchema","schema","INVALID","valid","PLAIN_NUMBER","LEADING_DOT_NUMBER","GROUPED_NUMBER","STRIPPED_CHARS","parseNumberText","s","negative","percent","parseDateText","current","TRUE_WORDS","FALSE_WORDS","parseBooleanText","labels","parseSingleSelectText","lower","ok","fromParsed","parsed","isBlank","coerceString","coerceNumber","coerceDate","coerceBoolean","coerceSingleSelect","colDef","coerceValue","MAX_LIST","MAX_ERRORS","fail","path","message","show","keysOf","column","what","list","items","oneOf","choices","filterValue","raw","result","filterItem","operator","item","rawValue","entry","i","r","filterItems","at","filterModel","model","word","sortModel","sort","fieldList","canAggregate","canPivot","aggregationModel","pivotModel","valueFields","aggFn","visibilityModel","visible","readPart","state","validateGridAiState","json","input","p"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -95,12 +95,19 @@ export declare function CellSelectionStats({ count, sum, average }: CellSelectio
95
95
 
96
96
  export declare type CellSelectionStatsProps = GridCellSelectionStatsSlotProps & Record<string, unknown>;
97
97
 
98
- export declare const Checkbox: default_2.FC<CheckboxProps>;
98
+ /**
99
+ * A styled checkbox: a visually hidden `<input type="checkbox">` inside a `<label>`. Other props
100
+ * (`onChange`, `onMouseDown`, `tabIndex`, `aria-*`, …) go to the `<input>`, and so does `ref`.
101
+ */
102
+ export declare const Checkbox: default_2.ForwardRefExoticComponent<CheckboxProps & default_2.RefAttributes<HTMLInputElement>>;
99
103
 
100
104
  export declare interface CheckboxProps extends Omit<default_2.InputHTMLAttributes<HTMLInputElement>, 'type'> {
101
105
  indeterminate?: boolean;
102
106
  label?: string;
107
+ /** A ref to the `<input>`; the forwarded `ref` reaches it as well. */
103
108
  inputRef?: default_2.Ref<HTMLInputElement>;
109
+ /** Classes added to the `<input>` itself, next to `ogx-checkbox__input`. `className` goes to the wrapper `<label>`. */
110
+ inputClassName?: string;
104
111
  }
105
112
 
106
113
  declare type ColumnKey = string;
@@ -271,6 +278,38 @@ export declare interface DataGridProps<R extends GridValidRowModel = GridRowMode
271
278
  * `slots.cellSelectionStats`. Needs `cellSelection`. Default: false. @since v3.3
272
279
  */
273
280
  showCellSelectionStats?: boolean;
281
+ /**
282
+ * With `cellSelection` on, Ctrl/Cmd+V pastes tab-separated text (Excel, Google Sheets) into the
283
+ * editable cells from the range's top-left cell (or the focused cell), through `valueSetter` and
284
+ * `processRowUpdate`. `true` turns the shortcut off; `apiRef.pasteText()` still works. Default: false.
285
+ * @since v3.4
286
+ */
287
+ disableClipboardPaste?: boolean;
288
+ /**
289
+ * Fired after every paste with the result (`updated` rows, `failed` rows, `skipped` cells and why)
290
+ * and the pasted text. @since v3.4
291
+ */
292
+ onClipboardPaste?: (result: GridClipboardPasteResult) => void;
293
+ /**
294
+ * Called before a paste is applied. Return `false` to cancel it, or a string to paste instead of the
295
+ * clipboard text. A throw cancels the paste. @since v3.4
296
+ */
297
+ onBeforeClipboardPaste?: (params: GridBeforeClipboardPasteParams) => boolean | string;
298
+ /**
299
+ * With `cellSelection` on, Delete / Backspace on a range of more than one cell empties its editable
300
+ * cells (`null`, or `''` in string columns) as one edit. `true` turns that off. Default: false.
301
+ * @since v3.4
302
+ */
303
+ disableRangeClear?: boolean;
304
+ /**
305
+ * Undo and redo of cell edits, pastes and range clears: Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z and Ctrl+Y while
306
+ * focus is in the grid and no editor is open, and `apiRef.undo()` / `redo()`. Undo and redo write
307
+ * through `valueSetter` and `processRowUpdate`, like an edit. `{ limit }` sets how many actions are
308
+ * kept (default 100). Default: false. @since v3.4
309
+ */
310
+ undoRedo?: boolean | GridUndoRedoOptions;
311
+ /** Fired when what can be undone or redone changes (`undoRedo`). @since v3.4 */
312
+ onHistoryChange?: (params: GridHistoryChangeParams) => void;
274
313
  /** Loading state. With no rows the body shows skeleton rows (or `slots.loadingOverlay`); with rows, they stay and a progress bar (or `slots.loadingOverlay`) is shown over them. */
275
314
  loading?: boolean;
276
315
  /** Visual density of the grid. */
@@ -756,6 +795,47 @@ export declare interface GridApi<R extends GridValidRowModel = GridRowModel> {
756
795
  * copy; rejects when the clipboard write fails. @since v3.3
757
796
  */
758
797
  copySelectedCells: () => Promise<void>;
798
+ /**
799
+ * Pastes tab-separated text as Ctrl/Cmd+V does: from `anchor` (default: the range's top-left cell,
800
+ * else the focused cell), with `onBeforeClipboardPaste` and `onClipboardPaste`. Works with
801
+ * `disableClipboardPaste`. Resolves once every row's `processRowUpdate` has settled. @since v3.4
802
+ */
803
+ pasteText: (text: string, anchor?: GridCellCoordinates) => Promise<GridBatchEditResult>;
804
+ /** Undoes the last action (`undoRedo`). Resolves with what was written. @since v3.4 */
805
+ undo: () => Promise<GridBatchEditResult>;
806
+ /** Redoes the last undone action (`undoRedo`). @since v3.4 */
807
+ redo: () => Promise<GridBatchEditResult>;
808
+ /** Whether there is an action to undo. @since v3.4 */
809
+ canUndo: () => boolean;
810
+ /** Whether there is an undone action to redo. @since v3.4 */
811
+ canRedo: () => boolean;
812
+ /** Forgets every action (undo and redo). @since v3.4 */
813
+ clearHistory: () => void;
814
+ }
815
+
816
+ /** What a batch edit (paste, range clear, undo, redo) did. @since v3.4 */
817
+ export declare interface GridBatchEditResult {
818
+ /** Rows whose `processRowUpdate` succeeded and that were stored, in the order they were first touched. */
819
+ updated: GridRowId[];
820
+ /** Rows whose `valueSetter` or `processRowUpdate` threw or rejected (also reported to `onProcessRowUpdateError`). */
821
+ failed: {
822
+ id: GridRowId;
823
+ error: unknown;
824
+ }[];
825
+ /** Cells that were not written, with the reason. */
826
+ skipped: {
827
+ id: GridRowId;
828
+ field: string;
829
+ reason: GridEditSkipReason;
830
+ }[];
831
+ }
832
+
833
+ /** `onBeforeClipboardPaste` params. @since v3.4 */
834
+ export declare interface GridBeforeClipboardPasteParams {
835
+ /** The clipboard text (`text/plain`). */
836
+ text: string;
837
+ /** The cell the paste starts from (the range's top-left cell, or the focused cell). */
838
+ anchor: GridCellCoordinates | null;
759
839
  }
760
840
 
761
841
  /** One cell, addressed by its row id and column field. @since v3.3 */
@@ -821,6 +901,11 @@ export declare interface GridCellSelectionStatsSlotProps {
821
901
  average: number | null;
822
902
  }
823
903
 
904
+ /** `onClipboardPaste` details: the batch edit result plus the text that was pasted. @since v3.4 */
905
+ export declare interface GridClipboardPasteResult extends GridBatchEditResult {
906
+ text: string;
907
+ }
908
+
824
909
  /**
825
910
  * Metadata for a single column.
826
911
  * Governs rendering, sorting, filtering, and data transformation.
@@ -893,6 +978,14 @@ export declare interface GridColDef<R extends GridValidRowModel = GridRowModel>
893
978
  * @since v3.0
894
979
  */
895
980
  valueSetter?(params: GridValueSetterParams<R>): R;
981
+ /**
982
+ * Turns pasted text into this column's value (clipboard paste), instead of the default parser for
983
+ * the column `type` (see `docs/features/clipboard.md`). Use it for locales such as `1.234,5` or for
984
+ * custom codes. Throw (or return `undefined`) to reject the text: the cell is skipped with reason
985
+ * `'invalidValue'`. The value then goes through `valueSetter` and `processRowUpdate` like an edit.
986
+ * @since v3.4
987
+ */
988
+ valueParser?(text: string, params: GridValueParserParams<R>): unknown;
896
989
  /**
897
990
  * Custom ascending comparator for client-side sorting by this column, used instead of the built-in
898
991
  * type-aware comparison. `v1` / `v2` are the cell values (`valueGetter` applied) and **include
@@ -951,6 +1044,15 @@ export declare interface GridColDef<R extends GridValidRowModel = GridRowModel>
951
1044
  * @default true
952
1045
  */
953
1046
  exportable?: boolean;
1047
+ /**
1048
+ * Example values for this column, put into the schema from `getGridAiSchema`
1049
+ * (`@opencorestack/opengridx/ai`) to help a language model write filters ("Acme" → `customer`).
1050
+ * **These values are sent to the model.** The grid never reads row data for the schema; only what
1051
+ * you list here leaves the app, so list nothing private. Strings, numbers and booleans are used
1052
+ * (at most 10); other values are ignored. Not used by the grid itself.
1053
+ * @since v3.4
1054
+ */
1055
+ aiExamples?: unknown[];
954
1056
  }
955
1057
 
956
1058
  /**
@@ -1049,6 +1151,17 @@ export declare interface GridDetailPanelParams<R extends GridValidRowModel = Gri
1049
1151
  rowIndex: number;
1050
1152
  }
1051
1153
 
1154
+ /**
1155
+ * Why a cell of a batch edit (paste, range clear, undo, redo) was not written:
1156
+ * - `'notEditable'`: the column is not `editable`, `isCellEditable` returned false, or the row is a
1157
+ * synthetic row (group header, subtotal, tree auto-parent, pivot Grand Total);
1158
+ * - `'invalidValue'`: the pasted text does not parse for the column type (or `valueParser` rejected it);
1159
+ * - `'changed'`: undo/redo only, the cell no longer holds the value the history recorded;
1160
+ * - `'missing'`: undo/redo only, the row is gone.
1161
+ * @since v3.4
1162
+ */
1163
+ export declare type GridEditSkipReason = 'notEditable' | 'invalidValue' | 'changed' | 'missing';
1164
+
1052
1165
  /** Describes a group of filters combined with a logical operator. */
1053
1166
  export declare interface GridFilterGroup {
1054
1167
  /** Optional ID for the group. */
@@ -1150,6 +1263,14 @@ export declare interface GridGroupedExportRow {
1150
1263
  row?: GridRowModel;
1151
1264
  }
1152
1265
 
1266
+ /** `onHistoryChange` params. @since v3.4 */
1267
+ export declare interface GridHistoryChangeParams {
1268
+ canUndo: boolean;
1269
+ canRedo: boolean;
1270
+ /** Number of actions that can be undone. */
1271
+ size: number;
1272
+ }
1273
+
1153
1274
  /**
1154
1275
  * The state the grid starts from. Every part is optional, including each column field, so a
1155
1276
  * partial state such as `{ columns: { columnVisibilityModel: { age: false } } }` is valid.
@@ -1705,6 +1826,12 @@ export declare interface GridTreeNode {
1705
1826
  serverChildrenCount?: number;
1706
1827
  }
1707
1828
 
1829
+ /** `undoRedo` options. @since v3.4 */
1830
+ export declare interface GridUndoRedoOptions {
1831
+ /** How many actions are kept; the oldest is dropped beyond it. Default: 100. */
1832
+ limit?: number;
1833
+ }
1834
+
1708
1835
  /**
1709
1836
  * The constraint on the row type `R` of the generic grid types (`DataGridProps<R>`, `GridColDef<R>`,
1710
1837
  * `GridRenderCellParams<R>` …): any object type. Your own interfaces and type aliases can be used as `R`
@@ -1734,6 +1861,14 @@ export declare interface GridValueGetterParams<R extends GridValidRowModel = Gri
1734
1861
  value: unknown;
1735
1862
  }
1736
1863
 
1864
+ /** Parameters passed to `GridColDef.valueParser`. @since v3.4 */
1865
+ export declare interface GridValueParserParams<R extends GridValidRowModel = GridRowModel> {
1866
+ /** The row the text is pasted into, as stored now. */
1867
+ row: R;
1868
+ field: string;
1869
+ colDef: GridColDef<R>;
1870
+ }
1871
+
1737
1872
  /**
1738
1873
  * Parameters passed to the `valueSetter` function.
1739
1874
  * @since v3.0
@@ -1801,13 +1936,24 @@ export declare interface HeaderProps<R extends GridRowModel = GridRowModel> {
1801
1936
  headerHeight?: number;
1802
1937
  }
1803
1938
 
1804
- export declare const Input: default_2.FC<InputProps>;
1939
+ /**
1940
+ * A text field: an `<input>` inside an `.ogx-input-wrapper` that holds the adornments.
1941
+ * `ref` reaches the `<input>` (React 18 and 19).
1942
+ */
1943
+ export declare const Input: default_2.ForwardRefExoticComponent<InputProps & default_2.RefAttributes<HTMLInputElement>>;
1805
1944
 
1806
1945
  export declare interface InputProps extends default_2.InputHTMLAttributes<HTMLInputElement> {
1807
1946
  fullWidth?: boolean;
1808
1947
  error?: boolean;
1809
1948
  startAdornment?: default_2.ReactNode;
1810
1949
  endAdornment?: default_2.ReactNode;
1950
+ /** Classes added to the `<input>` itself, next to `ogx-input`. `className` goes to the wrapper. */
1951
+ inputClassName?: string;
1952
+ /**
1953
+ * `'field'` (default): a bordered form field. `'cell'`: fills a grid cell with no border,
1954
+ * background or focus ring, in the cell's font, for use in `renderEditCell`.
1955
+ */
1956
+ variant?: 'field' | 'cell';
1811
1957
  }
1812
1958
 
1813
1959
  export declare interface JsonExportOptions<R extends GridValidRowModel = GridRowModel> {