@gridkitjs/core 0.0.0-dev-20261106222533
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.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/index.d.ts +4229 -0
- package/dist/index.js +4757 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/util/grid.ts","../src/util/position.ts","../src/util/sorting.ts","../src/util/grouping.ts","../src/util/memoize.ts","../src/util/ordering.ts","../src/util/paging.ts","../src/util/report.ts","../src/util/filterOperators.ts","../src/util/serialize.ts","../src/util/sizing.ts","../src/util/aggregation.ts","../src/util/filtering.ts","../src/util/rows.ts","../src/util/visibility.ts","../src/util/view.ts","../src/controller/changes.ts","../src/util/selection.ts","../src/controller/selectionEvents.ts","../src/controller/selectionActions.ts","../src/controller/createGridController.ts","../src/commands/context.ts","../src/util/format.ts","../src/export/buildExportTable.ts","../src/export/htmlTable.ts","../src/export/records.ts","../src/export/tsv.ts","../src/export/copy.ts","../src/export/exportFile.ts","../src/export/print.ts","../src/export/csv.ts","../src/export/json.ts","../src/export/writer.ts","../src/filterMenu/operators.ts","../src/filterMenu/options.ts","../src/messages.ts","../src/util/filterEditor.ts","../src/commands/builtInCommands.ts","../src/commands/registry.ts","../src/menu/resolveMenu.ts","../src/menu/contextMenu.ts","../src/menu/navigation.ts","../src/toolbar/options.ts","../src/toolbar/resolveToolbar.ts","../src/toolbar/overflow.ts","../src/toolbar/search.ts","../src/util/navigation.ts","../src/util/paginationWindow.ts","../src/util/columnChooser.ts","../src/filterMenu/conditions.ts","../src/filterMenu/valueCache.ts","../src/filterMenu/checklist.ts","../src/util/virtualization.ts","../src/presets.ts"],"sourcesContent":["import type { ColumnAlignment, ColumnDefinition, ColumnType } from \"../types\";\n\n/**\n * Narrows to a value worth drilling into. Mirrors the `LeafValue` union in\n * `../types`: arrays and `Date`s are cell values rather than groups of\n * columns, and `null` cannot be introspected. Keep the two in sync.\n */\nfunction isNested(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value instanceof Date)\n );\n}\n\nfunction getType(value: unknown): ColumnType {\n if (value instanceof Date) return \"dateTime\";\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"bigint\") return \"number\";\n if (typeof value === \"symbol\") return \"string\";\n return \"string\";\n}\n\n/**\n * How a column of `type` aligns by default. Numeric types align right so that\n * their digits line up by place value; everything else reads from the left.\n */\nexport function alignmentForType(type: ColumnType): ColumnAlignment {\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return \"right\";\n default:\n return \"left\";\n }\n}\n\nfunction getAlignment(value: unknown): ColumnAlignment {\n return alignmentForType(getType(value));\n}\n\n/**\n * Derives one column per field across `rows`, in the order each field is first\n * seen — so a key that only appears in a later row still gets a column,\n * appended at the end. Nested objects contribute their non-object properties\n * as `\"Parent.Child\"`; anything deeper is skipped, as is the nested object\n * itself.\n *\n * Order follows `Object.entries`, which lists integer-like keys first\n * regardless of the order they were written in.\n *\n * `Node` is whatever the caller's renderer draws: an inferred column sets no\n * template, so it suits any.\n */\nexport function defineColumnsFromRows<Row, Node = string>(\n rows: readonly Row[],\n): readonly ColumnDefinition<Row, Node>[] {\n const columns: ColumnDefinition<Row, Node>[] = [];\n const seen = new Set<string>();\n\n function add(field: string, value: unknown): void {\n if (seen.has(field)) {\n return;\n }\n seen.add(field);\n columns.push({\n field,\n type: getType(value),\n alignment: getAlignment(value),\n });\n }\n\n for (const row of rows) {\n if (!isNested(row)) {\n continue;\n }\n for (const [key, value] of Object.entries(row)) {\n if (!isNested(value)) {\n add(key, value);\n continue;\n }\n for (const [nestedKey, nestedValue] of Object.entries(value)) {\n if (!isNested(nestedValue)) {\n add(`${key}.${nestedKey}`, nestedValue);\n }\n }\n }\n }\n\n return columns;\n}\n\n/**\n * The key state about a column is stored under, and the key it renders with.\n * Every such lookup goes through here so the two can never disagree.\n */\nexport function getColumnId<Row>(\n column: ColumnDefinition<Row, unknown>,\n): string {\n return column.id ?? column.field;\n}\n\n/**\n * The key state about a row is stored under, and the key it renders with — the\n * row's counterpart to `getColumnId`, and for the same reason: every such\n * lookup goes through here so no two can disagree.\n *\n * Falls back to the position so a grid given no `getRowId` still works. That\n * fallback ties a selection to where a row sits rather than to the row, so\n * anything that sorts, filters or pages its data has to supply one — otherwise\n * a re-sort leaves the same positions selected under different rows.\n */\nexport function resolveRowId<Row>(\n row: Row,\n index: number,\n getRowId?: (row: Row, index: number) => string,\n): string {\n return getRowId?.(row, index) ?? String(index);\n}\n\n/** A label read off the field path — `\"Application.Id\"` reading as `\"Application Id\"`. */\nfunction labelFromField(field: string): string {\n return field.split(\".\").join(\" \");\n}\n\n/**\n * What a column's header shows: its own `headerTemplate`, called first if it is\n * a function, or else its plain-text `header`, or else a label read off the\n * field path.\n */\nexport function resolveColumnLabel<Row, Node>(\n column: ColumnDefinition<Row, Node>,\n): Node | string {\n const { headerTemplate } = column;\n if (headerTemplate === undefined) {\n return column.header ?? labelFromField(column.field);\n }\n // `Node` is open, so it could itself be a function type and the `typeof`\n // check cannot narrow on its own. A header that is callable is the lazy\n // form by definition — no adapter binds `Node` to a function.\n return typeof headerTemplate === \"function\"\n ? (headerTemplate as () => Node)()\n : headerTemplate;\n}\n\n/**\n * A column's name as text, for wherever markup will not do — an\n * announcement, an export. Its `header` first, even beside a\n * `headerTemplate`, since a template's output need not be text; then the\n * label `resolveColumnLabel` gives, when that is a string; then the label\n * read off the field path.\n */\nexport function resolveColumnHeaderText<Row>(\n column: ColumnDefinition<Row, unknown>,\n): string {\n if (column.header !== undefined) {\n return column.header;\n }\n const label = resolveColumnLabel(column);\n return typeof label === \"string\" ? label : labelFromField(column.field);\n}\n\n/** Which of a column header's keyboard interactions to announce. */\nexport interface KeyShortcutCapabilities {\n reorderable: boolean;\n resizable: boolean;\n sortable: boolean;\n groupable: boolean;\n /** Whether the column has a filter menu the header opens. Defaults to `false`. */\n filterable?: boolean | undefined;\n /** Whether the header opens the grid's context menu. Defaults to `false`. */\n contextMenu?: boolean | undefined;\n}\n\n/**\n * The `aria-keyshortcuts` string for a column header, naming only the keys\n * that column actually responds to — so the keys are discoverable, since\n * none of them is a convention a user would try unprompted.\n */\nexport function buildKeyShortcuts(\n capabilities: KeyShortcutCapabilities,\n): string {\n return [\n capabilities.reorderable ? \"Control+ArrowLeft Control+ArrowRight\" : \"\",\n // Alt+Enter is the keyboard equivalent of double-clicking the resize\n // handle to size the column to its content — same gate as the nudge\n // shortcuts, since both are resize actions.\n capabilities.resizable ? \"Alt+ArrowLeft Alt+ArrowRight Alt+Enter\" : \"\",\n capabilities.sortable ? \"Alt+ArrowUp\" : \"\",\n // Down rather than reusing Up: it reads as \"drill into groups\", and Up is\n // already sort's own mnemonic on the same header.\n capabilities.groupable ? \"Alt+ArrowDown\" : \"\",\n // Excel's own key for its filter dropdown is Alt+ArrowDown, which\n // grouping already holds here; Shift sets the filter apart from it.\n capabilities.filterable === true ? \"Alt+Shift+ArrowDown\" : \"\",\n // The ContextMenu key needs no mention: it says what it does on its face.\n capabilities.contextMenu === true ? \"Shift+F10\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\n/**\n * Accesses a value at a dotted path, e.g. `foo.bar.baz`.\n *\n * @param obj The object to access\n * @param path Path to the value, e.g. `\"foo.bar\"`\n * @returns The value at `path`, or `undefined` if it doesn't exist\n */\nexport function accessDotted(obj: unknown, path: string): unknown {\n return path\n .split(\".\")\n .reduce((value, key) => (isNested(value) ? value[key] : undefined), obj);\n}\n","/**\n * `entries` with each one's `rowIndex` and `datasetIndex` set to its\n * position in the array. Every stage ahead of pagination that reorders,\n * drops or inserts rows ends with this, so the two always agree before\n * `paginateRows` makes `rowIndex` page-relative: `datasetIndex` is then a\n * row's place in the whole displayed result, which is what `aria-rowindex`\n * is built from and why no two rows, of any kind, share one.\n *\n * An entry already at its position is kept as it is, so a stage that moved\n * nothing hands back entries reference-equal to its input's.\n */\nexport function renumberRows<\n Entry extends { readonly rowIndex: number; readonly datasetIndex: number },\n>(entries: readonly Entry[]): Entry[] {\n return entries.map((entry, index) =>\n entry.rowIndex === index && entry.datasetIndex === index\n ? entry\n : { ...entry, rowIndex: index, datasetIndex: index },\n );\n}\n","import type {\n ColumnSortState,\n ColumnType,\n DataColumn,\n ResolvedRow,\n SortDirection,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { renumberRows } from \"./position\";\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/** A date/time value converted to a comparable instant. */\nfunction toTime(value: unknown): number {\n return value instanceof Date\n ? value.getTime()\n : new Date(String(value)).getTime();\n}\n\n/**\n * Compares two cell values the way `type` implies — numerically for the\n * numeric types, chronologically for the date/time types, lexically\n * otherwise. Defaults to string comparison when `type` is absent, mirroring\n * `ColumnDefinition.type`'s own default.\n *\n * `null`/`undefined` sort after every value on both sides. Used directly,\n * that ordering is fixed; `sortRows` applies it directionally without\n * disturbing it — see its own doc comment.\n */\nexport function compareValues(\n a: unknown,\n b: unknown,\n type?: ColumnType,\n): number {\n if (isEmpty(a)) {\n return isEmpty(b) ? 0 : 1;\n }\n if (isEmpty(b)) {\n return -1;\n }\n\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return Number(a) - Number(b);\n case \"boolean\":\n return Number(Boolean(a)) - Number(Boolean(b));\n case \"date\":\n case \"dateTime\":\n case \"time\":\n return toTime(a) - toTime(b);\n default:\n return String(a).localeCompare(String(b));\n }\n}\n\n/** This column's direction in `sort`, or `null` outside it. */\nexport function sortDirectionFor(\n sort: ColumnSortState,\n columnId: string,\n): SortDirection | null {\n return sort.find((entry) => entry.columnId === columnId)?.direction ?? null;\n}\n\n/** This column's 1-based place in `sort`, or `null` outside it. */\nexport function sortPriorityFor(\n sort: ColumnSortState,\n columnId: string,\n): number | null {\n const index = sort.findIndex((entry) => entry.columnId === columnId);\n return index === -1 ? null : index + 1;\n}\n\n/**\n * The sort with `columnId` cycled to its next direction — none → asc → desc →\n * none.\n *\n * `stack: false` (a plain click) means \"sort by only this column\": unless\n * `columnId` is already the sole entry, in which case its own cycle just\n * continues, it collapses `sort` down to `columnId` alone at `\"asc\"`,\n * regardless of any direction it held as part of a larger stack.\n *\n * `stack: true` (a Shift-click) cycles or appends `columnId` in place without\n * disturbing the rest of the stack; cycling it back to `\"none\"` removes it\n * and closes the gap, leaving the others in their existing order.\n */\nexport function toggleColumnSort(\n sort: ColumnSortState,\n columnId: string,\n options: { readonly stack: boolean },\n): ColumnSortState {\n const index = sort.findIndex((entry) => entry.columnId === columnId);\n const isSoleEntry = sort.length === 1 && index === 0;\n\n if (!options.stack && !isSoleEntry) {\n return [{ columnId, direction: \"asc\" }];\n }\n\n const current = index === -1 ? undefined : sort[index]?.direction;\n const next: SortDirection | null =\n current === undefined ? \"asc\" : current === \"asc\" ? \"desc\" : null;\n\n if (next === null) {\n return sort.filter((entry) => entry.columnId !== columnId);\n }\n if (index === -1) {\n return [...sort, { columnId, direction: next }];\n }\n return sort.map((entry, i) =>\n i === index ? { columnId, direction: next } : entry,\n );\n}\n\n/**\n * `rows` ordered by `sort` — each entry read against `columns` for its\n * `field` and `type` — with `rowIndex` and `datasetIndex` renumbered to\n * match the new positions, the invariant the rest of the grid relies on for\n * keyboard navigation and `aria-rowindex`.\n *\n * Stable (`Array.prototype.sort` has been stable since ES2019), so rows\n * equal under every active key keep their relative order. A `null`/\n * `undefined` value sorts last under either direction — resolved before\n * `compareValues` is asked, and left out of the direction flip below, so\n * that toggling a column reorders the values it holds rather than moving its\n * gaps to the front.\n *\n * Returns `rows` itself, untouched, when `sort` is empty or names only\n * columns absent from `columns` — a stored sort tolerates a column removed\n * from the definition the same way a stored `ColumnOrderState` does.\n */\nexport function sortRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n sort: ColumnSortState,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n if (sort.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = sort.filter((entry) => byId.has(entry.columnId));\n if (active.length === 0) {\n return rows;\n }\n\n const sorted = [...rows].sort((a, b) => {\n for (const { columnId, direction } of active) {\n const column = byId.get(columnId);\n if (column === undefined) {\n continue;\n }\n const left = accessDotted(a.row, column.field);\n const right = accessDotted(b.row, column.field);\n const leftEmpty = isEmpty(left);\n const rightEmpty = isEmpty(right);\n if (leftEmpty || rightEmpty) {\n if (leftEmpty && rightEmpty) {\n continue;\n }\n return leftEmpty ? 1 : -1;\n }\n\n const result = compareValues(left, right, column.type);\n if (result !== 0) {\n return direction === \"asc\" ? result : -result;\n }\n }\n return 0;\n });\n\n return renumberRows(sorted);\n}\n","import type {\n ColumnDefinition,\n DataColumn,\n DisplayRow,\n GroupByEntry,\n GroupByState,\n GroupExpansionState,\n ResolvedGroupRow,\n ResolvedRow,\n SortDirection,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { renumberRows } from \"./position\";\nimport { compareValues } from \"./sorting\";\n\n/**\n * This group's id, from its path. Every group-id producer/consumer in this\n * package goes through this — never join `path` by hand elsewhere.\n *\n * `JSON.stringify` rather than a delimiter join: a delimiter would have to be\n * escaped in every segment to stay collision-free against a value that\n * legitimately contains it, and `JSON.stringify` already draws that\n * boundary between array entries for free.\n */\nexport function groupRowId(path: readonly unknown[]): string {\n return JSON.stringify(path);\n}\n\ninterface ValueGroup<Row> {\n value: unknown;\n rows: ResolvedRow<Row>[];\n}\n\n/**\n * A key `accessDotted`'s result can be bucketed by, distinguishing values\n * that `compareValues`/`===` would treat as equal-but-not-identical (two\n * `Date` instances for the same instant) while keeping values of different\n * types apart (the number `1` and the string `\"1\"`).\n *\n * Exported for `aggregation.ts`, which needs the identical notion of\n * \"same value\" to match a leaf row back against a group header's `path` —\n * two producers of the same key would drift apart silently otherwise.\n */\nexport function bucketKey(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\\0empty\";\n }\n if (value instanceof Date) {\n return `\\0date:${String(value.getTime())}`;\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return `\\0${typeof value}:${String(value)}`;\n case \"function\":\n return \"\\0function\";\n default:\n // Arrays, and anything else `accessDotted` could return.\n return `\\0object:${JSON.stringify(value)}`;\n }\n}\n\n/**\n * `rows` bucketed by `column`'s value, one bucket per distinct value in\n * first-seen order, then ordered by `direction` via `compareValues` — the\n * same comparator `sortRows` uses, so a grouped column and a sorted column\n * order their values identically.\n */\nfunction partitionByValue<Row>(\n rows: readonly ResolvedRow<Row>[],\n column: ColumnDefinition<Row, unknown>,\n direction: SortDirection,\n): readonly ValueGroup<Row>[] {\n const buckets = new Map<string, ValueGroup<Row>>();\n for (const row of rows) {\n const value = accessDotted(row.row, column.field);\n const key = bucketKey(value);\n const bucket = buckets.get(key);\n if (bucket === undefined) {\n buckets.set(key, { value, rows: [row] });\n } else {\n bucket.rows.push(row);\n }\n }\n\n const groups = [...buckets.values()];\n groups.sort((a, b) => {\n const result = compareValues(a.value, b.value, column.type);\n return direction === \"asc\" ? result : -result;\n });\n return groups;\n}\n\n/**\n * Depth-first builder behind `groupRows`: partitions `rows` by `levels[0]`,\n * appends a header per resulting group, and recurses into `levels.slice(1)`\n * for each — unless that group is collapsed, in which case only its header\n * is appended. `rows` with no levels left (either `levels` started empty, or\n * recursion exhausted it) are appended as plain data rows, keeping the\n * relative order filter/sort already gave them.\n */\nfunction buildLevel<Row>(\n rows: readonly ResolvedRow<Row>[],\n levels: readonly GroupByEntry[],\n parentPath: readonly unknown[],\n expansion: GroupExpansionState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n out: DisplayRow<Row>[],\n): void {\n const level = levels[0];\n if (level === undefined) {\n out.push(...rows);\n return;\n }\n\n // `levels` is pre-filtered to entries naming a column present in `byId`\n // (see `groupRows`), so this is always found.\n const column = byId.get(level.columnId);\n if (column === undefined) {\n out.push(...rows);\n return;\n }\n\n const rest = levels.slice(1);\n const groups = partitionByValue(rows, column, level.direction ?? \"asc\");\n\n for (const group of groups) {\n const path = [...parentPath, group.value];\n const groupId = groupRowId(path);\n const expanded = !expansion.includes(groupId);\n const header: ResolvedGroupRow = {\n kind: \"group\",\n groupId,\n level: parentPath.length,\n columnId: level.columnId,\n value: group.value,\n path,\n expanded,\n count: group.rows.length,\n // Both set by `groupRows` once it has the whole flattened array.\n rowIndex: -1,\n datasetIndex: -1,\n // Set by `withGroupAggregates`, downstream of grouping — empty here\n // since `groupRows` itself never knows about `AggregateState`.\n aggregates: new Map(),\n };\n out.push(header);\n if (expanded) {\n buildLevel(group.rows, rest, path, expansion, byId, out);\n }\n }\n}\n\n/**\n * `rows`, regrouped into `groupBy`'s stacked levels — a group header per\n * distinct value at each level, ordered by `compareValues` per that level's\n * own `direction`, followed depth-first by its nested groups and/or data\n * rows. A collapsed group (its `groupId` present in `expansion`) contributes\n * only its own header, nothing beneath it — but its `count` still reports\n * the group's full leaf-row count either way.\n *\n * Filter and sort are expected to have already run (see `resolveShownRows`):\n * this only reshapes their output, and never changes which rows appear or\n * their relative order within a group.\n *\n * `rowIndex` and `datasetIndex` are renumbered across the whole flattened\n * output, header rows included — the same invariant `sortRows`/`filterRows`\n * keep for a `ResolvedRow`, extended to `ResolvedGroupRow` since `GridBody`\n * addresses both kinds by the same flat position, and `aria-rowindex`\n * counts both.\n *\n * Returns `rows` itself, untouched, when `groupBy` is empty or names only\n * columns absent from `columns` — a stored grouping tolerates a column\n * removed from the definition the same way a stored `ColumnSortState` does.\n */\nexport function groupRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n expansion: GroupExpansionState,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly DisplayRow<Row>[] {\n if (groupBy.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = groupBy.filter((entry) => byId.has(entry.columnId));\n if (active.length === 0) {\n return rows;\n }\n\n const out: DisplayRow<Row>[] = [];\n buildLevel(rows, active, [], expansion, byId, out);\n\n return renumberRows(out);\n}\n\n/**\n * The expansion with `groupId` collapsed if it was expanded, or expanded if\n * it was collapsed.\n */\nexport function toggleGroupExpansion(\n expansion: GroupExpansionState,\n groupId: string,\n): GroupExpansionState {\n return expansion.includes(groupId)\n ? expansion.filter((id) => id !== groupId)\n : [...expansion, groupId];\n}\n\n/** `expansion` reduced to empty — every group expanded. Mirrors `clearAllFilters`. */\nexport function expandAllGroups(\n expansion: GroupExpansionState,\n): GroupExpansionState {\n return expansion.length === 0 ? expansion : [];\n}\n\n/**\n * Every group id present in `rows` — for collapsing every group currently\n * shown in one call. Operates on the already-grouped display, not the raw\n * grouping, so a group hidden beneath an already-collapsed ancestor (and so\n * absent from `rows`) keeps whatever expansion it already had rather than\n * being forced closed too; expanding that ancestor again reveals it exactly\n * as it was left.\n *\n * Group headers only: a summary row (`groupAggregateDisplay: \"row\"`) carries\n * its group's id too, and counting it would list that group twice.\n */\nexport function collapseAllGroups<Row>(\n rows: readonly DisplayRow<Row>[],\n): GroupExpansionState {\n return rows\n .filter(\n (entry): entry is ResolvedGroupRow =>\n \"kind\" in entry && entry.kind === \"group\",\n )\n .map((entry) => entry.groupId);\n}\n\n/**\n * `groupBy` with `columnId` positioned in front of `beforeColumnId` — or at\n * the end when that is `null` — inserting a fresh entry if `columnId` isn't\n * already part of the stack, or lifting its existing entry out and back in\n * if it is. The one function both a header dropped on the group-by bar and\n * a chip dragged within it need: the former's `columnId` is usually new to\n * the stack, the latter's never is, and this doesn't need to be told which.\n *\n * An existing entry keeps its own object (and so its own `direction`)\n * rather than being rebuilt, so a level merely repositioned stays\n * reference-equal at its new index — the same reason `moveColumnBefore`\n * moves ids rather than rebuilding them.\n *\n * Returns `groupBy` itself, untouched, when the move changes nothing: a\n * drop on the entry's own id, or back into the gap it already occupies, or\n * naming a `beforeColumnId` absent from the stack. Inserting a column not\n * yet in the stack is never a no-op.\n */\nexport function moveGroupByBefore(\n groupBy: GroupByState,\n columnId: string,\n beforeColumnId: string | null,\n): GroupByState {\n if (columnId === beforeColumnId) {\n return groupBy;\n }\n\n const without = groupBy.filter((entry) => entry.columnId !== columnId);\n const moved = groupBy.find((entry) => entry.columnId === columnId) ?? {\n columnId,\n };\n const target =\n beforeColumnId === null\n ? without.length\n : without.findIndex((entry) => entry.columnId === beforeColumnId);\n if (target === -1) {\n return groupBy;\n }\n\n const next = [...without];\n next.splice(target, 0, moved);\n return next.length === groupBy.length &&\n next.every((entry, index) => entry === groupBy[index])\n ? groupBy\n : next;\n}\n\n/**\n * Whether moving `columnId` in front of `beforeColumnId` would change\n * `groupBy` at all, so that a drop indicator promises exactly the move that\n * happens. Defined against `moveGroupByBefore` rather than restating its\n * conditions, the same relationship `movesColumn` keeps with\n * `moveColumnBefore`.\n */\nexport function movesGroupBy(\n groupBy: GroupByState,\n columnId: string,\n beforeColumnId: string | null,\n): boolean {\n return moveGroupByBefore(groupBy, columnId, beforeColumnId) !== groupBy;\n}\n","/**\n * `compute`, remembering its last arguments and result: called again with\n * every argument identical (`Object.is`), it hands back that same result\n * rather than recomputing. One slot is all a stage needs — the grid asks for\n * the current view, never an older one — and returning the same reference is\n * what lets each later stage, and a renderer, skip work of its own.\n */\nexport function memoizeLast<Args extends readonly unknown[], Result>(\n compute: (...args: Args) => Result,\n): (...args: Args) => Result {\n let last: { readonly args: Args; readonly result: Result } | undefined;\n return (...args) => {\n const previous = last;\n if (\n previous !== undefined &&\n args.every((arg, index) => Object.is(arg, previous.args[index]))\n ) {\n return previous.result;\n }\n const result = compute(...args);\n last = { args, result };\n return result;\n };\n}\n","import type {\n ColumnDefinition,\n ColumnOrderState,\n DataColumn,\n DropSide,\n} from \"../types\";\nimport { getColumnId } from \"./grid\";\n\n/**\n * Puts `columns` in the order `order` gives. Ids it lists come first, in that\n * order; columns it omits keep their position among the definitions and\n * follow. Ids naming no column are ignored.\n *\n * Tolerating both gaps is what lets a stored order outlive the column list it\n * was made against.\n */\nexport function applyColumnOrder<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n order: ColumnOrderState,\n): readonly ColumnDefinition<Row, Node>[] {\n if (order.length === 0) {\n return columns;\n }\n\n const byId = new Map(columns.map((column) => [getColumnId(column), column]));\n const listed = order\n .map((id) => byId.get(id))\n .filter((column) => column !== undefined);\n const taken = new Set(listed.map((column) => getColumnId(column)));\n\n return [\n ...listed,\n ...columns.filter((column) => !taken.has(getColumnId(column))),\n ];\n}\n\n/**\n * `columns` in the order `order` gives, each paired with its id — the\n * width-free column list the data stages (filter, sort, group, aggregate)\n * read. Ordered here, ahead of sizing, so every later stage sees the one\n * already-ordered list and no part of the grid has to know a reorder\n * happened.\n */\nexport function resolveDataColumns<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n order: ColumnOrderState,\n): readonly DataColumn<Row, Node>[] {\n return applyColumnOrder(columns, order).map((column) => ({\n id: getColumnId(column),\n column,\n }));\n}\n\n/**\n * The order with `movedId` lifted out and put back in front of `beforeId`, or\n * at the end when that is `null`.\n *\n * Returns `orderedIds` itself when the move changes nothing, so callers can\n * treat an unchanged reference as \"no move happened\".\n */\nexport function moveColumnBefore(\n orderedIds: ColumnOrderState,\n movedId: string,\n beforeId: string | null,\n): ColumnOrderState {\n if (movedId === beforeId || !orderedIds.includes(movedId)) {\n return orderedIds;\n }\n\n const without = orderedIds.filter((id) => id !== movedId);\n // Taken after the removal: an index read before it would be one too far\n // right for every move that travels rightwards.\n const target = beforeId === null ? without.length : without.indexOf(beforeId);\n if (target === -1) {\n return orderedIds;\n }\n\n const next = [...without];\n next.splice(target, 0, movedId);\n return next.every((id, index) => id === orderedIds[index])\n ? orderedIds\n : next;\n}\n\n/**\n * Whether moving `movedId` in front of `beforeId` would rearrange anything, so\n * that a drop indicator promises exactly the moves that happen.\n *\n * Defined against `moveColumnBefore` rather than restating its conditions, so\n * the two cannot disagree about what a no-op is.\n */\nexport function movesColumn(\n orderedIds: ColumnOrderState,\n movedId: string,\n beforeId: string | null,\n): boolean {\n return moveColumnBefore(orderedIds, movedId, beforeId) !== orderedIds;\n}\n\n/**\n * The id a drop on `side` of `targetId` lands in front of, which is `null`\n * past the last column.\n *\n * \"After C\" and \"before D\" name the same gap, so collapsing both to one id\n * keeps a drop target a single nullable string.\n */\nexport function resolveDropBefore(\n orderedIds: ColumnOrderState,\n targetId: string,\n side: DropSide,\n): string | null {\n if (side === \"before\") {\n return targetId;\n }\n const index = orderedIds.indexOf(targetId);\n return index === -1 ? null : (orderedIds[index + 1] ?? null);\n}\n\n/**\n * The `beforeId` a keyboard nudge on `columnId` produces, for `onDrop` to\n * apply the same way a pointer drop does — or `undefined` when the nudge is a\n * no-op: `columnId` is not in `orderedIds`, or the nudge would move it left\n * of the start.\n *\n * `null` is a real answer here, not \"no-op\": it means append to the end, the\n * same convention `moveColumnBefore` uses.\n */\nexport function resolveKeyboardDropTarget(\n orderedIds: ColumnOrderState,\n columnId: string,\n direction: -1 | 1,\n): string | null | undefined {\n const index = orderedIds.indexOf(columnId);\n if (index === -1) {\n return undefined;\n }\n\n /**\n * Moving right lands in front of the id two along: the gap immediately\n * after a column is the one it already sits in.\n */\n const targetIndex = direction === -1 ? index - 1 : index + 2;\n if (targetIndex < 0) {\n return undefined;\n }\n\n return orderedIds[targetIndex] ?? null;\n}\n","import type { DisplayRow, PaginationState } from \"../types\";\n\nexport interface PaginatedRows<Row> {\n readonly rows: readonly DisplayRow<Row>[];\n readonly pageCount: number;\n /**\n * `pagination.pageIndex` clamped into `[0, pageCount - 1]` (or `0` when\n * `pageCount` is `0`) — read this back rather than trusting the input\n * verbatim, the same way `sortRows`/`filterRows` tolerate a stale stored\n * state.\n */\n readonly pageIndex: number;\n}\n\n/** A contiguous run of `rows` that pagination treats as one unit — a top-level group's header plus every entry beneath it, or a single bare data row. */\ninterface Unit {\n readonly start: number;\n readonly end: number; // exclusive\n}\n\n/**\n * `rows` split into pagination units: a top-level (`level === 0`) group\n * header together with every entry up to (not including) the next unit\n * boundary, or a single bare data row of its own. A nested group (`level >\n * 0`) and the data rows beneath it contribute no boundary — they're carried\n * along inside their top-level ancestor's span, which is what keeps a page\n * from ever splitting a group. A bare data row *outside* any top-level\n * group's span starts (and immediately ends) its own unit, which is what\n * makes an entirely ungrouped `rows` produce one unit per row rather than\n * collapsing into a single unit for the whole array.\n *\n * A `\"group-summary\"` row (`groupAggregateDisplay: \"row\"`) never opens a\n * boundary of its own, at any level — including a top-level one, despite\n * carrying that same `level: 0` a top-level header does. It always belongs\n * to the unit its own group already opened, the same way a nested header\n * and the data rows beneath it do.\n *\n * `openedByGroup` tracks whether the unit currently being built started at a\n * top-level header (in which case everything until the next one, headers and\n * bare rows alike, belongs to it) or at a bare row (in which case it holds\n * exactly that one row).\n */\nfunction unitsOf<Row>(rows: readonly DisplayRow<Row>[]): readonly Unit[] {\n const units: Unit[] = [];\n let start = 0;\n let openedByGroup = false;\n for (let index = 0; index < rows.length; index++) {\n const entry = rows[index];\n if (entry === undefined) {\n continue;\n }\n const isTopLevelHeader =\n \"kind\" in entry && entry.kind === \"group\" && entry.level === 0;\n const isBoundary = index !== start && (isTopLevelHeader || !openedByGroup);\n if (isBoundary) {\n units.push({ start, end: index });\n start = index;\n openedByGroup = isTopLevelHeader;\n } else if (index === start) {\n openedByGroup = isTopLevelHeader;\n }\n }\n if (start < rows.length) {\n units.push({ start, end: rows.length });\n }\n return units;\n}\n\n/**\n * `rows` sliced into pages of `pagination.pageSize` units — see `unitsOf`\n * for what a unit is. `pageIndex` is clamped into range, `pageSize <= 0` is\n * clamped to `1` (this codebase's general tolerance for stale/odd stored\n * state, matching `sortRows`/`filterRows`), and the returned page's\n * `rowIndex` is renumbered to be page-relative — 0-based from the top of the\n * page, header rows included, mirroring `groupRows`'s own renumbering\n * invariant. `datasetIndex` is left untouched: the stages ahead of this one\n * set it to each row's position in the whole displayed result, which stays\n * the same whichever page is showing.\n */\nexport function paginateRows<Row>(\n rows: readonly DisplayRow<Row>[],\n pagination: PaginationState,\n): PaginatedRows<Row> {\n const pageSize = Math.max(1, pagination.pageSize);\n const units = unitsOf(rows);\n const pageCount = Math.ceil(units.length / pageSize);\n\n if (pageCount === 0) {\n return { rows: [], pageCount: 0, pageIndex: 0 };\n }\n\n const pageIndex = Math.min(Math.max(pagination.pageIndex, 0), pageCount - 1);\n const firstUnit = units[pageIndex * pageSize];\n const lastUnit =\n units[Math.min(pageIndex * pageSize + pageSize, units.length) - 1];\n if (firstUnit === undefined || lastUnit === undefined) {\n return { rows: [], pageCount, pageIndex };\n }\n\n const page = rows.slice(firstUnit.start, lastUnit.end);\n const renumbered = page.map((entry, index) =>\n entry.rowIndex === index ? entry : { ...entry, rowIndex: index },\n );\n\n return { rows: renumbered, pageCount, pageIndex };\n}\n","/**\n * The one global this package touches. Declared here rather than taken from a\n * `lib`, which would bring the whole DOM (or Node) along with it: every\n * runtime core runs in has a `console`, and this is all of it core uses.\n */\ndeclare const console: { error: (message: string) => void };\n\n/**\n * Tells the developer about a mistake that does not stop the grid working —\n * two settings that contradict each other, state that cannot be saved — so it\n * is reported rather than thrown.\n */\nexport function reportError(message: string): void {\n console.error(`GridKit: ${message}`);\n}\n","import type { ColumnType, OperatorFilterEntry } from \"../types\";\nimport { bucketKey } from \"./grouping\";\nimport { compareValues } from \"./sorting\";\n\ntype CellTest = (value: unknown) => boolean;\n\ntype Operand = OperatorFilterEntry<unknown>[\"value\"];\n\n/**\n * Where a cell stands against one operand: below it, equal to it or above\n * it as `compareValues` orders them — or `undefined` when the two can't be\n * compared at all (an empty cell, a cell of another kind).\n */\ntype Comparison = (value: unknown) => number | undefined;\n\n/** How a column's values compare, which decides what an operand must be. */\nexport type ValueKind = \"number\" | \"boolean\" | \"date\" | \"text\";\n\nconst matchNothing: CellTest = () => false;\n\n/**\n * The kind a column of `type` compares as. A filter menu's operator family\n * is this same kind (`filterOperatorFamily`), so the operators it offers and\n * the operands it parses are the ones the column filters by.\n */\nexport function kindOf(type: ColumnType | undefined): ValueKind {\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"date\":\n case \"dateTime\":\n case \"time\":\n return \"date\";\n default:\n return \"text\";\n }\n}\n\n/** Whether a column of `type` holds dates — what a saved string is revived for. */\nexport function isDateType(type: ColumnType | undefined): boolean {\n return kindOf(type) === \"date\";\n}\n\n/**\n * `null`, `undefined` and `\"\"` — the three a filter user calls blank. Wider\n * than the `null`/`undefined` a `TextFilterEntry` stringifies to `\"\"`,\n * because an empty string is just as blank to someone reading the grid.\n */\nexport function isEmptyCell(value: unknown): boolean {\n return value === null || value === undefined || value === \"\";\n}\n\n/**\n * `value` as a `Date`, when it is one or a string that reads as one —\n * `undefined` otherwise, an invalid date included, so an unparseable value\n * never compares as a date.\n */\nexport function toDate(value: unknown): Date | undefined {\n const date =\n value instanceof Date\n ? value\n : typeof value === \"string\"\n ? new Date(value)\n : undefined;\n return date === undefined || Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * `value` in the form `compareValues` compares under `kind`, or `undefined`\n * when it isn't of that kind. Text is lowercased here, once, so every text\n * comparison is case-insensitive the way a query is.\n */\nfunction comparable(value: unknown, kind: ValueKind): unknown {\n switch (kind) {\n case \"number\":\n return typeof value === \"number\" && !Number.isNaN(value)\n ? value\n : undefined;\n case \"boolean\":\n return typeof value === \"boolean\" ? value : undefined;\n case \"date\":\n return toDate(value);\n case \"text\":\n return String(value).toLowerCase();\n }\n}\n\n/** Whether an operand can stand for a value of `kind` at all. */\nfunction isOperandOfKind(operand: unknown, kind: ValueKind): boolean {\n if (kind !== \"text\") {\n return comparable(operand, kind) !== undefined;\n }\n return (\n typeof operand === \"string\" ||\n typeof operand === \"number\" ||\n typeof operand === \"boolean\"\n );\n}\n\n/**\n * Compares each cell against `operand` the way the column's `type` orders\n * values, or `undefined` when `operand` is of the wrong kind for the column\n * and so can be compared with nothing.\n */\nfunction compileComparison(\n operand: Operand,\n type: ColumnType | undefined,\n): Comparison | undefined {\n const kind = kindOf(type);\n if (!isOperandOfKind(operand, kind)) {\n return undefined;\n }\n const target = comparable(operand, kind);\n return (value) => {\n if (isEmptyCell(value)) {\n return undefined;\n }\n const cell = comparable(value, kind);\n return cell === undefined ? undefined : compareValues(cell, target, type);\n };\n}\n\n/** Whether an operand is a list — what `in` and `between` take. */\nexport function isScalarList<Scalar>(\n operand: Scalar | readonly Scalar[] | undefined,\n): operand is readonly Scalar[] {\n return Array.isArray(operand);\n}\n\nfunction compileOrdering(\n operator: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\",\n operand: Operand,\n type: ColumnType | undefined,\n): CellTest {\n const compare = compileComparison(operand, type);\n if (compare === undefined) {\n return matchNothing;\n }\n /** A cell that can't be compared satisfies no ordering. */\n const where =\n (holds: (result: number) => boolean): CellTest =>\n (value) => {\n const result = compare(value);\n return result !== undefined && holds(result);\n };\n switch (operator) {\n case \"eq\":\n return where((result) => result === 0);\n case \"ne\": {\n const equals = where((result) => result === 0);\n return (value) => !equals(value);\n }\n case \"gt\":\n return where((result) => result > 0);\n case \"gte\":\n return where((result) => result >= 0);\n case \"lt\":\n return where((result) => result < 0);\n case \"lte\":\n return where((result) => result <= 0);\n }\n}\n\nfunction compileBetween(\n operand: Operand,\n type: ColumnType | undefined,\n): CellTest {\n if (!isScalarList(operand) || operand.length !== 2) {\n return matchNothing;\n }\n const [low, high] = operand;\n const fromLow = compileComparison(low, type);\n const fromHigh = compileComparison(high, type);\n if (fromLow === undefined || fromHigh === undefined) {\n return matchNothing;\n }\n return (value) => {\n const aboveLow = fromLow(value);\n const belowHigh = fromHigh(value);\n return (\n aboveLow !== undefined &&\n belowHigh !== undefined &&\n aboveLow >= 0 &&\n belowHigh <= 0\n );\n };\n}\n\n/**\n * The key `in` matches by: grouping's own `bucketKey`, so two values are\n * \"the same\" exactly when grouping would put them in one group — except that\n * a date column reads a date string as the date it names, so a list saved as\n * `Date`s still matches cells that hold ISO strings, and the other way round.\n */\nexport function filterValueKey(\n value: unknown,\n type: ColumnType | undefined,\n): string {\n return bucketKey(isDateType(type) ? (toDate(value) ?? value) : value);\n}\n\nfunction compileIn(operand: Operand, type: ColumnType | undefined): CellTest {\n if (!isScalarList(operand)) {\n return matchNothing;\n }\n const keys = new Set(\n operand\n .filter((scalar) => !isEmptyCell(scalar))\n .map((scalar) => filterValueKey(scalar, type)),\n );\n return (value) =>\n !isEmptyCell(value) && keys.has(filterValueKey(value, type));\n}\n\nfunction compileText(\n operator: \"contains\" | \"notContains\" | \"startsWith\" | \"endsWith\",\n operand: Operand,\n): CellTest {\n if (!isOperandOfKind(operand, \"text\")) {\n return matchNothing;\n }\n const text = String(operand).toLowerCase();\n const read = (value: unknown) => String(value).toLowerCase();\n switch (operator) {\n case \"contains\":\n return (value) => !isEmptyCell(value) && read(value).includes(text);\n case \"notContains\":\n return (value) => isEmptyCell(value) || !read(value).includes(text);\n case \"startsWith\":\n return (value) => !isEmptyCell(value) && read(value).startsWith(text);\n case \"endsWith\":\n return (value) => !isEmptyCell(value) && read(value).endsWith(text);\n }\n}\n\n/**\n * One reusable test for an `OperatorFilterEntry`, given its column's `type`\n * — its operand read, checked and normalised once, so `filterRows`'s row\n * loop only reads the cell. See `OperatorFilterEntry` for what each\n * operator matches.\n */\nexport function compileOperatorEntry(\n entry: OperatorFilterEntry<unknown>,\n type: ColumnType | undefined,\n): CellTest {\n const { operator, value } = entry;\n switch (operator) {\n case \"isEmpty\":\n return isEmptyCell;\n case \"isNotEmpty\":\n return (cell) => !isEmptyCell(cell);\n case \"contains\":\n case \"notContains\":\n case \"startsWith\":\n case \"endsWith\":\n return compileText(operator, value);\n case \"between\":\n return compileBetween(value, type);\n case \"in\":\n return compileIn(value, type);\n case \"eq\":\n case \"ne\":\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\":\n return compileOrdering(operator, value, type);\n }\n}\n","import type {\n ColumnType,\n DataColumn,\n FilterEntry,\n FilterScalar,\n FilterState,\n GridState,\n OperatorFilterEntry,\n SerializedFilterEntry,\n SerializedFilterScalar,\n SerializedFilterState,\n SerializedGridState,\n SerializedOperatorFilterEntry,\n} from \"../types\";\nimport { isDateType, isScalarList, toDate } from \"./filterOperators\";\nimport { reportError } from \"./report\";\n\ntype Operand = Exclude<OperatorFilterEntry<unknown>[\"value\"], undefined>;\ntype SerializedOperand = Exclude<\n SerializedOperatorFilterEntry<unknown>[\"value\"],\n undefined\n>;\n\nfunction serializeScalar(scalar: FilterScalar): SerializedFilterScalar {\n return scalar instanceof Date ? scalar.toISOString() : scalar;\n}\n\nfunction serializeOperand(operand: Operand): SerializedOperand {\n return isScalarList(operand)\n ? operand.map(serializeScalar)\n : serializeScalar(operand);\n}\n\n/**\n * `entry` as JSON can hold it, or `undefined` when it cannot be written down\n * at all — a predicate, or a group left with nothing but predicates.\n */\nfunction serializeEntry<Row>(\n entry: FilterEntry<Row>,\n): SerializedFilterEntry<Row> | undefined {\n if (\"combinator\" in entry) {\n const entries = serializeFilter(entry.entries);\n // A group emptied by dropping its predicates would match everything (an\n // \"and\") or nothing (an \"or\") — neither what was saved — so it goes too.\n return entries.length === 0 && entry.entries.length > 0\n ? undefined\n : { combinator: entry.combinator, entries };\n }\n if (\"predicate\" in entry) {\n reportError(\n entry.columnId === undefined\n ? \"a predicate filter entry across every column cannot be serialised, so it is left out of the saved state.\"\n : `a predicate filter entry on \\`${entry.columnId}\\` cannot be serialised, so it is left out of the saved state.`,\n );\n return undefined;\n }\n if (\"operator\" in entry) {\n const { value, ...rest } = entry;\n return value === undefined\n ? rest\n : { ...rest, value: serializeOperand(value) };\n }\n if (\"value\" in entry) {\n const { value, ...rest } = entry;\n return {\n ...rest,\n value: value instanceof Date ? value.toISOString() : value,\n };\n }\n return entry;\n}\n\nfunction serializeFilter<Row>(\n filter: FilterState<Row>,\n): SerializedFilterState<Row> {\n return filter\n .map((entry) => serializeEntry(entry))\n .filter((entry) => entry !== undefined);\n}\n\n/**\n * `state` in a form that survives `JSON.stringify` and back unchanged, for\n * saving a layout — to local storage, a URL, a user's profile — and handing\n * it to `restoreState` later. Every slice is plain data already except the\n * filter: a `Date` value or operand is written as its ISO string, and a\n * predicate entry, being a function, cannot be written at all and is left\n * out with a `console.error` naming its column.\n */\nexport function serializeGridState<Row>(\n state: GridState<Row>,\n): SerializedGridState<Row> {\n return { ...state, filter: serializeFilter(state.filter) };\n}\n\n/** A saved scalar back as a `Date` when a date column's string reads as one. */\nfunction reviveScalar(\n scalar: FilterScalar,\n type: ColumnType | undefined,\n): FilterScalar {\n return isDateType(type) && typeof scalar === \"string\"\n ? (toDate(scalar) ?? scalar)\n : scalar;\n}\n\nfunction reviveOperand(\n operand: Operand | SerializedOperand,\n type: ColumnType | undefined,\n): Operand {\n return isScalarList(operand)\n ? operand.map((scalar) => reviveScalar(scalar, type))\n : reviveScalar(operand, type);\n}\n\nfunction reviveEntry<Row>(\n entry: FilterEntry<Row> | SerializedFilterEntry<Row>,\n typeOf: (columnId: string) => ColumnType | undefined,\n): FilterEntry<Row> {\n if (\"combinator\" in entry) {\n return {\n combinator: entry.combinator,\n entries: reviveEntries(entry.entries, typeOf),\n };\n }\n if (\"operator\" in entry) {\n const { value, ...rest } = entry;\n return value === undefined\n ? rest\n : { ...rest, value: reviveOperand(value, typeOf(entry.columnId)) };\n }\n if (\"value\" in entry) {\n const { value, ...rest } = entry;\n return {\n ...rest,\n value: typeof value === \"string\" ? new Date(value) : value,\n };\n }\n return entry;\n}\n\nfunction reviveEntries<Row>(\n filter: FilterState<Row> | SerializedFilterState<Row>,\n typeOf: (columnId: string) => ColumnType | undefined,\n): FilterState<Row> {\n return filter.map((entry) => reviveEntry(entry, typeOf));\n}\n\n/**\n * A filter as `serializeGridState` wrote it, back as a `FilterState`. A\n * value entry holding a string held a `Date`, since that is the only way one\n * comes to hold a string. An operator entry's strings are read as dates only\n * on a date, date-time or time column in `columns`, since elsewhere a string\n * is just a string. A filter that was never serialised passes through as it\n * is.\n */\nexport function reviveFilter<Row>(\n filter: FilterState<Row> | SerializedFilterState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): FilterState<Row> {\n const types = new Map(columns.map((entry) => [entry.id, entry.column.type]));\n return reviveEntries(filter, (columnId) => types.get(columnId));\n}\n","import type {\n ColumnConstraints,\n ColumnDefinition,\n ColumnResizeSession,\n ColumnResolveOptions,\n ColumnSizeDefaults,\n ColumnSizingState,\n ResolvedColumn,\n} from \"../types\";\nimport { alignmentForType, getColumnId, resolveColumnLabel } from \"./grid\";\n\n/**\n * Applied to any column that does not size itself. The minimum is a width a\n * header stays legible at rather than a measured value — a column dragged\n * narrower than this reads as a rendering fault.\n */\nexport const DEFAULT_COLUMN_SIZES: ColumnSizeDefaults = {\n width: 150,\n minWidth: 40,\n maxWidth: Number.POSITIVE_INFINITY,\n};\n\n/** How far one arrow key press moves a column edge. */\nexport const KEYBOARD_STEP = 10;\n\nfunction withDefaults(\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnSizeDefaults {\n return { ...DEFAULT_COLUMN_SIZES, ...defaults };\n}\n\n/**\n * The bounds `column` may be sized between. Resolved in one place so that a\n * drag, a clamp and an auto-fit cannot disagree about a column's limits.\n */\nexport function resolveColumnConstraints<Row>(\n column: ColumnDefinition<Row, unknown>,\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnConstraints {\n const resolved = withDefaults(defaults);\n return {\n minWidth: column.minWidth ?? resolved.minWidth,\n maxWidth: column.maxWidth ?? resolved.maxWidth,\n };\n}\n\n/** Holds `width` within `constraints`. */\nexport function clampColumnWidth(\n width: number,\n constraints: ColumnConstraints,\n): number {\n return Math.min(Math.max(width, constraints.minWidth), constraints.maxWidth);\n}\n\n/**\n * Pairs each column with everything needed to render it — the width it sits\n * at, the label its header shows, whether it may be resized and how its cells\n * align. Widths take the first of the sizing state, the column's own `width`,\n * and the default, then clamp.\n *\n * The sizing state winning means a user's drag outlives a re-render; a column\n * absent from it still tracks a `width` edited in the definition.\n */\nexport function resolveColumnWidths<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n sizing: ColumnSizingState,\n options?: ColumnResolveOptions,\n): readonly ResolvedColumn<Row, Node>[] {\n const resolved = withDefaults(options?.sizes);\n\n return columns.map((column) => {\n const id = getColumnId(column);\n const stored = sizing[id];\n\n return {\n column,\n id,\n sized: stored !== undefined,\n width: clampColumnWidth(\n stored ?? column.width ?? resolved.width,\n resolveColumnConstraints(column, resolved),\n ),\n label: resolveColumnLabel(column),\n resizable: column.resizable ?? options?.resizable ?? false,\n reorderable: column.reorderable ?? options?.reorderable ?? false,\n groupByDraggable:\n column.groupByDraggable ?? options?.groupByDraggable ?? false,\n alignment: column.alignment ?? alignmentForType(column.type ?? \"string\"),\n };\n });\n}\n\nexport function totalColumnWidth<Row, Node>(\n resolved: readonly ResolvedColumn<Row, Node>[],\n): number {\n return resolved.reduce((total, entry) => total + entry.width, 0);\n}\n\n/**\n * Opens a resize. The session captures its constraints and starting point up\n * front, so applying a pointer position later is arithmetic on numbers alone —\n * which is what keeps the drag testable without a DOM.\n *\n * @param startPosition Where the pointer went down, on the axis being dragged.\n */\nexport function beginColumnResize<Row>(\n column: ColumnDefinition<Row, unknown>,\n startWidth: number,\n startPosition: number,\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnResizeSession {\n return {\n columnId: getColumnId(column),\n startWidth,\n startPosition,\n constraints: resolveColumnConstraints(column, defaults),\n };\n}\n\n/**\n * The width the dragged column takes with the pointer at `position`. The delta\n * is signed, so a right-to-left adapter negates it and nothing else changes.\n */\nexport function applyColumnResize(\n session: ColumnResizeSession,\n position: number,\n): number {\n return clampColumnWidth(\n session.startWidth + (position - session.startPosition),\n session.constraints,\n );\n}\n\ninterface SizingEntry<Row, Node> {\n entry: ResolvedColumn<Row, Node>;\n width: number;\n bound: number;\n adjustable: boolean;\n}\n\n/**\n * Whether `item` has reached `bound` in the direction it moves toward — above\n * it for a column growing to a `maxWidth`, below it for one shrinking to a\n * `minWidth`.\n */\nfunction reachedBound<Row, Node>(\n width: number,\n item: SizingEntry<Row, Node>,\n): boolean {\n return item.bound > item.width ? width >= item.bound : width <= item.bound;\n}\n\n/**\n * Moves every adjustable entry's `width` toward `bound` by its proportional\n * share of `remaining`'s current surplus or deficit, looping so a column\n * clamped at its bound in one pass frees the remainder for the others to\n * absorb in the next.\n */\nfunction redistribute<Row, Node>(\n entries: readonly SizingEntry<Row, Node>[],\n remaining: (sum: number) => number,\n): void {\n for (;;) {\n const movable = entries.filter(\n (item) => item.adjustable && !reachedBound(item.width, item),\n );\n const left = remaining(entries.reduce((t, i) => t + i.width, 0));\n if (left <= 0 || movable.length === 0) {\n break;\n }\n\n const base = movable.reduce((total, item) => total + item.width, 0);\n let clamped = false;\n\n for (const item of movable) {\n const share =\n base === 0 ? left / movable.length : (left * item.width) / base;\n const next = item.width + (item.bound > item.width ? share : -share);\n\n if (reachedBound(next, item)) {\n item.width = item.bound;\n clamped = true;\n } else {\n item.width = next;\n }\n }\n\n if (!clamped) {\n break;\n }\n }\n}\n\n/**\n * Fits columns to `availableWidth`: grows them to fill leftover space, or\n * shrinks them to relieve an overflow, in both cases proportionally to each\n * column's current width. Columns the user has sized are left alone in\n * either direction, so dragging one column neither rubber-bands it back nor\n * has it absorb a squeeze meant for the rest.\n *\n * Growing stops at each column's `maxWidth`; shrinking stops at its\n * `minWidth`. If shrinking every adjustable column to its floor still does\n * not reach `availableWidth`, the columns are returned untouched and the\n * container scrolls rather than crushing them further.\n */\nexport function fitColumnsToWidth<Row, Node>(\n resolved: readonly ResolvedColumn<Row, Node>[],\n availableWidth: number,\n defaults?: Partial<ColumnSizeDefaults>,\n): readonly ResolvedColumn<Row, Node>[] {\n const target = Math.floor(availableWidth);\n const total = totalColumnWidth(resolved);\n if (resolved.length === 0 || total === target) {\n return resolved;\n }\n\n const growing = total < target;\n const entries: SizingEntry<Row, Node>[] = resolved.map((entry) => {\n const constraints = resolveColumnConstraints(entry.column, defaults);\n return {\n entry,\n width: entry.width,\n bound: growing ? constraints.maxWidth : constraints.minWidth,\n adjustable: !entry.sized,\n };\n });\n\n if (!growing) {\n // Only unsized columns can be shrunk, so if they alone cannot reach the\n // target the grid genuinely cannot fit and should scroll, unchanged.\n const floor = entries.reduce(\n (sum, item) => sum + (item.adjustable ? item.bound : item.width),\n 0,\n );\n if (floor > target) {\n return resolved;\n }\n }\n\n redistribute(entries, (sum) => (growing ? target - sum : sum - target));\n\n // Fractional widths would leave the table a sub-pixel off its container and\n // show a scrollbar that never goes away, so round every column toward the\n // target and hand the remaining pixels back out (growing) or claw them\n // back (shrinking) one at a time.\n const rounded = entries.map((item) =>\n growing ? Math.floor(item.width) : Math.ceil(item.width),\n );\n let remainder = target - rounded.reduce((total, width) => total + width, 0);\n\n return entries.map((item, index) => {\n let width = rounded[index] ?? item.width;\n // Rounding toward the target can only ever leave it short when growing\n // (floor) or over when shrinking (ceil), so only one direction is ever\n // live here — but each still needs room left before its own bound.\n const hasRoom = growing ? width < item.bound : width > item.bound;\n\n if (remainder !== 0 && item.adjustable && hasRoom) {\n width += growing ? 1 : -1;\n remainder += growing ? -1 : 1;\n }\n\n return { ...item.entry, width };\n });\n}\n\n/**\n * The width a column needs to show `measuredWidth` of content.\n *\n * `padding` is an allowance on top of the measurement, since a column sized to\n * exactly its content can still round down into an ellipsis.\n */\nexport function sizeColumnToContent(\n measuredWidth: number,\n constraints: ColumnConstraints,\n padding = 2,\n): number {\n return clampColumnWidth(Math.ceil(measuredWidth + padding), constraints);\n}\n\n/**\n * `current` with `columnId` reverted to its width in `base` — or omitted\n * entirely if `base` had none — for Escape to restore a resize in progress.\n *\n * A column with no stored width in `base` is correctly omitted by deleting\n * the key rather than merging its `base` width back in, which would\n * otherwise leave it pinned and hidden from auto-fit.\n */\nexport function revertColumnSize(\n current: ColumnSizingState,\n base: ColumnSizingState,\n columnId: string,\n): ColumnSizingState {\n const next = Object.fromEntries(\n Object.entries(current).filter(([id]) => id !== columnId),\n );\n if (columnId in base) {\n next[columnId] = base[columnId] as number;\n }\n return next;\n}\n","import type {\n AggregateResults,\n AggregateSpec,\n AggregateState,\n BuiltInAggregate,\n ColumnDefinition,\n DataColumn,\n DisplayRow,\n GroupAggregateDisplay,\n GroupByState,\n ResolvedGroupRow,\n ResolvedGroupSummaryRow,\n ResolvedRow,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { bucketKey } from \"./grouping\";\nimport { renumberRows } from \"./position\";\nimport { compareValues } from \"./sorting\";\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/** A value's numeric reading for `sum`/`avg` — `NaN` is treated as absent, same as an empty value. */\nfunction toNumber(value: unknown): number {\n return Number(value);\n}\n\n/**\n * A key distinguishing `countDistinct`'s buckets — reuses `bucketKey`'s\n * approach in `grouping.ts` (distinct values bucketed by kind and content,\n * two `Date`s for the same instant collapsing together) rather than a\n * second implementation of the same idea.\n */\nfunction distinctKey(value: unknown): string {\n if (isEmpty(value)) {\n return \"\\0empty\";\n }\n if (value instanceof Date) {\n return `\\0date:${String(value.getTime())}`;\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return `\\0${typeof value}:${String(value)}`;\n case \"function\":\n return \"\\0function\";\n default:\n return `\\0object:${JSON.stringify(value)}`;\n }\n}\n\n/**\n * One built-in reducer over the raw values read off `rows` at `column`'s\n * field. `min`/`max` compare via `compareValues` so a `date`/`dateTime`\n * column orders chronologically rather than numerically; `sum`/`avg`\n * coerce numerically regardless of `column.type`, matching how a\n * `currency`/`decimal`/`percent`/`number` column is expected to be used.\n *\n * Null/undefined handling: `min`/`max` ignore empty entries entirely rather\n * than letting them win by `compareValues`'s own \"empty sorts last\"\n * convention — an aggregate that returned `undefined` merely because every\n * value happened to be null would be a worse answer than skipping them.\n * `count` counts every row in scope regardless of whether its value at this\n * column is empty (it answers \"how many rows\", not \"how many non-null\n * values\") — `countDistinct` excludes empty values from its distinct set,\n * since \"blank\" is not a value to count as one of the distinct ones.\n */\nfunction reduceBuiltIn<Row>(\n rows: readonly Row[],\n fn: BuiltInAggregate,\n column: DataColumn<Row, unknown> | undefined,\n): unknown {\n if (fn === \"count\") {\n return rows.length;\n }\n\n const field = column?.column.field;\n const values =\n field === undefined ? [] : rows.map((row) => accessDotted(row, field));\n\n switch (fn) {\n case \"sum\": {\n let total = 0;\n for (const value of values) {\n if (isEmpty(value)) continue;\n total += toNumber(value);\n }\n return total;\n }\n case \"avg\": {\n const present = values.filter((value) => !isEmpty(value));\n if (present.length === 0) return undefined;\n const total = present.reduce(\n (acc: number, value) => acc + toNumber(value),\n 0,\n );\n return total / present.length;\n }\n case \"min\":\n case \"max\": {\n const type = column?.column.type;\n let result: unknown;\n for (const value of values) {\n if (isEmpty(value)) continue;\n if (result === undefined) {\n result = value;\n continue;\n }\n const comparison = compareValues(value, result, type);\n if (fn === \"min\" ? comparison < 0 : comparison > 0) {\n result = value;\n }\n }\n return result;\n }\n case \"countDistinct\": {\n const seen = new Set<string>();\n for (const value of values) {\n if (isEmpty(value)) continue;\n seen.add(distinctKey(value));\n }\n return seen.size;\n }\n }\n}\n\n/** This spec's result key — `id` when given, `columnId` otherwise. */\nfunction keyOf<Row>(spec: AggregateSpec<Row>): string {\n return spec.id ?? spec.columnId;\n}\n\n/**\n * `rows` reduced through every spec in `specs`, keyed by `spec.id ??\n * spec.columnId`. A custom `fn` (a plain function, not a `BuiltInAggregate`\n * name) is called once with the raw `rows` — no wrapping, no\n * pre-processing, so it sees exactly the same leaf set a built-in reducer\n * does.\n *\n * Two specs resolving to the same key: the later one wins, matching\n * `setColumnFilter`'s own silent-replace precedent for a key collision\n * rather than throwing.\n *\n * Returns a fresh empty `Map` for empty `rows` or empty `specs` — never a\n * shared singleton — matching this codebase's general avoidance of shared\n * mutable module state.\n */\nexport function computeAggregates<Row>(\n rows: readonly Row[],\n specs: AggregateState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): AggregateResults {\n const results = new Map<string, unknown>();\n if (specs.length === 0) {\n return results;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry]));\n for (const spec of specs) {\n const value =\n typeof spec.fn === \"function\"\n ? spec.fn(rows)\n : reduceBuiltIn(rows, spec.fn, byId.get(spec.columnId));\n results.set(keyOf(spec), value);\n }\n return results;\n}\n\n/**\n * A group header's full leaf-row descendant set, found by re-filtering\n * `flatRows` (the same pre-group, filtered/sorted rows `groupRows` itself\n * partitioned) against `header.path` — each ancestor level's value matched\n * via `bucketKey`, the identical notion of \"same value\" `groupRows` uses to\n * bucket in the first place.\n *\n * Deliberately independent of `displayRows`' own flattened shape: a\n * collapsed group's descendants are never emitted into `displayRows` at\n * all (see `buildLevel`'s `if (expanded)` guard), so a header's subtotal\n * has to be recomputed from the original row list rather than walked out\n * of the grouped-and-collapsed output — the only way a collapsed group's\n * header still gets a correct count regardless of its own collapse state.\n */\nfunction leafDescendantsOf<Row>(\n flatRows: readonly ResolvedRow<Row>[],\n path: readonly unknown[],\n groupBy: GroupByState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n): Row[] {\n const keys = path.map((value) => bucketKey(value));\n return flatRows\n .filter((row) =>\n keys.every((key, level) => {\n const columnId = groupBy[level]?.columnId;\n const column = columnId === undefined ? undefined : byId.get(columnId);\n if (column === undefined) return false;\n return bucketKey(accessDotted(row.row, column.field)) === key;\n }),\n )\n .map((row) => row.row);\n}\n\n/**\n * `displayRows` (already regrouped by `groupBy`, per `groupRows`) with\n * every group header's `aggregates` field set to `specs` computed over\n * that group's full leaf-row descendants, re-derived from `flatRows` (the\n * same pre-group rows `groupRows` was given) — regardless of the group's\n * own collapse state, since a collapsed group's header still needs a\n * correct subtotal and its descendants are otherwise absent from\n * `displayRows` entirely. Each level's `aggregates` comes from its own\n * full descendant set, computed independently rather than combined from\n * its children's already-computed results, so a non-associative custom\n * aggregate (median, distinct count) is never silently wrong at a nested\n * level.\n *\n * `display: \"row\"` additionally emits a `ResolvedGroupSummaryRow` right\n * after each group's last visible entry (its last nested group/data row,\n * or immediately after its own header when collapsed) — every level gets\n * its own, the same way every level already gets its own `aggregates`.\n * `display: \"inline\"` (the default) emits none; a header's `aggregates`\n * field is populated either way, since `GridGroupRow`'s own inline\n * rendering and a summary row both read from it.\n *\n * `rowIndex`/`datasetIndex` are renumbered across the whole output when a\n * row was inserted, the same invariant `groupRows` itself keeps.\n *\n * Returns `displayRows` itself, untouched, when `specs` is empty — the\n * same reference-equality no-op every other transform across\n * grouping/pagination uses.\n */\n/**\n * One pass over a contiguous run of `displayRows` sharing one parent — the\n * top-level call covers the whole array, and each group header found along\n * the way recurses into its own span (every entry up to the next one at\n * its level or shallower) the same way, so a group at any nesting depth\n * gets its own `aggregates` computed and, under `display: \"row\"`, its own\n * summary row appended right after everything beneath it.\n *\n * Returns the index just past the run this call consumed, so the caller\n * (itself, one level up, or `withGroupAggregates`) knows where to resume.\n */\nfunction appendAggregatedSpan<Row>(\n displayRows: readonly DisplayRow<Row>[],\n start: number,\n levelFloor: number | null,\n flatRows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n specs: AggregateState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n display: GroupAggregateDisplay,\n out: DisplayRow<Row>[],\n): number {\n let index = start;\n while (index < displayRows.length) {\n const entry = displayRows[index];\n if (entry === undefined) {\n index++;\n continue;\n }\n if (\n levelFloor !== null &&\n \"kind\" in entry &&\n entry.kind === \"group\" &&\n entry.level <= levelFloor\n ) {\n // The next entry at this level or shallower ends the current span —\n // handled by the caller's own iteration, not this one.\n break;\n }\n index++;\n if (!(\"kind\" in entry) || entry.kind !== \"group\") {\n out.push(entry);\n continue;\n }\n\n const leaves = leafDescendantsOf(flatRows, entry.path, groupBy, byId);\n const aggregates = computeAggregates(leaves, specs, columns);\n const withAggregates: ResolvedGroupRow = { ...entry, aggregates };\n out.push(withAggregates);\n\n index = appendAggregatedSpan(\n displayRows,\n index,\n entry.level,\n flatRows,\n groupBy,\n byId,\n specs,\n columns,\n display,\n out,\n );\n\n if (display === \"row\") {\n const summary: ResolvedGroupSummaryRow = {\n kind: \"group-summary\",\n groupId: entry.groupId,\n level: entry.level,\n rowIndex: -1,\n datasetIndex: -1,\n aggregates,\n };\n out.push(summary);\n }\n }\n return index;\n}\n\nexport function withGroupAggregates<Row>(\n displayRows: readonly DisplayRow<Row>[],\n flatRows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n specs: AggregateState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n display: GroupAggregateDisplay = \"inline\",\n): readonly DisplayRow<Row>[] {\n if (specs.length === 0) {\n return displayRows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const out: DisplayRow<Row>[] = [];\n appendAggregatedSpan(\n displayRows,\n 0,\n null,\n flatRows,\n groupBy,\n byId,\n specs,\n columns,\n display,\n out,\n );\n\n return renumberRows(out);\n}\n","import type {\n ColumnDefinition,\n ColumnType,\n DataColumn,\n FieldPath,\n FilterEntry,\n FilterState,\n ResolvedRow,\n TextFilterEntry,\n} from \"../types\";\nimport { compileOperatorEntry } from \"./filterOperators\";\nimport { accessDotted } from \"./grid\";\nimport { renumberRows } from \"./position\";\n\ninterface FilterPattern {\n mode: \"exact\" | \"contains\" | \"startsWith\" | \"endsWith\";\n text: string; // anchors stripped, lowercased once\n}\n\n/**\n * Reads a query's leading/trailing `%` into a match mode — see\n * `TextFilterEntry`'s own doc comment for the four shapes. Only the first\n * and last characters are read as anchors — a `%` anywhere else in the\n * query is a literal character, not a wildcard.\n */\nfunction parseFilterPattern(query: string): FilterPattern {\n const start = query.startsWith(\"%\");\n const end = query.endsWith(\"%\");\n let text = query;\n if (start) {\n text = text.slice(1);\n }\n if (end) {\n text = text.slice(0, -1);\n }\n text = text.toLowerCase();\n\n if (start && end) {\n return { mode: \"contains\", text };\n }\n if (start) {\n return { mode: \"endsWith\", text };\n }\n if (end) {\n return { mode: \"startsWith\", text };\n }\n return { mode: \"exact\", text };\n}\n\nfunction isEmptyValue(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/**\n * `parseFilterPattern`, compiled to a reusable test — parsed once, reused\n * per row, unlike a per-call `matchesQuery`.\n */\nfunction compileFilterQuery(query: string): (value: unknown) => boolean {\n const { mode, text } = parseFilterPattern(query);\n return (value: unknown) => {\n const candidate = (isEmptyValue(value) ? \"\" : String(value)).toLowerCase();\n switch (mode) {\n case \"exact\":\n return candidate === text;\n case \"contains\":\n return candidate.includes(text);\n case \"startsWith\":\n return candidate.startsWith(text);\n case \"endsWith\":\n return candidate.endsWith(text);\n }\n };\n}\n\n/**\n * Whether `target` (a `ValueFilterEntry`'s value) equals `value` under\n * `type` — `false` whenever `type` doesn't agree with `target`'s own kind,\n * so a number filter never silently matches a string column.\n */\nfunction matchesTypedValue(\n value: unknown,\n target: number | boolean | Date,\n type: ColumnType | undefined,\n): boolean {\n if (typeof target === \"number\") {\n if (\n type !== \"number\" &&\n type !== \"decimal\" &&\n type !== \"currency\" &&\n type !== \"percent\"\n ) {\n return false;\n }\n return typeof value === \"number\" && value === target;\n }\n if (typeof target === \"boolean\") {\n if (type !== \"boolean\") {\n return false;\n }\n return typeof value === \"boolean\" && value === target;\n }\n if (type !== \"date\" && type !== \"dateTime\" && type !== \"time\") {\n return false;\n }\n return value instanceof Date && value.getTime() === target.getTime();\n}\n\n/**\n * Whether a non-group entry names a column present in `byId` (or names\n * none at all) — lets a stored filter tolerate a column removed from the\n * definition the same way a stored `ColumnSortState` does, by dropping only\n * the entries that reference it.\n *\n * A `GroupFilterEntry` is always usable, regardless of its own contents:\n * its vacuous truth value under an empty or fully-unusable `entries` list\n * depends on its own `combinator` (`\"and\"` vacuously matches everything,\n * `\"or\"` vacuously matches nothing) — a group can't be dropped from its\n * parent's list the way an unusable simple entry can, since whether\n * dropping it would be safe depends on the *parent's* combinator too,\n * which this check has no way to know. Compiling it and letting `.every()`/\n * `.some()` resolve the vacuous case naturally is what stays correct in\n * every context; deciding upfront here is not.\n */\nfunction isEntryUsable<Row>(\n entry: FilterEntry<Row>,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n): boolean {\n if (\"combinator\" in entry) {\n return true;\n }\n return entry.columnId === undefined || byId.has(entry.columnId);\n}\n\n/**\n * One compiled test per usable `FilterEntry`, closing over its column\n * lookup so `filterRows`'s row loop is just `.every(test)`.\n */\nfunction compileFilterEntry<Row>(\n entry: FilterEntry<Row>,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n columns: readonly DataColumn<Row, unknown>[],\n): (row: Row) => boolean {\n if (\"combinator\" in entry) {\n const tests = entry.entries\n .filter((nested) => isEntryUsable(nested, byId))\n .map((nested) => compileFilterEntry(nested, byId, columns));\n return entry.combinator === \"and\"\n ? (row) => tests.every((test) => test(row))\n : (row) => tests.some((test) => test(row));\n }\n\n if (\"predicate\" in entry) {\n const { columnId, predicate } = entry;\n const column = columnId === undefined ? undefined : byId.get(columnId);\n return (row) =>\n predicate(\n column === undefined ? undefined : accessDotted(row, column.field),\n row,\n );\n }\n\n // Before the `value` check: an operator entry usually has a `value` too.\n if (\"operator\" in entry) {\n const column = byId.get(entry.columnId);\n if (column === undefined) {\n return () => false;\n }\n const test = compileOperatorEntry(entry, column.type);\n return (row) => test(accessDotted(row, column.field));\n }\n\n if (\"value\" in entry) {\n const { columnId, value } = entry;\n if (columnId !== undefined) {\n const column = byId.get(columnId);\n if (column === undefined) {\n return () => false;\n }\n return (row) =>\n matchesTypedValue(accessDotted(row, column.field), value, column.type);\n }\n return (row) =>\n columns.some((entry) =>\n matchesTypedValue(\n accessDotted(row, entry.column.field),\n value,\n entry.column.type,\n ),\n );\n }\n\n const { columnId, query } = entry;\n const test = compileFilterQuery(query);\n if (columnId !== undefined) {\n const column = byId.get(columnId);\n if (column === undefined) {\n return () => false;\n }\n return (row) => test(accessDotted(row, column.field));\n }\n return (row) =>\n columns.some((entry) => test(accessDotted(row, entry.column.field)));\n}\n\n/**\n * `filter` compiled to one test of a row, every entry ANDed as `filterRows`\n * applies them — or `undefined` when no entry applies to `columns`, so a\n * caller can skip the row loop. Entries naming a column absent from\n * `columns` are dropped, as `filterRows` drops them.\n */\nexport function compileFilter<Row>(\n filter: FilterState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): ((row: Row) => boolean) | undefined {\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const compiled = filter\n .filter((entry) => isEntryUsable(entry, byId))\n .map((entry) => compileFilterEntry(entry, byId, columns));\n return compiled.length === 0\n ? undefined\n : (row) => compiled.every((test) => test(row));\n}\n\n/**\n * Whether `value`, stringified, matches `query`'s SQL LIKE-style pattern —\n * case-insensitive always. A bare query is an exact match; `%text%` is\n * contains; `text%` is starts-with; `%text` is ends-with. `null`/`undefined`\n * stringify to `\"\"`.\n *\n * A one-shot convenience: parses `query` fresh on every call. `filterRows`\n * does not call this per cell — it compiles each `TextFilterEntry` once,\n * outside its row loop.\n */\nexport function matchesQuery(value: unknown, query: string): boolean {\n return compileFilterQuery(query)(value);\n}\n\n/**\n * This column's current text query, or the global entry's when `columnId`\n * is omitted; `null` if no `TextFilterEntry` names it — including when the\n * entry that exists for that key is a `ValueFilterEntry`/\n * `PredicateFilterEntry`/`OperatorFilterEntry`/`GroupFilterEntry` instead,\n * since none of those hold a query string to report.\n */\nexport function filterQueryFor<Row>(\n filter: FilterState<Row>,\n columnId?: FieldPath<Row> | (string & {}),\n): string | null {\n const entry = filter.find(\n (candidate): candidate is TextFilterEntry<Row> =>\n \"query\" in candidate && candidate.columnId === columnId,\n );\n return entry?.query ?? null;\n}\n\n/**\n * The filter with the `TextFilterEntry` for `columnId` (or the global\n * entry, when `columnId` is omitted) set to `query` — replacing whatever\n * entry already holds that key, of any variant, if present; appending a new\n * `TextFilterEntry` if not. An empty `query` removes the entry instead of\n * storing a filter that can never usefully match.\n *\n * Returns `filter` itself, unchanged, when the result would be a no-op: an\n * empty `query` naming a key with no existing entry, or a `query` equal to\n * an existing `TextFilterEntry`'s.\n */\nexport function setColumnFilter<Row>(\n filter: FilterState<Row>,\n columnId: (FieldPath<Row> | (string & {})) | undefined,\n query: string,\n): FilterState<Row> {\n const index = filter.findIndex(\n (entry) => !(\"combinator\" in entry) && entry.columnId === columnId,\n );\n\n if (query === \"\") {\n return index === -1 ? filter : filter.filter((_entry, i) => i !== index);\n }\n\n const next: TextFilterEntry<Row> =\n columnId === undefined ? { query } : { columnId, query };\n\n if (index === -1) {\n return [...filter, next];\n }\n const existing = filter[index];\n if (\n existing !== undefined &&\n \"query\" in existing &&\n existing.query === query\n ) {\n return filter;\n }\n return filter.map((entry, i) => (i === index ? next : entry));\n}\n\n/** `filter` reduced to empty. Returns `filter` itself when already empty. */\nexport function clearAllFilters<Row>(\n filter: FilterState<Row>,\n): FilterState<Row> {\n return filter.length === 0 ? filter : [];\n}\n\n/**\n * `rows` reduced to those matching every entry in `filter` (AND at the top\n * level — nest a `GroupFilterEntry` for OR). `rowIndex` and `datasetIndex`\n * are renumbered to match the retained positions — the same invariant\n * `sortRows` keeps,\n * needed here independently since `filterRows` runs before `sortRows` in\n * the composed pipeline (see `resolveShownRows`).\n *\n * Order-preserving: surviving rows keep their relative order, which is what\n * makes running this before a sort produce the identical final order a\n * sort-then-filter would — only the cost differs.\n *\n * Every entry is compiled once, before the row loop.\n *\n * Returns `rows` itself, untouched, when `filter` is empty or names only\n * columns absent from `columns` — a stored filter tolerates a column\n * removed from the definition the same way a stored `ColumnSortState` does.\n */\nexport function filterRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n filter: FilterState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n if (filter.length === 0) {\n return rows;\n }\n const test = compileFilter(filter, columns);\n if (test === undefined) {\n return rows;\n }\n\n const filtered = rows.filter((row) => test(row.row));\n\n return renumberRows(filtered);\n}\n","import type {\n ColumnSortState,\n DataColumn,\n FilterState,\n ResolvedColumn,\n ResolvedRow,\n SelectedCell,\n SelectedCellRef,\n SelectedColumn,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { filterRows } from \"./filtering\";\nimport { sortRows } from \"./sorting\";\n\n/**\n * `rows`, filtered then sorted — the one function `DataGrid.tsx` (and any\n * future framework binding) calls instead of composing `filterRows`/\n * `sortRows` itself.\n *\n * Filter always runs first: an O(n) pass that shrinks what the O(n log n)\n * sort has to touch whenever a filter is active, free when it isn't. This\n * is a performance choice, not a correctness one — filtering is an\n * order-preserving predicate and sort is a stable total order over whatever\n * it's handed, so the final order is identical either way.\n */\nexport function resolveShownRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n filter: FilterState<Row>,\n sort: ColumnSortState,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n return sortRows(filterRows(rows, filter, columns), sort, columns);\n}\n\n/**\n * `ids` resolved back to the rows behind them, keyed by `rowsById`.\n *\n * An id with no row behind it is dropped rather than left `undefined`: a\n * selection outlives a change to the data, so that filtering a row out and\n * back leaves it selected, and only what still exists can be handed to a\n * callback.\n */\nexport function resolveRows<Row>(\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n ids: readonly string[],\n): readonly ResolvedRow<Row>[] {\n return ids.map((id) => rowsById.get(id)).filter((row) => row !== undefined);\n}\n\n/**\n * `ids` resolved back to the columns behind them, paired with the position\n * each holds in `columns` — a stale id is dropped, matching `resolveRows`.\n */\nexport function resolveColumns<Row, Node>(\n columns: readonly ResolvedColumn<Row, Node>[],\n ids: readonly string[],\n): readonly SelectedColumn<Row, Node>[] {\n return ids\n .map((id) => {\n const columnIndex = columns.findIndex((entry) => entry.id === id);\n const column = columns[columnIndex];\n return column === undefined\n ? undefined\n : { columnId: id, column, columnIndex };\n })\n .filter((column) => column !== undefined);\n}\n\n/**\n * `cell` resolved down to the row, column and value it addresses — `null`\n * when there is no cell, or when either half of it names a row or column\n * that no longer exists.\n */\nexport function resolveCell<Row, Node>(\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n columns: readonly ResolvedColumn<Row, Node>[],\n cell: SelectedCellRef | null,\n): SelectedCell<Row, Node> | null {\n if (cell === null) {\n return null;\n }\n const entry = rowsById.get(cell.rowId);\n const columnIndex = columns.findIndex(\n (candidate) => candidate.id === cell.columnId,\n );\n const column = columns[columnIndex];\n if (entry === undefined || column === undefined) {\n return null;\n }\n return {\n rowId: cell.rowId,\n columnId: cell.columnId,\n row: entry.row,\n column,\n rowIndex: entry.rowIndex,\n columnIndex,\n value: accessDotted(entry.row, column.column.field),\n };\n}\n","import type {\n ColumnDefinition,\n ColumnVisibilityState,\n DataColumn,\n} from \"../types\";\nimport { getColumnId } from \"./grid\";\n\n/**\n * Whether `column` is shown: what the user last chose for it, if anything,\n * else what its definition says. The one place that precedence is decided,\n * so the view and an imperative \"is it showing?\" cannot disagree.\n */\nexport function isColumnVisible<Row>(\n column: ColumnDefinition<Row, unknown>,\n visibility: ColumnVisibilityState,\n): boolean {\n return visibility[getColumnId(column)] ?? column.hidden !== true;\n}\n\n/**\n * `columns` without the hidden ones, in the same order. `columns` itself when\n * every column is shown — the common case — so a stage memoised on this\n * output sees nothing change.\n */\nexport function applyColumnVisibility<Row, Node>(\n columns: readonly DataColumn<Row, Node>[],\n visibility: ColumnVisibilityState,\n): readonly DataColumn<Row, Node>[] {\n const visible = columns.filter((entry) =>\n isColumnVisible(entry.column, visibility),\n );\n return visible.length === columns.length ? columns : visible;\n}\n\n/**\n * `visibility` with each of `columnIds` shown (`visible: true`) or hidden.\n * Only a column whose visibility actually changes gets an entry, and ids\n * naming no column are ignored, so asking to show what is already showing\n * hands back `visibility` itself — the same reference, for a caller deciding\n * whether anything happened.\n */\nexport function setColumnVisibility<Row>(\n columns: readonly DataColumn<Row, unknown>[],\n visibility: ColumnVisibilityState,\n columnIds: readonly string[],\n visible: boolean,\n): ColumnVisibilityState {\n const requested = new Set(columnIds);\n const changed = columns.filter(\n (entry) =>\n requested.has(entry.id) &&\n isColumnVisible(entry.column, visibility) !== visible,\n );\n if (changed.length === 0) {\n return visibility;\n }\n return {\n ...visibility,\n ...Object.fromEntries(changed.map((entry) => [entry.id, visible])),\n };\n}\n","import type {\n AggregateResults,\n AggregateState,\n ColumnSizeDefaults,\n ColumnSizingState,\n DataColumn,\n DisplayRow,\n GridView,\n GridViewInput,\n PaginationState,\n ResizeMode,\n ResolvedColumn,\n ResolvedRow,\n} from \"../types\";\nimport { computeAggregates, withGroupAggregates } from \"./aggregation\";\nimport { resolveRowId } from \"./grid\";\nimport { groupRows } from \"./grouping\";\nimport { memoizeLast } from \"./memoize\";\nimport { resolveDataColumns } from \"./ordering\";\nimport { paginateRows, type PaginatedRows } from \"./paging\";\nimport { resolveShownRows } from \"./rows\";\nimport { fitColumnsToWidth, resolveColumnWidths } from \"./sizing\";\nimport { applyColumnVisibility } from \"./visibility\";\n\n/**\n * A stable empty fallback for omitted `aggregates` — a fresh `[]` per call\n * would change identity each time and defeat every stage memoised on it.\n */\nconst NO_AGGREGATES: AggregateState<never> = [];\n\n/**\n * The rows, each carrying the id everything downstream keys it by. Resolved\n * once here rather than per consumer so a row's id cannot come out\n * differently in two places — the same reason widths are resolved once ahead\n * of the header and the body.\n *\n * An array rather than a map keyed by id: two rows given the same id is a\n * caller's mistake, and one that should render twice and look wrong rather\n * than silently lose a row.\n */\nfunction identifyRows<Row>(\n rows: readonly Row[],\n getRowId: ((row: Row, index: number) => string) | undefined,\n): readonly ResolvedRow<Row>[] {\n return rows.map((row, rowIndex) => ({\n rowId: resolveRowId(row, rowIndex, getRowId),\n row,\n rowIndex,\n datasetIndex: rowIndex,\n }));\n}\n\n/**\n * The columns as rendered. Auto-fit is a derivation rather than a write back\n * into `sizing`, so that a `width` set in a column definition is never\n * overwritten and nothing chases its own output; `\"fixed\"` is then simply\n * the absence of it.\n *\n * The only stage that reads `sizing` or `viewportWidth`, and nothing reads\n * its output but the renderer: a resize re-runs this and leaves every data\n * stage alone. Handed the visible columns only, so the hidden ones take no\n * share of a fitted width.\n */\nfunction sizeColumns<Row, Node>(\n visibleColumns: readonly DataColumn<Row, Node>[],\n sizing: ColumnSizingState,\n sizes: Partial<ColumnSizeDefaults> | undefined,\n resizable: boolean | undefined,\n reorderable: boolean | undefined,\n groupByDraggable: boolean | undefined,\n resizeMode: ResizeMode,\n viewportWidth: number | null,\n): readonly ResolvedColumn<Row, Node>[] {\n const widths = resolveColumnWidths(\n visibleColumns.map((entry) => entry.column),\n sizing,\n { sizes, resizable, reorderable, groupByDraggable },\n );\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, sizes)\n : widths;\n}\n\n/**\n * The grand total: every aggregate over the whole filtered/sorted dataset,\n * ungrouped. Computed from `rows` directly rather than combined from any\n * group's result, for the same reason a nested group's own subtotal is: a\n * non-associative custom aggregate would be wrong if combined from parts.\n */\nfunction totalAggregates<Row>(\n rows: readonly ResolvedRow<Row>[],\n aggregates: AggregateState<Row>,\n dataColumns: readonly DataColumn<Row, unknown>[],\n): AggregateResults {\n return computeAggregates(\n rows.map((entry) => entry.row),\n aggregates,\n dataColumns,\n );\n}\n\n/**\n * Always last, after grouping and aggregation, so a page never splits a\n * group and a subtotal never changes value depending on which page is\n * showing. Unpaginated, the grid is a single page over every row, and\n * `pageCount`/`pageIndex` report that (`1`/`0`) rather than whatever a\n * stored `pagination` might still carry.\n */\nfunction paginate<Row>(\n displayRows: readonly DisplayRow<Row>[],\n paginated: boolean,\n pagination: PaginationState,\n): PaginatedRows<Row> {\n return paginated\n ? paginateRows(displayRows, pagination)\n : { rows: displayRows, pageCount: 1, pageIndex: 0 };\n}\n\n/**\n * `pageRows` narrowed back to its data rows, in the same (possibly\n * regrouped, possibly paginated) order — what a range selection anchors\n * against, so that a Shift-click spans the rows adjacent on screen rather\n * than their pre-grouping, pre-pagination order. A collapsed group, or a row\n * on another page, contributes nothing here, so a range spanning its\n * position includes only what was visible when it was drawn.\n *\n * `rows` itself when nothing could have reshaped it, sparing the filter pass\n * on the common ungrouped, unpaginated grid.\n */\nfunction narrowToDataRows<Row>(\n pageRows: readonly DisplayRow<Row>[],\n rows: readonly ResolvedRow<Row>[],\n reshaped: boolean,\n): readonly ResolvedRow<Row>[] {\n return reshaped\n ? pageRows.filter((entry): entry is ResolvedRow<Row> => !(\"kind\" in entry))\n : rows;\n}\n\n/**\n * `resolveGridView`, memoised per stage: each stage remembers its last\n * inputs and returns its last output when none of them changed identity, so\n * a call that changes one slice of state recomputes only what depends on\n * it. The data stages (filter → sort → group → aggregate → paginate) read\n * `dataColumns`, which carry no width, so a resize or a viewport change\n * leaves `rows`, `displayRows`, `pageRows`, `displayDataRows` and\n * `grandTotal` reference-equal to the previous call's — only `columns` is\n * new. The view object itself is reused when every field is unchanged, so a\n * snapshot-based renderer sees nothing to re-render.\n *\n * Hold one resolver per grid and call it with the current input every time\n * the view is needed; the memo only pays off across calls to the same one.\n */\nexport function createGridViewResolver<Row, Node = string>(): (\n input: GridViewInput<Row, Node>,\n) => GridView<Row, Node> {\n const identify = memoizeLast(identifyRows<Row>);\n const orderColumns = memoizeLast(resolveDataColumns<Row, Node>);\n const showColumns = memoizeLast(applyColumnVisibility<Row, Node>);\n const size = memoizeLast(sizeColumns<Row, Node>);\n const filterAndSort = memoizeLast(resolveShownRows<Row>);\n const group = memoizeLast(groupRows<Row>);\n const aggregate = memoizeLast(withGroupAggregates<Row>);\n const total = memoizeLast(totalAggregates<Row>);\n const page = memoizeLast(paginate<Row>);\n const narrow = memoizeLast(narrowToDataRows<Row>);\n const assemble = memoizeLast(\n (\n dataColumns: readonly DataColumn<Row, Node>[],\n columns: readonly ResolvedColumn<Row, Node>[],\n rows: readonly ResolvedRow<Row>[],\n displayRows: readonly DisplayRow<Row>[],\n pageRows: readonly DisplayRow<Row>[],\n displayDataRows: readonly ResolvedRow<Row>[],\n pageCount: number,\n pageIndex: number,\n grandTotal: AggregateResults,\n ): GridView<Row, Node> => ({\n dataColumns,\n columns,\n rows,\n displayRows,\n pageRows,\n displayDataRows,\n pageCount,\n pageIndex,\n grandTotal,\n }),\n );\n\n return ({ rows: data, getRowId, columns: definitions, state, options }) => {\n const paginated = options.paginated ?? false;\n const aggregates =\n options.aggregates ?? (NO_AGGREGATES as AggregateState<Row>);\n\n const dataColumns = orderColumns(definitions, state.columnOrder);\n // Hidden after ordering, so a hidden column keeps its slot in the order\n // and comes back to it when shown; the data stages below still read\n // every column, so a sort or filter on a hidden one still applies.\n const columns = size(\n showColumns(dataColumns, state.columnVisibility),\n state.columnSizing,\n options.columnSizeDefaults,\n options.resizableColumns,\n options.reorderableColumns,\n options.groupByDraggableColumns,\n options.resizeMode ?? \"fit\",\n options.viewportWidth ?? null,\n );\n\n const rows = filterAndSort(\n identify(data, getRowId),\n state.filter,\n state.columnSort,\n dataColumns,\n );\n // `groupRows` and `withGroupAggregates` each hand back their input\n // untouched when there is nothing to do, so an ungrouped grid without\n // aggregates pays only those checks.\n const displayRows = aggregate(\n group(rows, state.groupBy, state.groupExpansion, dataColumns),\n rows,\n state.groupBy,\n aggregates,\n dataColumns,\n options.groupAggregateDisplay ?? \"inline\",\n );\n const {\n rows: pageRows,\n pageCount,\n pageIndex,\n } = page(displayRows, paginated, state.pagination);\n\n return assemble(\n dataColumns,\n columns,\n rows,\n displayRows,\n pageRows,\n narrow(pageRows, rows, state.groupBy.length > 0 || paginated),\n pageCount,\n pageIndex,\n total(rows, aggregates, dataColumns),\n );\n };\n}\n\n/**\n * What the user is looking at, derived from the rows, the columns, the\n * grid's state and its options in one call: rows filtered → sorted →\n * grouped → aggregated → paginated, and columns ordered → hidden → sized.\n * The one function a renderer, an export or a toolbar calls instead of\n * composing the stages itself, so none of them can disagree about what is\n * shown.\n *\n * Unmemoised — a one-off resolver. A renderer that derives the view on every\n * change holds a `createGridViewResolver()` instead.\n */\nexport function resolveGridView<Row, Node = string>(\n input: GridViewInput<Row, Node>,\n): GridView<Row, Node> {\n return createGridViewResolver<Row, Node>()(input);\n}\n","import type {\n FilterEntry,\n FilterState,\n OperatorFilterEntry,\n PaginationState,\n SortDirection,\n} from \"../types\";\nimport { isScalarList } from \"../util/filterOperators\";\n\n/** A sort or group-by level: a column, and which way it orders. */\ninterface ColumnEntry {\n readonly columnId: string;\n readonly direction?: SortDirection | undefined;\n}\n\n/**\n * The column a whole-stack change is about: the first level whose column or\n * direction differs between the two stacks. `undefined` when they are the\n * same, which is how a setter knows it has nothing to do.\n *\n * A change event names one column because the change it was made for — a\n * header toggle, a drop — touched one. A setter can touch several, and the\n * first is the most useful one to name; the whole stack is in the event.\n */\nexport function changedEntryColumnId(\n previous: readonly ColumnEntry[],\n next: readonly ColumnEntry[],\n): string | undefined {\n const length = Math.max(previous.length, next.length);\n for (let index = 0; index < length; index++) {\n const before = previous[index];\n const after = next[index];\n if (\n before?.columnId !== after?.columnId ||\n before?.direction !== after?.direction\n ) {\n return (after ?? before)?.columnId;\n }\n }\n return undefined;\n}\n\n/**\n * The first id whose position differs between two orders — the column a\n * whole-order change names, for the reason `changedEntryColumnId` gives.\n */\nexport function changedId(\n previous: readonly string[],\n next: readonly string[],\n): string | undefined {\n const length = Math.max(previous.length, next.length);\n for (let index = 0; index < length; index++) {\n if (previous[index] !== next[index]) {\n return next[index] ?? previous[index];\n }\n }\n return undefined;\n}\n\n/**\n * Every key whose value differs between two keyed states — those `next`\n * sets first, in its order, then those only `previous` had.\n */\nexport function changedKeys(\n previous: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n): readonly string[] {\n const keys = new Set([...Object.keys(next), ...Object.keys(previous)]);\n return [...keys].filter((key) => previous[key] !== next[key]);\n}\n\n/** Whether two lists hold the same items in the same order. */\nexport function sameItems<Item>(\n previous: readonly Item[],\n next: readonly Item[],\n): boolean {\n return (\n previous.length === next.length &&\n previous.every((item, index) => item === next[index])\n );\n}\n\nexport function samePagination(\n previous: PaginationState,\n next: PaginationState,\n): boolean {\n return (\n previous.pageIndex === next.pageIndex && previous.pageSize === next.pageSize\n );\n}\n\nfunction sameValue(previous: unknown, next: unknown): boolean {\n return previous instanceof Date && next instanceof Date\n ? previous.getTime() === next.getTime()\n : previous === next;\n}\n\n/** Whether two operator operands hold the same scalars, a list item by item. */\nfunction sameOperand(\n previous: OperatorFilterEntry<unknown>[\"value\"],\n next: OperatorFilterEntry<unknown>[\"value\"],\n): boolean {\n if (isScalarList(previous) || isScalarList(next)) {\n return (\n isScalarList(previous) &&\n isScalarList(next) &&\n previous.length === next.length &&\n previous.every((scalar, index) => sameValue(scalar, next[index]))\n );\n }\n return sameValue(previous, next);\n}\n\nfunction sameEntry<Row>(\n previous: FilterEntry<Row>,\n next: FilterEntry<Row>,\n): boolean {\n if (\"combinator\" in previous || \"combinator\" in next) {\n return (\n \"combinator\" in previous &&\n \"combinator\" in next &&\n previous.combinator === next.combinator &&\n sameFilter(previous.entries, next.entries)\n );\n }\n if (previous.columnId !== next.columnId) {\n return false;\n }\n if (\"predicate\" in previous || \"predicate\" in next) {\n return (\n \"predicate\" in previous &&\n \"predicate\" in next &&\n previous.predicate === next.predicate\n );\n }\n // Before the `value` check: an operator entry usually has a `value` too.\n if (\"operator\" in previous || \"operator\" in next) {\n return (\n \"operator\" in previous &&\n \"operator\" in next &&\n previous.operator === next.operator &&\n sameOperand(previous.value, next.value)\n );\n }\n if (\"value\" in previous || \"value\" in next) {\n return (\n \"value\" in previous &&\n \"value\" in next &&\n sameValue(previous.value, next.value)\n );\n }\n return previous.query === next.query;\n}\n\n/**\n * Whether two filters match the same rows by construction: the same entries,\n * in the same order, each asking the same thing — a `Date` value compared by\n * time, a predicate by identity. A filter read back from JSON is equal to the\n * one that was saved, though not one entry is the same object.\n */\nexport function sameFilter<Row>(\n previous: FilterState<Row>,\n next: FilterState<Row>,\n): boolean {\n return (\n previous.length === next.length &&\n previous.every((entry, index) => {\n const other = next[index];\n return other !== undefined && sameEntry(entry, other);\n })\n );\n}\n","import type {\n CellSelectionMode,\n CellSelectionState,\n SelectedCellRef,\n SelectIntent,\n SelectionDiff,\n SelectionMode,\n SelectionState,\n} from \"../types\";\n\n/** Nothing changed, so nothing to report — shared to save an allocation. */\nconst NO_CHANGE: SelectionDiff = { added: [], removed: [] };\n\n/**\n * Whether two selections hold the same ids in the same order.\n *\n * Order counts because the selection's own order is what makes `at(-1)` the\n * most recently selected; a comparison that ignored it would have a transform\n * return the old reference after a reordering that a consumer can observe.\n */\nfunction sameSelection(a: SelectionState, b: SelectionState): boolean {\n return a.length === b.length && a.every((id, index) => id === b[index]);\n}\n\n/**\n * The selection with `id` added if absent and removed if present — a\n * Ctrl-click, or Space on the focused member.\n *\n * The mode is enforced here rather than by each caller, so `\"single\"` cannot\n * accumulate no matter which interaction reaches it. Returns `selection`\n * itself when `mode` is `false`, keeping the unchanged-reference contract\n * `moveColumnBefore` set: a caller treats an unchanged reference as \"nothing\n * happened\" and neither renders nor reports.\n */\nexport function toggleSelection(\n selection: SelectionState,\n id: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode === false) {\n return selection;\n }\n if (selection.includes(id)) {\n return selection.filter((selectedId) => selectedId !== id);\n }\n return mode === \"single\" ? [id] : [...selection, id];\n}\n\n/**\n * The selection reduced to `id` alone — a plain click, which discards what\n * came before rather than adding to it.\n *\n * Never deselects, so clicking the one selected row leaves it selected.\n * Letting go of it is Ctrl-click's job, and `toggleSelection`'s.\n */\nexport function selectOnly(\n selection: SelectionState,\n id: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode === false) {\n return selection;\n }\n return selection.length === 1 && selection[0] === id ? selection : [id];\n}\n\n/**\n * The selection replaced by every id from `anchorId` to `focusId` inclusive — a\n * Shift-click. The two may be given in either order.\n *\n * Spans `orderedIds`, the order as displayed, rather than the selection's own:\n * the range a user drew across the screen is the range they mean, whatever\n * order they clicked its ends in. Degrades to `selectOnly` under `\"single\"`,\n * where a range has nowhere to go.\n */\nexport function selectRange(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string,\n focusId: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode !== \"multiple\") {\n return selectOnly(selection, focusId, mode);\n }\n\n const anchor = orderedIds.indexOf(anchorId);\n const focus = orderedIds.indexOf(focusId);\n if (anchor === -1 || focus === -1) {\n return selection;\n }\n\n const next = orderedIds.slice(\n Math.min(anchor, focus),\n Math.max(anchor, focus) + 1,\n );\n return sameSelection(selection, next) ? selection : next;\n}\n\n/**\n * Every id in `orderedIds`, or `selection` untouched under any mode but\n * `\"multiple\"` — there is no selecting all of one thing.\n */\nexport function selectAll(\n selection: SelectionState,\n orderedIds: readonly string[],\n mode: SelectionMode,\n): SelectionState {\n if (mode !== \"multiple\") {\n return selection;\n }\n return sameSelection(selection, orderedIds) ? selection : orderedIds;\n}\n\nexport function clearSelection(selection: SelectionState): SelectionState {\n return selection.length === 0 ? selection : [];\n}\n\n/**\n * What one transition added and what it removed.\n *\n * Defined here rather than in an adapter so that every callback reporting a\n * selection change reads one answer, and a select and a deselect fired for the\n * same interaction cannot disagree about which it was.\n */\nexport function diffSelection(\n previous: SelectionState,\n next: SelectionState,\n): SelectionDiff {\n if (previous === next) {\n return NO_CHANGE;\n }\n\n const before = new Set(previous);\n const after = new Set(next);\n return {\n added: next.filter((id) => !before.has(id)),\n removed: previous.filter((id) => !after.has(id)),\n };\n}\n\nexport function isSameCell(\n a: CellSelectionState,\n b: CellSelectionState,\n): boolean {\n if (a === null || b === null) {\n return a === b;\n }\n return a.rowId === b.rowId && a.columnId === b.columnId;\n}\n\n/**\n * The cell selection moved to `cell` — a plain click. Idempotent: clicking the\n * selected cell again leaves it selected, matching `selectOnly`.\n */\nexport function selectCell(\n selection: CellSelectionState,\n cell: SelectedCellRef,\n mode: CellSelectionMode,\n): CellSelectionState {\n if (mode === false || isSameCell(selection, cell)) {\n return selection;\n }\n return cell;\n}\n\n/**\n * The cell selection moved to `cell`, or cleared when it is already there — a\n * Ctrl-click, matching `toggleSelection`.\n */\nexport function toggleCellSelection(\n selection: CellSelectionState,\n cell: SelectedCellRef,\n mode: CellSelectionMode,\n): CellSelectionState {\n if (mode === false) {\n return selection;\n }\n return isSameCell(selection, cell) ? null : cell;\n}\n\n/**\n * The intent a click or key press carries, by the modifiers held with it.\n *\n * `toggleOnClick` makes the unmodified press a toggle — the\n * `selectable.toggleOnClick` checklist behaviour — leaving Shift and Ctrl\n * to mean what they always do.\n */\nexport function intentOf(\n event: {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n },\n options?: { toggleOnClick?: boolean | undefined },\n): SelectIntent {\n if (event.shiftKey) {\n return \"range\";\n }\n // Cmd on a Mac is Ctrl everywhere else, and both mean the same thing here.\n if (event.ctrlKey || event.metaKey) {\n return \"toggle\";\n }\n return options?.toggleOnClick === true ? \"toggle\" : \"replace\";\n}\n\n/**\n * The transform an intent asks for. A function rather than a branch inside\n * each caller, so a row and a column cannot come to mean different things by\n * the same click.\n */\nexport function applySelectionIntent(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string | null,\n id: string,\n intent: SelectIntent,\n mode: SelectionMode,\n): SelectionState {\n switch (intent) {\n case \"toggle\":\n return toggleSelection(selection, id, mode);\n // A range with no anchor yet spans from the id to itself, which is the\n // plain click a first Shift-click may as well be.\n case \"range\":\n return selectRange(selection, orderedIds, anchorId ?? id, id, mode);\n default:\n return selectOnly(selection, id, mode);\n }\n}\n","import type { SelectionCallbacks } from \"../options\";\nimport type {\n CellSelectionState,\n ResolvedColumn,\n ResolvedRow,\n SelectionDiff,\n SelectionState,\n} from \"../types\";\nimport { resolveCell, resolveColumns, resolveRows } from \"../util/rows\";\nimport { diffSelection } from \"../util/selection\";\n\n/**\n * Fires every row selection callback for one change, from one diff of it, so\n * that no two can disagree about what the change did. Returns the diff by id,\n * which still counts ids no row on screen answers to — the resolved rows the\n * callbacks carry leave those out.\n */\nexport function reportRowSelection<Row, Node>(\n previous: SelectionState,\n next: SelectionState,\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n callbacks: SelectionCallbacks<Row, Node>,\n): SelectionDiff {\n const diff = diffSelection(previous, next);\n const added = resolveRows(rowsById, diff.added);\n const removed = resolveRows(rowsById, diff.removed);\n\n for (const row of added) {\n callbacks.onRowSelect?.({ row, selection: next });\n }\n if (added.length > 0) {\n callbacks.onRowsSelect?.({ rows: added, selection: next });\n }\n for (const row of removed) {\n callbacks.onRowDeselect?.({ row, selection: next });\n }\n if (removed.length > 0) {\n callbacks.onRowsDeselect?.({ rows: removed, selection: next });\n }\n callbacks.onRowSelectionChange?.({\n added,\n removed,\n selected: resolveRows(rowsById, next),\n selection: next,\n });\n return diff;\n}\n\n/** `reportRowSelection`, for the columns as rendered. */\nexport function reportColumnSelection<Row, Node>(\n previous: SelectionState,\n next: SelectionState,\n columns: readonly ResolvedColumn<Row, Node>[],\n callbacks: SelectionCallbacks<Row, Node>,\n): SelectionDiff {\n const diff = diffSelection(previous, next);\n const added = resolveColumns(columns, diff.added);\n const removed = resolveColumns(columns, diff.removed);\n\n for (const column of added) {\n callbacks.onColumnSelect?.({ column, selection: next });\n }\n if (added.length > 0) {\n callbacks.onColumnsSelect?.({ columns: added, selection: next });\n }\n for (const column of removed) {\n callbacks.onColumnDeselect?.({ column, selection: next });\n }\n if (removed.length > 0) {\n callbacks.onColumnsDeselect?.({ columns: removed, selection: next });\n }\n callbacks.onColumnSelectionChange?.({\n added,\n removed,\n selected: resolveColumns(columns, next),\n selection: next,\n });\n return diff;\n}\n\n/**\n * Fires the cell selection callbacks for one change. The cell left and the\n * cell arrived at are resolved together, so moving between two cells reports\n * the leaving and the arriving as one change.\n */\nexport function reportCellSelection<Row, Node>(\n previous: CellSelectionState,\n next: CellSelectionState,\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n columns: readonly ResolvedColumn<Row, Node>[],\n callbacks: SelectionCallbacks<Row, Node>,\n): void {\n const selected = resolveCell(rowsById, columns, next);\n const deselected = resolveCell(rowsById, columns, previous);\n\n if (deselected !== null) {\n callbacks.onCellDeselect?.({ cell: deselected, selection: next });\n }\n if (selected !== null) {\n callbacks.onCellSelect?.({ cell: selected, selection: next });\n }\n callbacks.onCellSelectionChange?.({\n selected,\n deselected,\n selection: next,\n });\n}\n","import type {\n CellSelectionState,\n GridState,\n GridView,\n ResolvedRow,\n SelectionState,\n} from \"../types\";\nimport { memoizeLast } from \"../util/memoize\";\nimport {\n applySelectionIntent,\n clearSelection,\n isSameCell,\n selectAll,\n selectCell,\n toggleCellSelection,\n toggleSelection,\n} from \"../util/selection\";\nimport { sameItems } from \"./changes\";\nimport type { GridController, GridControllerOptions } from \"./gridController\";\nimport {\n reportCellSelection,\n reportColumnSelection,\n reportRowSelection,\n} from \"./selectionEvents\";\n\n/** What the selection actions need of the controller they belong to. */\nexport interface SelectionContext<Row, Node> {\n readonly getState: () => GridState<Row>;\n readonly getOptions: () => GridControllerOptions<Row, Node>;\n readonly getView: () => GridView<Row, Node>;\n /** The controller's shared commit — see `createGridController`. */\n readonly commit: <K extends keyof GridState<Row>>(\n key: K,\n next: GridState<Row>[K],\n report: () => void,\n ) => void;\n}\n\ntype SelectionActions<Row, Node> = Pick<\n GridController<Row, Node>,\n | \"setRowSelection\"\n | \"selectRows\"\n | \"selectRow\"\n | \"selectAllRows\"\n | \"clearSelection\"\n | \"setColumnSelection\"\n | \"selectColumn\"\n | \"setCellSelection\"\n | \"selectCell\"\n>;\n\nfunction indexRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n): ReadonlyMap<string, ResolvedRow<Row>> {\n return new Map(rows.map((entry) => [entry.rowId, entry]));\n}\n\n/** `ids` without repeats, each where it first appears. */\nfunction distinct(ids: readonly string[]): readonly string[] {\n return [...new Set(ids)];\n}\n\n/**\n * The row, column and cell selection actions of one controller. Kept in a\n * module of their own as the largest group of actions, and the only one with\n * memory beyond the state: the anchor a range is measured from.\n *\n * Rows are resolved against the data rows on the current page and columns\n * against the columns as rendered — what the user can see and click — so a\n * range spans what is adjacent on screen.\n */\nexport function createSelectionActions<Row, Node>(\n grid: SelectionContext<Row, Node>,\n): SelectionActions<Row, Node> {\n /**\n * Where a range is measured from: the last row or column selected by\n * anything but a range, so that repeated Shift-clicks re-draw one span\n * instead of walking the anchor along with them.\n */\n let rowAnchor: string | null = null;\n let columnAnchor: string | null = null;\n const rowsById = memoizeLast(indexRows<Row>);\n\n function modes() {\n const selectable = grid.getOptions().selectable;\n return {\n rows: selectable?.rows ?? false,\n columns: selectable?.columns ?? false,\n cells: selectable?.cells ?? false,\n };\n }\n\n function rowIds(): readonly string[] {\n return grid.getView().displayDataRows.map((entry) => entry.rowId);\n }\n\n function columnIds(): readonly string[] {\n return grid.getView().columns.map((entry) => entry.id);\n }\n\n function commitRows(next: SelectionState): void {\n const previous = grid.getState().rowSelection;\n grid.commit(\"rowSelection\", next, () => {\n const options = grid.getOptions();\n const diff = reportRowSelection(\n previous,\n next,\n rowsById(grid.getView().displayDataRows),\n options,\n );\n options.onSelectionDiff?.({ target: \"rows\", ...diff, selection: next });\n });\n }\n\n function commitColumns(next: SelectionState): void {\n const previous = grid.getState().columnSelection;\n grid.commit(\"columnSelection\", next, () => {\n const options = grid.getOptions();\n const diff = reportColumnSelection(\n previous,\n next,\n grid.getView().columns,\n options,\n );\n options.onSelectionDiff?.({\n target: \"columns\",\n ...diff,\n selection: next,\n });\n });\n }\n\n function commitCell(next: CellSelectionState): void {\n const previous = grid.getState().cellSelection;\n grid.commit(\"cellSelection\", next, () => {\n const view = grid.getView();\n reportCellSelection(\n previous,\n next,\n rowsById(view.displayDataRows),\n view.columns,\n grid.getOptions(),\n );\n });\n }\n\n return {\n setRowSelection(selection) {\n if (!sameItems(grid.getState().rowSelection, selection)) {\n commitRows(selection);\n }\n },\n selectRows(ids, intent = \"replace\") {\n const mode = modes().rows;\n const current = grid.getState().rowSelection;\n if (mode === false || ids.length === 0) {\n return;\n }\n const next =\n intent === \"toggle\"\n ? ids.reduce(\n (selection, id) => toggleSelection(selection, id, mode),\n current,\n )\n : mode === \"single\"\n ? ids.slice(-1)\n : distinct(ids);\n rowAnchor = ids.at(-1) ?? null;\n if (!sameItems(current, next)) {\n commitRows(next);\n }\n },\n selectRow(rowId, intent) {\n const next = applySelectionIntent(\n grid.getState().rowSelection,\n rowIds(),\n rowAnchor,\n rowId,\n intent,\n modes().rows,\n );\n if (intent !== \"range\") {\n rowAnchor = rowId;\n }\n commitRows(next);\n },\n selectAllRows() {\n commitRows(\n selectAll(grid.getState().rowSelection, rowIds(), modes().rows),\n );\n },\n clearSelection() {\n commitRows(clearSelection(grid.getState().rowSelection));\n commitColumns(clearSelection(grid.getState().columnSelection));\n commitCell(null);\n },\n\n setColumnSelection(selection) {\n if (!sameItems(grid.getState().columnSelection, selection)) {\n commitColumns(selection);\n }\n },\n selectColumn(columnId, intent) {\n const next = applySelectionIntent(\n grid.getState().columnSelection,\n columnIds(),\n columnAnchor,\n columnId,\n intent,\n modes().columns,\n );\n if (intent !== \"range\") {\n columnAnchor = columnId;\n }\n commitColumns(next);\n },\n\n setCellSelection(selection) {\n if (!isSameCell(grid.getState().cellSelection, selection)) {\n commitCell(selection);\n }\n },\n selectCell(cell, intent) {\n const current = grid.getState().cellSelection;\n const mode = modes().cells;\n commitCell(\n intent === \"toggle\"\n ? toggleCellSelection(current, cell, mode)\n : selectCell(current, cell, mode),\n );\n },\n };\n}\n","import type { GridOptions } from \"../options\";\nimport type {\n ColumnDefinition,\n ColumnSizingState,\n ColumnVisibilityState,\n GridState,\n GridView,\n GroupByState,\n GroupExpansionState,\n PaginationState,\n} from \"../types\";\nimport { defineColumnsFromRows } from \"../util/grid\";\nimport {\n collapseAllGroups as collapsedGroups,\n expandAllGroups as expandedGroups,\n moveGroupByBefore,\n toggleGroupExpansion as toggledGroupExpansion,\n} from \"../util/grouping\";\nimport { memoizeLast } from \"../util/memoize\";\nimport { moveColumnBefore } from \"../util/ordering\";\nimport { paginateRows } from \"../util/paging\";\nimport { reportError } from \"../util/report\";\nimport { reviveFilter } from \"../util/serialize\";\nimport { resolveColumnWidths, revertColumnSize } from \"../util/sizing\";\nimport { toggleColumnSort as toggledColumnSort } from \"../util/sorting\";\nimport { createGridViewResolver } from \"../util/view\";\nimport { setColumnVisibility as withColumnVisibility } from \"../util/visibility\";\nimport {\n changedEntryColumnId,\n changedId,\n changedKeys,\n sameFilter,\n sameItems,\n samePagination,\n} from \"./changes\";\nimport type { GridController, GridControllerOptions } from \"./gridController\";\nimport { createSelectionActions } from \"./selectionActions\";\n\n/** `pagination.pageSize` an uncontrolled grid starts at when `defaultPagination` omits one — a reasonable default for an ERP-grade dataset. */\nconst DEFAULT_PAGE_SIZE = 25;\n\n/**\n * Stable empty fallbacks: a fresh `[]` per call would change identity each\n * time and defeat every view stage memoised on it.\n */\nconst NO_ROWS: readonly never[] = [];\nconst NO_COLUMNS: readonly never[] = [];\n\ntype SliceKey = keyof GridState<unknown>;\n\nconst SLICE_KEYS = [\n \"columnSizing\",\n \"columnOrder\",\n \"columnVisibility\",\n \"columnSort\",\n \"filter\",\n \"groupBy\",\n \"groupExpansion\",\n \"pagination\",\n \"rowSelection\",\n \"columnSelection\",\n \"cellSelection\",\n] as const satisfies readonly SliceKey[];\n\n/** The option that seeds each slice while it is uncontrolled. */\nconst DEFAULT_OPTION: { readonly [K in SliceKey]: `default${Capitalize<K>}` } =\n {\n columnSizing: \"defaultColumnSizing\",\n columnOrder: \"defaultColumnOrder\",\n columnVisibility: \"defaultColumnVisibility\",\n columnSort: \"defaultColumnSort\",\n filter: \"defaultFilter\",\n groupBy: \"defaultGroupBy\",\n groupExpansion: \"defaultGroupExpansion\",\n pagination: \"defaultPagination\",\n rowSelection: \"defaultRowSelection\",\n columnSelection: \"defaultColumnSelection\",\n cellSelection: \"defaultCellSelection\",\n };\n\n/** The slices the controller keeps itself — those not controlled. */\ntype OwnState<Row> = { -readonly [K in SliceKey]: GridState<Row>[K] };\n\n/** The options read as controlled values: a slice given here is the caller's. */\ntype ControlledState<Row> = {\n readonly [K in SliceKey]?: GridState<Row>[K] | undefined;\n};\n\n/** The slices a filter, sort or grouping change sends back to the first page. */\ntype PagingInputs<Row> = Pick<\n GridState<Row>,\n \"filter\" | \"columnSort\" | \"groupBy\"\n>;\n\nfunction startingState<Row>(options: GridOptions<Row>): OwnState<Row> {\n return {\n columnSizing: options.defaultColumnSizing ?? {},\n columnOrder: options.defaultColumnOrder ?? [],\n columnVisibility: options.defaultColumnVisibility ?? {},\n columnSort: options.defaultColumnSort ?? [],\n filter: options.defaultFilter ?? [],\n groupBy: options.defaultGroupBy ?? [],\n groupExpansion: options.defaultGroupExpansion ?? [],\n pagination: options.defaultPagination ?? {\n pageIndex: 0,\n pageSize: DEFAULT_PAGE_SIZE,\n },\n rowSelection: options.defaultRowSelection ?? [],\n columnSelection: options.defaultColumnSelection ?? [],\n cellSelection: options.defaultCellSelection ?? null,\n };\n}\n\n/**\n * The columns the grid shows: the caller's, or — when it gives none — one per\n * field of the rows, re-inferred only when the rows change.\n */\nfunction definedColumns<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[] | undefined,\n rows: readonly Row[] | undefined,\n): readonly ColumnDefinition<Row, Node>[] {\n if (columns !== undefined && columns.length > 0) {\n return columns;\n }\n if (rows !== undefined && rows.length > 0) {\n return defineColumnsFromRows<Row, Node>(rows);\n }\n return NO_COLUMNS;\n}\n\nfunction pagingInputsOf<Row>(state: GridState<Row>): PagingInputs<Row> {\n return {\n filter: state.filter,\n columnSort: state.columnSort,\n groupBy: state.groupBy,\n };\n}\n\n/**\n * Creates the state container for one grid — see `GridController`. Hold one\n * per grid for its whole life: it keeps the uncontrolled slices, and its view\n * is memoised across calls the way `createGridViewResolver`'s is.\n */\nexport function createGridController<Row, Node = string>(\n initial: GridControllerOptions<Row, Node>,\n): GridController<Row, Node> {\n let options = initial;\n const own = startingState(initial);\n const resolveView = createGridViewResolver<Row, Node>();\n const resolveColumns = memoizeLast(definedColumns<Row, Node>);\n const listeners = new Set<() => void>();\n /** Slices already reported as given both ways, so each is reported once. */\n const reportedConflicts = new Set<SliceKey>();\n /**\n * While `restoreState` applies its slices, the callbacks they would fire,\n * held back until every slice is in place.\n */\n let heldReports: (() => void)[] | undefined;\n\n let state = resolveSlices();\n let pagingInputs = pagingInputsOf(state);\n reportConflicts();\n\n function controlledValue<K extends SliceKey>(\n key: K,\n ): GridState<Row>[K] | undefined {\n const controlled: ControlledState<Row> = options;\n return controlled[key];\n }\n\n function isControlled(key: SliceKey): boolean {\n return controlledValue(key) !== undefined;\n }\n\n function resolveSlice<K extends SliceKey>(key: K): GridState<Row>[K] {\n const controlled = controlledValue(key);\n return controlled === undefined ? own[key] : controlled;\n }\n\n function resolveSlices(): GridState<Row> {\n return {\n columnSizing: resolveSlice(\"columnSizing\"),\n columnOrder: resolveSlice(\"columnOrder\"),\n columnVisibility: resolveSlice(\"columnVisibility\"),\n columnSort: resolveSlice(\"columnSort\"),\n filter: resolveSlice(\"filter\"),\n groupBy: resolveSlice(\"groupBy\"),\n groupExpansion: resolveSlice(\"groupExpansion\"),\n pagination: resolveSlice(\"pagination\"),\n rowSelection: resolveSlice(\"rowSelection\"),\n columnSelection: resolveSlice(\"columnSelection\"),\n cellSelection: resolveSlice(\"cellSelection\"),\n };\n }\n\n /**\n * A controlled value and its default together is a contradiction React's\n * own inputs report the same way: the controlled value wins, and the\n * default is never read.\n */\n function reportConflicts(): void {\n for (const key of SLICE_KEYS) {\n const defaultKey = DEFAULT_OPTION[key];\n if (\n reportedConflicts.has(key) ||\n !isControlled(key) ||\n options[defaultKey] === undefined\n ) {\n continue;\n }\n reportedConflicts.add(key);\n reportError(\n `\\`${key}\\` and \\`${defaultKey}\\` are both set — \\`${key}\\` is controlled, so \\`${defaultKey}\\` is ignored.`,\n );\n }\n }\n\n /**\n * Re-resolves every slice after a change, keeping the previous state object\n * when none differs, so a snapshot read twice is the same object.\n *\n * Applies the one rule linking slices: a user on page 7 of a result that\n * filtering, sorting or regrouping just shrank to 2 pages must not be left\n * on an empty page, so a change to any of the three sends an uncontrolled\n * pagination back to the first page. It is a consequence of that change,\n * not a page change of its own, so it reports nothing — the change that\n * caused it already did. A controlled pagination is the caller's to reset.\n */\n function refresh(): void {\n let next = resolveSlices();\n if (\n next.filter !== pagingInputs.filter ||\n next.columnSort !== pagingInputs.columnSort ||\n next.groupBy !== pagingInputs.groupBy\n ) {\n pagingInputs = pagingInputsOf(next);\n if (!isControlled(\"pagination\") && own.pagination.pageIndex !== 0) {\n own.pagination = { ...own.pagination, pageIndex: 0 };\n next = { ...next, pagination: own.pagination };\n }\n }\n state = SLICE_KEYS.every((key) => next[key] === state[key]) ? state : next;\n }\n\n function notify(): void {\n for (const listener of [...listeners]) {\n listener();\n }\n }\n\n /**\n * The shared tail of every action — see `GridController`. `report` fires\n * the slice's callback; it runs after the value is kept, so a callback\n * reading `getState()` or calling another action sees the change.\n */\n function commit<K extends SliceKey>(\n key: K,\n next: GridState<Row>[K],\n report: () => void,\n ): void {\n if (next === state[key]) {\n return;\n }\n if (!isControlled(key)) {\n own[key] = next;\n }\n if (heldReports !== undefined) {\n heldReports.push(report);\n return;\n }\n refresh();\n report();\n notify();\n }\n\n function getView(): GridView<Row, Node> {\n return resolveView({\n rows: options.dataSource ?? NO_ROWS,\n getRowId: options.getRowId,\n columns: resolveColumns(options.columns, options.dataSource),\n state,\n options: {\n paginated: options.paginated,\n aggregates: options.aggregates,\n groupAggregateDisplay: options.groupAggregateDisplay,\n columnSizeDefaults: options.columnSizeDefaults,\n resizableColumns: options.resizableColumns,\n reorderableColumns: options.reorderableColumns,\n groupByDraggableColumns: options.groupByDraggableColumns,\n resizeMode: options.resizeMode,\n viewportWidth: options.viewportWidth,\n },\n });\n }\n\n function commitColumnSizing(\n next: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n commit(\"columnSizing\", next, () => {\n options.onColumnResize?.({ columnId, width, sizing: next, phase });\n });\n }\n\n /**\n * The width a column's definition gives it, before any user resize or fit\n * — what a column reverts to when its sizing entry goes.\n */\n function definedWidth(columnId: string): number {\n const entry = getView().dataColumns.find(\n (candidate) => candidate.id === columnId,\n );\n const [resolved] =\n entry === undefined\n ? []\n : resolveColumnWidths(\n [entry.column],\n {},\n {\n sizes: options.columnSizeDefaults,\n },\n );\n return resolved?.width ?? 0;\n }\n\n /**\n * Reported once per change, naming every column it touched in the order\n * they are shown, whatever order the caller named them in — and ids naming\n * no column last.\n */\n function commitColumnVisibility(next: ColumnVisibilityState): void {\n const previous = state.columnVisibility;\n commit(\"columnVisibility\", next, () => {\n const changed = new Set(changedKeys(previous, next));\n const shown = getView()\n .dataColumns.map((entry) => entry.id)\n .filter((id) => changed.delete(id));\n options.onColumnVisibilityChange?.({\n columnIds: [...shown, ...changed],\n visibility: next,\n });\n });\n }\n\n function changeColumnVisibility(\n columnIds: readonly string[],\n visible: boolean,\n ): void {\n commitColumnVisibility(\n withColumnVisibility(\n getView().dataColumns,\n state.columnVisibility,\n columnIds,\n visible,\n ),\n );\n }\n\n function commitGroupBy(next: GroupByState, columnId: string): void {\n commit(\"groupBy\", next, () => {\n options.onGroupByChange?.({ columnId, groupBy: next });\n });\n }\n\n function commitGroupExpansion(\n next: GroupExpansionState,\n groupId: string | null,\n ): void {\n commit(\"groupExpansion\", next, () => {\n options.onGroupExpansionChange?.({ groupId, expansion: next });\n });\n }\n\n /**\n * The page count reported is over every display row whether or not the\n * grid is paginated, which is what a pager built on the event shows. A\n * pagination equal to the current one — `nextPage` on the last page,\n * `goToPage` to the page shown — reports nothing.\n */\n function commitPagination(next: PaginationState): void {\n if (samePagination(state.pagination, next)) {\n return;\n }\n commit(\"pagination\", next, () => {\n options.onPaginationChange?.({\n pagination: next,\n pageCount: paginateRows(getView().displayRows, next).pageCount,\n });\n });\n }\n\n /**\n * `pageIndex` clamped into the pages that exist, by `paginateRows` itself\n * rather than by hand, so it can never disagree with the page the view\n * shows.\n */\n function goToPage(pageIndex: number): void {\n const current = state.pagination;\n const clamped = paginateRows(getView().displayRows, {\n ...current,\n pageIndex,\n }).pageIndex;\n commitPagination({ ...current, pageIndex: clamped });\n }\n\n /** The page shown, which may sit below a stored index past the last page. */\n function shownPageIndex(): number {\n return paginateRows(getView().displayRows, state.pagination).pageIndex;\n }\n\n const selection = createSelectionActions<Row, Node>({\n getState: () => state,\n getOptions: () => options,\n getView,\n commit,\n });\n\n const controller: GridController<Row, Node> = {\n ...selection,\n getOptions: () => options,\n setOptions(next) {\n options = next;\n reportConflicts();\n refresh();\n },\n getState: () => state,\n getView,\n restoreState(saved) {\n const reports: (() => void)[] = [];\n heldReports = reports;\n try {\n restoreSlices(saved);\n } finally {\n heldReports = undefined;\n }\n if (saved.pagination !== undefined) {\n // Taken as already seen, so the sort, filter or grouping this same\n // call restored does not send the restored page back to the first.\n pagingInputs = pagingInputsOf(resolveSlices());\n }\n refresh();\n for (const report of reports) {\n report();\n }\n if (reports.length > 0) {\n notify();\n }\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n\n setColumnSizing(sizing) {\n const [columnId] = changedKeys(state.columnSizing, sizing);\n if (columnId !== undefined) {\n commitColumnSizing(\n sizing,\n columnId,\n sizing[columnId] ?? definedWidth(columnId),\n \"end\",\n );\n }\n },\n resizeColumn(columnId, width, phase) {\n commitColumnSizing(\n { ...state.columnSizing, [columnId]: width },\n columnId,\n width,\n phase,\n );\n },\n cancelColumnResize(columnId, startSizing, startWidth) {\n commitColumnSizing(\n revertColumnSize(state.columnSizing, startSizing, columnId),\n columnId,\n startWidth,\n \"end\",\n );\n },\n\n setColumnOrder(order) {\n const columnId = changedId(state.columnOrder, order);\n if (columnId === undefined) {\n return;\n }\n commit(\"columnOrder\", order, () => {\n options.onColumnOrderChange?.({ columnId, order });\n });\n },\n /**\n * Applied to every id in display order rather than to the stored order,\n * which starts empty and may name only some columns, so would have\n * nothing to rearrange.\n */\n moveColumn(columnId, beforeId) {\n const orderedIds = getView().dataColumns.map((entry) => entry.id);\n const next = moveColumnBefore(orderedIds, columnId, beforeId);\n if (next === orderedIds) {\n return;\n }\n commit(\"columnOrder\", next, () => {\n options.onColumnOrderChange?.({ columnId, order: next });\n });\n },\n\n setColumnVisibility(visibility) {\n if (changedKeys(state.columnVisibility, visibility).length > 0) {\n commitColumnVisibility(visibility);\n }\n },\n showColumns(columnIds) {\n changeColumnVisibility(columnIds, true);\n },\n hideColumns(columnIds) {\n changeColumnVisibility(columnIds, false);\n },\n\n setFilter(filter) {\n if (sameFilter(state.filter, filter)) {\n return;\n }\n commit(\"filter\", filter, () => {\n options.onFilterChange?.({ filter });\n });\n },\n\n setColumnSort(sort) {\n const columnId = changedEntryColumnId(state.columnSort, sort);\n if (columnId === undefined) {\n return;\n }\n commit(\"columnSort\", sort, () => {\n options.onColumnSortChange?.({ columnId, sort });\n });\n },\n toggleColumnSort(columnId, { stack = false } = {}) {\n const next = toggledColumnSort(state.columnSort, columnId, { stack });\n commit(\"columnSort\", next, () => {\n options.onColumnSortChange?.({ columnId, sort: next });\n });\n },\n clearColumnSort(columnId) {\n const next = state.columnSort.filter(\n (entry) => entry.columnId !== columnId,\n );\n if (next.length === state.columnSort.length) {\n return;\n }\n commit(\"columnSort\", next, () => {\n options.onColumnSortChange?.({ columnId, sort: next });\n });\n },\n\n setGroupBy(groupBy) {\n const columnId = changedEntryColumnId(state.groupBy, groupBy);\n if (columnId !== undefined) {\n commitGroupBy(groupBy, columnId);\n }\n },\n toggleGroupBy(columnId) {\n const grouped = state.groupBy.some(\n (entry) => entry.columnId === columnId,\n );\n commitGroupBy(\n grouped\n ? state.groupBy.filter((entry) => entry.columnId !== columnId)\n : [...state.groupBy, { columnId }],\n columnId,\n );\n },\n moveGroupBy(columnId, beforeColumnId) {\n commitGroupBy(\n moveGroupByBefore(state.groupBy, columnId, beforeColumnId),\n columnId,\n );\n },\n\n setGroupExpansion(expansion) {\n if (!sameItems(state.groupExpansion, expansion)) {\n commitGroupExpansion(expansion, null);\n }\n },\n toggleGroupExpansion(groupId) {\n commitGroupExpansion(\n toggledGroupExpansion(state.groupExpansion, groupId),\n groupId,\n );\n },\n expandAllGroups() {\n commitGroupExpansion(expandedGroups(state.groupExpansion), null);\n },\n collapseAllGroups() {\n commitGroupExpansion(collapsedGroups(getView().displayRows), null);\n },\n\n setPagination: commitPagination,\n goToPage,\n nextPage() {\n goToPage(shownPageIndex() + 1);\n },\n previousPage() {\n goToPage(shownPageIndex() - 1);\n },\n setPageSize(pageSize) {\n const first = { pageIndex: 0, pageSize };\n commitPagination({\n ...first,\n pageIndex: paginateRows(getView().displayRows, first).pageIndex,\n });\n },\n };\n\n /** Each slice `saved` holds, through the action that sets it. */\n function restoreSlices(\n saved: Parameters<GridController<Row, Node>[\"restoreState\"]>[0],\n ): void {\n if (saved.columnSizing !== undefined) {\n controller.setColumnSizing(saved.columnSizing);\n }\n if (saved.columnOrder !== undefined) {\n controller.setColumnOrder(saved.columnOrder);\n }\n if (saved.columnVisibility !== undefined) {\n controller.setColumnVisibility(saved.columnVisibility);\n }\n if (saved.columnSort !== undefined) {\n controller.setColumnSort(saved.columnSort);\n }\n if (saved.filter !== undefined) {\n controller.setFilter(reviveFilter(saved.filter, getView().dataColumns));\n }\n if (saved.groupBy !== undefined) {\n controller.setGroupBy(saved.groupBy);\n }\n if (saved.groupExpansion !== undefined) {\n controller.setGroupExpansion(saved.groupExpansion);\n }\n if (saved.pagination !== undefined) {\n controller.setPagination(saved.pagination);\n }\n if (saved.rowSelection !== undefined) {\n controller.setRowSelection(saved.rowSelection);\n }\n if (saved.columnSelection !== undefined) {\n controller.setColumnSelection(saved.columnSelection);\n }\n if (saved.cellSelection !== undefined) {\n controller.setCellSelection(saved.cellSelection);\n }\n }\n\n return controller;\n}\n","import type { GridController } from \"../controller/gridController\";\nimport type { GridMessages } from \"../messages\";\nimport type { ResolvedRow, SelectionState } from \"../types\";\nimport type {\n GridCommandContext,\n GridCommandHost,\n GridCommandTarget,\n} from \"./types\";\n\n/** What `createCommandContext` builds a context from. */\nexport interface GridCommandContextInput<Row, Node> {\n readonly controller: GridController<Row, Node>;\n readonly target: GridCommandTarget;\n /** The grid's messages, already laid over the defaults — see `resolveMessages`. */\n readonly messages: GridMessages;\n readonly host: GridCommandHost;\n}\n\n/**\n * The rows in `rows` that `selection` names, in `rows`' order. An empty\n * selection — the common case — is answered without walking the rows.\n */\nfunction selectedRowsOf<Row>(\n rows: readonly ResolvedRow<Row>[],\n selection: SelectionState,\n): readonly ResolvedRow<Row>[] {\n if (selection.length === 0) {\n return [];\n }\n const selected = new Set(selection);\n return rows.filter((entry) => selected.has(entry.rowId));\n}\n\n/**\n * A command context for `target`, over the controller's state, view and\n * options as they are now. The controller itself serves as `actions`, typed\n * down to them, so a command cannot reach `setOptions`.\n *\n * `row` and `column` are looked up once here, against every filtered row and\n * every column, hidden ones included, so a target the API names off screen\n * still resolves.\n */\nexport function createCommandContext<Row, Node>({\n controller,\n target,\n messages,\n host,\n}: GridCommandContextInput<Row, Node>): GridCommandContext<Row> {\n const state = controller.getState();\n const view = controller.getView();\n let selectedRows: readonly ResolvedRow<Row>[] | undefined;\n\n return {\n target,\n state,\n view,\n options: controller.getOptions(),\n messages,\n actions: controller,\n host,\n row:\n target.area === \"cell\"\n ? (view.rows.find((entry) => entry.rowId === target.rowId) ?? null)\n : null,\n column:\n \"columnId\" in target\n ? (view.dataColumns.find((entry) => entry.id === target.columnId) ??\n null)\n : null,\n selectedRows: () =>\n (selectedRows ??= selectedRowsOf(view.rows, state.rowSelection)),\n };\n}\n","import type { GridMessages } from \"../messages\";\nimport type { AggregateSpec, ColumnDefinition, ColumnType } from \"../types\";\n\n/** The locale(s) values are formatted for — `undefined` is the runtime's own. */\nexport type FormatLocale = string | readonly string[] | undefined;\n\ntype FormatOptions = Intl.NumberFormatOptions | Intl.DateTimeFormatOptions;\n\n/**\n * The fields `Date.prototype.toLocaleString` and its date-/time-only\n * siblings print, so a column given a `locale` but no `format` reads as\n * those would in that locale. `Intl.DateTimeFormat` with no fields at all\n * prints the date alone, which suits `\"date\"` but would drop the time from a\n * date-and-time column.\n */\nconst DATE_FIELDS: Intl.DateTimeFormatOptions = {\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n};\nconst TIME_FIELDS: Intl.DateTimeFormatOptions = {\n hour: \"numeric\",\n minute: \"numeric\",\n second: \"numeric\",\n};\nconst DATE_TIME_FIELDS: Intl.DateTimeFormatOptions = {\n ...DATE_FIELDS,\n ...TIME_FIELDS,\n};\n\n/** Without a `format.currency` there is no symbol to show, only the digits a price has. */\nconst CURRENCY_DIGITS: Intl.NumberFormatOptions = {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n};\n\n/** Stands in for an absent `format` as a `WeakMap` key. */\nconst NO_FORMAT: FormatOptions = {};\n\n/**\n * Formatters already built, keyed first by the column's `format` object and\n * then by type and locale. Building an `Intl` formatter costs far more than\n * using one, and a grid formats every visible cell on every render, so each\n * distinct (type, locale, format) gets one formatter for the life of the\n * page. Weakly keyed on `format` so that a column definition thrown away\n * takes its formatters with it.\n */\nconst formatters = new WeakMap<\n FormatOptions,\n Map<string, Intl.NumberFormat | Intl.DateTimeFormat>\n>();\n\nfunction cached<Formatter extends Intl.NumberFormat | Intl.DateTimeFormat>(\n format: FormatOptions | undefined,\n key: string,\n create: () => Formatter,\n): Formatter {\n const owner = format ?? NO_FORMAT;\n let byKey = formatters.get(owner);\n if (byKey === undefined) {\n byKey = new Map();\n formatters.set(owner, byKey);\n }\n const existing = byKey.get(key);\n if (existing !== undefined) {\n // Each key is only ever filled by the `create` of the same kind.\n return existing as Formatter;\n }\n const formatter = create();\n byKey.set(key, formatter);\n return formatter;\n}\n\nfunction localeKey(locale: FormatLocale): string {\n return typeof locale === \"string\" ? locale : (locale?.join(\",\") ?? \"\");\n}\n\nfunction isNumericType(type: ColumnType | undefined): boolean {\n return (\n type === \"number\" ||\n type === \"decimal\" ||\n type === \"currency\" ||\n type === \"percent\"\n );\n}\n\n/**\n * The options a numeric `type` starts from, with the column's own `format`\n * laid over them — so `{ maximumFractionDigits: 0 }` on a currency column\n * keeps the currency style and changes only the digits.\n */\nfunction numberOptions(\n type: ColumnType | undefined,\n format: Intl.NumberFormatOptions | undefined,\n): Intl.NumberFormatOptions {\n switch (type) {\n case \"currency\":\n return format?.currency === undefined\n ? { ...CURRENCY_DIGITS, ...format }\n : { style: \"currency\", ...format };\n case \"percent\":\n // Intl's own reading: `0.25` is a quarter, shown as \"25%\".\n return { style: \"percent\", ...format };\n default:\n return format ?? {};\n }\n}\n\n/**\n * The fields a date `type` prints. A column's own `format` replaces them\n * rather than merging in: `dateStyle`/`timeStyle` refuse to be combined with\n * individual fields, and a format naming only a month means only a month.\n */\nfunction dateOptions(\n type: ColumnType | undefined,\n format: Intl.DateTimeFormatOptions | undefined,\n): Intl.DateTimeFormatOptions {\n if (format !== undefined) {\n return format;\n }\n if (type === \"date\") return DATE_FIELDS;\n if (type === \"time\") return TIME_FIELDS;\n return DATE_TIME_FIELDS;\n}\n\nfunction formatNumber(\n value: number | bigint,\n type: ColumnType | undefined,\n format: FormatOptions | undefined,\n locale: FormatLocale,\n): string {\n const formatter = cached(\n format,\n `number|${type ?? \"\"}|${localeKey(locale)}`,\n () =>\n new Intl.NumberFormat(\n locale,\n numberOptions(type, format as Intl.NumberFormatOptions | undefined),\n ),\n );\n return formatter.format(value);\n}\n\nfunction formatDate(\n value: Date,\n type: ColumnType | undefined,\n format: FormatOptions | undefined,\n locale: FormatLocale,\n): string {\n // `Intl.DateTimeFormat` throws on an invalid date rather than printing one.\n if (Number.isNaN(value.getTime())) {\n return String(value);\n }\n const formatter = cached(\n format,\n `date|${type ?? \"\"}|${localeKey(locale)}`,\n () =>\n new Intl.DateTimeFormat(\n locale,\n dateOptions(type, format as Intl.DateTimeFormatOptions | undefined),\n ),\n );\n return formatter.format(value);\n}\n\n/**\n * Anything without a reading of its own. A plain object or an array is\n * written out as JSON, since `String` would make every one of them\n * `\"[object Object]\"`. One JSON cannot write — a cycle, a `bigint` inside\n * — is left at that `\"[object Object]\"` after all. A function is named\n * rather than printed, since `String` would print its source.\n */\nfunction formatOther(value: unknown): string {\n if (typeof value === \"function\") {\n return \"(function)\";\n }\n if (typeof value === \"object\" && value !== null) {\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n }\n return String(value);\n}\n\n/**\n * The text a value reads as in `column` — what a cell shows when the column\n * has no `cellTemplate`, and what an export or a print writes, so the two\n * cannot disagree.\n *\n * A `valueFormatter` decides outright. `null`/`undefined` read `\"\"`, a\n * boolean `\"true\"`/`\"false\"` — or `messages.booleanTrue`/`booleanFalse`\n * when given, for a grid speaking another language — a string as it is, a\n * plain object or array as JSON.\n *\n * Dates and numbers are formatted through `Intl` only once asked to — the\n * column has a `format`, or a `locale` is given. Until then they print as a\n * grid always printed them, so adopting this changes nothing on screen: a\n * `Date` through `toLocaleString()`, a number as-is (`1234.5`, never\n * `1,234.5`). Once asked:\n *\n * - A `Date` → `Intl.DateTimeFormat`: the date alone under `\"date\"`, the time\n * alone under `\"time\"`, both otherwise.\n * - A number under a numeric `type` → `Intl.NumberFormat`: `\"currency\"` with\n * a currency symbol once `format.currency` names one (two fraction digits\n * until then), `\"percent\"` reading `0.25` as 25 %. Under any other type it\n * is still printed as-is, the way a number id should be.\n *\n * `format` and `locale` go to the `Intl` constructor unchanged, so any\n * option it accepts is honoured.\n */\nexport function formatCellValue<Row>(\n value: unknown,\n column: ColumnDefinition<Row, unknown>,\n locale?: FormatLocale,\n row?: Row,\n messages?: Pick<GridMessages, \"booleanTrue\" | \"booleanFalse\">,\n): string {\n if (column.valueFormatter !== undefined) {\n return column.valueFormatter(value, row);\n }\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"boolean\" && messages !== undefined) {\n return value ? messages.booleanTrue : messages.booleanFalse;\n }\n const { type, format } = column;\n const formatted = format !== undefined || locale !== undefined;\n if (value instanceof Date) {\n return formatted\n ? formatDate(value, type, format, locale)\n : value.toLocaleString();\n }\n if (\n formatted &&\n (typeof value === \"number\" || typeof value === \"bigint\") &&\n isNumericType(type)\n ) {\n return formatNumber(value, type, format, locale);\n }\n if (typeof value === \"string\") {\n return value;\n }\n return formatOther(value);\n}\n\n/**\n * Whose rules an aggregate result formats by: the column's, unless the\n * result is plainly not one of the column's values. A `count` or\n * `countDistinct` is a number of rows — a count of a currency column is 12,\n * not $12.00 — and a number reduced from a column whose `type` is not\n * numeric (the sum of a column left untyped) is still a number to read as\n * one, unless the column's own `valueFormatter` claims it.\n */\nfunction aggregateFormatColumn<Row>(\n value: unknown,\n spec: AggregateSpec<Row>,\n column: ColumnDefinition<Row, unknown> | undefined,\n): ColumnDefinition<Row, unknown> {\n const plain: ColumnDefinition<Row, unknown> = {\n field: spec.columnId,\n type: \"number\",\n };\n if (\n column === undefined ||\n spec.fn === \"count\" ||\n spec.fn === \"countDistinct\"\n ) {\n return plain;\n }\n const numeric = typeof value === \"number\" || typeof value === \"bigint\";\n return column.valueFormatter === undefined &&\n numeric &&\n !isNumericType(column.type)\n ? plain\n : column;\n}\n\n/**\n * The text an aggregate result reads as — a footer cell, a group's subtotal\n * — through `formatCellValue`, so once a `format` or `locale` asks for it a\n * `sum` of a currency column reads as currency and a `max` of a date column\n * as a date. `column` is `undefined` for a spec naming a column the grid\n * does not have, which then formats by its value alone.\n *\n * Until then a numeric result reads through `toLocaleString()`, with digit\n * grouping, where a cell prints its number as-is: that is how a grid has\n * always shown its totals, and a sum easily runs into the thousands.\n */\nexport function formatAggregateValue<Row>(\n value: unknown,\n spec: AggregateSpec<Row>,\n column: ColumnDefinition<Row, unknown> | undefined,\n locale?: FormatLocale,\n): string {\n const target = aggregateFormatColumn(value, spec, column);\n if (\n typeof value === \"number\" &&\n target.valueFormatter === undefined &&\n target.format === undefined &&\n locale === undefined\n ) {\n return value.toLocaleString();\n }\n return formatCellValue(value, target, locale);\n}\n\n/**\n * The text a group's own value reads as — a group header's name, and the\n * label an export writes for it: as the grouped column's cells read it,\n * except that a missing value reads `messages.blankGroupValue` (\"(blank)\"),\n * since an empty label would leave the group looking unnamed rather than\n * named \"nothing\".\n */\nexport function formatGroupValue<Row>(\n value: unknown,\n column: ColumnDefinition<Row, unknown>,\n locale: FormatLocale,\n messages: Pick<\n GridMessages,\n \"booleanTrue\" | \"booleanFalse\" | \"blankGroupValue\"\n >,\n): string {\n return value === null || value === undefined\n ? messages.blankGroupValue\n : formatCellValue(value, column, locale, undefined, messages);\n}\n","import type { GridMessages } from \"../messages\";\nimport type {\n AggregateResults,\n AggregateSpec,\n AggregateState,\n ColumnDefinition,\n ColumnSizeDefaults,\n DataColumn,\n DisplayRow,\n GridState,\n GridView,\n GroupAggregateDisplay,\n ResolvedGroupRow,\n ResolvedRow,\n} from \"../types\";\nimport { computeAggregates, withGroupAggregates } from \"../util/aggregation\";\nimport {\n formatAggregateValue,\n formatCellValue,\n formatGroupValue,\n type FormatLocale,\n} from \"../util/format\";\nimport { accessDotted, resolveColumnHeaderText } from \"../util/grid\";\nimport { groupRows } from \"../util/grouping\";\nimport { resolveColumnWidths } from \"../util/sizing\";\nimport type {\n ExportCell,\n ExportColumn,\n ExportOptions,\n ExportRow,\n ExportScalar,\n ExportTable,\n ExportTotalRow,\n} from \"./types\";\n\n/**\n * What an export is built from: the grid's view and state as a controller\n * holds them, never the page — so rows virtualised, paged or scrolled out of\n * sight still export. Typed as the few fields it reads, so a\n * `GridCommandContext` is one as it stands.\n */\nexport interface ExportSource<Row> {\n readonly view: GridView<Row, unknown>;\n readonly state: Pick<\n GridState<Row>,\n \"groupBy\" | \"rowSelection\" | \"columnSizing\"\n >;\n readonly options: {\n readonly locale?: FormatLocale;\n readonly aggregates?: AggregateState<Row> | undefined;\n readonly groupAggregateDisplay?: GroupAggregateDisplay | undefined;\n readonly columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;\n };\n readonly messages: Pick<\n GridMessages,\n \"booleanTrue\" | \"booleanFalse\" | \"blankGroupValue\"\n >;\n}\n\n/** Everything turning one row into cells reads, settled once per export. */\ninterface CellContext<Row> {\n readonly columns: readonly DataColumn<Row, unknown>[];\n /** Each column's aggregate specs, in `AggregateState` order. */\n readonly specsByColumn: ReadonlyMap<string, readonly AggregateSpec<Row>[]>;\n readonly display: GroupAggregateDisplay;\n readonly locale: FormatLocale;\n readonly messages: ExportSource<Row>[\"messages\"];\n}\n\nconst EMPTY_CELL: ExportCell = { value: null, text: \"\" };\n\nfunction isDataRow<Row>(entry: DisplayRow<Row>): entry is ResolvedRow<Row> {\n return !(\"kind\" in entry);\n}\n\n/**\n * The columns an export holds, in order. An id list is read against every\n * column, hidden ones included, and an id the grid does not have is skipped\n * rather than failing the export. `exportable: false` wins over every\n * selection, even one naming the column.\n */\nfunction pickColumns<Row>(\n view: GridView<Row, unknown>,\n selection: NonNullable<ExportOptions[\"columns\"]>,\n): readonly DataColumn<Row, unknown>[] {\n let picked: readonly DataColumn<Row, unknown>[];\n if (selection === \"visible\") {\n picked = view.columns;\n } else if (selection === \"all\") {\n picked = view.dataColumns;\n } else {\n const byId = new Map(view.dataColumns.map((entry) => [entry.id, entry]));\n picked = [...new Set(selection)].flatMap((id) => byId.get(id) ?? []);\n }\n return picked.filter((entry) => entry.column.exportable !== false);\n}\n\n/**\n * The picked columns as an export describes them. A visible column takes\n * the width and alignment it renders with; a hidden one renders with none,\n * so it is resolved the way it would start out if shown.\n */\nfunction describeColumns<Row>(\n picked: readonly DataColumn<Row, unknown>[],\n source: ExportSource<Row>,\n): readonly ExportColumn[] {\n const shown = new Map(source.view.columns.map((entry) => [entry.id, entry]));\n const resolved = resolveColumnWidths(\n picked.map((entry) => entry.column),\n source.state.columnSizing,\n { sizes: source.options.columnSizeDefaults },\n );\n return resolved.map((entry) => {\n const rendered = shown.get(entry.id) ?? entry;\n return {\n id: rendered.id,\n header: resolveColumnHeaderText(rendered.column),\n type: rendered.column.type ?? \"string\",\n format: rendered.column.format,\n alignment: rendered.alignment,\n width: rendered.width,\n };\n });\n}\n\n/** The rows `scope` asks for, ungrouped, in the order the grid sorts them. */\nfunction scopedRows<Row>(\n source: ExportSource<Row>,\n scope: NonNullable<ExportOptions[\"scope\"]>,\n): readonly ResolvedRow<Row>[] {\n const { view, state } = source;\n switch (scope) {\n case \"all\":\n return view.rows;\n case \"page\":\n return view.displayDataRows;\n case \"selection\": {\n const selected = new Set(state.rowSelection);\n return view.rows.filter((entry) => selected.has(entry.rowId));\n }\n }\n}\n\n/**\n * `value` itself when an export can store it as it is; otherwise the text\n * it reads as, so an object or a function never reaches a writer. A missing\n * value is `null`, the one empty every format has.\n */\nfunction typedValue(value: unknown, text: string): ExportScalar {\n if (value === null || value === undefined) {\n return null;\n }\n return typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value instanceof Date\n ? value\n : text;\n}\n\nfunction dataCell<Row>(\n row: Row,\n column: ColumnDefinition<Row, unknown>,\n context: CellContext<Row>,\n): ExportCell {\n const raw = accessDotted(row, column.field);\n const text = formatCellValue(\n raw,\n column,\n context.locale,\n row,\n context.messages,\n );\n return {\n value:\n column.exportValue === undefined\n ? typedValue(raw, text)\n : column.exportValue(raw, row),\n text,\n };\n}\n\n/**\n * One column's aggregates as a cell. An empty result is empty text, not the\n * dash the grid shows: a file is read by a program as often as by a person,\n * and to a program a dash is a value. Two specs on one column share the\n * cell comma-separated, as the grid's footer shows them, and the cell's\n * value is then that text, since no one typed value stands for both.\n */\nfunction aggregateCell<Row>(\n results: AggregateResults,\n specs: readonly AggregateSpec<Row>[],\n column: ColumnDefinition<Row, unknown>,\n locale: FormatLocale,\n): ExportCell {\n const parts = specs.flatMap((spec) => {\n const value = results.get(spec.id ?? spec.columnId);\n return value === null || value === undefined\n ? []\n : [{ value, text: formatAggregateValue(value, spec, column, locale) }];\n });\n const [only] = parts;\n if (only === undefined) {\n return EMPTY_CELL;\n }\n if (parts.length === 1) {\n return { value: typedValue(only.value, only.text), text: only.text };\n }\n const text = parts.map((part) => part.text).join(\", \");\n return { value: text, text };\n}\n\nfunction aggregateCells<Row>(\n results: AggregateResults,\n context: CellContext<Row>,\n): readonly ExportCell[] {\n return context.columns.map((entry) => {\n const specs = context.specsByColumn.get(entry.id);\n return specs === undefined\n ? EMPTY_CELL\n : aggregateCell(results, specs, entry.column, context.locale);\n });\n}\n\n/**\n * `\"Region: West\"` — the group header's text, naming the column by its text\n * rather than its header markup.\n */\nfunction groupLabel<Row>(\n entry: ResolvedGroupRow,\n source: ExportSource<Row>,\n): string {\n const column = source.view.dataColumns.find(\n (candidate) => candidate.id === entry.columnId,\n )?.column ?? { field: entry.columnId };\n const value = formatGroupValue(\n entry.value,\n column,\n source.options.locale,\n source.messages,\n );\n return `${resolveColumnHeaderText(column)}: ${value}`;\n}\n\nfunction toExportRow<Row>(\n entry: DisplayRow<Row>,\n source: ExportSource<Row>,\n context: CellContext<Row>,\n): ExportRow {\n if (isDataRow(entry)) {\n return {\n kind: \"data\",\n rowId: entry.rowId,\n cells: context.columns.map((column) =>\n dataCell(entry.row, column.column, context),\n ),\n };\n }\n if (entry.kind === \"group\") {\n return {\n kind: \"group\",\n level: entry.level,\n groupId: entry.groupId,\n label: groupLabel(entry, source),\n count: entry.count,\n cells:\n context.display === \"inline\"\n ? aggregateCells(entry.aggregates, context)\n : context.columns.map(() => EMPTY_CELL),\n };\n }\n return {\n kind: \"groupSummary\",\n level: entry.level,\n cells: aggregateCells(entry.aggregates, context),\n };\n}\n\nfunction specsByColumnOf<Row>(\n specs: AggregateState<Row>,\n): ReadonlyMap<string, readonly AggregateSpec<Row>[]> {\n const byColumn = new Map<string, AggregateSpec<Row>[]>();\n for (const spec of specs) {\n const owned = byColumn.get(spec.columnId);\n if (owned === undefined) {\n byColumn.set(spec.columnId, [spec]);\n } else {\n owned.push(spec);\n }\n }\n return byColumn;\n}\n\n/**\n * The grid's view as an `ExportTable` — the one model every export format,\n * the clipboard and print are written from, so none of them reads the page\n * and none can disagree with another.\n *\n * By default it holds what the user sees, minus what only hides it: every\n * row the filter, search and sort leave, across every page; the visible\n * columns in their current order, less any with `exportable: false`; and,\n * in a grouped grid, every group expanded whatever its state on screen,\n * with its aggregates where the grid shows them. `options` narrows it.\n *\n * Each cell carries the text `formatCellValue` makes of it, so the export\n * reads as the screen does, and a typed value — the column's `exportValue`,\n * else the raw value when it is a string, number, boolean or `Date`.\n *\n * The groups are rebuilt from the exported rows rather than read off\n * `displayRows`, which omits a collapsed group's rows; so group counts,\n * subtotals and the grand total describe exactly the rows exported — the\n * selection, under `scope: \"selection\"`, not the whole grid.\n */\nexport function buildExportTable<Row>(\n source: ExportSource<Row>,\n options: ExportOptions = {},\n): ExportTable {\n const { view, state } = source;\n const specs: AggregateState<Row> =\n (options.includeAggregates ?? true)\n ? (source.options.aggregates ?? [])\n : [];\n const columns = pickColumns(view, options.columns ?? \"visible\");\n const context: CellContext<Row> = {\n columns,\n specsByColumn: specsByColumnOf(specs),\n display: source.options.groupAggregateDisplay ?? \"inline\",\n locale: source.options.locale,\n messages: source.messages,\n };\n\n const rows = scopedRows(source, options.scope ?? \"all\");\n // No collapsed ids: a collapsed group hides its rows from the screen, not\n // from an export.\n const grouped = groupRows(rows, state.groupBy, [], view.dataColumns);\n const displayRows =\n (options.includeGroups ?? true)\n ? withGroupAggregates(\n grouped,\n rows,\n state.groupBy,\n specs,\n view.dataColumns,\n context.display,\n )\n : grouped.filter(isDataRow);\n\n let footer: ExportTotalRow | null = null;\n if (specs.length > 0) {\n const totals =\n rows === view.rows\n ? view.grandTotal\n : computeAggregates(\n rows.map((entry) => entry.row),\n specs,\n view.dataColumns,\n );\n footer = { kind: \"total\", cells: aggregateCells(totals, context) };\n }\n\n return {\n columns: describeColumns(columns, source),\n header: options.includeHeader ?? true,\n rows: displayRows.map((entry) => toExportRow(entry, source, context)),\n footer,\n };\n}\n","import type {\n ExportCell,\n ExportColumn,\n ExportGroupRow,\n ExportRow,\n ExportTable,\n} from \"./types\";\n\n/** How `toHtmlTable` writes its markup. */\nexport interface HtmlTableOptions {\n /** Text for a `<caption>` above the table; none by default. */\n readonly caption?: string | undefined;\n}\n\nconst ENTITIES: Readonly<Record<string, string>> = {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\",\n};\n\n/**\n * `text` safe to place in markup, as content or as a quoted attribute: a\n * cell's text is data, and data can hold `<script>`.\n */\nexport function escapeHtml(text: string): string {\n return text.replace(/[&<>\"']/g, (char) => ENTITIES[char] ?? char);\n}\n\n/**\n * One cell. Alignment is written inline rather than as a class, so it\n * survives a paste into a spreadsheet or a word processor, which keep a\n * `style` attribute and have no stylesheet to read a class from.\n */\nfunction cellHtml(\n tag: \"th\" | \"td\",\n text: string,\n column: ExportColumn | undefined,\n): string {\n const alignment = column?.alignment ?? \"left\";\n const style = alignment === \"left\" ? \"\" : ` style=\"text-align:${alignment}\"`;\n return `<${tag}${style}>${escapeHtml(text)}</${tag}>`;\n}\n\nfunction cellsHtml(\n cells: readonly ExportCell[],\n columns: readonly ExportColumn[],\n): string {\n return cells\n .map((cell, index) => cellHtml(\"td\", cell.text, columns[index]))\n .join(\"\");\n}\n\n/**\n * A group header: its label in one cell spanning every column, as the grid\n * draws it. When the group shows aggregates inline, the label spans only the\n * columns before the first of them, so each aggregate stays under its own\n * column — at least the first column, where an aggregate gives way to the\n * label.\n */\nfunction groupRowHtml(\n row: ExportGroupRow,\n columns: readonly ExportColumn[],\n): string {\n const firstAggregate = row.cells.findIndex((cell) => cell.text !== \"\");\n const span = Math.max(\n 1,\n firstAggregate === -1 ? row.cells.length : firstAggregate,\n );\n const colspan = span > 1 ? ` colspan=\"${String(span)}\"` : \"\";\n const label = `<td${colspan}>${escapeHtml(row.label)}</td>`;\n const aggregates = row.cells\n .slice(span)\n .map((cell, index) => cellHtml(\"td\", cell.text, columns[span + index]))\n .join(\"\");\n return `<tr class=\"export-group\" data-level=\"${String(row.level)}\">${label}${aggregates}</tr>`;\n}\n\nfunction rowHtml(row: ExportRow, columns: readonly ExportColumn[]): string {\n switch (row.kind) {\n case \"data\":\n return `<tr>${cellsHtml(row.cells, columns)}</tr>`;\n case \"group\":\n return groupRowHtml(row, columns);\n case \"groupSummary\":\n return `<tr class=\"export-group-summary\" data-level=\"${String(row.level)}\">${cellsHtml(row.cells, columns)}</tr>`;\n }\n}\n\n/**\n * The table as an HTML `<table>` string: a `<thead>` of column names when\n * the table has a header, every row in `<tbody>`, and the grand total in\n * `<tfoot>`. Every piece of text is escaped. It carries the semantic class\n * names a stylesheet targets — `gridkit-export-table` on the table,\n * `export-group` with a `data-level` on group headers,\n * `export-group-summary` on summary rows — and nothing else of style but\n * each column's alignment, so it reads the same pasted into a document as\n * it does printed.\n */\nexport function toHtmlTable(\n table: ExportTable,\n options: HtmlTableOptions = {},\n): string {\n const { columns } = table;\n const caption =\n options.caption === undefined\n ? \"\"\n : `<caption>${escapeHtml(options.caption)}</caption>`;\n const head = table.header\n ? `<thead><tr>${columns.map((column) => cellHtml(\"th\", column.header, column)).join(\"\")}</tr></thead>`\n : \"\";\n const body = `<tbody>${table.rows.map((row) => rowHtml(row, columns)).join(\"\")}</tbody>`;\n const foot =\n table.footer === null\n ? \"\"\n : `<tfoot><tr>${cellsHtml(table.footer.cells, columns)}</tr></tfoot>`;\n return `<table class=\"gridkit-export-table\">${caption}${head}${body}${foot}</table>`;\n}\n","import type { ExportCell, ExportScalar, ExportTable } from \"./types\";\n\n/**\n * One field of a delimited text record, before the format's own escaping.\n * `isNumber` marks a cell whose typed value is a number, so a formula guard\n * can tell the sign of `-5` from the start of a formula.\n */\nexport interface TextField {\n readonly text: string;\n readonly isNumber: boolean;\n}\n\n/**\n * Which reading of a cell a text format writes: `\"text\"`, as the grid shows\n * it, or `\"raw\"`, its typed value written plainly, for a program to read.\n */\nexport type TextValues = \"text\" | \"raw\";\n\n/**\n * A typed value as plain text: a number without grouping or a locale's\n * decimal comma, a date in ISO 8601, a boolean as `true` or `false` — the\n * forms every program parses the same way. An invalid date has no ISO form,\n * so it is written empty, as a missing value is.\n */\nfunction rawText(value: ExportScalar): string {\n if (value === null) {\n return \"\";\n }\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? \"\" : value.toISOString();\n }\n return String(value);\n}\n\nfunction cellField(cell: ExportCell, values: TextValues): TextField {\n return {\n text: values === \"raw\" ? rawText(cell.value) : cell.text,\n isNumber: typeof cell.value === \"number\",\n };\n}\n\nfunction textField(text: string): TextField {\n return { text, isNumber: false };\n}\n\n/**\n * The table as records of fields, one per column: the header row when the\n * table has one, every body row, then the footer. A group row writes its\n * label in the first column, where a reader scanning down the left edge\n * finds it, and its inline aggregates under their own columns after it.\n */\nexport function textRecords(\n table: ExportTable,\n values: TextValues,\n): TextField[][] {\n const records: TextField[][] = [];\n if (table.header) {\n records.push(table.columns.map((column) => textField(column.header)));\n }\n for (const row of table.rows) {\n records.push(\n row.cells.map((cell, index) =>\n row.kind === \"group\" && index === 0\n ? textField(row.label)\n : cellField(cell, values),\n ),\n );\n }\n if (table.footer !== null) {\n records.push(table.footer.cells.map((cell) => cellField(cell, values)));\n }\n return records;\n}\n","import { textRecords } from \"./records\";\nimport type { ExportTable } from \"./types\";\n\n/** How `toTsv` writes its text. */\nexport interface TsvOptions {\n /**\n * Which reading of each cell is written: `\"text\"` (the default), as the\n * grid shows it; or `\"raw\"`, the typed value written plainly.\n */\n readonly values?: \"text\" | \"raw\" | undefined;\n}\n\n/** A tab or a line break, which would end a TSV field or record early. */\nconst SEPARATORS = /\\r\\n|[\\t\\r\\n]/g;\n\n/**\n * The table as tab-separated text, records ending `\"\\n\"` — the plain-text\n * form a spreadsheet splits into cells when it is pasted, which is what the\n * clipboard carries. TSV has no quoting a paste target agrees on, so a tab\n * or line break inside a cell becomes a space instead. Unlike `toCsv` it\n * writes no byte order mark and leaves formulas alone: what is copied is\n * exactly what the grid shows, and pasting it is the user's own act.\n */\nexport function toTsv(table: ExportTable, options: TsvOptions = {}): string {\n return textRecords(table, options.values ?? \"text\")\n .map((record) =>\n record.map((field) => field.text.replace(SEPARATORS, \" \")).join(\"\\t\"),\n )\n .join(\"\\n\");\n}\n","import type { DataColumn, GridState } from \"../types\";\nimport { buildExportTable, type ExportSource } from \"./buildExportTable\";\nimport { toHtmlTable } from \"./htmlTable\";\nimport { toTsv } from \"./tsv\";\n\n/**\n * What a copy is built from: an export's source, with the column and cell\n * selection a selection copy reads as well. A `GridCommandContext` is one\n * as it stands.\n */\nexport interface CopySource<Row> extends ExportSource<Row> {\n readonly state: Pick<\n GridState<Row>,\n | \"groupBy\"\n | \"rowSelection\"\n | \"columnSizing\"\n | \"columnSelection\"\n | \"cellSelection\"\n >;\n}\n\n/**\n * What to copy: one cell, one row, or whatever the grid has selected — the\n * selected rows, else the selected columns, else the selected cell.\n */\nexport type CopyRequest =\n | {\n readonly kind: \"cell\";\n readonly rowId: string;\n readonly columnId: string;\n }\n | { readonly kind: \"row\"; readonly rowId: string }\n | { readonly kind: \"selection\" };\n\n/**\n * A copy in the two forms the clipboard carries, with what it holds for the\n * announcement: `count` cells, rows or columns.\n */\nexport interface CopyContent {\n /** Tab-separated text, as `toTsv` writes it — what a spreadsheet splits into cells. */\n readonly text: string;\n /** The same as an HTML table, as `toHtmlTable` writes it — what a word processor keeps the columns of. */\n readonly html: string;\n readonly count: number;\n readonly unit: \"cells\" | \"rows\" | \"columns\";\n}\n\n/**\n * What a selection copy holds, settled without building anything — so a\n * menu can ask whether there is anything to copy each time it resolves.\n */\ntype SelectionCopy =\n | { readonly kind: \"rows\"; readonly count: number }\n | { readonly kind: \"columns\"; readonly columnIds: readonly string[] }\n | {\n readonly kind: \"cell\";\n readonly rowId: string;\n readonly columnId: string;\n };\n\nfunction isCopyable<Row>(column: DataColumn<Row, unknown>): boolean {\n return column.column.exportable !== false;\n}\n\n/** Whether the row passes the filter, on whichever page it falls. */\nfunction hasRow<Row>(source: ExportSource<Row>, rowId: string): boolean {\n return source.view.rows.some((entry) => entry.rowId === rowId);\n}\n\n/** Whether the column is shown and may leave the grid. */\nfunction hasColumn<Row>(source: ExportSource<Row>, columnId: string): boolean {\n return source.view.columns.some(\n (entry) => entry.id === columnId && isCopyable(entry),\n );\n}\n\n/**\n * The selection a copy reads, in order of precedence: the selected rows the\n * filter leaves; else the selected columns that are shown and exportable,\n * while the filter leaves any row; else the selected cell, when its row and\n * its column both would copy — or `null` when nothing selected can be.\n */\nfunction selectionCopy<Row>(source: CopySource<Row>): SelectionCopy | null {\n const { state, view } = source;\n const selectedRows = new Set(state.rowSelection);\n const count = view.rows.filter((entry) =>\n selectedRows.has(entry.rowId),\n ).length;\n if (count > 0) {\n return { kind: \"rows\", count };\n }\n const selectedColumns = new Set(state.columnSelection);\n const columnIds = view.columns\n .filter((entry) => selectedColumns.has(entry.id) && isCopyable(entry))\n .map((entry) => entry.id);\n if (columnIds.length > 0 && view.rows.length > 0) {\n return { kind: \"columns\", columnIds };\n }\n const cell = state.cellSelection;\n if (\n cell !== null &&\n hasRow(source, cell.rowId) &&\n hasColumn(source, cell.columnId)\n ) {\n return { kind: \"cell\", rowId: cell.rowId, columnId: cell.columnId };\n }\n return null;\n}\n\n/**\n * Whether `copyContent(source, { kind: \"selection\" })` has anything to\n * copy, worked out without building it — cheap enough to ask each time a\n * menu or toolbar resolves.\n */\nexport function canCopySelection<Row>(source: CopySource<Row>): boolean {\n return selectionCopy(source) !== null;\n}\n\n/**\n * The source with `rowIds` as its row selection, so `scope: \"selection\"`\n * exports exactly those rows, in the order the grid shows them.\n */\nfunction withRows<Row>(\n source: ExportSource<Row>,\n rowIds: readonly string[],\n): ExportSource<Row> {\n return { ...source, state: { ...source.state, rowSelection: rowIds } };\n}\n\ninterface CopyTableOptions {\n readonly scope: \"all\" | \"selection\";\n /** Column ids, in order; the shown columns when left out. */\n readonly columns?: readonly string[];\n readonly header: boolean;\n}\n\n/**\n * The table as the clipboard carries it. Group headers and aggregates stay\n * behind: a copy is of data, which a paste lays out in rows of its own.\n */\nfunction contentOf<Row>(\n source: ExportSource<Row>,\n { scope, columns, header }: CopyTableOptions,\n unit: CopyContent[\"unit\"],\n): CopyContent | null {\n const table = buildExportTable(source, {\n scope,\n columns: columns ?? \"visible\",\n includeHeader: header,\n includeGroups: false,\n includeAggregates: false,\n });\n if (table.columns.length === 0 || table.rows.length === 0) {\n return null;\n }\n return {\n text: toTsv(table),\n html: toHtmlTable(table),\n count: unit === \"columns\" ? table.columns.length : table.rows.length,\n unit,\n };\n}\n\nfunction cellContent<Row>(\n source: ExportSource<Row>,\n rowId: string,\n columnId: string,\n): CopyContent | null {\n if (!hasRow(source, rowId) || !hasColumn(source, columnId)) {\n return null;\n }\n return contentOf(\n withRows(source, [rowId]),\n { scope: \"selection\", columns: [columnId], header: false },\n \"cells\",\n );\n}\n\nfunction rowContent<Row>(\n source: ExportSource<Row>,\n rowId: string,\n): CopyContent | null {\n if (!hasRow(source, rowId)) {\n return null;\n }\n return contentOf(\n withRows(source, [rowId]),\n { scope: \"selection\", header: false },\n \"rows\",\n );\n}\n\nfunction selectionContent<Row>(source: CopySource<Row>): CopyContent | null {\n const selection = selectionCopy(source);\n switch (selection?.kind) {\n case undefined:\n return null;\n case \"rows\":\n return contentOf(\n source,\n { scope: \"selection\", header: selection.count > 1 },\n \"rows\",\n );\n case \"columns\":\n return contentOf(\n source,\n { scope: \"all\", columns: selection.columnIds, header: true },\n \"columns\",\n );\n case \"cell\":\n return cellContent(source, selection.rowId, selection.columnId);\n }\n}\n\n/**\n * What `request` copies, as tab-separated text and an HTML table, or `null`\n * when there is nothing to copy — a row the filter hides, a column hidden\n * or marked `exportable: false`, or an empty selection.\n *\n * Built from the export model, never the page, so a copy holds exactly what\n * an export would and reads as the grid shows it: each cell's formatted\n * text, the shown columns in their order less any with `exportable: false`.\n * The text has no byte order mark and no formula neutralising — what is\n * copied is what is seen, and pasting it is the user's own act.\n *\n * A cell copies its text alone, and a row its cells without a header. A\n * selection copies the selected rows, in the order the grid shows them and\n * under a header row once there are two or more; else the selected columns\n * over every row the filter leaves, under their header; else the selected\n * cell.\n */\nexport function copyContent<Row>(\n source: CopySource<Row>,\n request: CopyRequest,\n): CopyContent | null {\n switch (request.kind) {\n case \"cell\":\n return cellContent(source, request.rowId, request.columnId);\n case \"row\":\n return rowContent(source, request.rowId);\n case \"selection\":\n return selectionContent(source);\n }\n}\n","import type { GridMessages } from \"../messages\";\nimport { reportError } from \"../util/report\";\nimport { buildExportTable, type ExportSource } from \"./buildExportTable\";\nimport type { ExportFile, ExportWriter, GridExportOptions } from \"./writer\";\n\n/**\n * What `exportFile` exports from: an `ExportSource` whose messages are the\n * grid's whole set, since a writer may print any of them. A\n * `GridCommandContext` is one as it stands.\n */\nexport interface ExportFileSource<Row> extends ExportSource<Row> {\n readonly messages: GridMessages;\n}\n\n/**\n * `fileName` with `extension` after it, unless it already ends with it — so\n * `\"orders\"` and `\"orders.csv\"` both save as `orders.csv`.\n */\nfunction withExtension(fileName: string, extension: string): string {\n const suffix = `.${extension}`;\n return fileName.toLowerCase().endsWith(suffix.toLowerCase())\n ? fileName\n : fileName + suffix;\n}\n\n/** `format` when it is a writer, else the one registered for it — reported when there is none. */\nfunction writerFor(\n format: string | ExportWriter,\n writers: ReadonlyMap<string, ExportWriter>,\n): ExportWriter | null {\n if (typeof format !== \"string\") {\n return format;\n }\n const writer = writers.get(format);\n if (writer === undefined) {\n reportError(\n `there is no export writer for \\`${format}\\` — register one through \\`exportWriters\\`.`,\n );\n return null;\n }\n return writer;\n}\n\nfunction fileNameFor(options: GridExportOptions, writer: ExportWriter): string {\n const { fileName = \"export\" } = options;\n const name =\n typeof fileName === \"function\" ? fileName(writer.format) : fileName;\n return withExtension(name, writer.fileExtension);\n}\n\n/**\n * The grid's view exported as a file of `format`: the table `options`\n * narrow, written by that format's writer among `writers` (see\n * `resolveExportWriters`) — or by `format` itself, when it is a writer —\n * and named. A writer that returns a promise gives a promise of the file.\n *\n * A format no writer is registered for is reported and gives `null`, so a\n * renderer saves nothing rather than failing.\n */\nexport function exportFile<Row>(\n source: ExportFileSource<Row>,\n format: string | ExportWriter,\n options: GridExportOptions,\n writers: ReadonlyMap<string, ExportWriter>,\n): ExportFile | Promise<ExportFile> | null {\n const writer = writerFor(format, writers);\n if (writer === null) {\n return null;\n }\n const content = writer.write(buildExportTable(source, options), {\n locale: source.options.locale,\n messages: source.messages,\n options,\n });\n const fileName = fileNameFor(options, writer);\n const { mimeType } = writer;\n return content instanceof Promise\n ? content.then((resolved) => ({ fileName, mimeType, content: resolved }))\n : { fileName, mimeType, content };\n}\n","import type { FormatLocale } from \"../util/format\";\nimport { buildExportTable, type ExportSource } from \"./buildExportTable\";\nimport { escapeHtml, toHtmlTable } from \"./htmlTable\";\nimport type { ExportOptions, ExportTable } from \"./types\";\n\n/** Which way the paper is turned. */\nexport type PrintOrientation = \"portrait\" | \"landscape\";\n\n/**\n * How a grid prints: which rows and columns (every `ExportOptions` field),\n * the text around the table, and the page it is laid out on. The grid's\n * `print` option.\n */\nexport interface PrintOptions extends ExportOptions {\n /** A heading above the table, and the printed document's title. */\n readonly title?: string | undefined;\n /** A line under the title. */\n readonly subtitle?: string | undefined;\n /** A line after the table. */\n readonly footer?: string | undefined;\n /**\n * When the print was made, under the title: `true` for now, or a `Date`\n * to print instead. Off by default.\n */\n readonly timestamp?: boolean | Date | undefined;\n /** The language the timestamp is written in. Defaults to the grid's. */\n readonly locale?: FormatLocale;\n /**\n * Which way the paper is turned. Defaults to `\"landscape\"` for a table of\n * more than six columns, which rarely fits a portrait page, else\n * `\"portrait\"`.\n */\n readonly orientation?: PrintOrientation | undefined;\n /**\n * A page size CSS names — `\"A4\"` (the default), `\"Letter\"`, `\"A3\"`,\n * `\"Legal\"`.\n */\n readonly paperSize?: \"A4\" | \"Letter\" | (string & {}) | undefined;\n /** Whether each page is numbered, \"3 / 12\", where the browser can. Defaults to `true`. */\n readonly pageNumbers?: boolean | undefined;\n /**\n * Whether a wide table is squeezed onto the page — a smaller font and\n * fixed column widths that wrap their text — rather than run off its\n * edge. Defaults to `false`.\n */\n readonly fitToWidth?: boolean | undefined;\n /** CSS added after the print stylesheet, to restyle the printed table. */\n readonly styles?: string | undefined;\n}\n\n/**\n * The page a print is laid out on, every choice settled — what\n * `@gridkitjs/dom`'s `printStyles` turns into the page's CSS.\n */\nexport interface PrintPage {\n readonly paperSize: string;\n readonly orientation: PrintOrientation;\n readonly pageNumbers: boolean;\n readonly fitToWidth: boolean;\n}\n\n/** A print ready for a renderer to put on paper: what `buildPrintDocument` returns. */\nexport interface PrintDocument {\n /**\n * The document's title as text, `\"\"` when untitled — what the browser\n * puts in a page's header and names a PDF saved from the print dialog.\n */\n readonly title: string;\n /** The `<body>`'s markup: the heading, the table and the footer, every piece of text escaped. */\n readonly bodyHtml: string;\n readonly page: PrintPage;\n}\n\n/** Past this many columns, a page turned on its side by default. */\nconst PORTRAIT_COLUMN_LIMIT = 6;\n\n/**\n * The orientation `options` ask for, else the one the table's width\n * suggests: landscape once it has more columns than a portrait page\n * comfortably holds.\n */\nfunction resolveOrientation(\n table: ExportTable,\n options: PrintOptions,\n): PrintOrientation {\n return (\n options.orientation ??\n (table.columns.length > PORTRAIT_COLUMN_LIMIT ? \"landscape\" : \"portrait\")\n );\n}\n\nfunction timestampText(timestamp: true | Date, locale: FormatLocale): string {\n const date = timestamp === true ? new Date() : timestamp;\n return new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n }).format(date);\n}\n\n/** One line of text in its element, or nothing for a line left out. */\nfunction line(\n tag: string,\n className: string,\n text: string | undefined,\n): string {\n return text === undefined || text === \"\"\n ? \"\"\n : `<${tag} class=\"${className}\">${escapeHtml(text)}</${tag}>`;\n}\n\n/** The title, subtitle and timestamp above the table, or nothing when none is set. */\nfunction headerHtml(options: PrintOptions): string {\n const { timestamp = false } = options;\n const lines =\n line(\"h1\", \"print-title\", options.title) +\n line(\"p\", \"print-subtitle\", options.subtitle) +\n (timestamp === false\n ? \"\"\n : line(\"p\", \"print-timestamp\", timestampText(timestamp, options.locale)));\n return lines === \"\"\n ? \"\"\n : `<header class=\"gridkit-print-header\">${lines}</header>`;\n}\n\n/**\n * The table as a printable document: its heading — the title, subtitle and\n * timestamp `options` set — then the table as `toHtmlTable` writes it, then\n * the footer line, with the page it is laid out on. Every piece of text is\n * escaped. It holds no styles: putting it on paper, with a stylesheet for\n * the page, is the renderer's — `@gridkitjs/dom`'s `printStyles` and\n * `printDocument` in a browser.\n *\n * The heading and footer carry semantic class names for a stylesheet:\n * `gridkit-print-header` around `print-title`, `print-subtitle` and\n * `print-timestamp`, and `gridkit-print-footer`.\n */\nexport function buildPrintDocument(\n table: ExportTable,\n options: PrintOptions = {},\n): PrintDocument {\n const footer = line(\"footer\", \"gridkit-print-footer\", options.footer);\n return {\n title: options.title ?? \"\",\n bodyHtml: `${headerHtml(options)}${toHtmlTable(table)}${footer}`,\n page: {\n paperSize: options.paperSize ?? \"A4\",\n orientation: resolveOrientation(table, options),\n pageNumbers: options.pageNumbers ?? true,\n fitToWidth: options.fitToWidth ?? false,\n },\n };\n}\n\n/**\n * What `exportPrintDocument` prints from: an `ExportSource` that may carry\n * the grid's `label`. A `GridCommandContext` is one as it stands.\n */\nexport interface PrintSource<Row> extends ExportSource<Row> {\n readonly options: ExportSource<Row>[\"options\"] & {\n readonly label?: string | undefined;\n };\n}\n\n/**\n * The grid's view as a print document: the table `options` narrow, laid out\n * as `buildPrintDocument` lays it out, with the timestamp in the grid's\n * locale unless `options` name another. Given no `title`, it takes the\n * grid's `label` — the name a screen reader already reads for it; `\"\"`\n * leaves it untitled.\n */\nexport function exportPrintDocument<Row>(\n source: PrintSource<Row>,\n options: PrintOptions = {},\n): PrintDocument {\n return buildPrintDocument(buildExportTable(source, options), {\n ...options,\n title: options.title ?? source.options.label,\n locale: options.locale ?? source.options.locale,\n });\n}\n","import type { FormatLocale } from \"../util/format\";\nimport { type TextField, textRecords } from \"./records\";\nimport type { ExportTable } from \"./types\";\n\n/** How `toCsv` writes a file. Every field is optional. */\nexport interface CsvOptions {\n /**\n * The field separator: `\",\"` by default, any string, or `\"auto\"` for the\n * separator a spreadsheet expects in `locale` — `\";\"` where a decimal is\n * written with a comma, as in most of Europe, since a comma there is part\n * of a number; `\",\"` elsewhere.\n */\n readonly delimiter?: string | undefined;\n /** The locale `delimiter: \"auto\"` reads; the runtime's own when absent. */\n readonly locale?: FormatLocale;\n /** What ends each record. Defaults to `\"\\r\\n\"`, as RFC 4180 writes it. */\n readonly eol?: string | undefined;\n /**\n * Whether the file starts with a UTF-8 byte order mark. Defaults to\n * `true`: without one, Excel reads the file in the system's legacy code\n * page and garbles every character outside ASCII.\n */\n readonly bom?: boolean | undefined;\n /**\n * Whether a field a spreadsheet would run as a formula is written as text\n * instead. Defaults to `true`; see `toCsv`.\n */\n readonly neutralizeFormulas?: boolean | undefined;\n /**\n * Which reading of each cell is written: `\"text\"` (the default), as the\n * grid shows it; or `\"raw\"`, the typed value — numbers plain, dates in ISO\n * 8601, booleans as `true` and `false` — for a file a program reads.\n */\n readonly values?: \"text\" | \"raw\" | undefined;\n}\n\nconst BOM = \"\";\n\n/** What a spreadsheet takes for the start of a formula, or a DDE call. */\nconst FORMULA_START = /^[=+\\-@\\t\\r]/;\n\n/** The signs a formatted number can lead with — `-5`, `+5` — and still be one. */\nconst SIGN_START = /^[+-]/;\n\n/**\n * Whether a field needs quotes: RFC 4180 quotes one holding the delimiter,\n * a quote, or a line break, and nothing else.\n */\nconst NEEDS_QUOTES = /[\"\\r\\n]/;\n\n/**\n * `\",\"`, or `\";\"` where `locale` writes a decimal with a comma — the\n * separator a spreadsheet in that locale splits a CSV on, since it reads a\n * comma as part of a number.\n */\nfunction autoDelimiter(locale: FormatLocale): string {\n const decimal = new Intl.NumberFormat(locale)\n .formatToParts(1.5)\n .find((part) => part.type === \"decimal\")?.value;\n return decimal === \",\" ? \";\" : \",\";\n}\n\n/**\n * The field with a leading `'` when a spreadsheet would run it as a\n * formula, which it then shows as text. A number keeps its sign: a cell\n * whose typed value is a number may read `-5` or `+5`, and those stay\n * numbers a formula can sum.\n */\nfunction neutralize(field: TextField): string {\n const { text } = field;\n if (!FORMULA_START.test(text) || (field.isNumber && SIGN_START.test(text))) {\n return text;\n }\n return `'${text}`;\n}\n\nfunction quote(text: string, delimiter: string): string {\n return text.includes(delimiter) || NEEDS_QUOTES.test(text)\n ? `\"${text.replaceAll('\"', '\"\"')}\"`\n : text;\n}\n\n/**\n * The table as CSV, quoted per RFC 4180: a field is quoted when it holds the\n * delimiter, a quote or a line break, and a quote inside one is doubled, so\n * a line break inside a cell survives. A group row writes its label in the\n * first column; summary rows and the footer write their aggregates under\n * their columns.\n *\n * A CSV file opened in a spreadsheet runs any field that starts with `=`,\n * `+`, `-` or `@` as a formula — and a tab or a carriage return can hide\n * such a start — so a value a user typed into the data could make another\n * user's spreadsheet fetch a URL or run a command. By default such a field\n * gets a leading `'`, which the spreadsheet shows as text. A cell whose\n * value is a number keeps its leading sign, since it is one.\n *\n * Returns a string, not a file: making a `Blob` of it, with the type\n * `text/csv;charset=utf-8`, is the renderer's job.\n */\nexport function toCsv(table: ExportTable, options: CsvOptions = {}): string {\n const delimiter =\n options.delimiter === \"auto\"\n ? autoDelimiter(options.locale)\n : (options.delimiter ?? \",\");\n const guard = options.neutralizeFormulas ?? true;\n const lines = textRecords(table, options.values ?? \"text\").map((record) =>\n record\n .map((field) => quote(guard ? neutralize(field) : field.text, delimiter))\n .join(delimiter),\n );\n return ((options.bom ?? true) ? BOM : \"\") + lines.join(options.eol ?? \"\\r\\n\");\n}\n","import type { ExportTable } from \"./types\";\n\n/** How `toJson` writes its text. Every field is optional. */\nexport interface JsonOptions {\n /**\n * What each record is keyed by: `\"id\"` (the default), the column's id,\n * stable whatever the header says; or `\"header\"`, its header text, for a\n * reader who sees the keys. A header repeated across columns is suffixed\n * ` (2)`, ` (3)` and so on, so no column overwrites another.\n */\n readonly keys?: \"id\" | \"header\" | undefined;\n /** Indentation, as `JSON.stringify` takes it; none by default. */\n readonly space?: number | string | undefined;\n}\n\n/**\n * `names` made unique in order: the first of a name keeps it, each repeat\n * takes the first ` (n)` suffix not already in use.\n */\nfunction uniqueNames(names: readonly string[]): string[] {\n const used = new Set<string>();\n return names.map((name) => {\n let unique = name;\n for (let n = 2; used.has(unique); n += 1) {\n unique = `${name} (${String(n)})`;\n }\n used.add(unique);\n return unique;\n });\n}\n\n/**\n * The table's data rows as a JSON array of objects, one property per\n * column holding the cell's typed value — a number stays a number, a `Date`\n * becomes its ISO 8601 string. Group headers, summary rows and the footer\n * are left out: JSON is read by programs, which group and total for\n * themselves, and a row that is not data would only have to be filtered\n * out again.\n *\n * Returns a string; making a `Blob` of it, with the type\n * `application/json`, is the renderer's job.\n */\nexport function toJson(table: ExportTable, options: JsonOptions = {}): string {\n const keys =\n options.keys === \"header\"\n ? uniqueNames(table.columns.map((column) => column.header))\n : table.columns.map((column) => column.id);\n const records = table.rows.flatMap((row) =>\n row.kind === \"data\"\n ? [\n Object.fromEntries(\n keys.map((key, index) => [key, row.cells[index]?.value ?? null]),\n ),\n ]\n : [],\n );\n // `JSON.stringify` writes a `Date` through its `toJSON`, the ISO string —\n // or `null` for an invalid one, as it does a `NaN`.\n return JSON.stringify(records, null, options.space);\n}\n","import type { GridMessages } from \"../messages\";\nimport type { FormatLocale } from \"../util/format\";\nimport { type CsvOptions, toCsv } from \"./csv\";\nimport { type JsonOptions, toJson } from \"./json\";\nimport type { ExportOptions, ExportTable } from \"./types\";\n\n/**\n * How a grid exports unless a call says otherwise: which rows and columns\n * (every `ExportOptions` field), what the file is called, and each built-in\n * format's settings. The grid's `export` option.\n */\nexport interface GridExportOptions extends ExportOptions {\n /**\n * The file's name, without its extension — the writer's is added unless\n * the name already ends with it. A function is asked per export with the\n * format, `\"csv\"` or `\"xlsx\"`. Defaults to `\"export\"`.\n */\n readonly fileName?: string | ((format: string) => string) | undefined;\n /**\n * How the CSV writer writes. Its `locale`, which `delimiter: \"auto\"`\n * reads, defaults to the grid's.\n */\n readonly csv?: CsvOptions | undefined;\n /** How the JSON writer writes. */\n readonly json?: JsonOptions | undefined;\n}\n\n/** What a writer is given beside the table: the grid's language and the export's settings. */\nexport interface ExportWriteContext {\n /** The grid's `locale`. */\n readonly locale: FormatLocale;\n /** The grid's messages, over the defaults. */\n readonly messages: GridMessages;\n /**\n * The export's options, where a writer finds its own settings: the CSV\n * writer reads `csv`, the JSON writer `json`. A writer of the app's own\n * takes its settings when it is made instead, as a closure.\n */\n readonly options: GridExportOptions;\n}\n\n/**\n * One export format: how to write an `ExportTable` as a file of it, and what\n * the file is. CSV and JSON ship with the grid; any other — xlsx from\n * `@gridkitjs/export-xlsx`, or one of the app's own — is registered through\n * the grid's `exportWriters`.\n *\n * `write` returns the file's contents, not a file: text, bytes, or a promise\n * of either for a writer that loads a library first. Making a `Blob` of it\n * is the renderer's job.\n */\nexport interface ExportWriter {\n /** The id the grid knows it by — `\"csv\"`, `\"xlsx\"`; one per grid. */\n readonly format: string;\n /** Without the dot: `\"csv\"`. */\n readonly fileExtension: string;\n /** The file's media type, the `Blob`'s `type`. */\n readonly mimeType: string;\n readonly write: (\n table: ExportTable,\n context: ExportWriteContext,\n ) => string | Uint8Array | Promise<string | Uint8Array>;\n}\n\n/** An export ready to save: what `exportFile` hands a renderer to download. */\nexport interface ExportFile {\n /** With its extension: `\"export.csv\"`. */\n readonly fileName: string;\n readonly mimeType: string;\n readonly content: string | Uint8Array;\n}\n\n/** CSV through `toCsv`, its delimiter read for the grid's locale unless `csv.locale` says otherwise. */\nexport const csvWriter: ExportWriter = {\n format: \"csv\",\n fileExtension: \"csv\",\n mimeType: \"text/csv;charset=utf-8\",\n write: (table, { locale, options }) =>\n toCsv(table, { locale, ...options.csv }),\n};\n\n/** The data rows as JSON, through `toJson`. */\nexport const jsonWriter: ExportWriter = {\n format: \"json\",\n fileExtension: \"json\",\n mimeType: \"application/json\",\n write: (table, { options }) => toJson(table, options.json),\n};\n\n/**\n * Every writer a grid can export with, by format: CSV and JSON, then\n * `writers` — one with a built-in's format replacing it, as an app command\n * replaces a built-in of the same id.\n */\nexport function resolveExportWriters(\n writers: readonly ExportWriter[] | undefined,\n): ReadonlyMap<string, ExportWriter> {\n return new Map(\n [csvWriter, jsonWriter, ...(writers ?? [])].map((writer) => [\n writer.format,\n writer,\n ]),\n );\n}\n","import type { ColumnType, FilterOperator, FilterScalar } from \"../types\";\nimport type { ValueKind } from \"../util/filterOperators\";\nimport { kindOf, toDate } from \"../util/filterOperators\";\n\n/**\n * The kind of value a column filters as — what decides which conditions a\n * filter menu offers on it, how their operators read, and what a typed\n * operand must be.\n */\nexport type FilterOperatorFamily = ValueKind;\n\n/**\n * The family a column of `type` falls in: `\"number\"` for the numeric\n * types, `\"date\"` for date, date-time and time, `\"boolean\"`, and `\"text\"`\n * for everything else. It is the filter engine's own reading of `type`, so\n * a menu never offers a condition the column would compare differently.\n */\nexport function filterOperatorFamily(\n type: ColumnType | undefined,\n): FilterOperatorFamily {\n return kindOf(type);\n}\n\nconst familyOperators: Readonly<\n Record<FilterOperatorFamily, readonly FilterOperator[]>\n> = {\n text: [\n \"contains\",\n \"notContains\",\n \"eq\",\n \"ne\",\n \"startsWith\",\n \"endsWith\",\n \"isEmpty\",\n \"isNotEmpty\",\n ],\n number: [\n \"eq\",\n \"ne\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"between\",\n \"isEmpty\",\n \"isNotEmpty\",\n ],\n date: [\"eq\", \"ne\", \"lt\", \"gt\", \"between\", \"isEmpty\", \"isNotEmpty\"],\n boolean: [\"eq\", \"isEmpty\", \"isNotEmpty\"],\n};\n\n/**\n * A date-time or time column's cells are instants, which a typed day or\n * minute seldom equals to the millisecond — so its menu offers before, after\n * and between, not equals.\n */\nconst instantOperators: readonly FilterOperator[] = [\n \"lt\",\n \"gt\",\n \"between\",\n \"isEmpty\",\n \"isNotEmpty\",\n];\n\n/**\n * The conditions a filter menu offers on a column of `type`, in the order it\n * lists them, unless the column names its own. Never `in`: a list of values\n * is the checklist's to pick, not a condition's to type.\n */\nexport function defaultFilterOperators(\n type: ColumnType | undefined,\n): readonly FilterOperator[] {\n return type === \"dateTime\" || type === \"time\"\n ? instantOperators\n : familyOperators[filterOperatorFamily(type)];\n}\n\n/**\n * How many operands `operator` takes — how many inputs a condition row\n * shows: none for the blanks, `between`'s two ends, one for the rest. `in`\n * takes one list, which only a checklist writes.\n */\nexport function filterOperandArity(operator: FilterOperator): 0 | 1 | 2 {\n switch (operator) {\n case \"isEmpty\":\n case \"isNotEmpty\":\n return 0;\n case \"between\":\n return 2;\n case \"eq\":\n case \"ne\":\n case \"contains\":\n case \"notContains\":\n case \"startsWith\":\n case \"endsWith\":\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\":\n case \"in\":\n return 1;\n }\n}\n\n/**\n * A number as a number input gives it: digits with a point for decimals and\n * an optional exponent. No thousands separator — whether `1,500` is fifteen\n * hundred or one and a half depends on the locale, so it is not guessed at.\n */\nconst NUMBER_INPUT = /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[+-]?\\d+)?$/i;\n\n/**\n * A day as a date input gives it, `yyyy-mm-dd`, or a moment as a date-time\n * input does, `yyyy-mm-ddThh:mm` with optional seconds and milliseconds.\n */\nconst DATE_INPUT =\n /^(\\d{4})-(\\d{2})-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{1,3}))?)?)?$/;\n\nfunction parseNumber(text: string): number | undefined {\n const value = Number(text);\n return NUMBER_INPUT.test(text) && Number.isFinite(value) ? value : undefined;\n}\n\n/**\n * The local day or moment `text` names — local, as the input meant it,\n * where `new Date(\"2024-03-01\")` would read midnight in UTC.\n */\nfunction parseDate(text: string): Date | undefined {\n const match = DATE_INPUT.exec(text);\n if (match === null) {\n return undefined;\n }\n const [\n ,\n year,\n month,\n day,\n hours = \"0\",\n minutes = \"0\",\n seconds = \"0\",\n fraction = \"\",\n ] = match;\n if (Number(hours) > 23 || Number(minutes) > 59 || Number(seconds) > 59) {\n return undefined;\n }\n const date = new Date(\n Number(year),\n Number(month) - 1,\n Number(day),\n Number(hours),\n Number(minutes),\n Number(seconds),\n Number(fraction.padEnd(3, \"0\")),\n );\n // A day past the month's end rolls into the next month, and a year below\n // 100 reads as 19xx: either way the date reads back changed.\n return date.getFullYear() === Number(year) &&\n date.getMonth() === Number(month) - 1 &&\n date.getDate() === Number(day)\n ? date\n : undefined;\n}\n\nfunction parseBoolean(text: string): boolean | undefined {\n if (text === \"true\") {\n return true;\n }\n return text === \"false\" ? false : undefined;\n}\n\n/**\n * The operand a condition input's `text` stands for on a column of `type`,\n * read as the column filters — or `undefined` when the text is empty or\n * doesn't read as one, which an editor shows as a value still to fix.\n *\n * - Text is kept as typed, spaces and all.\n * - A number reads with a point for decimals, as a number input gives it:\n * `\"12abc\"` and `\"1,5\"` read as nothing rather than as a guess.\n * - A date reads as a date input gives it, `yyyy-mm-dd`, at that day's\n * local midnight; or as a date-time input does, `yyyy-mm-ddThh:mm`, at\n * that local time.\n * - A boolean reads `\"true\"` or `\"false\"`.\n */\nexport function parseFilterOperand(\n text: string,\n type: ColumnType | undefined,\n): Exclude<FilterScalar, null> | undefined {\n if (text === \"\") {\n return undefined;\n }\n switch (filterOperatorFamily(type)) {\n case \"text\":\n return text;\n case \"number\":\n return parseNumber(text.trim());\n case \"date\":\n return parseDate(text.trim());\n case \"boolean\":\n return parseBoolean(text.trim());\n }\n}\n\nfunction pad(value: number, width = 2): string {\n return String(value).padStart(width, \"0\");\n}\n\n/** `yyyy-mm-dd`, the local day — what a date input takes. */\nfunction dayInput(date: Date): string {\n return `${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\n/** `yyyy-mm-ddThh:mm`, seconds and milliseconds when set — what a date-time input takes. */\nfunction momentInput(date: Date): string {\n const minute = `${dayInput(date)}T${pad(date.getHours())}:${pad(date.getMinutes())}`;\n const seconds = date.getSeconds();\n const milliseconds = date.getMilliseconds();\n if (seconds === 0 && milliseconds === 0) {\n return minute;\n }\n const second = `${minute}:${pad(seconds)}`;\n return milliseconds === 0 ? second : `${second}.${pad(milliseconds, 3)}`;\n}\n\n/**\n * The text a condition input shows for `value` — `parseFilterOperand`'s\n * inverse, for opening a condition already applied. A date reads back in\n * the form its column's input takes: the day alone on a `\"date\"` column,\n * the day and time on a `\"dateTime\"` or `\"time\"` one. A blank operand is\n * empty, and one that isn't a date on a date column — a string set in code\n * that names none — shows as it is, for the user to fix.\n */\nexport function formatFilterOperand(\n value: FilterScalar | undefined,\n type: ColumnType | undefined,\n): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n const date =\n filterOperatorFamily(type) === \"date\" ? toDate(value) : undefined;\n if (date === undefined) {\n return String(value);\n }\n return type === \"date\" ? dayInput(date) : momentInput(date);\n}\n","import type { GridOptions } from \"../options\";\nimport type { ColumnDefinition, FilterOperator } from \"../types\";\nimport type { FilterOperatorFamily } from \"./operators\";\nimport { defaultFilterOperators, filterOperatorFamily } from \"./operators\";\n\n/**\n * Which editor a filter menu opens. Both edit the same `FilterState`, so\n * switching between them keeps every filter applied.\n *\n * - `\"simple\"`: one or two conditions — an operator and a value each —\n * joined by and/or.\n * - `\"excel\"`: a search box over a checklist of the column's values, with\n * the conditions a submenu away.\n */\nexport type FilterMenuUi = \"simple\" | \"excel\";\n\n/** How a grid's filter menus look, unless a column says otherwise. */\nexport interface GridFilterMenuOptions {\n /** Which editor a filter menu opens. Defaults to `\"simple\"`. */\n readonly ui?: FilterMenuUi | undefined;\n /** Whether the excel editor's checklist shows how many rows hold each value. Off by default. */\n readonly showCounts?: boolean | undefined;\n /**\n * How many distinct values the excel editor's checklist lists before it\n * asks for a search first. Defaults to `DEFAULT_FILTER_VALUE_LIMIT`.\n */\n readonly valueLimit?: number | undefined;\n}\n\n/** A column's own filter menu settings, over the grid's `filterMenu`. */\nexport interface ColumnFilterMenuOptions {\n /** Which editor this column's filter menu opens, over the grid's `filterMenu.ui`. */\n readonly ui?: FilterMenuUi | undefined;\n /**\n * The operators this column's conditions offer, in order, in place of its\n * type's `defaultFilterOperators`. `in` is dropped — the checklist is its\n * editor — and `[]` offers no condition, leaving the excel editor its\n * checklist alone.\n */\n readonly operators?: readonly FilterOperator[] | undefined;\n}\n\n/** One column's filter menu with every setting settled — what a renderer draws. */\nexport interface ResolvedColumnFilterMenu {\n readonly ui: FilterMenuUi;\n /** The operators its conditions offer, in order. Never `in`. */\n readonly operators: readonly FilterOperator[];\n /** The family the column's `type` falls in, which its operators are labelled by. */\n readonly family: FilterOperatorFamily;\n readonly showCounts: boolean;\n readonly valueLimit: number;\n}\n\n/**\n * How many distinct values a checklist lists before asking for a search —\n * Excel's own cap. The list is virtualized, so what this bounds is counting\n * the values, not drawing them.\n */\nexport const DEFAULT_FILTER_VALUE_LIMIT = 10_000;\n\n/** `operators` without `in`, and itself when it has none, so it keeps its identity. */\nfunction conditionOperators(\n operators: readonly FilterOperator[],\n): readonly FilterOperator[] {\n return operators.includes(\"in\")\n ? operators.filter((operator) => operator !== \"in\")\n : operators;\n}\n\n/**\n * The filter menu `column` opens, or `null` when it has none: a column is\n * filterable when its own `filterable` says so, else when the grid's\n * `filterableColumns` does — off unless one of them turns it on, as\n * `sortable` is. The column's `filterMenu` settings win over the grid's\n * one by one; what neither sets takes its default.\n */\nexport function resolveColumnFilterMenu(\n options: Pick<GridOptions<unknown>, \"filterableColumns\" | \"filterMenu\">,\n column: Pick<\n ColumnDefinition<unknown, unknown>,\n \"type\" | \"filterable\" | \"filterMenu\"\n >,\n): ResolvedColumnFilterMenu | null {\n if (!(column.filterable ?? options.filterableColumns ?? false)) {\n return null;\n }\n const grid = options.filterMenu;\n const own = column.filterMenu;\n return {\n ui: own?.ui ?? grid?.ui ?? \"simple\",\n operators: conditionOperators(\n own?.operators ?? defaultFilterOperators(column.type),\n ),\n family: filterOperatorFamily(column.type),\n showCounts: grid?.showCounts ?? false,\n valueLimit: grid?.valueLimit ?? DEFAULT_FILTER_VALUE_LIMIT,\n };\n}\n","import type { FilterOperatorFamily } from \"./filterMenu/operators\";\nimport type { FilterOperator, SortDirection } from \"./types\";\nimport type { FormatLocale } from \"./util/format\";\n\n/**\n * Every string a grid shows or announces of its own — the pager, the group-by\n * bar, the loading row, the text of a boolean or missing value, the labels of\n * its built-in commands, the names of its menus, toolbar and column chooser,\n * and the live-region\n * announcements — so a grid can\n * speak a language other than English. A message that names something takes\n * a function, so a translation can put the name where its own grammar wants\n * it.\n *\n * Text the data supplies (cells, headers, labels) is not here: it is already\n * the app's to choose. Nor is formatting — dates and numbers follow\n * `locale`, and so do the counts the defaults print: \"1,204 of 10,000 rows\"\n * under `\"en\"`, \"1.204 of 10.000 rows\" under `\"de-DE\"`.\n */\nexport interface GridMessages {\n /** The pager's accessible name. */\n pagerLabel: string;\n /** The pager button to the first page; drawn as an icon, so this is its accessible name. */\n firstPage: string;\n /** The pager button to the previous page; its accessible name. */\n previousPage: string;\n /** The pager button to the next page; its accessible name. */\n nextPage: string;\n /** The pager button to the last page; its accessible name. */\n lastPage: string;\n /** The page-size control's label. */\n pageSizeLabel: string;\n /** A numbered pager button's accessible name. */\n pageButtonLabel: (page: number) => string;\n /**\n * The compact pager's status, and what a page change announces. `page`\n * counts from one, and is `0` while there are no pages.\n */\n pageStatus: (page: number, pageCount: number) => string;\n /** The row shown while `infiniteScroll` loads more. */\n loadingMore: string;\n /** A boolean cell's text. */\n booleanTrue: string;\n booleanFalse: string;\n /** What a group header names a group of missing values. */\n blankGroupValue: string;\n /** The group-by bar's accessible name. */\n groupByBarLabel: string;\n /** Shown in an empty group-by bar a header can be dragged into. */\n groupByBarPlaceholder: string;\n /** A group-by chip's accessible name. `level` counts from one. */\n groupByChipLabel: (\n columnName: string,\n level: number,\n levelCount: number,\n ) => string;\n /** A group-by chip's remove button's accessible name. */\n removeGroupBy: (columnName: string) => string;\n /** Announced when a resize ends, `width` in whole pixels. */\n columnResized: (columnName: string, width: number) => string;\n /** Announced when a column is moved. `position` counts from one. */\n columnMoved: (\n columnName: string,\n position: number,\n columnCount: number,\n ) => string;\n /** Announced when a column is sorted. `key` is its place in the sort, from one. */\n columnSorted: (\n columnName: string,\n direction: SortDirection,\n key: number,\n keyCount: number,\n ) => string;\n /** Announced when a column leaves the sort. */\n sortCleared: (columnName: string) => string;\n /** Announced when a column is grouped by. `level` counts from one. */\n groupedBy: (columnName: string, level: number, levelCount: number) => string;\n /** Announced when a column leaves the grouping. */\n groupingRemoved: (columnName: string) => string;\n groupExpanded: string;\n groupCollapsed: string;\n allGroupsExpanded: string;\n allGroupsCollapsed: string;\n /** Announced when one change selects or deselects more than one row or column. */\n selectedCount: (count: number, target: \"rows\" | \"columns\") => string;\n /** Announced when a cell is selected. `rowNumber` counts from one. */\n cellSelected: (columnName: string, rowNumber: number) => string;\n /** Announced when one column is hidden. */\n columnHidden: (columnName: string) => string;\n /** Announced when one column is shown. */\n columnShown: (columnName: string) => string;\n /** Announced when one change hides more than one column. */\n columnsHidden: (count: number) => string;\n /** Announced when one change shows more than one column. */\n columnsShown: (count: number) => string;\n /**\n * Announced when one action autofits more than one column, as\n * `column.autoFitAll` does, in place of each column's `columnResized`.\n */\n columnsAutoFitted: (count: number) => string;\n /** A column header's context menu's accessible name. */\n headerMenuLabel: (columnName: string) => string;\n /** A data cell's context menu's accessible name — a menu for its row. */\n cellMenuLabel: string;\n /** A group header row's context menu's accessible name. */\n groupMenuLabel: string;\n /** The accessible name of the menu in the body's empty space. */\n bodyMenuLabel: string;\n /** The built-in `sort.ascending` command's label. */\n sortAscending: string;\n sortDescending: string;\n /** `sort.clear`: takes one column out of the sort. */\n clearSort: string;\n /** `sort.clearAll` */\n clearAllSorting: string;\n /** `group.add`, naming the column it groups by. */\n groupByColumn: (columnName: string) => string;\n /** `group.clearAll`. `group.remove` reads `removeGroupBy`, as the group-by chip's button does. */\n ungroupAll: string;\n expandAllGroups: string;\n collapseAllGroups: string;\n /** `column.hide` */\n hideColumn: string;\n /** `column.autoFit`: sizes the column to its content. */\n autoFitColumn: string;\n autoFitAllColumns: string;\n /** `selection.selectAllRows` */\n selectAllRows: string;\n /** `selection.clear` */\n clearSelection: string;\n /** `filter.clearAll`, which clears the search too. */\n clearFilters: string;\n /** `column.choose`, which opens the column chooser. */\n chooseColumns: string;\n /** The toolbar's accessible name, unless its `label` gives one. */\n toolbarLabel: string;\n /** The toolbar's search box's accessible name. */\n searchLabel: string;\n /** Shown in the toolbar's empty search box. */\n searchPlaceholder: string;\n /** The toolbar's \"More\" button, holding the items that do not fit. */\n moreToolbarItems: string;\n /** Announced when a search settles: how many rows it found. */\n searchResults: (count: number) => string;\n /** The column chooser's accessible name. */\n columnChooserLabel: string;\n /** The column chooser's search box's accessible name. */\n columnChooserSearchLabel: string;\n /** The column chooser's checkbox showing or hiding every column its search lists. */\n showAllColumns: string;\n /** Shown in the column chooser when its search matches no column. */\n noMatchingColumns: string;\n /**\n * A condition's operator, as a filter menu lists it. `family` is the\n * column's (`filterOperatorFamily`), so a date can read `lt` as \"Before\"\n * where a number reads \"Less than\".\n */\n filterOperatorLabel: (\n operator: FilterOperator,\n family: FilterOperatorFamily,\n ) => string;\n /** A filter checklist's item for the column's blank cells. */\n filterBlanks: string;\n /**\n * Shown in place of a filter checklist whose column holds more values\n * than `filterMenu.valueLimit`, until something is searched.\n */\n filterSearchFirst: (total: number) => string;\n /** Shown under a searched filter checklist `filterMenu.valueLimit` cut short: how many matches it left out. */\n filterMoreValues: (count: number) => string;\n /** `filter.open`, which opens a column's filter menu. */\n openFilter: string;\n /** `filter.clear`, and the filter menu's button doing the same: clears one column's filter. */\n clearColumnFilter: string;\n /** A column's filter menu's accessible name. */\n filterMenuLabel: (columnName: string) => string;\n /** What a column header is described as while its column is filtered. */\n columnFiltered: string;\n /** The filter menu's button applying what it holds. */\n applyFilter: string;\n /** The filter menu's button closing it without applying. */\n cancelFilter: string;\n /**\n * Shown in a filter menu for a filter its editor cannot show — a\n * predicate, a text query, a group across columns — which applying\n * replaces.\n */\n customFilter: string;\n /** Announced when a filter menu applies: how many rows the filter keeps, of how many. */\n filterResults: (shown: number, total: number) => string;\n /** The accessible name of one of a filter menu's conditions. `position` counts from one. */\n filterConditionLabel: (position: number) => string;\n /** The accessible name of a condition's operator picker. */\n filterOperatorFieldLabel: string;\n /** The accessible name of a condition's value box. */\n filterValueLabel: string;\n /** The accessible name of a `between` condition's first value box, its lower end. */\n filterFromLabel: string;\n /** The accessible name of a `between` condition's second value box, its upper end. */\n filterToLabel: string;\n /** The accessible name of the choice joining a filter menu's two conditions. */\n filterCombinatorLabel: string;\n /** Joins two conditions: a row has to meet both. */\n filterAnd: string;\n /** Joins two conditions: a row has to meet either. */\n filterOr: string;\n /**\n * Shown under a filter menu's conditions when one's value is missing or\n * doesn't read as its column's `family` (`filterOperatorFamily`) — \"Enter\n * a number\" on a number column.\n */\n filterValueInvalid: (family: FilterOperatorFamily) => string;\n /** The accessible name of a filter checklist's search box. */\n filterSearchLabel: string;\n /** The checkbox above a filter checklist checking every value its search shows. */\n filterSelectAll: string;\n /** The accessible name of a filter checklist's list of values. */\n filterValuesLabel: string;\n /**\n * Shown above a filter checklist whose column is filtered by conditions,\n * which checking values replaces.\n */\n filterByCondition: string;\n /**\n * The excel editor's button opening the conditions its column offers, and\n * that menu's accessible name — \"Number filters\" on a number column, by\n * its `family` (`filterOperatorFamily`).\n */\n filterOperatorMenu: (family: FilterOperatorFamily) => string;\n /** The button taking the excel editor from a condition back to its checklist. */\n filterBackToValues: string;\n /** The toolbar's `\"export\"` dropdown, listing the export commands. */\n exportMenu: string;\n /** `export.csv` */\n exportCsv: string;\n /** `export.json` */\n exportJson: string;\n /** `export.xlsx`, shown once an xlsx writer is registered. */\n exportXlsx: string;\n /** `export.pdf`, shown once a PDF writer is registered. */\n exportPdf: string;\n /** `exportSelection.csv`: the selected rows only. */\n exportSelectionCsv: string;\n /** `exportSelection.json` */\n exportSelectionJson: string;\n /** `exportSelection.xlsx` */\n exportSelectionXlsx: string;\n /** Announced when an export's writer fails, so no file is saved. */\n exportFailed: string;\n /** `copy.cell` */\n copyCell: string;\n /** `copy.row` */\n copyRow: string;\n /** `copy.selection` */\n copySelection: string;\n /** Announced once a copy is on the clipboard. */\n copied: (count: number, unit: \"cells\" | \"rows\" | \"columns\") => string;\n /** Announced when the browser refuses the clipboard, so nothing was copied. */\n copyFailed: string;\n /** `print` */\n print: string;\n}\n\n/** Prints a count — \"1,204\" under `\"en\"`, \"1.204\" under `\"de-DE\"`. */\ntype CountFormat = (count: number) => string;\n\nfunction localeKey(locale: FormatLocale): string {\n return typeof locale === \"string\" ? locale : (locale?.join(\",\") ?? \"\");\n}\n\n/**\n * Count formats already built, one per locale: building an\n * `Intl.NumberFormat` costs far more than using one.\n */\nconst countFormats = new Map<string, CountFormat>();\n\n/** A count in `locale`'s digits and separators, whole — a count has no fraction. */\nfunction countFormat(locale: FormatLocale): CountFormat {\n const key = localeKey(locale);\n let format = countFormats.get(key);\n if (format === undefined) {\n const numberFormat = new Intl.NumberFormat(locale, {\n maximumFractionDigits: 0,\n });\n format = (count) => numberFormat.format(count);\n countFormats.set(key, format);\n }\n return format;\n}\n\n/** \"3 columns hidden\", \"1 column shown\", \"2 columns autofitted\". */\nfunction columnCount(\n n: CountFormat,\n count: number,\n change: \"hidden\" | \"shown\" | \"autofitted\",\n): string {\n return count === 1 ? `1 column ${change}` : `${n(count)} columns ${change}`;\n}\n\n/** \"3 rows found\", \"1 row found\", \"No rows found\". */\nfunction searchResults(n: CountFormat, count: number): string {\n if (count === 0) {\n return \"No rows found\";\n }\n return count === 1 ? \"1 row found\" : `${n(count)} rows found`;\n}\n\n/** \"3 rows selected\", \"1 column selected\", \"No rows selected\". */\nfunction selectedCount(\n n: CountFormat,\n count: number,\n target: \"rows\" | \"columns\",\n): string {\n const noun = target === \"rows\" ? \"row\" : \"column\";\n if (count === 0) {\n return `No ${noun}s selected`;\n }\n return count === 1 ? `1 ${noun} selected` : `${n(count)} ${noun}s selected`;\n}\n\nconst operatorLabels: Readonly<Record<FilterOperator, string>> = {\n eq: \"Equals\",\n ne: \"Does not equal\",\n contains: \"Contains\",\n notContains: \"Does not contain\",\n startsWith: \"Starts with\",\n endsWith: \"Ends with\",\n gt: \"Greater than\",\n gte: \"Greater than or equal to\",\n lt: \"Less than\",\n lte: \"Less than or equal to\",\n between: \"Between\",\n in: \"Is one of\",\n isEmpty: \"Is blank\",\n isNotEmpty: \"Is not blank\",\n};\n\n/** Where a date's order reads as time rather than size. */\nconst dateOperatorLabels: Readonly<Partial<Record<FilterOperator, string>>> = {\n lt: \"Before\",\n lte: \"On or before\",\n gt: \"After\",\n gte: \"On or after\",\n};\n\n/** \"Before\" on a date, \"Less than\" on a number, \"Contains\" on either. */\nfunction filterOperatorLabel(\n operator: FilterOperator,\n family: FilterOperatorFamily,\n): string {\n return (\n (family === \"date\" ? dateOperatorLabels[operator] : undefined) ??\n operatorLabels[operator]\n );\n}\n\n/** \"Type to search 12,000 values\", \"Type to search 1 value\". */\nfunction filterSearchFirst(n: CountFormat, total: number): string {\n return total === 1\n ? \"Type to search 1 value\"\n : `Type to search ${n(total)} values`;\n}\n\n/** \"1,204 of 10,000 rows\", \"1 of 1 row\". */\nfunction filterResults(n: CountFormat, shown: number, total: number): string {\n return `${n(shown)} of ${n(total)} ${total === 1 ? \"row\" : \"rows\"}`;\n}\n\n/** What a condition's value box asks for, by the kind of value its column holds. */\nconst filterValueRequests: Readonly<Record<FilterOperatorFamily, string>> = {\n text: \"Enter a value\",\n number: \"Enter a number\",\n date: \"Enter a date\",\n boolean: \"Choose a value\",\n};\n\n/** The excel editor's menu of conditions, by the kind of value its column holds. */\nconst filterOperatorMenus: Readonly<Record<FilterOperatorFamily, string>> = {\n text: \"Text filters\",\n number: \"Number filters\",\n date: \"Date filters\",\n boolean: \"Boolean filters\",\n};\n\n/** \"1 cell copied\", \"3 rows copied\", \"2 columns copied\". */\nfunction copied(\n n: CountFormat,\n count: number,\n unit: \"cells\" | \"rows\" | \"columns\",\n): string {\n return count === 1\n ? `1 ${unit.slice(0, -1)} copied`\n : `${n(count)} ${unit} copied`;\n}\n\n/**\n * The grid's own English, its counts printed in `locale`'s digits —\n * \"1,204 of 10,000 rows\" under `\"en\"`, \"1.204 of 10.000 rows\" under\n * `\"de-DE\"`. Without a locale, the runtime's own; that one is\n * `defaultMessages`.\n */\nexport function createDefaultMessages(locale?: FormatLocale): GridMessages {\n const n = countFormat(locale);\n return {\n pagerLabel: \"Pagination\",\n firstPage: \"First\",\n previousPage: \"Previous\",\n nextPage: \"Next\",\n lastPage: \"Last\",\n pageSizeLabel: \"Rows per page\",\n pageButtonLabel: (page) => `Page ${n(page)}`,\n pageStatus: (page, pageCount) => `Page ${n(page)} of ${n(pageCount)}`,\n loadingMore: \"Loading more…\",\n booleanTrue: \"true\",\n booleanFalse: \"false\",\n blankGroupValue: \"(blank)\",\n groupByBarLabel: \"Grouped by\",\n groupByBarPlaceholder: \"Drag a column here to group by it\",\n groupByChipLabel: (columnName, level, levelCount) =>\n levelCount > 1\n ? `${columnName}, level ${n(level)} of ${n(levelCount)}`\n : columnName,\n removeGroupBy: (columnName) => `Stop grouping by ${columnName}`,\n columnResized: (columnName, width) =>\n `${columnName}, ${n(width)} pixels wide`,\n columnMoved: (columnName, position, columnCount) =>\n `${columnName}, column ${n(position)} of ${n(columnCount)}`,\n columnSorted: (columnName, direction, key, keyCount) => {\n const sorted = `${columnName} sorted ${direction === \"asc\" ? \"ascending\" : \"descending\"}`;\n return keyCount > 1\n ? `${sorted}, key ${n(key)} of ${n(keyCount)}`\n : sorted;\n },\n sortCleared: (columnName) => `${columnName}, sort cleared`,\n groupedBy: (columnName, level, levelCount) =>\n levelCount > 1\n ? `Grouped by ${columnName}, level ${n(level)} of ${n(levelCount)}`\n : `Grouped by ${columnName}`,\n groupingRemoved: (columnName) => `${columnName}, grouping removed`,\n groupExpanded: \"Group expanded\",\n groupCollapsed: \"Group collapsed\",\n allGroupsExpanded: \"All groups expanded\",\n allGroupsCollapsed: \"All groups collapsed\",\n selectedCount: (count, target) => selectedCount(n, count, target),\n cellSelected: (columnName, rowNumber) =>\n `${columnName}, row ${n(rowNumber)}, selected`,\n columnHidden: (columnName) => `${columnName}, column hidden`,\n columnShown: (columnName) => `${columnName}, column shown`,\n columnsHidden: (count) => columnCount(n, count, \"hidden\"),\n columnsShown: (count) => columnCount(n, count, \"shown\"),\n columnsAutoFitted: (count) => columnCount(n, count, \"autofitted\"),\n headerMenuLabel: (columnName) => `${columnName} column menu`,\n cellMenuLabel: \"Row menu\",\n groupMenuLabel: \"Group menu\",\n bodyMenuLabel: \"Grid menu\",\n sortAscending: \"Sort ascending\",\n sortDescending: \"Sort descending\",\n clearSort: \"Clear sort\",\n clearAllSorting: \"Clear all sorting\",\n groupByColumn: (columnName) => `Group by ${columnName}`,\n ungroupAll: \"Ungroup all\",\n expandAllGroups: \"Expand all groups\",\n collapseAllGroups: \"Collapse all groups\",\n hideColumn: \"Hide column\",\n autoFitColumn: \"Autofit column\",\n autoFitAllColumns: \"Autofit all columns\",\n selectAllRows: \"Select all rows\",\n clearSelection: \"Clear selection\",\n clearFilters: \"Clear filters\",\n chooseColumns: \"Choose columns\",\n toolbarLabel: \"Grid toolbar\",\n searchLabel: \"Search\",\n searchPlaceholder: \"Search…\",\n moreToolbarItems: \"More\",\n searchResults: (count) => searchResults(n, count),\n columnChooserLabel: \"Columns\",\n columnChooserSearchLabel: \"Search columns\",\n showAllColumns: \"Show all\",\n noMatchingColumns: \"No matching columns\",\n filterOperatorLabel,\n filterBlanks: \"(Blanks)\",\n filterSearchFirst: (total) => filterSearchFirst(n, total),\n filterMoreValues: (count) => `${n(count)} more, refine the search`,\n openFilter: \"Filter…\",\n clearColumnFilter: \"Clear filter\",\n filterMenuLabel: (columnName) => `${columnName} filter`,\n columnFiltered: \"Filtered\",\n applyFilter: \"OK\",\n cancelFilter: \"Cancel\",\n customFilter: \"Custom filter\",\n filterResults: (shown, total) => filterResults(n, shown, total),\n filterConditionLabel: (position) => `Condition ${n(position)}`,\n filterOperatorFieldLabel: \"Operator\",\n filterValueLabel: \"Value\",\n filterFromLabel: \"From\",\n filterToLabel: \"To\",\n filterCombinatorLabel: \"Combine conditions\",\n filterAnd: \"And\",\n filterOr: \"Or\",\n filterValueInvalid: (family) => filterValueRequests[family],\n filterSearchLabel: \"Search values\",\n filterSelectAll: \"Select all\",\n filterValuesLabel: \"Values\",\n filterByCondition: \"Filtered by condition\",\n filterOperatorMenu: (family) => filterOperatorMenus[family],\n filterBackToValues: \"Back to values\",\n exportMenu: \"Export\",\n exportCsv: \"Export to CSV\",\n exportJson: \"Export to JSON\",\n exportXlsx: \"Export to Excel\",\n exportPdf: \"Export to PDF\",\n exportSelectionCsv: \"Export selection to CSV\",\n exportSelectionJson: \"Export selection to JSON\",\n exportSelectionXlsx: \"Export selection to Excel\",\n exportFailed: \"Export failed\",\n copyCell: \"Copy cell\",\n copyRow: \"Copy row\",\n copySelection: \"Copy selection\",\n copied: (count, unit) => copied(n, count, unit),\n copyFailed: \"Copy failed\",\n print: \"Print\",\n };\n}\n\n/** The grid's own English, which `messages` replaces key by key. */\nexport const defaultMessages: GridMessages = createDefaultMessages();\n\n/** The defaults made for each `locale` so far — one object per locale. */\nconst localeDefaults = new Map<string, GridMessages>();\n\nfunction defaultsFor(locale: FormatLocale): GridMessages {\n if (locale === undefined) {\n return defaultMessages;\n }\n const key = localeKey(locale);\n let defaults = localeDefaults.get(key);\n if (defaults === undefined) {\n defaults = createDefaultMessages(locale);\n localeDefaults.set(key, defaults);\n }\n return defaults;\n}\n\n/**\n * `messages` over the defaults for `locale` — every key the grid needs,\n * whichever the caller gave, the defaults counting in `locale`'s digits. The\n * defaults themselves, same object for the same locale, when it gave none, so\n * a renderer memoising on the result does not see a change that is not one.\n */\nexport function resolveMessages(\n messages: Partial<GridMessages> | undefined,\n locale?: FormatLocale,\n): GridMessages {\n const defaults = defaultsFor(locale);\n return messages === undefined ? defaults : { ...defaults, ...messages };\n}\n","import type { GridMessages } from \"../messages\";\nimport { resolveMessages } from \"../messages\";\nimport type {\n ColumnType,\n DataColumn,\n FilterEntry,\n FilterScalar,\n FilterState,\n OperatorFilterEntry,\n} from \"../types\";\nimport { filterValueKey, isEmptyCell, isScalarList } from \"./filterOperators\";\nimport { compileFilter } from \"./filtering\";\nimport type { FormatLocale } from \"./format\";\nimport { formatCellValue } from \"./format\";\nimport { accessDotted } from \"./grid\";\nimport { compareValues } from \"./sorting\";\n\n/**\n * What one column's filter looks like to an editor — which of its forms can\n * show it, or that none can.\n *\n * - `\"none\"`: no entry touches the column.\n * - `\"values\"`: a checklist — one `in` entry, optionally OR-grouped with an\n * `isEmpty` on the same column (`includeBlanks`).\n * - `\"conditions\"`: one or two operator entries on the column (any but\n * `in`), at the top level (ANDed) or alone in one group with its\n * combinator.\n * - `\"custom\"`: anything else that touches the column — a text query, a\n * predicate, a group spanning several columns. An editor shows it as\n * such, and applying an editor's draft replaces it.\n */\nexport type ColumnFilterShape<Row> =\n | { readonly kind: \"none\" }\n | {\n readonly kind: \"values\";\n readonly values: readonly FilterScalar[];\n readonly includeBlanks: boolean;\n }\n | {\n readonly kind: \"conditions\";\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n readonly combinator: \"and\" | \"or\";\n }\n | { readonly kind: \"custom\" };\n\n/** One distinct value a column holds, as a checklist offers it. */\nexport interface ColumnValueOption {\n readonly value: Exclude<FilterScalar, null>;\n /** The value as the column prints it — what a search matches against. */\n readonly label: string;\n /** How many rows hold it, among the rows the other columns' filters keep. */\n readonly count: number;\n}\n\n/** What `columnValueOptions` narrows its list by. */\nexport interface ColumnValueQuery {\n /** Keeps the values whose label contains this, ignoring case. */\n readonly search?: string;\n /** Keeps at most this many values, first in sorted order. */\n readonly limit?: number;\n /** The locale labels are formatted for — the grid's own `locale`. */\n readonly locale?: FormatLocale;\n /**\n * The grid's own `messages`, over the defaults: a boolean is labelled\n * `booleanTrue`/`booleanFalse`, as its cells print it.\n */\n readonly messages?: Partial<GridMessages>;\n}\n\nexport interface ColumnValueOptions {\n /** The distinct values, sorted as the column sorts, searched and cut to `limit`. */\n readonly options: readonly ColumnValueOption[];\n /** How many values matched the search, before `limit` cut them. */\n readonly total: number;\n /** Whether `limit` left values out. */\n readonly truncated: boolean;\n /** How many of the same rows hold a blank — `null`, `undefined` or `\"\"`. */\n readonly blanks: number;\n /**\n * The column's `type`, which tells values apart the way an `in` filter\n * does — on a date column, a date string and the `Date` it names are one\n * value. `initialFilterEditorDraft` carries it into the draft.\n */\n readonly columnType?: ColumnType | undefined;\n}\n\n/**\n * A checklist or condition editor's working copy of one column's filter,\n * changed by `filterEditorReducer` and turned into a filter by\n * `draftToFilter` only when the user applies it — so cancelling is just\n * dropping the draft.\n */\nexport interface FilterEditorDraft<Row> {\n /** Which half of the draft `draftToFilter` applies: the last one changed. */\n readonly mode: \"values\" | \"conditions\";\n /** Every value the editor offers, from `columnValueOptions`. */\n readonly options: readonly ColumnValueOption[];\n /** How many rows hold a blank; the blanks entry only matters when some do. */\n readonly blanks: number;\n readonly search: string;\n /** The checked values, keyed as an `in` filter on the column keys them. */\n readonly checked: ReadonlyMap<string, FilterScalar>;\n readonly includeBlanks: boolean;\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n readonly combinator: \"and\" | \"or\";\n /** The column's `type`, from `ColumnValueOptions` — what values are keyed by. */\n readonly columnType?: ColumnType | undefined;\n}\n\nexport type FilterEditorAction<Row> =\n | { readonly type: \"search\"; readonly search: string }\n | { readonly type: \"toggleValue\"; readonly value: FilterScalar }\n /** Checks every value the search shows, or unchecks them once all are. */\n | { readonly type: \"toggleAll\" }\n | { readonly type: \"setIncludeBlanks\"; readonly includeBlanks: boolean }\n | {\n readonly type: \"setConditions\";\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n /** Keeps the draft's own when omitted. */\n readonly combinator?: \"and\" | \"or\";\n }\n /** Back to \"no filter\": every value checked, no conditions, no search. */\n | { readonly type: \"clear\" };\n\n/** A select-all checkbox's state over the values the search shows. */\nexport type SelectAllState = \"checked\" | \"unchecked\" | \"mixed\";\n\n/**\n * Whether `entry` is about `columnId`: names it, or is a group with an entry\n * anywhere inside that does. An entry across every column is about none.\n */\nexport function touchesColumn<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): boolean {\n return \"combinator\" in entry\n ? entry.entries.some((nested) => touchesColumn(nested, columnId))\n : entry.columnId === columnId;\n}\n\nfunction isOperatorOn<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): entry is OperatorFilterEntry<Row> {\n return \"operator\" in entry && entry.columnId === columnId;\n}\n\n/** An operator entry on `columnId` a condition editor can show: any but `in`. */\nfunction isConditionOn<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): entry is OperatorFilterEntry<Row> {\n return isOperatorOn(entry, columnId) && entry.operator !== \"in\";\n}\n\n/** `entry` as a checklist, when it is the `in` (+ `isEmpty`) one stores. */\nfunction valuesShape<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): ColumnFilterShape<Row> | undefined {\n const values = (candidate: FilterEntry<Row> | undefined) =>\n candidate !== undefined &&\n isOperatorOn(candidate, columnId) &&\n candidate.operator === \"in\" &&\n isScalarList(candidate.value)\n ? candidate.value\n : undefined;\n const blanks = (candidate: FilterEntry<Row> | undefined) =>\n candidate !== undefined &&\n isOperatorOn(candidate, columnId) &&\n candidate.operator === \"isEmpty\";\n\n const alone = values(entry);\n if (alone !== undefined) {\n return { kind: \"values\", values: alone, includeBlanks: false };\n }\n if (\n !(\"combinator\" in entry) ||\n entry.combinator !== \"or\" ||\n entry.entries.length !== 2\n ) {\n return undefined;\n }\n const [first, second] = entry.entries;\n const listed = blanks(first) ? values(second) : values(first);\n return listed !== undefined && (blanks(first) || blanks(second))\n ? { kind: \"values\", values: listed, includeBlanks: true }\n : undefined;\n}\n\n/** `touching` as one or two conditions, when that is all it is. */\nfunction conditionsShape<Row>(\n touching: FilterState<Row>,\n columnId: string,\n): ColumnFilterShape<Row> | undefined {\n const [only] = touching;\n const grouped =\n touching.length === 1 && only !== undefined && \"combinator\" in only;\n const entries = grouped ? only.entries : touching;\n const combinator = grouped ? only.combinator : \"and\";\n if (entries.length === 0 || entries.length > 2) {\n return undefined;\n }\n const conditions = entries.filter((entry) => isConditionOn(entry, columnId));\n return conditions.length === entries.length\n ? { kind: \"conditions\", conditions, combinator }\n : undefined;\n}\n\n/**\n * How `filter` filters `columnId`, as one of the forms an editor can show —\n * see `ColumnFilterShape`. Entries about other columns don't count, nor do\n * entries across every column (a global search).\n */\nexport function describeColumnFilter<Row>(\n filter: FilterState<Row>,\n columnId: string,\n): ColumnFilterShape<Row> {\n const touching = filter.filter((entry) => touchesColumn(entry, columnId));\n const [only] = touching;\n if (only === undefined) {\n return { kind: \"none\" };\n }\n return (\n (touching.length === 1 ? valuesShape(only, columnId) : undefined) ??\n conditionsShape(touching, columnId) ?? { kind: \"custom\" }\n );\n}\n\n/**\n * Whether `filter` filters `columnId` — whether `describeColumnFilter` reads\n * it as anything but `\"none\"` — for a header to show its column as\n * filtered. A global search filters every column alike, so it marks none.\n */\nexport function isColumnFiltered<Row>(\n filter: FilterState<Row>,\n columnId: string,\n): boolean {\n return filter.some((entry) => touchesColumn(entry, columnId));\n}\n\n/**\n * A value a checklist can offer: an `in` entry can hold it. An object or an\n * array in a cell can't be, so it isn't offered.\n */\nfunction isOfferable(value: unknown): value is Exclude<FilterScalar, null> {\n return (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value instanceof Date\n );\n}\n\nfunction matchesSearch(label: string, search: string): boolean {\n return label.toLowerCase().includes(search.toLowerCase());\n}\n\ninterface Bucket<Row> {\n readonly value: Exclude<FilterScalar, null>;\n /** The first row holding it, for a `valueFormatter` that reads the row. */\n readonly row: Row;\n count: number;\n}\n\n/**\n * The distinct values `columnId` holds, for a checklist editor: each with\n * its label and how many rows hold it.\n *\n * Counted over the rows every *other* column's filter keeps — every entry\n * except those `describeColumnFilter` would count for this column — so a\n * column's list cascades from the other filters without its own pick\n * hiding the values the user unchecked. Values are told apart as an `in`\n * filter tells them apart — as grouping does, except that a date column's\n * date strings are the dates they name — ordered as the column sorts, and\n * labelled as its cells print, a boolean in `query.messages`' words; blanks\n * are counted apart, in `blanks`.\n *\n * Costs one pass over `rows` (tens of milliseconds at 100k rows), so compute\n * it when an editor opens rather than on every render, and hand the whole\n * list to `initialFilterEditorDraft`, whose search needs no recount.\n */\nexport function columnValueOptions<Row>(\n rows: readonly Row[],\n dataColumns: readonly DataColumn<Row, unknown>[],\n filter: FilterState<Row>,\n columnId: string,\n query: ColumnValueQuery = {},\n): ColumnValueOptions {\n const column = dataColumns.find((entry) => entry.id === columnId)?.column;\n if (column === undefined) {\n return { options: [], total: 0, truncated: false, blanks: 0 };\n }\n const keep = compileFilter(\n filter.filter((entry) => !touchesColumn(entry, columnId)),\n dataColumns,\n );\n\n const buckets = new Map<string, Bucket<Row>>();\n let blanks = 0;\n for (const row of rows) {\n if (keep !== undefined && !keep(row)) {\n continue;\n }\n const value = accessDotted(row, column.field);\n if (isEmptyCell(value)) {\n blanks++;\n } else if (isOfferable(value)) {\n const key = filterValueKey(value, column.type);\n const bucket = buckets.get(key);\n if (bucket === undefined) {\n buckets.set(key, { value, row, count: 1 });\n } else {\n bucket.count++;\n }\n }\n }\n\n const { search = \"\", limit, locale } = query;\n const messages = resolveMessages(query.messages, locale);\n const options = [...buckets.values()]\n .sort((a, b) => compareValues(a.value, b.value, column.type))\n .map(({ value, row, count }) => ({\n value,\n label: formatCellValue(value, column, locale, row, messages),\n count,\n }))\n .filter((option) => matchesSearch(option.label, search));\n const shown = limit === undefined ? options : options.slice(0, limit);\n return {\n options: shown,\n total: options.length,\n truncated: shown.length < options.length,\n blanks,\n columnType: column.type,\n };\n}\n\n/** The key `draft.checked` holds `value` under. */\nexport function keyOf<Row>(\n draft: Pick<FilterEditorDraft<Row>, \"columnType\">,\n value: FilterScalar,\n): string {\n return filterValueKey(value, draft.columnType);\n}\n\nfunction everyOption<Row>(\n draft: Pick<FilterEditorDraft<Row>, \"columnType\" | \"options\">,\n): ReadonlyMap<string, FilterScalar> {\n return new Map(\n draft.options.map((option) => [keyOf(draft, option.value), option.value]),\n );\n}\n\n/**\n * A draft showing `shape` over `values` — what an editor opens with. A\n * column with no filter, or one only a custom editor could show, opens with\n * every value checked; a checklist with its own values checked, kept even\n * when the other filters now hide them; conditions as they are.\n */\nexport function initialFilterEditorDraft<Row>(\n shape: ColumnFilterShape<Row>,\n values: ColumnValueOptions,\n): FilterEditorDraft<Row> {\n const draft: FilterEditorDraft<Row> = {\n mode: \"values\",\n options: values.options,\n blanks: values.blanks,\n search: \"\",\n checked: everyOption(values),\n includeBlanks: values.blanks > 0,\n conditions: [],\n combinator: \"and\",\n columnType: values.columnType,\n };\n switch (shape.kind) {\n case \"values\":\n return {\n ...draft,\n checked: new Map(\n shape.values\n .filter((value) => !isEmptyCell(value))\n .map((value) => [keyOf(draft, value), value]),\n ),\n includeBlanks: shape.includeBlanks,\n };\n case \"conditions\":\n return {\n ...draft,\n mode: \"conditions\",\n conditions: shape.conditions,\n combinator: shape.combinator,\n };\n case \"none\":\n case \"custom\":\n return draft;\n }\n}\n\n/** The options the draft's search shows — those a select-all acts on. */\nexport function visibleFilterOptions<Row>(\n draft: FilterEditorDraft<Row>,\n): readonly ColumnValueOption[] {\n return draft.search === \"\"\n ? draft.options\n : draft.options.filter((option) =>\n matchesSearch(option.label, draft.search),\n );\n}\n\n/** Blanks count among what select-all covers only while nothing is searched. */\nexport function selectAllCoversBlanks<Row>(\n draft: FilterEditorDraft<Row>,\n): boolean {\n return draft.search === \"\" && draft.blanks > 0;\n}\n\n/**\n * The select-all checkbox's state: whether every value the search shows is\n * checked, none is, or some are — blanks included while nothing is\n * searched.\n */\nexport function selectAllState<Row>(\n draft: FilterEditorDraft<Row>,\n): SelectAllState {\n const states = visibleFilterOptions(draft).map((option) =>\n draft.checked.has(keyOf(draft, option.value)),\n );\n if (selectAllCoversBlanks(draft)) {\n states.push(draft.includeBlanks);\n }\n if (states.length > 0 && states.every(Boolean)) {\n return \"checked\";\n }\n return states.some(Boolean) ? \"mixed\" : \"unchecked\";\n}\n\nfunction toggleAll<Row>(draft: FilterEditorDraft<Row>): FilterEditorDraft<Row> {\n const check = selectAllState(draft) !== \"checked\";\n const checked = new Map(draft.checked);\n for (const option of visibleFilterOptions(draft)) {\n const key = keyOf(draft, option.value);\n if (check) {\n checked.set(key, option.value);\n } else {\n checked.delete(key);\n }\n }\n return {\n ...draft,\n mode: \"values\",\n checked,\n includeBlanks: selectAllCoversBlanks(draft) ? check : draft.includeBlanks,\n };\n}\n\n/**\n * The next draft after `action` — a plain reducer, so a renderer can hold\n * the draft in whatever state it has (`useReducer`, a signal, a store).\n * Changing a value or the blanks switches the draft to its checklist;\n * setting conditions switches it to them.\n */\nexport function filterEditorReducer<Row>(\n draft: FilterEditorDraft<Row>,\n action: FilterEditorAction<Row>,\n): FilterEditorDraft<Row> {\n switch (action.type) {\n case \"search\":\n return { ...draft, search: action.search };\n case \"toggleValue\": {\n const key = keyOf(draft, action.value);\n const checked = new Map(draft.checked);\n if (checked.has(key)) {\n checked.delete(key);\n } else {\n checked.set(key, action.value);\n }\n return { ...draft, mode: \"values\", checked };\n }\n case \"toggleAll\":\n return toggleAll(draft);\n case \"setIncludeBlanks\":\n return { ...draft, mode: \"values\", includeBlanks: action.includeBlanks };\n case \"setConditions\":\n return {\n ...draft,\n mode: \"conditions\",\n conditions: action.conditions,\n combinator: action.combinator ?? draft.combinator,\n };\n case \"clear\":\n return {\n ...draft,\n search: \"\",\n checked: everyOption(draft),\n includeBlanks: draft.blanks > 0,\n conditions: [],\n };\n }\n}\n\n/**\n * Whether the checklist keeps every row: every offered value checked, and\n * the blanks too when there are any.\n */\nfunction checksEverything<Row>(draft: FilterEditorDraft<Row>): boolean {\n return (\n draft.options.every((option) =>\n draft.checked.has(keyOf(draft, option.value)),\n ) &&\n (draft.includeBlanks || draft.blanks === 0)\n );\n}\n\n/** The entries `draft` stands for on `columnId` — none for \"no filter\". */\nfunction draftEntries<Row>(\n draft: FilterEditorDraft<Row>,\n columnId: string,\n): FilterState<Row> {\n if (draft.mode === \"conditions\") {\n const conditions = draft.conditions.map((condition) => ({\n ...condition,\n columnId,\n }));\n return conditions.length > 1\n ? [{ combinator: draft.combinator, entries: conditions }]\n : conditions;\n }\n if (checksEverything(draft)) {\n return [];\n }\n const picked: OperatorFilterEntry<Row> = {\n columnId,\n operator: \"in\",\n value: [...draft.checked.values()],\n };\n return draft.includeBlanks\n ? [\n {\n combinator: \"or\",\n entries: [picked, { columnId, operator: \"isEmpty\" }],\n },\n ]\n : [picked];\n}\n\n/**\n * `current` with `columnId`'s filter replaced by what `draft` holds — what\n * applying an editor sets. Every entry about the column goes (custom ones\n * included); the draft's entries take the place of the first, so the rest\n * keep their order.\n *\n * A checklist with everything checked is no filter at all, and a partial\n * pick is one `in` entry, OR-grouped with an `isEmpty` when blanks are\n * kept. One condition is stored as itself, two as a group with the\n * draft's combinator. Returns `current` itself when nothing changes.\n */\nexport function draftToFilter<Row>(\n draft: FilterEditorDraft<Row>,\n columnId: string,\n current: FilterState<Row>,\n): FilterState<Row> {\n const replacement = draftEntries(draft, columnId);\n const first = current.findIndex((entry) => touchesColumn(entry, columnId));\n if (first === -1) {\n return replacement.length === 0 ? current : [...current, ...replacement];\n }\n const kept = current.filter((entry) => !touchesColumn(entry, columnId));\n return [...kept.slice(0, first), ...replacement, ...kept.slice(first)];\n}\n","import {\n canCopySelection,\n copyContent,\n type CopyRequest,\n} from \"../export/copy\";\nimport { exportFile } from \"../export/exportFile\";\nimport { exportPrintDocument } from \"../export/print\";\nimport { resolveExportWriters } from \"../export/writer\";\nimport type { GridMessages } from \"../messages\";\nimport { resolveColumnFilterMenu } from \"../filterMenu/options\";\nimport type { DataColumn, SelectableConfig, SortDirection } from \"../types\";\nimport { isColumnFiltered, touchesColumn } from \"../util/filterEditor\";\nimport { resolveColumnHeaderText } from \"../util/grid\";\nimport { sortDirectionFor } from \"../util/sorting\";\nimport type {\n GridCommand,\n GridCommandContext,\n GridCommandTarget,\n} from \"./types\";\n\n/** The id of every command `builtInCommands` returns. */\nexport type BuiltInCommandId =\n | \"sort.ascending\"\n | \"sort.descending\"\n | \"sort.clear\"\n | \"sort.clearAll\"\n | \"group.add\"\n | \"group.remove\"\n | \"group.clearAll\"\n | \"group.expandAll\"\n | \"group.collapseAll\"\n | \"column.hide\"\n | \"column.autoFit\"\n | \"column.autoFitAll\"\n | \"column.choose\"\n | \"filter.open\"\n | \"filter.clear\"\n | \"selection.selectAllRows\"\n | \"selection.clear\"\n | \"filter.clearAll\"\n | \"export.csv\"\n | \"export.json\"\n | \"export.xlsx\"\n | \"export.pdf\"\n | \"exportSelection.csv\"\n | \"exportSelection.json\"\n | \"exportSelection.xlsx\"\n | \"copy.cell\"\n | \"copy.row\"\n | \"copy.selection\"\n | \"print\";\n\n/**\n * The icon keys the built-ins carry, which a renderer draws as icons of its\n * own. An app command may use them too, to look like the built-ins.\n */\nexport type BuiltInCommandIcon =\n | \"sortAscending\"\n | \"sortDescending\"\n | \"group\"\n | \"hide\"\n | \"autoFit\"\n | \"copy\"\n | \"print\";\n\ntype Area = GridCommandTarget[\"area\"];\ntype Column<Row> = DataColumn<Row, unknown>;\ntype Context<Row> = GridCommandContext<Row>;\n\n/**\n * Whether the command was asked for on one of `areas`. Each built-in acts on\n * a column, a row, a group or the whole grid, and is hidden on a target that\n * has none of what it needs — so any id can be listed in any menu unchecked.\n */\nfunction isOn<Row>(context: Context<Row>, areas: readonly Area[]): boolean {\n return areas.includes(context.target.area);\n}\n\n/** The target's column, when the target is one of `areas`. */\nfunction columnOn<Row>(\n context: Context<Row>,\n areas: readonly Area[],\n): Column<Row> | null {\n return isOn(context, areas) ? context.column : null;\n}\n\nfunction isGroupedBy<Row>(context: Context<Row>, columnId: string): boolean {\n return context.state.groupBy.some((entry) => entry.columnId === columnId);\n}\n\nfunction sortableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null &&\n (column.column.sortable ?? context.options.sortableColumns ?? false)\n ? column\n : null;\n}\n\n/** A header's column that may be grouped by, and is not yet. */\nfunction groupableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null &&\n (column.column.groupable ?? context.options.groupableColumns ?? false) &&\n !isGroupedBy(context, column.id)\n ? column\n : null;\n}\n\nfunction groupedColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\", \"group\"]);\n return column !== null && isGroupedBy(context, column.id) ? column : null;\n}\n\n/** A header's column with a filter menu — see `resolveColumnFilterMenu`. */\nfunction filterableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null &&\n resolveColumnFilterMenu(context.options, column.column) !== null\n ? column\n : null;\n}\n\nfunction hideableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null && column.column.hideable !== false ? column : null;\n}\n\n/**\n * Read off the columns as rendered, where resizability is settled against\n * the grid-level default — and where a hidden column, with no width to fit,\n * is not.\n */\nfunction resizableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n if (column === null) {\n return null;\n }\n return (\n context.view.columns.find(\n (entry) => entry.id === column.id && entry.resizable,\n ) ?? null\n );\n}\n\nfunction resizableColumnIds<Row>(context: Context<Row>): readonly string[] {\n return context.view.columns\n .filter((entry) => entry.resizable)\n .map((entry) => entry.id);\n}\n\nfunction isAnythingSelectable(\n selectable: SelectableConfig | undefined,\n): boolean {\n return [selectable?.rows, selectable?.columns, selectable?.cells].some(\n (mode) => mode !== undefined && mode !== false,\n );\n}\n\n/** The target's column by name, for a label that names it. */\nfunction columnName<Row>(context: Context<Row>): string {\n return context.column === null\n ? \"\"\n : resolveColumnHeaderText(context.column.column);\n}\n\n/** What a built-in acting on one column says about it. */\ninterface ColumnCommandSpec<Row> {\n readonly id: BuiltInCommandId;\n readonly label: (context: Context<Row>) => string;\n readonly icon?: BuiltInCommandIcon;\n /** The column the command acts on, or `null` where there is none — which hides it. */\n readonly find: (context: Context<Row>) => Column<Row> | null;\n readonly isEnabled?: (column: Column<Row>, context: Context<Row>) => boolean;\n readonly isChecked?: (column: Column<Row>, context: Context<Row>) => boolean;\n readonly execute: (column: Column<Row>, context: Context<Row>) => void;\n}\n\n/**\n * A built-in acting on the column `find` picks out. Every predicate and\n * `execute` look it up again rather than trusting an earlier answer, so each\n * holds up on its own when called with a context it was not resolved in.\n */\nfunction columnCommand<Row>({\n id,\n label,\n icon,\n find,\n isEnabled,\n isChecked,\n execute,\n}: ColumnCommandSpec<Row>): GridCommand<Row> {\n function test(\n predicate: (column: Column<Row>, context: Context<Row>) => boolean,\n ) {\n return (context: Context<Row>) => {\n const column = find(context);\n return column !== null && predicate(column, context);\n };\n }\n return {\n id,\n label,\n icon,\n isVisible: (context) => find(context) !== null,\n isEnabled: isEnabled === undefined ? undefined : test(isEnabled),\n isChecked: isChecked === undefined ? undefined : test(isChecked),\n execute: (context) => {\n const column = find(context);\n if (column !== null) {\n execute(column, context);\n }\n },\n };\n}\n\n/** What an export built-in says about itself. */\ninterface ExportCommandSpec {\n readonly id: BuiltInCommandId;\n /** The writer it exports with, by format. */\n readonly format: string;\n readonly label: (messages: GridMessages) => string;\n /** Whether it exports the selected rows only — and so shows only while some are. */\n readonly selection?: boolean;\n}\n\n/**\n * An export acts on the whole grid, so it shows wherever the grid as a\n * whole can be asked for — a cell's menu included, but not a header's or a\n * group's, which are about one column or one group.\n */\nconst EXPORT_AREAS: readonly Area[] = [\"grid\", \"toolbar\", \"body\", \"cell\"];\n\n/**\n * A built-in exporting the grid as a file of `format`, under the grid's\n * `export` defaults, and handing it to the host to save. Shown only once a\n * writer for `format` is registered — CSV's and JSON's always are — and\n * disabled while there is nothing to export, so the item still says what is\n * possible.\n */\nfunction exportCommand<Row>({\n id,\n format,\n label,\n selection = false,\n}: ExportCommandSpec): GridCommand<Row> {\n return {\n id,\n label: ({ messages }) => label(messages),\n isVisible: (context) =>\n isOn(context, EXPORT_AREAS) &&\n resolveExportWriters(context.options.exportWriters).has(format) &&\n (!selection || context.state.rowSelection.length > 0),\n isEnabled: (context) =>\n (selection ? context.selectedRows() : context.view.rows).length > 0,\n execute: (context) => {\n const { export: defaults = {}, exportWriters } = context.options;\n const file = exportFile(\n context,\n format,\n selection ? { ...defaults, scope: \"selection\" } : defaults,\n resolveExportWriters(exportWriters),\n );\n if (file !== null) {\n context.host.saveFile(file);\n }\n },\n };\n}\n\n/** What a copy built-in says about itself. */\ninterface CopyCommandSpec<Row> {\n readonly id: BuiltInCommandId;\n readonly label: (messages: GridMessages) => string;\n /** What it copies from here, or `null` where it does not show. */\n readonly request: (context: Context<Row>) => CopyRequest | null;\n /** Whether there is anything to copy, when that is cheaper to say than building the copy. */\n readonly isEnabled?: (context: Context<Row>) => boolean;\n}\n\n/**\n * The cell or row a cell target names — the copy a cell's menu offers, of\n * the cell or row it opened on.\n */\nfunction cellRequest<Row>(\n context: Context<Row>,\n kind: \"cell\" | \"row\",\n): CopyRequest | null {\n const { target } = context;\n if (target.area !== \"cell\") {\n return null;\n }\n return kind === \"cell\"\n ? { kind, rowId: target.rowId, columnId: target.columnId }\n : { kind, rowId: target.rowId };\n}\n\n/**\n * A built-in copying to the clipboard through the host, which writes the\n * text and HTML and says it did. Disabled where nothing would be copied —\n * a hidden or `exportable: false` column's cell, an empty selection — so\n * the item still says what is possible.\n */\nfunction copyCommand<Row>({\n id,\n label,\n request,\n isEnabled,\n}: CopyCommandSpec<Row>): GridCommand<Row> {\n function contentFor(context: Context<Row>) {\n const asked = request(context);\n return asked === null ? null : copyContent(context, asked);\n }\n return {\n id,\n label: ({ messages }) => label(messages),\n icon: \"copy\",\n isVisible: (context) => request(context) !== null,\n isEnabled: isEnabled ?? ((context) => contentFor(context) !== null),\n execute: (context) => {\n const content = contentFor(context);\n if (content !== null) {\n context.host.writeClipboard(content);\n }\n },\n };\n}\n\nfunction sortCommand<Row>(direction: SortDirection): GridCommand<Row> {\n return columnCommand({\n id: direction === \"asc\" ? \"sort.ascending\" : \"sort.descending\",\n label: ({ messages }) =>\n direction === \"asc\" ? messages.sortAscending : messages.sortDescending,\n icon: direction === \"asc\" ? \"sortAscending\" : \"sortDescending\",\n find: sortableColumn,\n isChecked: (column, { state }) =>\n sortDirectionFor(state.columnSort, column.id) === direction,\n execute: (column, { actions }) => {\n actions.setColumnSort([{ columnId: column.id, direction }]);\n },\n });\n}\n\n/**\n * The grid's own commands, one per action its menus and toolbar offer —\n * sorting, grouping, hiding, fitting and choosing columns, selecting,\n * clearing, exporting, copying and printing.\n * Labels come from `messages`, so they follow the grid's language.\n *\n * A function rather than a constant so each comes typed for the caller's\n * `Row`; the commands hold no state, and two calls build equal ones.\n */\nexport function builtInCommands<Row>(): readonly GridCommand<Row>[] {\n return [\n sortCommand(\"asc\"),\n sortCommand(\"desc\"),\n // Cleared rather than set, so the change reports this column — the one\n // the announcement names — rather than a key that moved up past it.\n columnCommand({\n id: \"sort.clear\",\n label: ({ messages }) => messages.clearSort,\n find: sortableColumn,\n isEnabled: (column, { state }) =>\n sortDirectionFor(state.columnSort, column.id) !== null,\n execute: (column, { actions }) => {\n actions.clearColumnSort(column.id);\n },\n }),\n {\n id: \"sort.clearAll\",\n label: ({ messages }) => messages.clearAllSorting,\n isVisible: (context) => isOn(context, [\"grid\", \"toolbar\", \"header\"]),\n isEnabled: ({ state }) => state.columnSort.length > 0,\n execute: ({ actions }) => {\n actions.setColumnSort([]);\n },\n },\n columnCommand({\n id: \"group.add\",\n label: (context) => context.messages.groupByColumn(columnName(context)),\n icon: \"group\",\n find: groupableColumn,\n execute: (column, { actions }) => {\n actions.toggleGroupBy(column.id);\n },\n }),\n // Toggled rather than set, so the change reports this column — the one\n // the announcement names — rather than the level that moved up.\n columnCommand({\n id: \"group.remove\",\n label: (context) => context.messages.removeGroupBy(columnName(context)),\n icon: \"group\",\n find: groupedColumn,\n execute: (column, { actions }) => {\n actions.toggleGroupBy(column.id);\n },\n }),\n {\n id: \"group.clearAll\",\n label: ({ messages }) => messages.ungroupAll,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\"]) && context.state.groupBy.length > 0,\n execute: ({ actions }) => {\n actions.setGroupBy([]);\n },\n },\n {\n id: \"group.expandAll\",\n label: ({ messages }) => messages.expandAllGroups,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\", \"group\", \"cell\"]) &&\n context.state.groupBy.length > 0,\n execute: ({ actions }) => {\n actions.expandAllGroups();\n },\n },\n {\n id: \"group.collapseAll\",\n label: ({ messages }) => messages.collapseAllGroups,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\", \"group\", \"cell\"]) &&\n context.state.groupBy.length > 0,\n execute: ({ actions }) => {\n actions.collapseAllGroups();\n },\n },\n columnCommand({\n id: \"column.hide\",\n label: ({ messages }) => messages.hideColumn,\n icon: \"hide\",\n find: hideableColumn,\n // The last column shown stays: a grid with none has no header left to\n // bring one back from.\n isEnabled: (column, { view }) =>\n view.columns.some((entry) => entry.id !== column.id),\n execute: (column, { actions }) => {\n actions.hideColumns([column.id]);\n },\n }),\n columnCommand({\n id: \"column.autoFit\",\n label: ({ messages }) => messages.autoFitColumn,\n icon: \"autoFit\",\n find: resizableColumn,\n execute: (column, { host }) => {\n host.autoFitColumns([column.id]);\n },\n }),\n {\n id: \"column.autoFitAll\",\n label: ({ messages }) => messages.autoFitAllColumns,\n icon: \"autoFit\",\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\", \"header\"]) &&\n resizableColumnIds(context).length > 0,\n execute: (context) => {\n context.host.autoFitColumns(resizableColumnIds(context));\n },\n },\n // The target goes along, so the renderer opens the chooser where it was\n // asked for: beside the toolbar button, below the header, or at the\n // grid's corner for a call from nowhere in particular.\n {\n id: \"column.choose\",\n label: ({ messages }) => messages.chooseColumns,\n isVisible: (context) => isOn(context, [\"grid\", \"toolbar\", \"header\"]),\n execute: ({ host, target }) => {\n host.openPanel(\"columnChooser\", target);\n },\n },\n // Opened below the header it was asked for, as the chooser is.\n columnCommand({\n id: \"filter.open\",\n label: ({ messages }) => messages.openFilter,\n find: filterableColumn,\n execute: (_column, { host, target }) => {\n host.openPanel(\"filter\", target);\n },\n }),\n // Every entry about the column goes, whichever editor wrote it — or\n // none did, as with a predicate set in code — as applying an editor\n // replaces them all.\n columnCommand({\n id: \"filter.clear\",\n label: ({ messages }) => messages.clearColumnFilter,\n find: filterableColumn,\n isEnabled: (column, { state }) =>\n isColumnFiltered(state.filter, column.id),\n execute: (column, { actions, state }) => {\n actions.setFilter(\n state.filter.filter((entry) => !touchesColumn(entry, column.id)),\n );\n },\n }),\n {\n id: \"selection.selectAllRows\",\n label: ({ messages }) => messages.selectAllRows,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"cell\"]) &&\n context.options.selectable?.rows === \"multiple\",\n isEnabled: ({ view }) => view.displayDataRows.length > 0,\n execute: ({ actions }) => {\n actions.selectAllRows();\n },\n },\n {\n id: \"selection.clear\",\n label: ({ messages }) => messages.clearSelection,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"cell\", \"header\"]) &&\n isAnythingSelectable(context.options.selectable),\n isEnabled: ({ state }) =>\n state.rowSelection.length > 0 ||\n state.columnSelection.length > 0 ||\n state.cellSelection !== null,\n execute: ({ actions }) => {\n actions.clearSelection();\n },\n },\n {\n id: \"filter.clearAll\",\n label: ({ messages }) => messages.clearFilters,\n isVisible: (context) => isOn(context, [\"grid\", \"toolbar\", \"header\"]),\n isEnabled: ({ state }) => state.filter.length > 0,\n execute: ({ actions }) => {\n actions.setFilter([]);\n },\n },\n exportCommand({\n id: \"export.csv\",\n format: \"csv\",\n label: ({ exportCsv }) => exportCsv,\n }),\n exportCommand({\n id: \"export.json\",\n format: \"json\",\n label: ({ exportJson }) => exportJson,\n }),\n exportCommand({\n id: \"export.xlsx\",\n format: \"xlsx\",\n label: ({ exportXlsx }) => exportXlsx,\n }),\n exportCommand({\n id: \"export.pdf\",\n format: \"pdf\",\n label: ({ exportPdf }) => exportPdf,\n }),\n exportCommand({\n id: \"exportSelection.csv\",\n format: \"csv\",\n label: ({ exportSelectionCsv }) => exportSelectionCsv,\n selection: true,\n }),\n exportCommand({\n id: \"exportSelection.json\",\n format: \"json\",\n label: ({ exportSelectionJson }) => exportSelectionJson,\n selection: true,\n }),\n exportCommand({\n id: \"exportSelection.xlsx\",\n format: \"xlsx\",\n label: ({ exportSelectionXlsx }) => exportSelectionXlsx,\n selection: true,\n }),\n copyCommand({\n id: \"copy.cell\",\n label: ({ copyCell }) => copyCell,\n request: (context) => cellRequest(context, \"cell\"),\n }),\n copyCommand({\n id: \"copy.row\",\n label: ({ copyRow }) => copyRow,\n request: (context) => cellRequest(context, \"row\"),\n }),\n // Shown wherever the grid as a whole is asked for, as the exports are,\n // once anything can be selected; enabled once something is.\n copyCommand({\n id: \"copy.selection\",\n label: ({ copySelection }) => copySelection,\n request: (context) =>\n isOn(context, EXPORT_AREAS) &&\n isAnythingSelectable(context.options.selectable)\n ? { kind: \"selection\" }\n : null,\n isEnabled: canCopySelection,\n }),\n // Shown where the exports are, under the grid's `print` defaults. A grid\n // with no rows still prints its header; one with no columns, nothing.\n {\n id: \"print\",\n label: ({ messages }) => messages.print,\n icon: \"print\",\n isVisible: (context) => isOn(context, EXPORT_AREAS),\n isEnabled: ({ view }) => view.columns.length > 0,\n execute: (context) => {\n const { print: options = {} } = context.options;\n context.host.print(exportPrintDocument(context, options), options);\n },\n },\n ];\n}\n","import { reportError } from \"../util/report\";\nimport { builtInCommands } from \"./builtInCommands\";\nimport type { GridCommand, GridCommandContext } from \"./types\";\n\n/** Whether `command` shows on `context`'s target. */\nexport function isCommandVisible<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): boolean {\n return command.isVisible?.(context) ?? true;\n}\n\n/** Whether `command` can run on `context`'s target. */\nexport function isCommandEnabled<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): boolean {\n return command.isEnabled?.(context) ?? true;\n}\n\n/**\n * Every command a grid knows, by id: the built-ins, then `commands` — an app\n * command with a built-in's id replacing it, so every menu and toolbar\n * listing that id gets the app's version (translated, gated by a privilege,\n * or doing something else) without being changed itself.\n *\n * A fresh map per call; a renderer resolves it once per change to\n * `commands`, not per menu.\n */\nexport function resolveCommands<Row>(\n commands: readonly GridCommand<Row>[] | undefined,\n): ReadonlyMap<string, GridCommand<Row>> {\n const registry = new Map(\n builtInCommands<Row>().map((command) => [command.id, command]),\n );\n for (const command of commands ?? []) {\n if (command.id === \"separator\") {\n reportError(\n \"a command cannot have the id `separator`, which a menu reads as a separator, so it is left out.\",\n );\n continue;\n }\n registry.set(command.id, command);\n }\n return registry;\n}\n\n/**\n * Runs `command` when it is visible and enabled on `context`'s target, and\n * says whether it did — so a renderer reports only a command that ran, and a\n * stale button or a call through the API cannot run one the grid's state no\n * longer allows.\n */\nexport function runCommand<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): boolean {\n if (\n !isCommandVisible(command, context) ||\n !isCommandEnabled(command, context)\n ) {\n return false;\n }\n command.execute(context);\n return true;\n}\n","import {\n isCommandEnabled,\n isCommandVisible,\n runCommand,\n} from \"../commands/registry\";\nimport type { GridCommand, GridCommandContext } from \"../commands/types\";\nimport { reportError } from \"../util/report\";\nimport type {\n MenuEntry,\n MenuItemEntry,\n MenuSubmenuEntry,\n ResolvedMenuEntry,\n ResolvedMenuItem,\n ResolvedMenuSubmenu,\n} from \"./types\";\n\n/** What `resolveMenu` resolves a menu's entries against. */\nexport interface MenuResolveOptions<Row> {\n /** Every command the grid knows, by id — see `resolveCommands`. */\n readonly commands: ReadonlyMap<string, GridCommand<Row>>;\n readonly context: GridCommandContext<Row>;\n}\n\n/**\n * Unknown ids already reported, per command map. A toolbar is resolved again\n * on every change to the grid, and one typo should say so once, not every\n * time; keyed weakly, so a map the renderer drops takes its ids with it.\n */\nconst reportedUnknownIds = new WeakMap<object, Set<string>>();\n\nfunction reportUnknownId(commands: object, id: string): void {\n let reported = reportedUnknownIds.get(commands);\n if (reported === undefined) {\n reported = new Set();\n reportedUnknownIds.set(commands, reported);\n }\n if (reported.has(id)) {\n return;\n }\n reported.add(id);\n reportError(\n `the menu or toolbar entry \\`${id}\\` names no command, so it is left out.`,\n );\n}\n\n/** A label or flag an entry gives outright, or as a function of the context. */\nfunction evaluate<Row, Value>(\n value: Value | ((context: GridCommandContext<Row>) => Value),\n context: GridCommandContext<Row>,\n): Value {\n // `Value` is never itself a function here — a label is a string, a flag a\n // boolean — so a function is always the form that reads the context.\n return typeof value === \"function\"\n ? (value as (context: GridCommandContext<Row>) => Value)(context)\n : value;\n}\n\nfunction commandItem<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): ResolvedMenuItem | null {\n if (!isCommandVisible(command, context)) {\n return null;\n }\n return {\n type: \"item\",\n id: command.id,\n label: evaluate(command.label, context),\n icon: command.icon,\n shortcut: command.shortcut,\n disabled: !isCommandEnabled(command, context),\n checked: command.isChecked?.(context),\n run: () => runCommand(command, context),\n };\n}\n\nfunction inlineItem<Row>(\n entry: MenuItemEntry<Row>,\n context: GridCommandContext<Row>,\n): ResolvedMenuItem | null {\n if (evaluate(entry.hidden ?? false, context)) {\n return null;\n }\n const disabled = evaluate(entry.disabled ?? false, context);\n return {\n type: \"item\",\n id: entry.id,\n label: evaluate(entry.label, context),\n icon: entry.icon,\n shortcut: entry.shortcut,\n disabled,\n checked:\n entry.checked === undefined\n ? undefined\n : evaluate(entry.checked, context),\n run: () => {\n if (disabled) {\n return false;\n }\n entry.onSelect(context);\n return true;\n },\n };\n}\n\n/**\n * `entries` with no separator first, last, or next to another — what is\n * left once the items between two separators have all been dropped. An\n * entry `isEdge` picks out — a toolbar's spacer — already parts what is on\n * either side of it, so a separator next to one goes too, as at the ends.\n */\nexport function collapseSeparators<Entry extends { readonly type: string }>(\n entries: readonly Entry[],\n isEdge: (entry: Entry) => boolean = () => false,\n): readonly Entry[] {\n const collapsed: Entry[] = [];\n for (const entry of entries) {\n const previous = collapsed.at(-1);\n if (entry.type !== \"separator\") {\n if (isEdge(entry) && previous?.type === \"separator\") {\n collapsed.pop();\n }\n collapsed.push(entry);\n } else if (\n previous !== undefined &&\n previous.type !== \"separator\" &&\n !isEdge(previous)\n ) {\n collapsed.push(entry);\n }\n }\n if (collapsed.at(-1)?.type === \"separator\") {\n collapsed.pop();\n }\n return collapsed;\n}\n\n/**\n * One entry resolved, `null` when it shows nothing — what `resolveMenu` does\n * to each of its entries, and a toolbar to each it shares with menus.\n * `index` is the entry's place among those it was listed with, which keys a\n * separator.\n */\nexport function resolveMenuEntry<Row>(\n entry: MenuEntry<Row>,\n index: number,\n options: MenuResolveOptions<Row>,\n): ResolvedMenuEntry | null {\n const { commands, context } = options;\n if (entry === \"separator\") {\n return { type: \"separator\", key: `separator-${String(index)}` };\n }\n if (typeof entry === \"string\") {\n const command = commands.get(entry);\n if (command === undefined) {\n reportUnknownId(commands, entry);\n return null;\n }\n return commandItem(command, context);\n }\n return entry.type === \"item\"\n ? inlineItem(entry, context)\n : resolveSubmenu(entry, options);\n}\n\nfunction resolveSubmenu<Row>(\n entry: MenuSubmenuEntry<Row>,\n options: MenuResolveOptions<Row>,\n): ResolvedMenuSubmenu | null {\n const items = resolveMenu(entry.items, options);\n return items.length === 0\n ? null\n : {\n type: \"submenu\",\n id: entry.id,\n label: evaluate(entry.label, options.context),\n icon: entry.icon,\n items,\n };\n}\n\n/**\n * A menu's entries resolved against the grid as `context` sees it, ready to\n * draw:\n *\n * - A command id becomes its command's item, and a hidden command or item\n * is left out. An id naming no command is left out too, and reported once\n * per command map through `console.error`.\n * - Labels become strings and flags booleans; `checked` stays `undefined`\n * for an item that is not checkable.\n * - A submenu is resolved the same way, and left out when nothing in it\n * shows.\n * - Separators never lead, trail or double up, however the items around\n * them came and went.\n *\n * An empty result means there is nothing to show — no grid menu at all\n * here.\n */\nexport function resolveMenu<Row>(\n entries: readonly MenuEntry<Row>[],\n options: MenuResolveOptions<Row>,\n): readonly ResolvedMenuEntry[] {\n return collapseSeparators(\n entries\n .map((entry, index) => resolveMenuEntry(entry, index, options))\n .filter((entry) => entry !== null),\n );\n}\n","import type { BuiltInCommandId } from \"../commands/builtInCommands\";\nimport type { GridCommandContext, GridCommandTarget } from \"../commands/types\";\nimport type { MenuEntry } from \"./types\";\n\n/** The parts of a grid that open a context menu of their own. */\nexport type GridContextMenuArea = \"header\" | \"cell\" | \"group\" | \"body\";\n\n/**\n * Where a context menu opens: a command target in one of the context menu\n * areas — a column header, a data cell, a group header row, or empty space\n * in the body — or in `Area` alone.\n */\nexport type GridContextMenuTarget<\n Area extends GridContextMenuArea = GridContextMenuArea,\n> = Extract<GridCommandTarget, { readonly area: Area }>;\n\n/** What `onContextMenuOpenChange` is told as a context menu opens or closes. */\nexport interface ContextMenuOpenChangeEvent {\n readonly open: boolean;\n /** Where the menu opened, or where the one closing had. */\n readonly target: GridContextMenuTarget;\n}\n\n/** What a function given for an area is asked, each time its menu opens. */\nexport interface GridContextMenuRequest<\n Row,\n Area extends GridContextMenuArea = GridContextMenuArea,\n> {\n /** Where the menu opens. */\n readonly target: GridContextMenuTarget<Area>;\n /** The area's default entries, to keep, trim, reorder or add to. */\n readonly defaults: readonly MenuEntry<Row>[];\n /** The grid as the menu sees it — the context its items run in. */\n readonly context: GridCommandContext<Row>;\n}\n\n/**\n * An area's menu: its entries, or a function that works them out each time\n * the menu opens — from where it opens, the area's defaults and the grid's\n * state. A function giving `null` or `[]` shows no grid menu there, so the\n * browser's own menu shows.\n */\nexport type GridContextMenuEntries<\n Row,\n Area extends GridContextMenuArea = GridContextMenuArea,\n> =\n | readonly MenuEntry<Row>[]\n | ((\n request: GridContextMenuRequest<Row, Area>,\n ) => readonly MenuEntry<Row>[] | null);\n\n/**\n * A grid's context menus, by area, in the vocabulary every grid menu is\n * written in. An area left out shows its defaults; one given `[]` shows no\n * grid menu, so the browser's own menu shows there.\n */\nexport interface GridContextMenuOptions<Row> {\n /** A column header's menu. */\n readonly header?: GridContextMenuEntries<Row, \"header\"> | undefined;\n /** A data cell's menu, acting on its row and cell. */\n readonly cell?: GridContextMenuEntries<Row, \"cell\"> | undefined;\n /** A group header row's menu. */\n readonly group?: GridContextMenuEntries<Row, \"group\"> | undefined;\n /** The menu of the body's empty space, below the last row or in a grid with none. */\n readonly body?: GridContextMenuEntries<Row, \"body\"> | undefined;\n}\n\n/**\n * The menu each area shows unless the grid says otherwise — built-in\n * commands only, each hidden where it has nothing to act on, so the menu a\n * column header shows holds only what that column can do. The body has\n * none: empty space keeps the browser's menu until a grid gives it one.\n */\nexport const defaultContextMenu: {\n readonly [Area in GridContextMenuArea]: readonly (\n BuiltInCommandId | \"separator\"\n )[];\n} = {\n header: [\n \"sort.ascending\",\n \"sort.descending\",\n \"sort.clear\",\n \"separator\",\n \"filter.open\",\n \"filter.clear\",\n \"separator\",\n \"group.add\",\n \"group.remove\",\n \"separator\",\n \"column.autoFit\",\n \"column.autoFitAll\",\n \"separator\",\n \"column.hide\",\n \"column.choose\",\n ],\n cell: [\n \"copy.cell\",\n \"copy.row\",\n \"copy.selection\",\n \"separator\",\n \"selection.selectAllRows\",\n \"selection.clear\",\n \"separator\",\n \"group.expandAll\",\n \"group.collapseAll\",\n ],\n group: [\"group.expandAll\", \"group.collapseAll\", \"separator\", \"group.remove\"],\n body: [],\n};\n\n/**\n * Whether the `contextMenu` option opens a grid menu on `area` at all: it is\n * on, and gives the area entries or a function rather than `[]`. A function\n * may still give no menu for one place or another; this answers for the\n * area, as a cell's `aria-keyshortcuts` needs to before anything is asked.\n */\nexport function hasContextMenu<Row>(\n contextMenu: boolean | GridContextMenuOptions<Row> | undefined,\n area: GridContextMenuArea,\n): boolean {\n if (contextMenu === undefined || contextMenu === false) {\n return false;\n }\n const entries =\n (contextMenu === true ? undefined : contextMenu[area]) ??\n defaultContextMenu[area];\n return typeof entries === \"function\" || entries.length > 0;\n}\n\n/** What an area's option gives one request: its defaults when left out. */\nfunction entriesFor<Row, Area extends GridContextMenuArea>(\n given: GridContextMenuEntries<Row, Area> | undefined,\n request: GridContextMenuRequest<Row, Area>,\n): readonly MenuEntry<Row>[] {\n if (given === undefined) {\n return request.defaults;\n }\n return typeof given === \"function\" ? (given(request) ?? []) : given;\n}\n\n/**\n * The entries a grid's `contextMenu` option gives the place `context.target`\n * names, to resolve with `resolveMenu` in that same context: none while the\n * option is off — left out or `false` — or for a target no context menu\n * opens on; the area's defaults under `true` or when the option leaves the\n * area out; the entries it lists; or what its function gives this request.\n * No entries means no grid menu there.\n */\nexport function contextMenuEntries<Row>(\n contextMenu: boolean | GridContextMenuOptions<Row> | undefined,\n context: GridCommandContext<Row>,\n): readonly MenuEntry<Row>[] {\n if (contextMenu === undefined || contextMenu === false) {\n return [];\n }\n const options: GridContextMenuOptions<Row> =\n contextMenu === true ? {} : contextMenu;\n const { target } = context;\n switch (target.area) {\n case \"header\":\n return entriesFor(options.header, {\n target,\n defaults: defaultContextMenu.header,\n context,\n });\n case \"cell\":\n return entriesFor(options.cell, {\n target,\n defaults: defaultContextMenu.cell,\n context,\n });\n case \"group\":\n return entriesFor(options.group, {\n target,\n defaults: defaultContextMenu.group,\n context,\n });\n case \"body\":\n return entriesFor(options.body, {\n target,\n defaults: defaultContextMenu.body,\n context,\n });\n default:\n return [];\n }\n}\n","import type { ResolvedMenuEntry } from \"./types\";\n\n/** Where an arrow, Home or End key moves a menu's focus. */\nexport type MenuMove = \"next\" | \"previous\" | \"first\" | \"last\";\n\n/** Where the search for the next item begins, before skipping separators. */\nfunction startIndex(count: number, from: number, move: MenuMove): number {\n const focused = from >= 0 && from < count;\n switch (move) {\n case \"first\":\n return 0;\n case \"last\":\n return count - 1;\n case \"next\":\n return focused ? from + 1 : 0;\n case \"previous\":\n return focused ? from - 1 : count - 1;\n }\n}\n\n/**\n * The index of the item focus moves to from `from` — `-1` when nothing is\n * focused yet, so `\"next\"` lands on the first item and `\"previous\"` on the\n * last. Separators are skipped and `\"next\"`/`\"previous\"` wrap round the\n * ends; disabled items count, since they stay focusable for a screen reader\n * to find. `-1` when there is no item at all.\n *\n * Takes anything with a `type`, so a behaviour that reads its items off the\n * page can pass `{ type: \"item\" }` for each.\n */\nexport function nextMenuIndex(\n entries: readonly Pick<ResolvedMenuEntry, \"type\">[],\n from: number,\n move: MenuMove,\n): number {\n const count = entries.length;\n const step = move === \"next\" || move === \"first\" ? 1 : -1;\n const start = startIndex(count, from, move);\n for (let offset = 0; offset < count; offset++) {\n const index = (((start + step * offset) % count) + count) % count;\n if (entries[index]?.type !== \"separator\") {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The index of the item `query` — what was typed, buffered for a moment —\n * picks, matched case-insensitively against the start of each label and\n * wrapping round the end; `-1` when none matches.\n *\n * `from` is the item focused now. A single letter, or the same letter\n * typed again and again, searches from the item after it, so repeating a\n * letter steps through every item it starts. A longer query searches from\n * `from` itself, so the item already found stays put while what is typed\n * still matches it.\n */\nexport function typeaheadIndex(\n labels: readonly string[],\n from: number,\n query: string,\n): number {\n const typed = query.toLowerCase();\n const firstCodePoint = typed.codePointAt(0);\n if (firstCodePoint === undefined) {\n return -1;\n }\n const first = String.fromCodePoint(firstCodePoint);\n const repeated = typed.replaceAll(first, \"\") === \"\";\n const prefix = repeated ? first : typed;\n const start = repeated ? from + 1 : Math.max(from, 0);\n for (let offset = 0; offset < labels.length; offset++) {\n const index = (start + offset) % labels.length;\n if (labels[index]?.toLowerCase().startsWith(prefix) === true) {\n return index;\n }\n }\n return -1;\n}\n","import type { BuiltInCommandId } from \"../commands/builtInCommands\";\nimport type { ToolbarEntry } from \"./types\";\n\n/** A grid's toolbar: what it lists, and what a screen reader calls it. */\nexport interface GridToolbarOptions<Row> {\n /** The toolbar's entries, in order. Left out, the defaults. */\n readonly items?: readonly ToolbarEntry<Row>[] | undefined;\n /** The toolbar's accessible name. Left out, `messages.toolbarLabel`. */\n readonly label?: string | undefined;\n}\n\n/**\n * What a toolbar lists unless the grid says otherwise: the search box, then\n * the free space, then \"Clear filters\" and \"Choose columns\" at the far end.\n */\nexport const defaultToolbar: readonly (\n BuiltInCommandId | \"search\" | \"spacer\"\n)[] = [\"search\", \"spacer\", \"filter.clearAll\", \"column.choose\"];\n\n/**\n * The entries a grid's `toolbar` option lists, to resolve with\n * `resolveToolbar`: none while it is off — left out or `false` — the\n * defaults under `true` or an object without `items`, else its `items`.\n * No entries means no toolbar.\n */\nexport function toolbarEntries<Row>(\n toolbar: boolean | GridToolbarOptions<Row> | undefined,\n): readonly ToolbarEntry<Row>[] {\n if (toolbar === undefined || toolbar === false) {\n return [];\n }\n return (toolbar === true ? undefined : toolbar.items) ?? defaultToolbar;\n}\n","import type { GridCommand, GridCommandContext } from \"../commands/types\";\nimport { collapseSeparators, resolveMenuEntry } from \"../menu/resolveMenu\";\nimport type { MenuSubmenuEntry } from \"../menu/types\";\nimport type {\n GridToolbarTarget,\n ResolvedToolbarItem,\n ToolbarEntry,\n} from \"./types\";\n\n/** What `resolveToolbar` resolves a toolbar's entries against. */\nexport interface ToolbarResolveOptions<Row> {\n /** Every command the grid knows, by id — see `resolveCommands`. */\n readonly commands: ReadonlyMap<string, GridCommand<Row>>;\n /**\n * The context an item resolves and runs in, for its target — the item\n * itself, or the dropdown an item in one is listed under. A command that\n * opens a panel anchors it there.\n */\n readonly contextFor: (target: GridToolbarTarget) => GridCommandContext<Row>;\n}\n\nfunction isSpacer(entry: ResolvedToolbarItem): boolean {\n return entry.type === \"spacer\";\n}\n\n/**\n * What the `\"export\"` entry stands for: a dropdown of every export\n * built-in, the selection exports after a separator. Each command hides\n * where it cannot act — xlsx and PDF until a writer is registered, the\n * selection exports while nothing is selected — so the dropdown lists what\n * the grid can export now, and is left out when that is nothing.\n */\nfunction exportMenu<Row>(): MenuSubmenuEntry<Row> {\n return {\n type: \"submenu\",\n id: \"export\",\n label: ({ messages }) => messages.exportMenu,\n items: [\n \"export.csv\",\n \"export.json\",\n \"export.xlsx\",\n \"export.pdf\",\n \"separator\",\n \"exportSelection.csv\",\n \"exportSelection.json\",\n \"exportSelection.xlsx\",\n ],\n };\n}\n\n/**\n * A toolbar's entries resolved against the grid, ready to draw, by the\n * rules `resolveMenu` follows:\n *\n * - A command id becomes its command's button, and an inline item a button\n * of its own; either is a toggle, with `pressed`, when it is checkable. A\n * hidden one is left out, and so is an id naming no command, reported\n * once per command map through `console.error`.\n * - A submenu becomes a dropdown, its items resolved as a menu's, and is\n * left out when nothing in it shows. `\"export\"` is one too, of the export\n * commands, keyed `\"export\"`.\n * - `\"search\"`, `\"spacer\"` and custom entries stay as they are.\n * - Separators never lead, trail, double up or sit next to a spacer, which\n * already parts what is on either side of it.\n *\n * Resolve again whenever the grid changes, so each button's label, flags\n * and `run` follow its state.\n */\nexport function resolveToolbar<Row>(\n entries: readonly ToolbarEntry<Row>[],\n options: ToolbarResolveOptions<Row>,\n): readonly ResolvedToolbarItem[] {\n const { commands, contextFor } = options;\n\n function resolveEntry(\n entry: ToolbarEntry<Row>,\n index: number,\n ): ResolvedToolbarItem | null {\n if (entry === \"search\") {\n return { type: \"search\", key: \"search\" };\n }\n if (entry === \"spacer\") {\n return { type: \"spacer\", key: `spacer-${String(index)}` };\n }\n if (typeof entry === \"object\" && entry.type === \"custom\") {\n return { type: \"custom\", id: entry.id, key: entry.id };\n }\n if (entry === \"separator\") {\n return { type: \"separator\", key: `separator-${String(index)}` };\n }\n const menuEntry = entry === \"export\" ? exportMenu<Row>() : entry;\n const resolved = resolveMenuEntry(menuEntry, index, {\n commands,\n context: contextFor({\n area: \"toolbar\",\n itemId: typeof menuEntry === \"string\" ? menuEntry : menuEntry.id,\n }),\n });\n if (resolved === null || resolved.type === \"separator\") {\n return resolved;\n }\n if (resolved.type === \"submenu\") {\n return { ...resolved, type: \"menu\", key: resolved.id };\n }\n const { checked, ...item } = resolved;\n return { ...item, type: \"button\", key: item.id, pressed: checked };\n }\n\n return collapseSeparators(\n entries.map(resolveEntry).filter((entry) => entry !== null),\n isSpacer,\n );\n}\n","import { collapseSeparators } from \"../menu/resolveMenu\";\nimport type { ResolvedMenuEntry } from \"../menu/types\";\nimport type { ResolvedToolbarItem } from \"./types\";\n\n/** What `fitToolbarItems` fits: a toolbar's entries, by width, into its space. */\nexport interface ToolbarFitInput {\n /** Each entry's width, in order — `0` for a spacer, whose width is only the space left over. */\n readonly widths: readonly number[];\n /** The width the entries share. */\n readonly available: number;\n /** The width of the \"More\" button the entries that do not fit go into. */\n readonly moreWidth: number;\n /** Whether each entry, in order, stays however little room there is. */\n readonly pinned: readonly boolean[];\n}\n\n/**\n * How many of a toolbar's entries fit, from the start: the first `count`\n * stay in the toolbar, with every pinned entry after them, and the rest go\n * into a \"More\" menu.\n *\n * Pinned entries take their room first, wherever they are. Room for \"More\"\n * is kept only when something does not fit — when everything does, the\n * result is every entry and no \"More\" is drawn. Entries are taken in order\n * and the first that does not fit ends the count, so the toolbar keeps its\n * order rather than filling gaps with later, narrower entries; one with no\n * width, a spacer, fits wherever the entries before it did.\n */\nexport function fitToolbarItems({\n widths,\n available,\n moreWidth,\n pinned,\n}: ToolbarFitInput): number {\n const total = widths.reduce((sum, width) => sum + width, 0);\n if (total <= available) {\n return widths.length;\n }\n let used =\n moreWidth +\n widths.reduce((sum, width, index) => sum + (pinned[index] ? width : 0), 0);\n for (const [index, width] of widths.entries()) {\n if (!pinned[index]) {\n used += width;\n if (used > available) {\n return index;\n }\n }\n }\n return widths.length;\n}\n\n/**\n * Whether a toolbar entry stays in the toolbar however narrow it gets: the\n * search box and custom entries, which have no menu item to become.\n */\nexport function isPinnedToolbarItem(\n item: Pick<ResolvedToolbarItem, \"type\">,\n): boolean {\n return item.type === \"search\" || item.type === \"custom\";\n}\n\n/** A toolbar split at the count `fitToolbarItems` gave — see `splitToolbarItems`. */\nexport interface ToolbarSplit {\n /** What stays in the toolbar. */\n readonly shown: readonly ResolvedToolbarItem[];\n /** The \"More\" menu's entries, empty when everything fits. */\n readonly overflow: readonly ResolvedMenuEntry[];\n}\n\n/** An entry that did not fit, as the \"More\" menu lists it; `null` for a spacer. */\nfunction asMenuEntry(item: ResolvedToolbarItem): ResolvedMenuEntry | null {\n switch (item.type) {\n case \"button\":\n return {\n type: \"item\",\n id: item.id,\n label: item.label,\n icon: item.icon,\n shortcut: item.shortcut,\n disabled: item.disabled,\n checked: item.pressed,\n run: item.run,\n };\n case \"menu\":\n return {\n type: \"submenu\",\n id: item.id,\n label: item.label,\n icon: item.icon,\n items: item.items,\n };\n case \"separator\":\n return item;\n default:\n return null;\n }\n}\n\n/**\n * `items` split at the first `fit`: those before it, and every pinned item,\n * stay in the toolbar; the rest become the \"More\" menu's entries — a button\n * an item, checked where it was pressed, and a dropdown a submenu. Neither\n * side keeps a separator at its ends, doubled, or beside a spacer.\n */\nexport function splitToolbarItems(\n items: readonly ResolvedToolbarItem[],\n fit: number,\n): ToolbarSplit {\n const fits = (item: ResolvedToolbarItem, index: number) =>\n index < fit || isPinnedToolbarItem(item);\n return {\n shown: collapseSeparators(\n items.filter(fits),\n (item) => item.type === \"spacer\",\n ),\n overflow: collapseSeparators(\n items\n .filter((item, index) => !fits(item, index))\n .map(asMenuEntry)\n .filter((entry) => entry !== null),\n ),\n };\n}\n","import type { FilterState } from \"../types\";\nimport { filterQueryFor, setColumnFilter } from \"../util/filtering\";\n\n/**\n * What a search box shows for `filter`: the global text entry's query — the\n * one naming no column — without the `%` anchors that make it a \"contains\"\n * match, or `\"\"` when there is none. A `%` the user typed inside the text\n * stays: only the first and last characters are anchors.\n */\nexport function searchTextOf<Row>(filter: FilterState<Row>): string {\n const query = filterQueryFor(filter) ?? \"\";\n const start = query.startsWith(\"%\") ? 1 : 0;\n const end = query.endsWith(\"%\") ? -1 : undefined;\n return query.slice(start, end);\n}\n\n/**\n * `filter` with its global text entry set to search for `text` anywhere in\n * any column — the query `%text%` — or removed for an empty `text`. Every\n * entry naming a column stays as it was. `filter` itself, unchanged, when\n * it already searches for `text`.\n *\n * `text` is written as typed, spaces and all: a search box reads its text\n * back from the filter, and trimming here would take a space away from\n * under the caret as the user types it.\n */\nexport function setSearchText<Row>(\n filter: FilterState<Row>,\n text: string,\n): FilterState<Row> {\n return setColumnFilter(filter, undefined, text === \"\" ? \"\" : `%${text}%`);\n}\n","/**\n * The header's row index. One coordinate space covers the header and the body\n * so that arrowing up out of the first row reaches the header without a case\n * of its own, and every other move is plain arithmetic.\n */\nexport const HEADER_ROW = -1;\n\n/** The cell the grid's single tab stop sits on. */\nexport interface GridFocus {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\n/** The modifier keys held with a navigation key press. */\nexport interface NavigationModifiers {\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly altKey: boolean;\n readonly shiftKey: boolean;\n}\n\n/**\n * Holds a coordinate inside the grid, so that a focus surviving a column\n * removal or a shorter page never leaves the grid with no tab stop at all —\n * which is a grid a keyboard cannot reach.\n */\nexport function clampFocus(\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n): GridFocus {\n return {\n rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),\n columnIndex: Math.min(\n Math.max(focus.columnIndex, 0),\n Math.max(columnCount - 1, 0),\n ),\n };\n}\n\n/** Never treats any row as unreachable — the default when a caller has no skippable rows at all. */\nfunction noRowsSkippable(): boolean {\n return false;\n}\n\n/**\n * `rowIndex` moved forward one row at a time in `direction` (`1` or `-1`)\n * until it lands on a row `isSkippableRow` says is reachable, or would run\n * off the grid's own bounds (`HEADER_ROW` to `rowCount - 1`) trying — in\n * which case it returns `fallback` (the position before this move started)\n * instead of an out-of-range index.\n *\n * Deliberately not \"step one past the bound\" the way an ordinary move here\n * left unclamped would: `clampFocus` downstream holds any out-of-range\n * `rowIndex` at the nearest in-range one, and if that nearest row happens\n * to be the very one that was skippable (the grid's actual last row is a\n * group's own summary row, say), clamping back onto it would silently\n * defeat the skip. Staying at `fallback` is what a \"there is nowhere valid\n * to move to\" press should do instead — the same way `ArrowLeft` at column\n * 0 already leaves `rowIndex`/`columnIndex` exactly where they were,\n * `clampFocus` is left with nothing to correct either way, and a caller\n * that still wants to detect \"did this move go anywhere\" can compare the\n * result to `focus` itself.\n */\nfunction skipSkippableRows(\n rowIndex: number,\n direction: 1 | -1,\n rowCount: number,\n isSkippableRow: (rowIndex: number) => boolean,\n fallback: number,\n): number {\n let next = rowIndex;\n // The header (HEADER_ROW) and anything already out of the body's own\n // [0, rowCount) range are never skippable — an ordinary PageUp/ArrowUp\n // overshoot past the header, in particular, has nothing to skip past, so\n // this function has nothing to do; `clampFocus` downstream still handles\n // holding it in bounds as it always has.\n while (next >= 0 && next < rowCount && isSkippableRow(next)) {\n const stepped = next + direction;\n // Landing on the header itself (moving up from row 0) is always valid —\n // only a step that would leave the header *and* the body's own range\n // behind (moving down past the last row) has nowhere left to go.\n if (stepped < HEADER_ROW || stepped >= rowCount) {\n return fallback;\n }\n next = stepped;\n }\n return next;\n}\n\n/**\n * The focus a navigation key press moves to, or `null` when the key isn't\n * this grid's to handle — left for the browser or another handler.\n *\n * `pageSize` is a pre-measured row count rather than a callback: this\n * function takes plain data only, so a caller measures the viewport once and\n * hands over the number.\n *\n * `isSkippableRow` names rows the vertical moves (`ArrowUp`/`ArrowDown`/\n * `PageUp`/`PageDown`/`Ctrl+End`) never land a tab stop on — a group's own\n * summary row (`groupAggregateDisplay: \"row\"`), which still occupies a real\n * row slot for `rowCount`/`aria-rowindex` purposes but is presentational,\n * not a stop of its own. Left/right and plain `Home`/`End` stay row-scoped\n * and so never consult it. Defaults to skipping nothing, so every existing\n * caller (and every horizontal move) is unaffected.\n */\nexport function nextFocusForKey(\n key: string,\n modifiers: NavigationModifiers,\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n pageSize: number,\n isSkippableRow: (rowIndex: number) => boolean = noRowsSkippable,\n): GridFocus | null {\n // Alt on an arrow resizes and Ctrl on one reorders; the header claims both\n // before this runs, and elsewhere they belong to the browser.\n if (modifiers.altKey) {\n return null;\n }\n\n const { rowIndex, columnIndex } = focus;\n\n switch (key) {\n case \"ArrowLeft\":\n if (modifiers.ctrlKey) return null;\n return { rowIndex, columnIndex: columnIndex - 1 };\n case \"ArrowRight\":\n if (modifiers.ctrlKey) return null;\n return { rowIndex, columnIndex: columnIndex + 1 };\n case \"ArrowUp\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex - 1,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n case \"ArrowDown\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex + 1,\n 1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n // Ctrl takes Home and End to the grid's ends rather than the row's, which\n // is the one place Ctrl is navigation rather than reorder.\n case \"Home\":\n return modifiers.ctrlKey\n ? { rowIndex: HEADER_ROW, columnIndex: 0 }\n : { rowIndex, columnIndex: 0 };\n case \"End\":\n return modifiers.ctrlKey\n ? {\n rowIndex: skipSkippableRows(\n rowCount - 1,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex: columnCount - 1,\n }\n : { rowIndex, columnIndex: columnCount - 1 };\n case \"PageUp\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex - pageSize,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n case \"PageDown\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex + pageSize,\n 1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n default:\n return null;\n }\n}\n","export type PaginationWindowEntry = number | \"ellipsis\";\n\n/**\n * Which page numbers a numbered pager should show for `currentPage` of\n * `pageCount` — the boundary + sibling windowing MUI's `usePagination` uses.\n * Always includes the first/last `boundaryCount` pages and a run of\n * `2 * siblingCount + 1` pages around `currentPage`, slid inwards rather than\n * cut short near either end, with one slot between each boundary and that\n * run holding either the single page it skips or an `\"ellipsis\"`.\n *\n * So once `pageCount` exceeds `2 * boundaryCount + 2 * siblingCount + 3`,\n * every window is exactly that many entries long, wherever `currentPage`\n * sits: a pager drawing one fixed-width slot per entry keeps its trailing\n * controls in place as the user pages through. Below that, every page shows.\n */\nexport function paginationWindow(\n currentPage: number,\n pageCount: number,\n options?: {\n boundaryCount?: number | undefined;\n siblingCount?: number | undefined;\n },\n): readonly PaginationWindowEntry[] {\n if (pageCount <= 0) {\n return [];\n }\n\n const boundaryCount = Math.max(0, Math.floor(options?.boundaryCount ?? 1));\n const siblingCount = Math.max(0, Math.floor(options?.siblingCount ?? 1));\n const slotCount = 2 * boundaryCount + 2 * siblingCount + 3;\n\n if (pageCount <= slotCount) {\n return Array.from({ length: pageCount }, (_, index) => index + 1);\n }\n\n const current = Math.min(Math.max(currentPage, 1), pageCount);\n // The sibling run, slid to stay clear of the slot beside each boundary.\n const runStart = Math.min(\n Math.max(current - siblingCount, boundaryCount + 2),\n pageCount - boundaryCount - 1 - 2 * siblingCount,\n );\n const runEnd = runStart + 2 * siblingCount;\n\n const entries: PaginationWindowEntry[] = [];\n for (let page = 1; page <= boundaryCount; page++) {\n entries.push(page);\n }\n entries.push(runStart === boundaryCount + 2 ? boundaryCount + 1 : \"ellipsis\");\n for (let page = runStart; page <= runEnd; page++) {\n entries.push(page);\n }\n entries.push(\n runEnd === pageCount - boundaryCount - 1\n ? pageCount - boundaryCount\n : \"ellipsis\",\n );\n for (let page = pageCount - boundaryCount + 1; page <= pageCount; page++) {\n entries.push(page);\n }\n\n return entries;\n}\n","import type { ColumnVisibilityState, DataColumn } from \"../types\";\nimport type { SelectAllState } from \"./filterEditor\";\nimport { resolveColumnHeaderText } from \"./grid\";\nimport { isColumnVisible } from \"./visibility\";\n\n/** What a column chooser is drawn from: every column, the visibility, and the search typed. */\nexport interface ColumnChooserInput<Row> {\n /** Every column in its current order, hidden ones included — a view's `dataColumns`. */\n readonly columns: readonly DataColumn<Row, unknown>[];\n readonly visibility: ColumnVisibilityState;\n /** Narrows the list to the columns whose header text contains it, ignoring case. */\n readonly search?: string | undefined;\n}\n\n/** One column's checkbox in a column chooser. */\nexport interface ColumnChooserEntry {\n readonly columnId: string;\n /** The column's header text — what the search matches, and the checkbox's label. */\n readonly label: string;\n /** Whether the column is shown — whether its checkbox is checked. */\n readonly visible: boolean;\n /**\n * Whether the checkbox cannot be unchecked: the column is shown and is\n * either not `hideable` or the last column shown. A hidden column can\n * always be shown, `hideable` or not.\n */\n readonly disabled: boolean;\n}\n\n/** What toggling a chooser's \"Show all\" checkbox does: shows these columns, or hides them. */\nexport interface ColumnChooserToggle {\n readonly visible: boolean;\n readonly columnIds: readonly string[];\n}\n\nexport interface ColumnChooserModel {\n /** The columns the search matches, in column order. */\n readonly entries: readonly ColumnChooserEntry[];\n /**\n * The \"Show all\" checkbox's state over the entries whose columns are\n * `hideable` — the ones it acts on. A column the user cannot hide is\n * always on, so counting it would leave \"Show all\" stuck at mixed.\n */\n readonly selectAll: SelectAllState;\n /** What toggling \"Show all\" does, or `null` when it can do nothing — a disabled checkbox. */\n readonly toggleAll: ColumnChooserToggle | null;\n}\n\n/** A column as the chooser reads it. */\ninterface ChooserColumn<Row> {\n readonly column: DataColumn<Row, unknown>;\n readonly label: string;\n readonly visible: boolean;\n}\n\nfunction isHideable<Row>(column: DataColumn<Row, unknown>): boolean {\n return column.column.hideable !== false;\n}\n\nfunction matchesSearch(label: string, search: string): boolean {\n return label.toLowerCase().includes(search.toLowerCase());\n}\n\nfunction selectAllStateOf(states: readonly boolean[]): SelectAllState {\n if (states.length > 0 && states.every(Boolean)) {\n return \"checked\";\n }\n return states.some(Boolean) ? \"mixed\" : \"unchecked\";\n}\n\n/**\n * A column chooser's list for a search, and what its \"Show all\" checkbox\n * says and does — the same tri-state over what the search shows that a\n * filter editor's select-all is (`selectAllState`).\n *\n * \"Show all\" shows every hidden column the search shows once any is hidden,\n * and hides those it shows once none is. It never touches a column that is\n * not `hideable`, and never hides the last column shown: when that is all\n * that would be left, the first of them in column order stays, since a grid\n * with no column shown has no header to bring one back from.\n */\nexport function resolveColumnChooser<Row>({\n columns,\n visibility,\n search = \"\",\n}: ColumnChooserInput<Row>): ColumnChooserModel {\n const all = columns.map((column): ChooserColumn<Row> => ({\n column,\n label: resolveColumnHeaderText(column.column),\n visible: isColumnVisible(column.column, visibility),\n }));\n const shownCount = all.filter(({ visible }) => visible).length;\n const matched = all.filter(({ label }) => matchesSearch(label, search));\n\n const entries = matched.map(\n ({ column, label, visible }): ColumnChooserEntry => ({\n columnId: column.id,\n label,\n visible,\n disabled: visible && (!isHideable(column) || shownCount === 1),\n }),\n );\n\n const covered = matched.filter(({ column }) => isHideable(column));\n const selectAll = selectAllStateOf(covered.map(({ visible }) => visible));\n return {\n entries,\n selectAll,\n toggleAll: toggleAllOf(covered, selectAll, shownCount),\n };\n}\n\nfunction toggleAllOf<Row>(\n covered: readonly ChooserColumn<Row>[],\n selectAll: SelectAllState,\n shownCount: number,\n): ColumnChooserToggle | null {\n const show = selectAll !== \"checked\";\n const changing = covered\n .filter(({ visible }) => visible !== show)\n .map(({ column }) => column.id);\n // Hiding every column shown would leave none: the first of them stays.\n const columnIds =\n !show && changing.length === shownCount ? changing.slice(1) : changing;\n return columnIds.length === 0 ? null : { visible: show, columnIds };\n}\n","import type { ColumnType, FilterOperator, OperatorFilterEntry } from \"../types\";\nimport type { ColumnFilterShape } from \"../util/filterEditor\";\nimport { isScalarList } from \"../util/filterOperators\";\nimport {\n filterOperandArity,\n formatFilterOperand,\n parseFilterOperand,\n} from \"./operators\";\n\n/**\n * One condition row of a simple filter editor as the user types it: text,\n * not yet a value, so a half-typed number or date stays in its input until\n * the editor is applied and `conditionsFromRows` reads it.\n */\nexport interface ConditionRowDraft {\n readonly operator: FilterOperator;\n /** The operand as typed — `between`'s lower end. */\n readonly text: string;\n /**\n * `between`'s upper end, as typed. Kept under any other operator, unread,\n * so switching back to `between` finds it still there.\n */\n readonly textTo: string;\n}\n\n/** What `conditionsFromRows` reads off an editor's rows. */\nexport interface ParsedConditionRows<Row> {\n /** A condition for each row that reads as one, in row order. */\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n /**\n * The indexes of the rows that don't, for the editor to mark. Apply the\n * conditions only once this is empty.\n */\n readonly invalid: readonly number[];\n}\n\n/** A simple editor's rows: one condition, and an optional second joined to it. */\nconst ROW_COUNT = 2;\n\nfunction rowOf<Row>(\n condition: OperatorFilterEntry<Row>,\n type: ColumnType | undefined,\n): ConditionRowDraft {\n const { operator, value } = condition;\n if (isScalarList(value)) {\n const [low, high] = value;\n return {\n operator,\n text: formatFilterOperand(low, type),\n textTo: formatFilterOperand(high, type),\n };\n }\n return { operator, text: formatFilterOperand(value, type), textTo: \"\" };\n}\n\n/**\n * The rows a simple editor opens with over a column's filter `shape`, its\n * operands written as the column's `type` reads them: two, holding the\n * column's conditions when its filter is conditions, and each row they\n * don't fill starting at the first of `operators`, empty. With no operator\n * to start one at, only the rows the filter fills.\n */\nexport function conditionRowsFrom<Row>(\n shape: ColumnFilterShape<Row>,\n operators: readonly FilterOperator[],\n type: ColumnType | undefined,\n): readonly ConditionRowDraft[] {\n const filled =\n shape.kind === \"conditions\"\n ? shape.conditions.map((condition) => rowOf(condition, type))\n : [];\n const [first] = operators;\n if (first === undefined) {\n return filled;\n }\n const blank: ConditionRowDraft = { operator: first, text: \"\", textTo: \"\" };\n return Array.from(\n { length: ROW_COUNT },\n (_, index) => filled[index] ?? blank,\n );\n}\n\n/** Whether a row was left empty: none of the operands its operator takes is typed. */\nfunction isEmptyRow(row: ConditionRowDraft): boolean {\n switch (filterOperandArity(row.operator)) {\n case 0:\n return false;\n case 1:\n return row.text === \"\";\n case 2:\n return row.text === \"\" && row.textTo === \"\";\n }\n}\n\n/** `row` as a condition on `columnId`, or `undefined` when an operand it needs doesn't read. */\nfunction conditionOf<Row>(\n row: ConditionRowDraft,\n columnId: string,\n type: ColumnType | undefined,\n): OperatorFilterEntry<Row> | undefined {\n const { operator } = row;\n switch (filterOperandArity(operator)) {\n case 0:\n return { columnId, operator };\n case 1: {\n const value = parseFilterOperand(row.text, type);\n return value === undefined ? undefined : { columnId, operator, value };\n }\n case 2: {\n const low = parseFilterOperand(row.text, type);\n const high = parseFilterOperand(row.textTo, type);\n return low === undefined || high === undefined\n ? undefined\n : { columnId, operator, value: [low, high] };\n }\n }\n}\n\n/**\n * The conditions a simple editor's rows stand for on `columnId`, each\n * operand read as the column's `type` filters (`parseFilterOperand`) — for\n * `filterEditorReducer`'s `setConditions`, with the combinator the editor\n * shows.\n *\n * A row needs every operand its operator takes, or it is `invalid`; the\n * blanks operators take none. A row after the first left empty is dropped\n * rather than invalid, since the second condition is optional; an empty\n * first row is invalid — clearing the filter is the editor's clear action,\n * not an apply with nothing typed.\n */\nexport function conditionsFromRows<Row>(\n rows: readonly ConditionRowDraft[],\n columnId: string,\n type: ColumnType | undefined,\n): ParsedConditionRows<Row> {\n const conditions: OperatorFilterEntry<Row>[] = [];\n const invalid: number[] = [];\n for (const [index, row] of rows.entries()) {\n if (index > 0 && isEmptyRow(row)) {\n continue;\n }\n const condition = conditionOf<Row>(row, columnId, type);\n if (condition === undefined) {\n invalid.push(index);\n } else {\n conditions.push(condition);\n }\n }\n return { conditions, invalid };\n}\n","import type { GridMessages } from \"../messages\";\nimport type { DataColumn, FilterEntry, FilterState } from \"../types\";\nimport type {\n ColumnValueOptions,\n ColumnValueQuery,\n} from \"../util/filterEditor\";\nimport { columnValueOptions, touchesColumn } from \"../util/filterEditor\";\nimport type { FormatLocale } from \"../util/format\";\n\n/**\n * What a cached list is labelled by: `columnValueOptions`' query without\n * `search` and `limit`, which a draft applies over the whole list.\n */\nexport type ColumnValueCacheQuery = Pick<\n ColumnValueQuery,\n \"locale\" | \"messages\"\n>;\n\n/** `columnValueOptions`, remembered per column. */\nexport interface ColumnValueOptionsCache<Row> {\n /**\n * `columnId`'s whole value list — `columnValueOptions` with no `search`\n * or `limit` — or the very list it returned last time, when nothing the\n * list is counted from or labelled by has changed since.\n */\n readonly get: (\n rows: readonly Row[],\n dataColumns: readonly DataColumn<Row, unknown>[],\n filter: FilterState<Row>,\n columnId: string,\n query?: ColumnValueCacheQuery,\n ) => ColumnValueOptions;\n}\n\n/** What every list in a cache is counted from and labelled by. */\ninterface CacheSource<Row> {\n readonly rows: readonly Row[];\n readonly dataColumns: readonly DataColumn<Row, unknown>[];\n readonly locale: FormatLocale;\n readonly messages: Partial<GridMessages> | undefined;\n}\n\ninterface CachedList<Row> {\n /** The entries it was counted under: every one not about its column. */\n readonly others: FilterState<Row>;\n readonly values: ColumnValueOptions;\n}\n\nfunction sameSource<Row>(a: CacheSource<Row>, b: CacheSource<Row>): boolean {\n return (\n a.rows === b.rows &&\n a.dataColumns === b.dataColumns &&\n a.locale === b.locale &&\n a.messages === b.messages\n );\n}\n\nfunction sameEntries<Row>(\n a: readonly FilterEntry<Row>[],\n b: readonly FilterEntry<Row>[],\n): boolean {\n return a.length === b.length && a.every((entry, index) => entry === b[index]);\n}\n\n/**\n * A memo of each column's checklist values, for a renderer to hold one of\n * per grid: reopening a column's checklist hands back the list it was given\n * last time — the same object — rather than counting `rows` again, until\n * something the list depends on changes.\n *\n * That is the `rows` and `dataColumns`, the `locale` and `messages` it is\n * labelled in, and the filter's entries not about the column — all compared\n * by identity, the entries one by one. Identity holds across an apply:\n * `draftToFilter` keeps every entry it doesn't replace as it was, so\n * filtering one column leaves the lists of the others to recount and its\n * own cached, since a column's list never depends on its own entries.\n *\n * Each column keeps its latest list. New rows, columns, locale or messages\n * drop every list, so the cache never holds on to rows the grid has let go\n * of — pass the grid's own, which keep their identity between renders.\n */\nexport function createColumnValueOptionsCache<\n Row,\n>(): ColumnValueOptionsCache<Row> {\n let source: CacheSource<Row> | undefined;\n const lists = new Map<string, CachedList<Row>>();\n return {\n get: (rows, dataColumns, filter, columnId, query = {}) => {\n const { locale, messages } = query;\n const current: CacheSource<Row> = { rows, dataColumns, locale, messages };\n if (source === undefined || !sameSource(source, current)) {\n lists.clear();\n source = current;\n }\n const others = filter.filter((entry) => !touchesColumn(entry, columnId));\n const cached = lists.get(columnId);\n if (cached !== undefined && sameEntries(cached.others, others)) {\n return cached.values;\n }\n const values = columnValueOptions(\n rows,\n dataColumns,\n filter,\n columnId,\n messages === undefined ? { locale } : { locale, messages },\n );\n lists.set(columnId, { others, values });\n return values;\n },\n };\n}\n","import type { FilterScalar } from \"../types\";\nimport type { FilterEditorDraft } from \"../util/filterEditor\";\nimport {\n keyOf,\n selectAllCoversBlanks,\n visibleFilterOptions,\n} from \"../util/filterEditor\";\n\n/** One row of a checklist: a value the column holds, or its blank cells. */\nexport type FilterChecklistItem = {\n /**\n * Tells the item apart from every other in the list: a value's key is the\n * one `draft.checked` holds it under, and the blanks have their own.\n */\n readonly key: string;\n /** The value as its cells print it, or the blanks' label. */\n readonly label: string;\n /** How many rows hold it, among those the other columns' filters keep. */\n readonly count: number;\n readonly checked: boolean;\n} & (\n | {\n /** Toggled with `filterEditorReducer`'s `toggleValue`. */\n readonly kind: \"value\";\n readonly value: Exclude<FilterScalar, null>;\n }\n | {\n /** Toggled with `filterEditorReducer`'s `setIncludeBlanks`. */\n readonly kind: \"blanks\";\n }\n);\n\nexport interface FilterChecklistOptions {\n /** How many values the list shows at most: the column's resolved `valueLimit`. */\n readonly valueLimit: number;\n /** The blanks item's label: the grid's `filterBlanks` message. */\n readonly blanksLabel: string;\n}\n\n/** What a checklist editor draws below its search box and select-all. */\nexport interface FilterChecklist {\n /**\n * The rows to draw, in order: the values the search shows, cut to\n * `valueLimit`, then the blanks while nothing is searched and some cells\n * are blank. Empty while `needsSearch`.\n */\n readonly items: readonly FilterChecklistItem[];\n /**\n * Whether the list waits for a search: the column holds more values than\n * `valueLimit` and nothing is searched yet — `filterSearchFirst(total)`.\n */\n readonly needsSearch: boolean;\n /**\n * How many of the values the search matches `valueLimit` left out of\n * `items` — `filterMoreValues(hiddenCount)`. `0` while `needsSearch`, so\n * the two notes never show together.\n */\n readonly hiddenCount: number;\n /** How many values the search matches — every value while nothing is searched. Blanks aside. */\n readonly total: number;\n}\n\n/**\n * The list a checklist editor draws for `draft`: the window of values its\n * search shows, as items carrying what each row says and whether it is\n * checked.\n *\n * A column can hold far more values than a list is worth scrolling, so the\n * list shows at most `valueLimit` of them. Past that, it shows nothing until\n * something is searched (`needsSearch`) — every value is still in the draft,\n * and select-all still covers them all — and a search matching more shows\n * the first `valueLimit` of its matches in sort order, with the rest counted\n * in `hiddenCount`.\n *\n * The blanks item comes last, as in Excel's, and only while nothing is\n * searched: exactly when select-all counts the blanks, so the checkbox acts\n * on what the list shows.\n */\nexport function filterChecklist<Row>(\n draft: FilterEditorDraft<Row>,\n { valueLimit, blanksLabel }: FilterChecklistOptions,\n): FilterChecklist {\n const visible = visibleFilterOptions(draft);\n const total = visible.length;\n if (draft.search === \"\" && total > valueLimit) {\n return { items: [], needsSearch: true, hiddenCount: 0, total };\n }\n const items = visible\n .slice(0, valueLimit)\n .map(({ value, label, count }): FilterChecklistItem => {\n const key = keyOf(draft, value);\n const checked = draft.checked.has(key);\n return { kind: \"value\", key, value, label, count, checked };\n });\n const hiddenCount = total - items.length;\n if (selectAllCoversBlanks(draft)) {\n items.push({\n kind: \"blanks\",\n // Blank cells' own key, which no offered value has.\n key: keyOf(draft, null),\n label: blanksLabel,\n count: draft.blanks,\n checked: draft.includeBlanks,\n });\n }\n return { items, needsSearch: false, hiddenCount, total };\n}\n","/**\n * One entry per row: its measured height once known, `undefined` until then.\n * A row never yet rendered (or rendered but not yet observed) falls back to\n * `visibleRange`'s own `estimatedHeight` argument.\n */\nexport type RowHeights = readonly (number | undefined)[];\n\nexport interface VisibleRange {\n readonly startIndex: number;\n readonly endIndex: number; // inclusive\n /** Total height of every row before `startIndex` — the leading spacer's height. */\n readonly offsetBefore: number;\n /** Total height of every row after `endIndex` — the trailing spacer's height. */\n readonly offsetAfter: number;\n}\n\n/**\n * Which rows of a dynamic-height, virtualized list fall within\n * `[scrollTop, scrollTop + viewportHeight)`, padded by `overscan` rows on\n * each side and clamped to the array's own bounds.\n *\n * Walks a cumulative-offset prefix sum built from `heights` (measured height\n * where known, `estimatedHeight` otherwise) rather than assuming a uniform\n * row height — this codebase's rows are not uniform (`.is-wrapped` cells,\n * group header/summary rows), so a fixed-height virtualizer would either\n * break wrapping or force it out of scope.\n *\n * `O(n)` in `heights.length`. Deliberately not a Fenwick tree or a\n * binary-searchable prefix-sum structure — that optimization belongs in the\n * mutable height cache that already owns mutability (`createRowVirtualizer`\n * in `@gridkitjs/dom`), not in this pure function's contract, and is not\n * worth taking on until a profiled scenario actually shows it matters at\n * realistic row counts.\n */\nexport function visibleRange(\n heights: RowHeights,\n estimatedHeight: number,\n scrollTop: number,\n viewportHeight: number,\n overscan: number,\n): VisibleRange {\n const rowCount = heights.length;\n if (rowCount === 0) {\n return { startIndex: 0, endIndex: -1, offsetBefore: 0, offsetAfter: 0 };\n }\n\n function heightAt(index: number): number {\n return heights[index] ?? estimatedHeight;\n }\n\n const viewportBottom = scrollTop + viewportHeight;\n\n // The first row whose bottom edge crosses `scrollTop` — everything before\n // it is fully scrolled past. `top` tracks that row's own top edge (the\n // cumulative height of every row before it) as the walk advances. Stops at\n // the last row rather than walking off the end when `scrollTop` reaches or\n // exceeds the total height.\n let start = 0;\n let top = 0;\n while (start < rowCount - 1 && top + heightAt(start) <= scrollTop) {\n top += heightAt(start);\n start += 1;\n }\n const startTop = top;\n\n // From `start`, the last row whose top edge is still above `viewportBottom`\n // — the first row no longer even partially visible ends the walk one row\n // earlier than it, or the array itself runs out first. `bottom` tracks the\n // current row's own bottom edge.\n let end = start;\n let bottom = startTop + heightAt(start);\n while (end < rowCount - 1 && bottom < viewportBottom) {\n end += 1;\n bottom += heightAt(end);\n }\n\n const overscanStart = Math.max(0, start - overscan);\n const overscanEnd = Math.min(rowCount - 1, end + overscan);\n\n let offsetBefore = 0;\n for (let index = 0; index < overscanStart; index++) {\n offsetBefore += heightAt(index);\n }\n let offsetAfter = 0;\n for (let index = overscanEnd + 1; index < rowCount; index++) {\n offsetAfter += heightAt(index);\n }\n\n return {\n startIndex: overscanStart,\n endIndex: overscanEnd,\n offsetBefore,\n offsetAfter,\n };\n}\n","import type { GridOptions } from \"./options\";\n\n/**\n * Turns on the per-column filter popup in its Excel-style form — a search\n * box, a checklist of the column's values with their counts, and an operator\n * submenu — in one spread: `<DataGrid {...excelFilter} />`.\n *\n * A preset is a plain value of `GridOptions`, not a component or a hook, so\n * any renderer can take it the way it takes its other options (a Vue spread,\n * an Angular binding) and a later option overrides it: spreading it before\n * `filterMenu={{ ui: \"simple\" }}` brings the simple editor back. `filterMenu`\n * is replaced whole, not merged, so repeat `showCounts` if it should stay.\n */\nexport const excelFilter = {\n filterableColumns: true,\n filterMenu: { ui: \"excel\", showCounts: true },\n} as const satisfies Partial<GridOptions<unknown>>;\n"],"mappings":"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","names":["total","isEmpty","test","columnId","entry","resolveColumns","localeKey","columnName","columnCount","keyOf","columnCount","matchesSearch","selectAll","cached","keyOf"]}
|