@x12i/data 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +549 -3
- package/dist/chunk-ASP4ABDG.js +1987 -0
- package/dist/chunk-ASP4ABDG.js.map +1 -0
- package/dist/index.d.ts +394 -0
- package/dist/index.js +219 -0
- package/dist/index.js.map +1 -0
- package/dist/messages-BF20Mq97.d.ts +508 -0
- package/dist/react.d.ts +328 -0
- package/dist/react.js +3078 -0
- package/dist/react.js.map +1 -0
- package/dist/styles.css +1169 -0
- package/package.json +87 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/columns.ts","../src/values.ts","../src/formatters.ts","../src/sort.ts","../src/filter.ts","../src/aggregate.ts","../src/group.ts","../src/view.ts","../src/selection.ts","../src/keyboard.ts","../src/state.ts","../src/csv.ts","../src/saved-views.ts","../src/server.ts","../src/message-format.ts","../src/messages.ts"],"sourcesContent":["/**\n * Contracts for the kit's DataGrid (spec section 7). The grid's data pipeline\n * is this package's own headless engine and its windowing is TanStack Virtual;\n * these types are the stable surface that apps, reports and charts depend on.\n *\n * Everything here is additive over the first release: a `ColumnDef` written\n * for 1.0.0 still type-checks and means the same thing.\n */\n\nexport type SortDirection = \"asc\" | \"desc\";\n\nexport interface SortModelItem {\n /** The column `id` the sort applies to. Server requests carry `column.field ?? column.id`. */\n field: string;\n direction: SortDirection;\n}\n\nexport type FilterOperator =\n | \"contains\"\n | \"not-contains\"\n | \"starts-with\"\n | \"equals\"\n | \"not-equals\"\n | \"gt\"\n | \"gte\"\n | \"lt\"\n | \"lte\"\n | \"between\"\n | \"in\"\n | \"before\"\n | \"after\"\n | \"is-empty\"\n | \"is-not-empty\";\n\nexport interface FilterModelItem {\n /** The column `id` the filter applies to. */\n field: string;\n operator: FilterOperator;\n /** Absent for `is-empty` and `is-not-empty`. An array for `in` and `between`. */\n value?: unknown;\n}\n\nexport interface GroupModelItem {\n /** The column `id` to group by. */\n field: string;\n}\n\n/** What the grid asks a server for. Row indexes are zero-based and `endRow` is exclusive. */\nexport interface GetRowsRequest {\n startRow: number;\n endRow: number;\n sort: SortModelItem[];\n filter: FilterModelItem[];\n group: GroupModelItem[];\n /** The quick-search text, when the grid has any. */\n quickFilter?: string;\n /**\n * Cursor from the previous block's `nextCursor`, for APIs that page by cursor\n * instead of offset. `null` for the first block.\n */\n cursor?: string | null;\n}\n\nexport interface GetRowsResult<Row> {\n rows: Row[];\n /** Total rows matching the filter, so the grid can size its scrollbar. */\n total: number;\n /** Cursor for the block after this one. Present only for cursor-paged APIs. */\n nextCursor?: string | null;\n}\n\nexport interface GetRowsOptions {\n /** Aborted when the grid no longer needs the answer, for example after a new sort. */\n signal?: AbortSignal;\n}\n\n/** The server data source: `getRows({ startRow, endRow, sort, filter, group })` returns `{ rows, total }`. */\nexport interface ServerDataSource<Row> {\n getRows(request: GetRowsRequest, options?: GetRowsOptions): Promise<GetRowsResult<Row>>;\n}\n\n/** Cell renderers the grid ships (spec section 7). */\nexport type CellType =\n | \"text\"\n | \"number\"\n | \"currency\"\n | \"percent\"\n | \"date\"\n | \"datetime\"\n | \"boolean\"\n | \"status\"\n | \"avatar\"\n | \"progress\"\n | \"sparkline\"\n | \"link\"\n | \"tags\"\n | \"actions\"\n | \"custom\";\n\n/** Logical sides, so a pinned column follows the reading direction in RTL. */\nexport type ColumnPin = \"start\" | \"end\";\n\n/** Cell text alignment on the inline axis. Numeric types default to `end`. */\nexport type ColumnAlign = \"start\" | \"center\" | \"end\";\n\n/** Tones of the kit `Badge`, shared by status cells and charts. */\nexport type StatusTone = \"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\" | \"info\";\n\n/** One choice of an enum column: status badge, select editor and set filter. */\nexport interface ColumnOption {\n value: string;\n /** Display text. Pass a translated string. */\n label: string;\n /** Badge tone for `status` cells. */\n tone?: StatusTone;\n}\n\nexport type AggregateName = \"sum\" | \"avg\" | \"min\" | \"max\" | \"count\";\n\n/** A custom aggregate: receives the column's values and the rows they came from. */\nexport type AggregateFn<Row> = (values: unknown[], rows: Row[]) => unknown;\n\n/** The filter UI and operators a column offers. Derived from `cellType` when absent. */\nexport type ColumnFilterType = \"text\" | \"number\" | \"date\" | \"enum\" | \"boolean\";\n\nexport type ColumnEditor = \"text\" | \"number\" | \"select\" | \"boolean\" | \"date\";\n\nexport interface ColumnDef<Row> {\n /** Stable identifier, also used in saved views. */\n id: string;\n /** Header text. Pass a translated string. */\n header: string;\n /** Property of the row to read. */\n field?: Extract<keyof Row, string>;\n cellType?: CellType;\n /**\n * An `Intl`-based format name, by cell type. Number: `integer`, `compact`,\n * `decimal:2`, `unit:kilobyte`. Currency: an ISO code such as `EUR`. Percent:\n * `whole` when the value is 0 to 100 instead of a fraction. Date and datetime:\n * `short`, `medium`, `long`, `full`, `iso`.\n */\n format?: string;\n width?: number;\n minWidth?: number;\n pinned?: ColumnPin;\n sortable?: boolean;\n filterable?: boolean;\n resizable?: boolean;\n editable?: boolean;\n\n // ---- Added in the DataGrid release. All optional. ----\n\n maxWidth?: number;\n align?: ColumnAlign;\n /** Reads the value when `field` is not enough, for example a nested property. */\n accessor?: (row: Row) => unknown;\n /**\n * Text for a value. Used by CSV export, copy, quick search and screen readers,\n * and by the default cell renderer. Overrides `format`.\n */\n formatter?: (value: unknown, row: Row) => string;\n /** Replaces the default comparison. Return a negative, zero or positive number. */\n comparator?: (a: unknown, b: unknown, rowA: Row, rowB: Row) => number;\n /** Shown in group rows and in the totals footer. */\n aggregate?: AggregateName | AggregateFn<Row>;\n filterType?: ColumnFilterType;\n /** Choices for `status` cells, enum filters and select editors. */\n options?: ColumnOption[];\n /** ISO 4217 code for `currency` cells. Defaults to `USD`. */\n currency?: string;\n numberFormat?: Intl.NumberFormatOptions;\n dateFormat?: Intl.DateTimeFormatOptions;\n /** Maximum for `progress` cells. Defaults to 100. */\n progressMax?: number;\n editor?: ColumnEditor;\n /** Per-row editability on top of `editable`. */\n canEdit?: (row: Row) => boolean;\n /** Return an error message to reject an edit, or nothing to accept it. */\n validate?: (value: unknown, row: Row) => string | null | undefined;\n /** Turns the editor's text into a value. Defaults by editor type. */\n parseValue?: (input: string, row: Row) => unknown;\n /** Hidden until the user shows the column. */\n hidden?: boolean;\n /** `false` keeps the column out of the visibility menu. Default `true`. */\n hideable?: boolean;\n /** `false` keeps the column out of the grouping menu. Default `true`. */\n groupable?: boolean;\n /** `false` leaves the column out of quick search. */\n searchable?: boolean;\n /** Adjacent columns with the same `group` share a header above them. */\n group?: string;\n /** Free-form data for custom renderers. The grid never reads it. */\n meta?: Record<string, unknown>;\n}\n\n/** Identity helper that infers `Row` for column authoring. */\nexport function defineColumns<Row>(columns: ColumnDef<Row>[]): ColumnDef<Row>[] {\n return columns;\n}\n\nexport interface ColumnState {\n id: string;\n width?: number;\n hidden?: boolean;\n pinned?: ColumnPin;\n}\n\nexport const SAVED_VIEW_VERSION = 1;\n\n/** Column state, filters and sort, serialized to JSON. */\nexport interface SavedView {\n version: typeof SAVED_VIEW_VERSION;\n name?: string;\n columns: ColumnState[];\n sort: SortModelItem[];\n filter: FilterModelItem[];\n group?: GroupModelItem[];\n}\n\n/** Every filter operator, as a runtime list for validation and pickers. */\nexport const FILTER_OPERATORS = [\n \"contains\",\n \"not-contains\",\n \"starts-with\",\n \"equals\",\n \"not-equals\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"between\",\n \"in\",\n \"before\",\n \"after\",\n \"is-empty\",\n \"is-not-empty\",\n] as const satisfies readonly FilterOperator[];\n\n// Compile-time guard: adding an operator to `FilterOperator` without listing it\n// above makes this line fail to type-check.\nconst _everyOperatorListed: Exclude<FilterOperator, (typeof FILTER_OPERATORS)[number]> extends never\n ? true\n : never = true;\nvoid _everyOperatorListed;\n","import type { CellType, ColumnAlign, ColumnDef, ColumnEditor, ColumnFilterType } from \"./types\";\n\nexport const DEFAULT_COLUMN_WIDTH = 160;\nexport const DEFAULT_COLUMN_MIN_WIDTH = 64;\nexport const DEFAULT_COLUMN_MAX_WIDTH = 1200;\n\n/** Reads the value of a column from a row: `accessor`, else `field`, else `undefined`. */\nexport function getColumnValue<Row>(column: ColumnDef<Row>, row: Row): unknown {\n if (column.accessor !== undefined) return column.accessor(row);\n if (column.field !== undefined) return (row as Record<string, unknown>)[column.field];\n return undefined;\n}\n\n/** The column's `field`, or its `id` when it has none. This is the name a server sees. */\nexport function columnFieldName<Row>(column: ColumnDef<Row>): string {\n return column.field ?? column.id;\n}\n\n/** The cell types whose values are numbers, aligned to the end by default. */\nconst NUMERIC: ReadonlySet<CellType> = new Set([\"number\", \"currency\", \"percent\"]);\n\nexport function isNumericCellType(cellType: CellType | undefined): boolean {\n return cellType !== undefined && NUMERIC.has(cellType);\n}\n\n/** The alignment of a column: its `align`, or `end` for numbers and `start` otherwise. */\nexport function resolveColumnAlign<Row>(column: ColumnDef<Row>): ColumnAlign {\n if (column.align !== undefined) return column.align;\n if (isNumericCellType(column.cellType)) return \"end\";\n if (column.cellType === \"boolean\") return \"center\";\n return \"start\";\n}\n\n/** The filter type of a column: `filterType`, else derived from `cellType`. */\nexport function resolveFilterType<Row>(column: ColumnDef<Row>): ColumnFilterType {\n if (column.filterType !== undefined) return column.filterType;\n switch (column.cellType) {\n case \"number\":\n case \"currency\":\n case \"percent\":\n case \"progress\":\n return \"number\";\n case \"date\":\n case \"datetime\":\n return \"date\";\n case \"boolean\":\n return \"boolean\";\n case \"status\":\n return \"enum\";\n case \"tags\":\n return column.options !== undefined ? \"enum\" : \"text\";\n default:\n return column.options !== undefined ? \"enum\" : \"text\";\n }\n}\n\n/** The editor of a column: `editor`, else derived from `cellType`. */\nexport function resolveEditor<Row>(column: ColumnDef<Row>): ColumnEditor {\n if (column.editor !== undefined) return column.editor;\n switch (column.cellType) {\n case \"number\":\n case \"currency\":\n case \"percent\":\n case \"progress\":\n return \"number\";\n case \"date\":\n case \"datetime\":\n return \"date\";\n case \"boolean\":\n return \"boolean\";\n case \"status\":\n return \"select\";\n default:\n return column.options !== undefined ? \"select\" : \"text\";\n }\n}\n\n/** Cell types that carry no sortable, filterable value of their own. */\nconst INERT: ReadonlySet<CellType> = new Set([\"actions\", \"custom\"]);\n\nexport function isSortable<Row>(column: ColumnDef<Row>): boolean {\n if (column.sortable !== undefined) return column.sortable;\n return column.cellType === undefined || !INERT.has(column.cellType);\n}\n\nexport function isFilterable<Row>(column: ColumnDef<Row>): boolean {\n if (column.filterable !== undefined) return column.filterable;\n return false;\n}\n\nexport function isResizable<Row>(column: ColumnDef<Row>): boolean {\n return column.resizable ?? true;\n}\n\nexport function isEditable<Row>(column: ColumnDef<Row>, row: Row): boolean {\n if (column.editable !== true) return false;\n return column.canEdit === undefined || column.canEdit(row);\n}\n\n/** Clamps a width to the column's `minWidth` and `maxWidth`. */\nexport function clampColumnWidth<Row>(column: ColumnDef<Row>, width: number): number {\n const min = column.minWidth ?? DEFAULT_COLUMN_MIN_WIDTH;\n const max = Math.max(min, column.maxWidth ?? DEFAULT_COLUMN_MAX_WIDTH);\n return Math.min(max, Math.max(min, Math.round(width)));\n}\n\n/** The width of a column before any resize: `width`, clamped, or the default. */\nexport function initialColumnWidth<Row>(column: ColumnDef<Row>): number {\n return clampColumnWidth(column, column.width ?? DEFAULT_COLUMN_WIDTH);\n}\n\n/** Looks columns up by id. The first column with an id wins. */\nexport function indexColumns<Row>(columns: readonly ColumnDef<Row>[]): Map<string, ColumnDef<Row>> {\n const map = new Map<string, ColumnDef<Row>>();\n for (const column of columns) if (!map.has(column.id)) map.set(column.id, column);\n return map;\n}\n","/** Small value helpers shared by the sort, filter, format and export engines. */\n\nconst DATE_ONLY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/** `YYYY-MM-DD`. Such a value names a calendar day, not an instant. */\nexport function isDateOnlyString(value: unknown): value is string {\n return typeof value === \"string\" && DATE_ONLY.test(value);\n}\n\n/** `null`, `undefined`, an empty string, `NaN` and an empty array. `0` and `false` are values. */\nexport function isEmptyValue(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n value === \"\" ||\n (typeof value === \"number\" && Number.isNaN(value)) ||\n (Array.isArray(value) && value.length === 0)\n );\n}\n\n/** A finite number from a number, bigint or numeric string; `NaN` for anything else. */\nexport function toNumber(value: unknown): number {\n if (typeof value === \"number\") return value;\n if (typeof value === \"bigint\") return Number(value);\n if (typeof value === \"string\") {\n const text = value.trim();\n return text === \"\" ? Number.NaN : Number(text);\n }\n return Number.NaN;\n}\n\n/** Milliseconds since the epoch from a `Date`, number or date string; `NaN` for anything else. */\nexport function toTimestamp(value: unknown): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\") return value === \"\" ? Number.NaN : Date.parse(value);\n return Number.NaN;\n}\n\n/** A `Date` from a date-like value, or `null` when it is not a valid date. */\nexport function toDate(value: unknown): Date | null {\n const time = toTimestamp(value);\n return Number.isNaN(time) ? null : new Date(time);\n}\n\n/** Plain text for any value. Arrays join with a comma, dates use ISO format, `null` is empty. */\nexport function toText(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\") {\n return String(value);\n }\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? \"\" : value.toISOString();\n if (Array.isArray(value)) return value.map(toText).join(\", \");\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n return \"\";\n }\n }\n return String(value);\n}\n\n/** Lower-cases and strips diacritics so \"José\" matches \"jose\". */\nexport function normalizeText(value: string, locale?: string): string {\n return value\n .normalize(\"NFD\")\n .replace(/\\p{M}+/gu, \"\")\n .toLocaleLowerCase(locale);\n}\n\n/** A boolean from a boolean or the strings `true`/`false`; `null` for anything else. */\nexport function toBoolean(value: unknown): boolean | null {\n if (typeof value === \"boolean\") return value;\n if (value === \"true\") return true;\n if (value === \"false\") return false;\n return null;\n}\n","import type { CellType, ColumnDef } from \"./types\";\nimport { isDateOnlyString, isEmptyValue, toBoolean, toDate, toNumber, toText } from \"./values\";\n\nexport interface FormatLabels {\n yes: string;\n no: string;\n}\n\n/** English labels for boolean values. The grid replaces them with its `messages`. */\nexport const defaultFormatLabels: FormatLabels = { yes: \"Yes\", no: \"No\" };\n\nexport interface FormatContext {\n /** BCP 47 locale for `Intl`. Defaults to the runtime locale. */\n locale?: string;\n /** IANA time zone for dates and times. Date-only values always format in UTC. */\n timeZone?: string;\n labels?: FormatLabels;\n}\n\nexport type CellFormatter<Row> = (value: unknown, row: Row) => string;\n\nconst cache = new Map<string, Intl.NumberFormat | Intl.DateTimeFormat>();\n\nfunction numberFormat(locale: string | undefined, options: Intl.NumberFormatOptions): Intl.NumberFormat | null {\n const key = `n|${locale ?? \"\"}|${JSON.stringify(options)}`;\n let format = cache.get(key) as Intl.NumberFormat | undefined;\n if (format === undefined) {\n try {\n format = new Intl.NumberFormat(locale, options);\n } catch {\n return null;\n }\n cache.set(key, format);\n }\n return format;\n}\n\nfunction dateFormat(locale: string | undefined, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat | null {\n const key = `d|${locale ?? \"\"}|${JSON.stringify(options)}`;\n let format = cache.get(key) as Intl.DateTimeFormat | undefined;\n if (format === undefined) {\n try {\n format = new Intl.DateTimeFormat(locale, options);\n } catch {\n return null;\n }\n cache.set(key, format);\n }\n return format;\n}\n\n/** `Intl.NumberFormat` options for a numeric column, from `cellType`, `format` and the overrides. */\nexport function resolveNumberFormatOptions<Row>(column: ColumnDef<Row>): Intl.NumberFormatOptions {\n const format = column.format;\n const type: CellType | undefined = column.cellType;\n\n if (type === \"currency\") {\n const code = column.currency ?? (format !== undefined && /^[A-Za-z]{3}$/.test(format) ? format.toUpperCase() : \"USD\");\n return { style: \"currency\", currency: code, ...column.numberFormat };\n }\n if (type === \"percent\" || type === \"progress\") {\n return { style: \"percent\", minimumFractionDigits: 0, maximumFractionDigits: 1, ...column.numberFormat };\n }\n\n const base: Intl.NumberFormatOptions = {};\n if (format === \"integer\") base.maximumFractionDigits = 0;\n else if (format === \"compact\") base.notation = \"compact\";\n else if (format?.startsWith(\"decimal:\")) {\n const digits = Number(format.slice(\"decimal:\".length));\n if (Number.isInteger(digits) && digits >= 0 && digits <= 20) {\n base.minimumFractionDigits = digits;\n base.maximumFractionDigits = digits;\n }\n } else if (format?.startsWith(\"unit:\")) {\n base.style = \"unit\";\n base.unit = format.slice(\"unit:\".length);\n }\n return { ...base, ...column.numberFormat };\n}\n\nconst DATE_STYLES = new Set([\"short\", \"medium\", \"long\", \"full\"]);\n\n/** `Intl.DateTimeFormat` options for a date or datetime column. */\nexport function resolveDateFormatOptions<Row>(column: ColumnDef<Row>): Intl.DateTimeFormatOptions {\n if (column.dateFormat !== undefined) return column.dateFormat;\n const style = (DATE_STYLES.has(column.format ?? \"\") ? column.format : \"medium\") as\n | \"short\"\n | \"medium\"\n | \"long\"\n | \"full\";\n if (column.cellType === \"datetime\") {\n return { dateStyle: style, timeStyle: style === \"short\" || style === \"medium\" ? \"short\" : \"medium\" };\n }\n return { dateStyle: style };\n}\n\nfunction formatDate<Row>(\n column: ColumnDef<Row>,\n value: unknown,\n ctx: FormatContext,\n options: Intl.DateTimeFormatOptions,\n): string {\n const date = toDate(value);\n if (date === null) return toText(value);\n const dateOnly = isDateOnlyString(value);\n if (column.format === \"iso\") {\n return column.cellType === \"datetime\" && !dateOnly ? date.toISOString() : date.toISOString().slice(0, 10);\n }\n const effective: Intl.DateTimeFormatOptions = { ...options };\n // A date-only string names a calendar day: format it in UTC so it never shifts.\n if (dateOnly) effective.timeZone = \"UTC\";\n else if (ctx.timeZone !== undefined) effective.timeZone = ctx.timeZone;\n const format = dateFormat(ctx.locale, effective);\n return format === null ? date.toISOString() : format.format(date);\n}\n\nfunction optionLabel<Row>(column: ColumnDef<Row>, value: unknown): string {\n const text = toText(value);\n return column.options?.find((option) => option.value === text)?.label ?? text;\n}\n\n/**\n * Builds a formatter for a column once, so formatting 100,000 cells reuses one\n * `Intl` object. A column's own `formatter` always wins. Empty values give \"\".\n *\n * Without a `cellType`, the value decides: numbers use number format, dates use\n * date format, booleans use yes/no, arrays join.\n */\nexport function createCellFormatter<Row>(column: ColumnDef<Row>, ctx: FormatContext = {}): CellFormatter<Row> {\n if (column.formatter !== undefined) {\n const custom = column.formatter;\n return (value, row) => custom(value, row);\n }\n const labels = ctx.labels ?? defaultFormatLabels;\n const type = column.cellType;\n\n const numeric = numberFormat(ctx.locale, resolveNumberFormatOptions({ ...column, cellType: type ?? \"number\" }));\n const dateOptions = resolveDateFormatOptions({ ...column, cellType: type ?? \"date\" });\n const percentWhole = column.format === \"whole\";\n const progressMax = column.progressMax ?? 100;\n\n const formatNumber = (value: unknown, scale = 1): string => {\n const number = toNumber(value);\n if (Number.isNaN(number)) return toText(value);\n return numeric === null ? String(number) : numeric.format(number / scale);\n };\n\n return (value) => {\n if (isEmptyValue(value)) return \"\";\n switch (type) {\n case \"number\":\n case \"currency\":\n return formatNumber(value);\n case \"percent\":\n return formatNumber(value, percentWhole ? 100 : 1);\n case \"progress\":\n return formatNumber(value, progressMax);\n case \"date\":\n case \"datetime\":\n return formatDate(column, value, ctx, dateOptions);\n case \"boolean\": {\n const flag = toBoolean(value);\n return flag === null ? toText(value) : flag ? labels.yes : labels.no;\n }\n case \"status\":\n return optionLabel(column, value);\n case \"tags\":\n return Array.isArray(value) ? value.map((item) => optionLabel(column, item)).join(\", \") : toText(value);\n case \"sparkline\":\n return Array.isArray(value) ? value.map(toText).join(\" \") : toText(value);\n case \"actions\":\n return \"\";\n case undefined: {\n if (typeof value === \"number\") return formatNumber(value);\n if (value instanceof Date) return formatDate(column, value, ctx, resolveDateFormatOptions({ ...column, cellType: \"date\" }));\n if (typeof value === \"boolean\") return value ? labels.yes : labels.no;\n if (column.options !== undefined) return optionLabel(column, value);\n return toText(value);\n }\n default:\n return toText(value);\n }\n };\n}\n\n/** One-off formatting. Prefer `createCellFormatter` when formatting many cells. */\nexport function formatCellValue<Row>(\n column: ColumnDef<Row>,\n value: unknown,\n row: Row,\n ctx: FormatContext = {},\n): string {\n return createCellFormatter(column, ctx)(value, row);\n}\n","import { getColumnValue, indexColumns } from \"./columns\";\nimport type { ColumnDef, SortModelItem } from \"./types\";\nimport { toNumber, toText, toTimestamp } from \"./values\";\n\nexport interface SortOptions {\n /** BCP 47 locale for string comparison. Defaults to the runtime locale. */\n locale?: string;\n /** Compare digit runs as numbers, so \"item 2\" sorts before \"item 10\". Default `true`. */\n numeric?: boolean;\n /** Ignore case and accents when comparing strings. Default `true`. */\n caseInsensitive?: boolean;\n}\n\n/** A comparable key: numbers and strings compare naturally, `null` always sorts last. */\ntype SortKey = number | string | null;\n\nexport function createCollator(options: SortOptions = {}): Intl.Collator {\n return new Intl.Collator(options.locale, {\n numeric: options.numeric ?? true,\n sensitivity: options.caseInsensitive === false ? \"variant\" : \"base\",\n });\n}\n\n/** The key a value sorts by. Numbers, dates and booleans become numbers; the rest become text. */\nexport function toSortKey(value: unknown): SortKey {\n if (value === null || value === undefined) return null;\n if (typeof value === \"number\") return Number.isNaN(value) ? null : value;\n if (typeof value === \"bigint\") return Number(value);\n if (typeof value === \"boolean\") return value ? 1 : 0;\n if (value instanceof Date) {\n const time = value.getTime();\n return Number.isNaN(time) ? null : time;\n }\n if (typeof value === \"string\") return value === \"\" ? null : value;\n if (Array.isArray(value)) return value.length === 0 ? null : toText(value);\n return toText(value);\n}\n\n/** The key for a column, using the column type to read strings as dates or numbers. */\nfunction columnSortKey<Row>(column: ColumnDef<Row>, value: unknown): SortKey {\n switch (column.cellType) {\n case \"number\":\n case \"currency\":\n case \"percent\":\n case \"progress\": {\n const number = toNumber(value);\n return Number.isNaN(number) ? null : number;\n }\n case \"date\":\n case \"datetime\": {\n const time = toTimestamp(value);\n return Number.isNaN(time) ? null : time;\n }\n default:\n return toSortKey(value);\n }\n}\n\n/** Compares two keys. `null` is not handled here; the caller sorts it last. */\nfunction compareKeys(a: number | string, b: number | string, collator: Intl.Collator): number {\n if (typeof a === \"number\") {\n if (typeof b === \"number\") return a < b ? -1 : a > b ? 1 : 0;\n return -1;\n }\n if (typeof b === \"number\") return 1;\n return collator.compare(a, b);\n}\n\n/**\n * Compares two values the way the grid sorts them: numbers by size, dates by\n * time, booleans false before true, strings with a locale-aware collator, and\n * empty values last. Returns a negative, zero or positive number (ascending).\n */\nexport function compareValues(a: unknown, b: unknown, collator: Intl.Collator = createCollator()): number {\n const keyA = toSortKey(a);\n const keyB = toSortKey(b);\n if (keyA === null) return keyB === null ? 0 : 1;\n if (keyB === null) return -1;\n return compareKeys(keyA, keyB, collator);\n}\n\ninterface SortSpec<Row> {\n column: ColumnDef<Row>;\n sign: 1 | -1;\n}\n\n/**\n * Sorts a list of row indexes by the sort model. The sort is stable, locale\n * aware and multi-column: later items break ties of earlier ones. Empty values\n * sort last in both directions. A column's `comparator` replaces the default.\n * Items naming an unknown column are ignored.\n *\n * Works on indexes so a 100,000-row sort moves numbers, not row objects.\n */\nexport function sortIndexes<Row>(\n rows: readonly Row[],\n indexes: readonly number[],\n sort: readonly SortModelItem[],\n columns: readonly ColumnDef<Row>[],\n options: SortOptions = {},\n): number[] {\n const byId = indexColumns(columns);\n const specs: SortSpec<Row>[] = [];\n for (const item of sort) {\n const column = byId.get(item.field);\n if (column !== undefined) specs.push({ column, sign: item.direction === \"desc\" ? -1 : 1 });\n }\n const count = indexes.length;\n if (specs.length === 0 || count < 2) return indexes.slice();\n\n const collator = createCollator(options);\n // Values are read once per row, not once per comparison.\n const keys: Array<Array<SortKey | unknown>> = specs.map(({ column }) => {\n const out = new Array<SortKey | unknown>(count);\n const custom = column.comparator !== undefined;\n for (let position = 0; position < count; position += 1) {\n const row = rows[indexes[position] as number] as Row;\n const value = getColumnValue(column, row);\n out[position] = custom ? value : columnSortKey(column, value);\n }\n return out;\n });\n\n const order = new Array<number>(count);\n for (let position = 0; position < count; position += 1) order[position] = position;\n\n order.sort((a, b) => {\n for (let s = 0; s < specs.length; s += 1) {\n const spec = specs[s] as SortSpec<Row>;\n const column = spec.column;\n const list = keys[s] as Array<SortKey | unknown>;\n const keyA = list[a];\n const keyB = list[b];\n let result: number;\n if (column.comparator !== undefined) {\n result = column.comparator(\n keyA,\n keyB,\n rows[indexes[a] as number] as Row,\n rows[indexes[b] as number] as Row,\n ) * spec.sign;\n } else if (keyA === null) {\n result = keyB === null ? 0 : 1; // empty values stay last in both directions\n } else if (keyB === null) {\n result = -1;\n } else {\n result = compareKeys(keyA as number | string, keyB as number | string, collator) * spec.sign;\n }\n if (result !== 0) return result;\n }\n return a - b; // stable: ties keep their original order\n });\n\n return order.map((position) => indexes[position] as number);\n}\n\n/** Sorts rows and returns a new array. See `sortIndexes`. */\nexport function sortRows<Row>(\n rows: readonly Row[],\n sort: readonly SortModelItem[],\n columns: readonly ColumnDef<Row>[],\n options: SortOptions = {},\n): Row[] {\n const all = new Array<number>(rows.length);\n for (let i = 0; i < rows.length; i += 1) all[i] = i;\n return sortIndexes(rows, all, sort, columns, options).map((index) => rows[index] as Row);\n}\n","import { createCellFormatter, type FormatContext } from \"./formatters\";\nimport { getColumnValue, indexColumns, resolveFilterType } from \"./columns\";\nimport { createCollator, compareValues } from \"./sort\";\nimport type { ColumnDef, ColumnFilterType, FilterModelItem, FilterOperator } from \"./types\";\nimport {\n isDateOnlyString,\n isEmptyValue,\n normalizeText,\n toBoolean,\n toNumber,\n toText,\n toTimestamp,\n} from \"./values\";\n\nexport interface FilterContext {\n locale?: string;\n /** IANA time zone that decides where a calendar day starts for date filters. */\n timeZone?: string;\n}\n\n/** The operators each filter type offers, in menu order. */\nexport const OPERATORS_BY_FILTER_TYPE: Record<ColumnFilterType, readonly FilterOperator[]> = {\n text: [\"contains\", \"not-contains\", \"starts-with\", \"equals\", \"not-equals\", \"is-empty\", \"is-not-empty\"],\n number: [\"equals\", \"not-equals\", \"gt\", \"gte\", \"lt\", \"lte\", \"between\", \"is-empty\", \"is-not-empty\"],\n date: [\"equals\", \"before\", \"after\", \"between\", \"is-empty\", \"is-not-empty\"],\n enum: [\"in\", \"is-empty\", \"is-not-empty\"],\n boolean: [\"equals\", \"is-empty\", \"is-not-empty\"],\n};\n\nexport function operatorsFor(type: ColumnFilterType): readonly FilterOperator[] {\n return OPERATORS_BY_FILTER_TYPE[type];\n}\n\n/** `is-empty` and `is-not-empty` take no value. */\nexport function isValuelessOperator(operator: FilterOperator): boolean {\n return operator === \"is-empty\" || operator === \"is-not-empty\";\n}\n\nfunction hasText(value: unknown): boolean {\n return !isEmptyValue(value) && toText(value).trim() !== \"\";\n}\n\n/**\n * Whether a filter item narrows anything. An item with no usable value (an empty\n * text box, `in` with no choices) is ignored instead of hiding every row.\n */\nexport function isFilterEffective(item: FilterModelItem): boolean {\n if (isValuelessOperator(item.operator)) return true;\n if (item.operator === \"between\") {\n const range = Array.isArray(item.value) ? item.value : [];\n return hasText(range[0]) || hasText(range[1]);\n }\n if (item.operator === \"in\") return Array.isArray(item.value) && item.value.length > 0;\n return hasText(item.value);\n}\n\n// ---------------------------------------------------------------- Calendar days\n\nfunction pad(value: number): string {\n return String(value).padStart(2, \"0\");\n}\n\n/** The `YYYY-MM-DD` of a filter value: a date-only string, or the local day of a `Date`. */\nexport function toDayString(value: unknown): string | null {\n if (isDateOnlyString(value)) return value;\n if (value instanceof Date && !Number.isNaN(value.getTime())) {\n return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;\n }\n if (typeof value === \"string\" && value.length >= 10 && isDateOnlyString(value.slice(0, 10))) {\n return value.slice(0, 10);\n }\n return null;\n}\n\nfunction offsetMs(timestamp: number, timeZone: string): number {\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hourCycle: \"h23\",\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n second: \"numeric\",\n }).formatToParts(timestamp);\n const get = (type: string) => Number(parts.find((part) => part.type === type)?.value);\n const asUtc = Date.UTC(get(\"year\"), get(\"month\") - 1, get(\"day\"), get(\"hour\"), get(\"minute\"), get(\"second\"));\n return asUtc - Math.floor(timestamp / 1000) * 1000;\n}\n\n/** Milliseconds at the start of a `YYYY-MM-DD` day in a time zone (local when none). */\nexport function dayStart(day: string, timeZone?: string): number {\n const [year, month, date] = day.split(\"-\").map(Number) as [number, number, number];\n if (timeZone === undefined) return new Date(year, month - 1, date).getTime();\n const guess = Date.UTC(year, month - 1, date);\n if (timeZone === \"UTC\") return guess;\n try {\n const first = offsetMs(guess, timeZone);\n let result = guess - first;\n const second = offsetMs(result, timeZone);\n if (second !== first) result = guess - second;\n return result;\n } catch {\n return guess;\n }\n}\n\n/** The `YYYY-MM-DD` after a given day. */\nexport function nextDay(day: string): string {\n const [year, month, date] = day.split(\"-\").map(Number) as [number, number, number];\n const next = new Date(Date.UTC(year, month - 1, date + 1));\n return `${next.getUTCFullYear()}-${pad(next.getUTCMonth() + 1)}-${pad(next.getUTCDate())}`;\n}\n\n// -------------------------------------------------------------------- Predicates\n\ntype ValuePredicate = (value: unknown) => boolean;\n\nconst ALWAYS: ValuePredicate = () => true;\n\nfunction textPredicate(item: FilterModelItem, ctx: FilterContext): ValuePredicate {\n const { operator } = item;\n const norm = (value: unknown) => normalizeText(toText(value), ctx.locale);\n\n if (operator === \"in\") {\n const wanted = new Set((Array.isArray(item.value) ? item.value : []).map((entry) => norm(entry)));\n return (value) => (Array.isArray(value) ? value.some((entry) => wanted.has(norm(entry))) : wanted.has(norm(value)));\n }\n if (operator === \"between\" || operator === \"gt\" || operator === \"gte\" || operator === \"lt\" || operator === \"lte\") {\n const collator = createCollator({ ...(ctx.locale === undefined ? {} : { locale: ctx.locale }) });\n const [low, high] = operator === \"between\" && Array.isArray(item.value) ? item.value : [item.value, item.value];\n return (value) => {\n if (isEmptyValue(value)) return false;\n const text = toText(value);\n switch (operator) {\n case \"gt\": return collator.compare(text, toText(item.value)) > 0;\n case \"gte\": return collator.compare(text, toText(item.value)) >= 0;\n case \"lt\": return collator.compare(text, toText(item.value)) < 0;\n case \"lte\": return collator.compare(text, toText(item.value)) <= 0;\n default:\n return (\n (!hasText(low) || collator.compare(text, toText(low)) >= 0) &&\n (!hasText(high) || collator.compare(text, toText(high)) <= 0)\n );\n }\n };\n }\n\n const needle = norm(item.value);\n switch (operator) {\n case \"contains\": return (value) => norm(value).includes(needle);\n case \"not-contains\": return (value) => !norm(value).includes(needle);\n case \"starts-with\": return (value) => norm(value).startsWith(needle);\n case \"equals\": return (value) => norm(value) === needle;\n case \"not-equals\": return (value) => norm(value) !== needle;\n // Date operators on a text column compare as text; they are meaningless but harmless.\n case \"before\":\n case \"after\":\n return ALWAYS;\n default:\n return ALWAYS;\n }\n}\n\nfunction numberPredicate(item: FilterModelItem): ValuePredicate {\n const { operator } = item;\n if (operator === \"in\") {\n const wanted = new Set((Array.isArray(item.value) ? item.value : []).map(toNumber));\n return (value) => wanted.has(toNumber(value));\n }\n if (operator === \"between\") {\n const range = Array.isArray(item.value) ? item.value : [];\n const low = hasText(range[0]) ? toNumber(range[0]) : Number.NEGATIVE_INFINITY;\n const high = hasText(range[1]) ? toNumber(range[1]) : Number.POSITIVE_INFINITY;\n return (value) => {\n const number = toNumber(value);\n return !Number.isNaN(number) && number >= low && number <= high;\n };\n }\n const target = toNumber(item.value);\n if (Number.isNaN(target)) return ALWAYS;\n switch (operator) {\n case \"equals\": return (value) => toNumber(value) === target;\n case \"not-equals\": return (value) => toNumber(value) !== target;\n case \"gt\":\n case \"after\": return (value) => toNumber(value) > target;\n case \"gte\": return (value) => toNumber(value) >= target;\n case \"lt\":\n case \"before\": return (value) => toNumber(value) < target;\n case \"lte\": return (value) => toNumber(value) <= target;\n default: return ALWAYS;\n }\n}\n\nfunction datePredicate(item: FilterModelItem, ctx: FilterContext): ValuePredicate {\n const { operator } = item;\n const range = operator === \"between\" && Array.isArray(item.value) ? item.value : [item.value, item.value];\n const first = toDayString(operator === \"between\" ? range[0] : item.value);\n const second = toDayString(operator === \"between\" ? range[1] : item.value);\n\n // [from, to) in milliseconds, and the same days for date-only strings.\n const startMs = (day: string) => dayStart(day, ctx.timeZone);\n\n const test = (\n inRange: (day: string | null, time: number) => boolean,\n ): ValuePredicate => (value) => {\n if (isEmptyValue(value)) return false;\n if (isDateOnlyString(value)) return inRange(value, Number.NaN);\n const time = toTimestamp(value);\n return !Number.isNaN(time) && inRange(null, time);\n };\n\n switch (operator) {\n case \"equals\":\n case \"not-equals\": {\n if (first === null) return ALWAYS;\n const equals = test((day, time) =>\n day !== null ? day === first : time >= startMs(first) && time < startMs(nextDay(first)),\n );\n return operator === \"equals\" ? equals : (value) => !equals(value);\n }\n case \"before\":\n case \"lt\": {\n if (first === null) return ALWAYS;\n return test((day, time) => (day !== null ? day < first : time < startMs(first)));\n }\n case \"lte\": {\n if (first === null) return ALWAYS;\n return test((day, time) => (day !== null ? day <= first : time < startMs(nextDay(first))));\n }\n case \"after\":\n case \"gt\": {\n if (first === null) return ALWAYS;\n return test((day, time) => (day !== null ? day > first : time >= startMs(nextDay(first))));\n }\n case \"gte\": {\n if (first === null) return ALWAYS;\n return test((day, time) => (day !== null ? day >= first : time >= startMs(first)));\n }\n case \"between\": {\n if (first === null && second === null) return ALWAYS;\n return test((day, time) => {\n if (day !== null) return (first === null || day >= first) && (second === null || day <= second);\n return (\n (first === null || time >= startMs(first)) &&\n (second === null || time < startMs(nextDay(second)))\n );\n });\n }\n default:\n return ALWAYS;\n }\n}\n\nfunction enumPredicate(item: FilterModelItem): ValuePredicate {\n const { operator } = item;\n const values = Array.isArray(item.value) ? item.value : [item.value];\n const wanted = new Set(values.filter((entry) => entry !== undefined && entry !== null).map(String));\n const hit = (value: unknown) =>\n Array.isArray(value) ? value.some((entry) => wanted.has(String(entry))) : wanted.has(String(value));\n switch (operator) {\n case \"in\":\n case \"equals\": return hit;\n case \"not-equals\": return (value) => !hit(value);\n default: return ALWAYS;\n }\n}\n\nfunction booleanPredicate(item: FilterModelItem): ValuePredicate {\n const target = toBoolean(item.value);\n if (target === null) return ALWAYS;\n switch (item.operator) {\n case \"equals\": return (value) => toBoolean(value) === target;\n case \"not-equals\": return (value) => toBoolean(value) !== target;\n default: return ALWAYS;\n }\n}\n\n/**\n * Compiles one filter item into a predicate on a cell value. Empty values match\n * only `is-empty`, `not-equals` and `not-contains`. An item with no usable value\n * matches everything.\n */\nexport function createValuePredicate<Row>(\n item: FilterModelItem,\n column: ColumnDef<Row>,\n ctx: FilterContext = {},\n): ValuePredicate {\n if (item.operator === \"is-empty\") return isEmptyValue;\n if (item.operator === \"is-not-empty\") return (value) => !isEmptyValue(value);\n if (!isFilterEffective(item)) return ALWAYS;\n\n let predicate: ValuePredicate;\n switch (resolveFilterType(column)) {\n case \"number\": predicate = numberPredicate(item); break;\n case \"date\": predicate = datePredicate(item, ctx); break;\n case \"enum\": predicate = enumPredicate(item); break;\n case \"boolean\": predicate = booleanPredicate(item); break;\n default: predicate = textPredicate(item, ctx);\n }\n if (predicate === ALWAYS) return ALWAYS;\n const keepsEmpty = item.operator === \"not-equals\" || item.operator === \"not-contains\";\n return (value) => (isEmptyValue(value) ? keepsEmpty : predicate(value));\n}\n\n/** Whether one value passes one filter item. Convenience over `createValuePredicate`. */\nexport function matchesFilter<Row>(\n value: unknown,\n item: FilterModelItem,\n column: ColumnDef<Row>,\n ctx: FilterContext = {},\n): boolean {\n return createValuePredicate(item, column, ctx)(value);\n}\n\n// ------------------------------------------------------------------ Quick search\n\n/** Splits quick-search text into normalized tokens. Every token must match. */\nexport function parseQuickFilter(text: string, locale?: string): string[] {\n return normalizeText(text, locale)\n .split(/\\s+/)\n .filter((token) => token !== \"\");\n}\n\n/** Cell types whose text is not worth searching. */\nconst NOT_SEARCHABLE = new Set([\"actions\", \"sparkline\", \"custom\"]);\n\nexport function isSearchable<Row>(column: ColumnDef<Row>): boolean {\n if (column.searchable !== undefined) return column.searchable;\n return column.cellType === undefined || !NOT_SEARCHABLE.has(column.cellType);\n}\n\n/**\n * Builds the text each row is searched by: the formatted text of every\n * searchable column, normalized. Build it once per rows and columns (React:\n * `useMemo`) and pass it to `filterIndexes`, so typing in the quick search box\n * does not format every cell again.\n */\nexport function createSearchIndex<Row>(\n rows: readonly Row[],\n columns: readonly ColumnDef<Row>[],\n ctx: FormatContext = {},\n): string[] {\n const searchable = columns.filter(isSearchable).map((column) => ({\n column,\n format: createCellFormatter(column, ctx),\n }));\n const out = new Array<string>(rows.length);\n for (let i = 0; i < rows.length; i += 1) {\n const row = rows[i] as Row;\n let text = \"\";\n for (const { column, format } of searchable) {\n const value = getColumnValue(column, row);\n if (isEmptyValue(value)) continue;\n text += `${format(value, row)}\\u0001`;\n }\n out[i] = normalizeText(text, ctx.locale);\n }\n return out;\n}\n\nexport interface FilterIndexesOptions<Row> extends FilterContext {\n /** Quick-search text. Every whitespace-separated token must appear in the row. */\n quickFilter?: string;\n /** From `createSearchIndex`, aligned to `rows`. Built on demand when absent. */\n searchIndex?: readonly string[];\n /** Columns the quick search reads when no `searchIndex` is given. Defaults to `columns`. */\n searchColumns?: readonly ColumnDef<Row>[];\n labels?: FormatContext[\"labels\"];\n}\n\n/**\n * Returns the indexes of the rows that pass every column filter and the quick\n * filter, in their original order. Filters on different columns combine with\n * AND, and so do several filters on one column. Items naming an unknown column\n * are ignored.\n */\nexport function filterIndexes<Row>(\n rows: readonly Row[],\n filter: readonly FilterModelItem[],\n columns: readonly ColumnDef<Row>[],\n options: FilterIndexesOptions<Row> = {},\n): number[] {\n const byId = indexColumns(columns);\n const ctx: FilterContext = {\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n ...(options.timeZone === undefined ? {} : { timeZone: options.timeZone }),\n };\n const tests: Array<{ column: ColumnDef<Row>; test: ValuePredicate }> = [];\n for (const item of filter) {\n const column = byId.get(item.field);\n if (column === undefined) continue;\n const test = createValuePredicate(item, column, ctx);\n if (test !== ALWAYS) tests.push({ column, test });\n }\n\n const tokens = options.quickFilter === undefined ? [] : parseQuickFilter(options.quickFilter, options.locale);\n let haystack: readonly string[] | null = null;\n if (tokens.length > 0) {\n haystack =\n options.searchIndex ??\n createSearchIndex(rows, options.searchColumns ?? columns, {\n ...ctx,\n ...(options.labels === undefined ? {} : { labels: options.labels }),\n });\n }\n\n const out: number[] = [];\n const total = rows.length;\n for (let i = 0; i < total; i += 1) {\n const row = rows[i] as Row;\n let pass = true;\n for (let t = 0; t < tests.length; t += 1) {\n const entry = tests[t] as { column: ColumnDef<Row>; test: ValuePredicate };\n if (!entry.test(getColumnValue(entry.column, row))) {\n pass = false;\n break;\n }\n }\n if (pass && haystack !== null) {\n const text = haystack[i] ?? \"\";\n for (const token of tokens) {\n if (!text.includes(token)) {\n pass = false;\n break;\n }\n }\n }\n if (pass) out.push(i);\n }\n return out;\n}\n\n/** Distinct values of a column, for set filters. Capped so a huge column cannot stall the UI. */\nexport function distinctValues<Row>(\n rows: readonly Row[],\n column: ColumnDef<Row>,\n limit = 500,\n): unknown[] {\n const seen = new Set<unknown>();\n for (const row of rows) {\n const value = getColumnValue(column, row);\n if (isEmptyValue(value)) continue;\n if (Array.isArray(value)) for (const entry of value) seen.add(entry);\n else seen.add(value);\n if (seen.size >= limit) break;\n }\n return [...seen].sort((a, b) => compareValues(a, b));\n}\n","import { getColumnValue } from \"./columns\";\nimport type { AggregateName, ColumnDef } from \"./types\";\nimport { isEmptyValue, toNumber, toTimestamp } from \"./values\";\n\nexport interface AggregateOptions {\n /** Return the original value of the earliest or latest entry, for date columns. */\n dates?: boolean;\n}\n\n/**\n * Reduces values to one: `sum`, `avg`, `min`, `max` over the numeric values, or\n * `count` of non-empty values. Non-numeric values are skipped. `sum` of nothing\n * is `0`; `avg`, `min` and `max` of nothing are `null`.\n */\nexport function aggregateValues(values: readonly unknown[], name: AggregateName, options: AggregateOptions = {}): unknown {\n if (name === \"count\") {\n let count = 0;\n for (const value of values) if (!isEmptyValue(value)) count += 1;\n return count;\n }\n\n const numeric = (value: unknown): number => (options.dates === true ? toTimestamp(value) : toNumber(value));\n\n if (name === \"sum\" || name === \"avg\") {\n let sum = 0;\n let count = 0;\n for (const value of values) {\n const number = toNumber(value);\n if (Number.isNaN(number)) continue;\n sum += number;\n count += 1;\n }\n if (name === \"sum\") return sum;\n return count === 0 ? null : sum / count;\n }\n\n let best: unknown = null;\n let bestKey = Number.NaN;\n for (const value of values) {\n const key = numeric(value);\n if (Number.isNaN(key)) continue;\n if (Number.isNaN(bestKey) || (name === \"min\" ? key < bestKey : key > bestKey)) {\n best = value;\n bestKey = key;\n }\n }\n return best;\n}\n\n/** The aggregate of one column over some rows, or `undefined` when the column has none. */\nexport function computeAggregate<Row>(column: ColumnDef<Row>, rows: readonly Row[]): unknown {\n const aggregate = column.aggregate;\n if (aggregate === undefined) return undefined;\n const values = rows.map((row) => getColumnValue(column, row));\n if (typeof aggregate === \"function\") return aggregate(values, rows as Row[]);\n return aggregateValues(values, aggregate, { dates: column.cellType === \"date\" || column.cellType === \"datetime\" });\n}\n\n/** The aggregates of every column that declares one, keyed by column id. */\nexport function computeAggregates<Row>(\n columns: readonly ColumnDef<Row>[],\n rows: readonly Row[],\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const column of columns) {\n if (column.aggregate === undefined) continue;\n out[column.id] = computeAggregate(column, rows);\n }\n return out;\n}\n","import { computeAggregates } from \"./aggregate\";\nimport { getColumnValue, indexColumns } from \"./columns\";\nimport { compareValues, createCollator, type SortOptions } from \"./sort\";\nimport type { ColumnDef, GroupModelItem, SortDirection } from \"./types\";\nimport { toText } from \"./values\";\n\nexport interface GroupNode {\n /** Stable path id, for example `region=EMEA/country=DE`. Use it as the expansion key. */\n id: string;\n /** The id of the column grouped by at this level. */\n field: string;\n /** The grouped value, as the first row of the group holds it. */\n value: unknown;\n /** 0 for the outermost level. */\n depth: number;\n /** Indexes (into the rows array) of every row below this group, in view order. */\n indexes: number[];\n /** Sub-groups. Empty at the innermost level. */\n children: GroupNode[];\n /** Aggregates of the columns that declare one, over every row below. */\n aggregates: Record<string, unknown>;\n}\n\nexport interface GroupOptions extends SortOptions {\n /**\n * How to order groups: `first` keeps the order rows arrive in, `asc` and\n * `desc` sort by group value. A function picks per column id.\n */\n order?: \"first\" | SortDirection | ((field: string) => \"first\" | SortDirection);\n}\n\nfunction encode(value: string): string {\n return encodeURIComponent(value);\n}\n\n/**\n * Splits row indexes into nested groups by the group model, one level per item,\n * and aggregates each group. Items naming an unknown column are ignored. With no\n * usable group item the result is empty.\n */\nexport function buildGroupTree<Row>(\n rows: readonly Row[],\n indexes: readonly number[],\n group: readonly GroupModelItem[],\n columns: readonly ColumnDef<Row>[],\n options: GroupOptions = {},\n): GroupNode[] {\n const byId = indexColumns(columns);\n const levels = group.map((item) => byId.get(item.field)).filter((column): column is ColumnDef<Row> => column !== undefined);\n if (levels.length === 0) return [];\n const collator = createCollator(options);\n\n const build = (subset: readonly number[], depth: number, parentId: string): GroupNode[] => {\n const column = levels[depth] as ColumnDef<Row>;\n const buckets = new Map<string, { value: unknown; indexes: number[] }>();\n for (const index of subset) {\n const value = getColumnValue(column, rows[index] as Row);\n const key = toText(value);\n let bucket = buckets.get(key);\n if (bucket === undefined) {\n bucket = { value, indexes: [] };\n buckets.set(key, bucket);\n }\n bucket.indexes.push(index);\n }\n\n let entries = [...buckets.entries()];\n const order = typeof options.order === \"function\" ? options.order(column.id) : (options.order ?? \"asc\");\n if (order !== \"first\") {\n const sign = order === \"desc\" ? -1 : 1;\n entries = entries.sort((a, b) => sign * compareValues(a[1].value, b[1].value, collator));\n }\n\n return entries.map(([key, bucket]) => {\n const id = `${parentId === \"\" ? \"\" : `${parentId}/`}${encode(column.id)}=${encode(key)}`;\n return {\n id,\n field: column.id,\n value: bucket.value,\n depth,\n indexes: bucket.indexes,\n children: depth + 1 < levels.length ? build(bucket.indexes, depth + 1, id) : [],\n aggregates: computeAggregates(\n columns,\n bucket.indexes.map((index) => rows[index] as Row),\n ),\n };\n });\n };\n\n return build(indexes, 0, \"\");\n}\n","import { filterIndexes, type FilterIndexesOptions } from \"./filter\";\nimport { buildGroupTree, type GroupNode } from \"./group\";\nimport { sortIndexes, type SortOptions } from \"./sort\";\nimport type { ColumnDef, FilterModelItem, GroupModelItem, SortModelItem } from \"./types\";\n\nexport interface ViewOptions<Row> extends FilterIndexesOptions<Row>, SortOptions {\n sort?: readonly SortModelItem[];\n filter?: readonly FilterModelItem[];\n}\n\n/**\n * The client-side pipeline: filter (columns, then quick search), then sort.\n * Returns the indexes of the surviving rows in presentation order. It never\n * copies a row, so 100,000 rows cost two integer arrays.\n */\nexport function computeViewIndexes<Row>(\n rows: readonly Row[],\n columns: readonly ColumnDef<Row>[],\n options: ViewOptions<Row> = {},\n): number[] {\n const matched = filterIndexes(rows, options.filter ?? [], columns, options);\n return sortIndexes(rows, matched, options.sort ?? [], columns, options);\n}\n\n/** A row as the grid lays it out: a data row, a group header, or a detail panel. */\nexport type DisplayRow<Row> =\n | {\n kind: \"data\";\n /** The row id from `getRowId`. */\n id: string;\n row: Row;\n /** Index into the source rows array. */\n index: number;\n /** Number of group levels above the row. `aria-level` is `depth + 1`. */\n depth: number;\n }\n | {\n kind: \"group\";\n /** The group path id. */\n id: string;\n field: string;\n value: unknown;\n depth: number;\n /** Rows below the group, at every depth. */\n count: number;\n expanded: boolean;\n aggregates: Record<string, unknown>;\n }\n | {\n kind: \"detail\";\n id: string;\n /** The id of the data row this panel belongs to. */\n parentId: string;\n row: Row;\n index: number;\n depth: number;\n };\n\nexport interface DisplayOptions<Row> {\n getRowId: (row: Row, index: number) => string;\n group?: readonly GroupModelItem[];\n /** Per group id. Groups without an entry follow `groupsExpandedByDefault`. */\n groupExpansion?: Readonly<Record<string, boolean>>;\n groupsExpandedByDefault?: boolean;\n /** Row ids whose detail panel is open. */\n expandedRows?: Readonly<Record<string, boolean>>;\n /** Insert a `detail` row below each expanded data row. */\n withDetail?: boolean;\n sort?: readonly SortModelItem[];\n locale?: string;\n}\n\n/**\n * Turns presentation-ordered indexes into the flat list the grid renders:\n * data rows, group headers for the group model, and detail rows below expanded\n * rows. Collapsed groups hide everything below them. Groups appear in ascending\n * order of their value unless the sort model sorts the group column.\n */\nexport function buildDisplayRows<Row>(\n rows: readonly Row[],\n indexes: readonly number[],\n columns: readonly ColumnDef<Row>[],\n options: DisplayOptions<Row>,\n): { rows: DisplayRow<Row>[]; groups: GroupNode[] } {\n const out: DisplayRow<Row>[] = [];\n const expandedRows = options.expandedRows ?? {};\n const pushData = (index: number, depth: number) => {\n const row = rows[index] as Row;\n const id = options.getRowId(row, index);\n out.push({ kind: \"data\", id, row, index, depth });\n if (options.withDetail === true && expandedRows[id] === true) {\n out.push({ kind: \"detail\", id: `${id}:detail`, parentId: id, row, index, depth });\n }\n };\n\n const group = options.group ?? [];\n const sorted = new Map((options.sort ?? []).map((item) => [item.field, item.direction] as const));\n const tree = buildGroupTree(rows, indexes, group, columns, {\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n order: (field) => sorted.get(field) ?? \"asc\",\n });\n\n if (tree.length === 0) {\n for (const index of indexes) pushData(index, 0);\n return { rows: out, groups: [] };\n }\n\n const expansion = options.groupExpansion ?? {};\n const byDefault = options.groupsExpandedByDefault ?? true;\n const walk = (nodes: readonly GroupNode[]) => {\n for (const node of nodes) {\n const expanded = expansion[node.id] ?? byDefault;\n out.push({\n kind: \"group\",\n id: node.id,\n field: node.field,\n value: node.value,\n depth: node.depth,\n count: node.indexes.length,\n expanded,\n aggregates: node.aggregates,\n });\n if (!expanded) continue;\n if (node.children.length > 0) walk(node.children);\n else for (const index of node.indexes) pushData(index, node.depth + 1);\n }\n };\n walk(tree);\n return { rows: out, groups: tree };\n}\n","/**\n * Row selection as a plain immutable value.\n *\n * `include` lists the selected ids. `exclude` means \"every row except these\n * ids\": it is how \"select all rows\" works when the grid cannot list ids, for\n * example when a server holds the rows. Both are safe to keep in React state.\n */\nexport interface SelectionState {\n readonly mode: \"include\" | \"exclude\";\n readonly ids: ReadonlySet<string>;\n}\n\nexport const EMPTY_SELECTION: SelectionState = Object.freeze({ mode: \"include\", ids: new Set<string>() });\n\nexport function createSelection(ids: Iterable<string> = []): SelectionState {\n return { mode: \"include\", ids: new Set(ids) };\n}\n\nexport function isSelected(state: SelectionState, id: string): boolean {\n return state.mode === \"include\" ? state.ids.has(id) : !state.ids.has(id);\n}\n\nexport function isSelectionEmpty(state: SelectionState): boolean {\n return state.mode === \"include\" && state.ids.size === 0;\n}\n\n/** Selects or deselects one row. Without `selected`, flips it. */\nexport function toggleRow(state: SelectionState, id: string, selected?: boolean): SelectionState {\n const next = selected ?? !isSelected(state, id);\n if (isSelected(state, id) === next) return state;\n const ids = new Set(state.ids);\n // In include mode a selected row is in the set; in exclude mode it is out of it.\n if (next === (state.mode === \"include\")) ids.add(id);\n else ids.delete(id);\n return { mode: state.mode, ids };\n}\n\n/** A selection of exactly one row. */\nexport function selectOnly(id: string): SelectionState {\n return createSelection([id]);\n}\n\n/**\n * Selects or deselects every row between two positions of `orderedIds`,\n * inclusive and in either direction. This is the Shift+click behavior.\n * Positions outside the list are clamped.\n */\nexport function selectRange(\n state: SelectionState,\n orderedIds: readonly string[],\n from: number,\n to: number,\n selected = true,\n): SelectionState {\n if (orderedIds.length === 0) return state;\n const last = orderedIds.length - 1;\n const start = Math.max(0, Math.min(last, Math.min(from, to)));\n const end = Math.max(0, Math.min(last, Math.max(from, to)));\n const ids = new Set(state.ids);\n const add = selected === (state.mode === \"include\");\n for (let position = start; position <= end; position += 1) {\n const id = orderedIds[position] as string;\n if (add) ids.add(id);\n else ids.delete(id);\n }\n return { mode: state.mode, ids };\n}\n\n/** Selects the given ids and nothing else. Use it when the grid knows every id. */\nexport function selectAll(ids: Iterable<string>): SelectionState {\n return createSelection(ids);\n}\n\n/** \"Every row except none\": the select-all of a grid that cannot list its ids. */\nexport function selectAllExceptNone(): SelectionState {\n return { mode: \"exclude\", ids: new Set<string>() };\n}\n\nexport function clearSelection(): SelectionState {\n return createSelection();\n}\n\n/** How many rows are selected, given the total row count (needed in `exclude` mode). */\nexport function countSelected(state: SelectionState, total: number): number {\n return state.mode === \"include\" ? state.ids.size : Math.max(0, total - state.ids.size);\n}\n\nexport type SelectionSummary = \"none\" | \"some\" | \"all\";\n\n/**\n * The state of a select-all checkbox for a set of ids (the rows the checkbox\n * stands for): `none`, `some` (indeterminate) or `all`.\n */\nexport function summarizeSelection(state: SelectionState, ids: readonly string[]): SelectionSummary {\n if (ids.length === 0) return \"none\";\n let selected = 0;\n for (const id of ids) if (isSelected(state, id)) selected += 1;\n if (selected === 0) return \"none\";\n return selected === ids.length ? \"all\" : \"some\";\n}\n\n/** The ids that are selected, given every id the grid has. */\nexport function resolveSelectedIds(state: SelectionState, allIds: Iterable<string>): string[] {\n const out: string[] = [];\n for (const id of allIds) if (isSelected(state, id)) out.push(id);\n return out;\n}\n\n/** JSON-safe form, for storage or a URL. */\nexport interface SerializedSelection {\n mode: \"include\" | \"exclude\";\n ids: string[];\n}\n\nexport function serializeSelection(state: SelectionState): SerializedSelection {\n return { mode: state.mode, ids: [...state.ids] };\n}\n\nexport function deserializeSelection(value: SerializedSelection): SelectionState {\n return { mode: value.mode === \"exclude\" ? \"exclude\" : \"include\", ids: new Set(value.ids) };\n}\n","/**\n * The keyboard model of the grid as a pure function: `(state, key, bounds)`\n * returns the next state. It knows nothing about the DOM, so it is the same on\n * the server, in tests and in the component.\n *\n * Coordinates are positions in the grid as a screen reader sees it: row 0 is\n * the header row, rows 1 and up are the body, column 0 is the first column.\n */\nexport interface NavState {\n row: number;\n col: number;\n}\n\nexport interface NavBounds {\n /** Rows including the header row. */\n rowCount: number;\n columnCount: number;\n /** Rows moved by PageUp and PageDown. Use the number of visible rows. */\n pageSize: number;\n /** Right-to-left: ArrowLeft moves forward and ArrowRight moves back. */\n rtl?: boolean;\n}\n\nexport interface NavKeyInput {\n key: string;\n ctrlKey?: boolean;\n metaKey?: boolean;\n shiftKey?: boolean;\n altKey?: boolean;\n}\n\nconst NAVIGATION_KEYS = new Set([\n \"ArrowUp\",\n \"ArrowDown\",\n \"ArrowLeft\",\n \"ArrowRight\",\n \"Home\",\n \"End\",\n \"PageUp\",\n \"PageDown\",\n]);\n\n/** Whether the key is one the model handles, so the caller can stop the page from scrolling. */\nexport function isNavigationKey(input: NavKeyInput): boolean {\n if (!NAVIGATION_KEYS.has(input.key)) return false;\n if (input.altKey === true || input.metaKey === true) return false;\n if (input.ctrlKey === true) return input.key === \"Home\" || input.key === \"End\";\n return true;\n}\n\nconst clamp = (value: number, max: number): number => Math.max(0, Math.min(max, value));\n\n/** Keeps a position inside the grid, for example after rows or columns disappear. */\nexport function clampNav(state: NavState, bounds: NavBounds): NavState {\n const row = clamp(state.row, bounds.rowCount - 1);\n const col = clamp(state.col, bounds.columnCount - 1);\n return row === state.row && col === state.col ? state : { row, col };\n}\n\n/**\n * Moves the cursor for a key press. Returns the same object when the key is not\n * a navigation key or the cursor cannot move, so `next === state` means \"nothing\n * to do\".\n *\n * - Arrow keys move one cell; they stop at the edges (no wrap).\n * - Home and End jump to the first and last column of the row.\n * - Ctrl+Home and Ctrl+End jump to the first and last cell of the grid.\n * - PageUp and PageDown move `pageSize` rows.\n * - In right-to-left, ArrowLeft and ArrowRight swap.\n */\nexport function navigate(state: NavState, input: NavKeyInput, bounds: NavBounds): NavState {\n if (!isNavigationKey(input) || bounds.rowCount <= 0 || bounds.columnCount <= 0) return state;\n const lastRow = bounds.rowCount - 1;\n const lastCol = bounds.columnCount - 1;\n const forward = bounds.rtl === true ? \"ArrowLeft\" : \"ArrowRight\";\n const pageSize = Math.max(1, Math.floor(bounds.pageSize));\n\n let row = state.row;\n let col = state.col;\n switch (input.key) {\n case \"ArrowUp\":\n row -= 1;\n break;\n case \"ArrowDown\":\n row += 1;\n break;\n case \"ArrowLeft\":\n case \"ArrowRight\":\n col += input.key === forward ? 1 : -1;\n break;\n case \"Home\":\n col = 0;\n if (input.ctrlKey === true) row = 0;\n break;\n case \"End\":\n col = lastCol;\n if (input.ctrlKey === true) row = lastRow;\n break;\n case \"PageUp\":\n row -= pageSize;\n break;\n case \"PageDown\":\n row += pageSize;\n break;\n default:\n return state;\n }\n\n row = clamp(row, lastRow);\n col = clamp(col, lastCol);\n return row === state.row && col === state.col ? state : { row, col };\n}\n","import { clampColumnWidth, indexColumns } from \"./columns\";\nimport type {\n ColumnDef,\n ColumnPin,\n FilterModelItem,\n GroupModelItem,\n SortDirection,\n SortModelItem,\n} from \"./types\";\n\n/** Pinned column ids, in display order. `start` and `end` follow the reading direction. */\nexport interface ColumnPinning {\n start: string[];\n end: string[];\n}\n\n/**\n * The part of the grid state a saved view keeps. Selection, expansion, paging\n * and quick search are about the data on screen, not the view, and stay out.\n */\nexport interface GridViewState {\n sort: SortModelItem[];\n filter: FilterModelItem[];\n group: GroupModelItem[];\n /** Column ids in display order. Ids missing here follow in definition order. */\n columnOrder: string[];\n /** `false` hides a column. A missing id is visible. */\n columnVisibility: Record<string, boolean>;\n /** Pixel widths of columns the user resized. */\n columnSizing: Record<string, number>;\n columnPinning: ColumnPinning;\n}\n\n/** The view a grid starts from, read from the column definitions (`hidden`, `pinned`). */\nexport function createViewState<Row>(columns: readonly ColumnDef<Row>[]): GridViewState {\n const visibility: Record<string, boolean> = {};\n const pinning: ColumnPinning = { start: [], end: [] };\n for (const column of columns) {\n if (column.hidden === true) visibility[column.id] = false;\n if (column.pinned === \"start\") pinning.start.push(column.id);\n if (column.pinned === \"end\") pinning.end.push(column.id);\n }\n return {\n sort: [],\n filter: [],\n group: [],\n columnOrder: columns.map((column) => column.id),\n columnVisibility: visibility,\n columnSizing: {},\n columnPinning: pinning,\n };\n}\n\n/** Known ids in the given order, then the rest in definition order. Duplicates and unknown ids drop out. */\nexport function resolveColumnOrder<Row>(columns: readonly ColumnDef<Row>[], order: readonly string[]): string[] {\n const known = new Set(columns.map((column) => column.id));\n const seen = new Set<string>();\n const out: string[] = [];\n for (const id of order) {\n if (known.has(id) && !seen.has(id)) {\n seen.add(id);\n out.push(id);\n }\n }\n for (const column of columns) {\n if (!seen.has(column.id)) {\n seen.add(column.id);\n out.push(column.id);\n }\n }\n return out;\n}\n\n/** The three zones of the grid, in display order. Hidden columns are left out. */\nexport interface ColumnLayout {\n start: string[];\n center: string[];\n end: string[];\n}\n\nexport function layoutColumns<Row>(\n columns: readonly ColumnDef<Row>[],\n state: Pick<GridViewState, \"columnOrder\" | \"columnVisibility\" | \"columnPinning\">,\n): ColumnLayout {\n const byId = indexColumns(columns);\n const visible = (id: string) => byId.has(id) && state.columnVisibility[id] !== false;\n const start = state.columnPinning.start.filter(visible);\n const end = state.columnPinning.end.filter((id) => visible(id) && !start.includes(id));\n const pinned = new Set([...start, ...end]);\n const center = resolveColumnOrder(columns, state.columnOrder).filter((id) => visible(id) && !pinned.has(id));\n return { start, center, end };\n}\n\n/**\n * The next sort model after the user activates a column header. A plain click\n * replaces the model and cycles that column: ascending, descending, off. With\n * `multi` (Shift+click) the column joins the model, or cycles inside it, and the\n * other columns keep their rank.\n */\nexport function toggleSort(\n sort: readonly SortModelItem[],\n field: string,\n multi = false,\n): SortModelItem[] {\n const current = sort.find((item) => item.field === field)?.direction;\n const next: SortDirection | null = current === undefined ? \"asc\" : current === \"asc\" ? \"desc\" : null;\n return setSort(sort, field, next, multi);\n}\n\n/** Sets the direction of one column, or removes it with `null`. */\nexport function setSort(\n sort: readonly SortModelItem[],\n field: string,\n direction: SortDirection | null,\n multi = false,\n): SortModelItem[] {\n if (!multi) return direction === null ? [] : [{ field, direction }];\n const exists = sort.some((item) => item.field === field);\n if (direction === null) return sort.filter((item) => item.field !== field);\n if (!exists) return [...sort, { field, direction }];\n return sort.map((item) => (item.field === field ? { field, direction } : item));\n}\n\n/** The 1-based rank of a column in a multi-column sort, or `null` when it is not sorted. */\nexport function sortRank(sort: readonly SortModelItem[], field: string): number | null {\n const position = sort.findIndex((item) => item.field === field);\n return position < 0 ? null : position + 1;\n}\n\n/** Replaces the filter items of one column, or clears them with `null`. */\nexport function setColumnFilter(\n filter: readonly FilterModelItem[],\n field: string,\n item: FilterModelItem | null,\n): FilterModelItem[] {\n const rest = filter.filter((entry) => entry.field !== field);\n return item === null ? rest : [...rest, item];\n}\n\n/** Adds the column to the group model, or removes it when it is already there. */\nexport function toggleGroup(group: readonly GroupModelItem[], field: string): GroupModelItem[] {\n return group.some((item) => item.field === field)\n ? group.filter((item) => item.field !== field)\n : [...group, { field }];\n}\n\n/** Pins a column to a side, or unpins it with `false`. A pinned column is appended to its side. */\nexport function setPinning(pinning: ColumnPinning, id: string, pin: ColumnPin | false): ColumnPinning {\n const start = pinning.start.filter((entry) => entry !== id);\n const end = pinning.end.filter((entry) => entry !== id);\n if (pin === \"start\") start.push(id);\n if (pin === \"end\") end.push(id);\n return { start, end };\n}\n\nfunction moveWithin(list: readonly string[], id: string, targetId: string): string[] {\n const from = list.indexOf(id);\n const to = list.indexOf(targetId);\n if (from < 0 || to < 0 || from === to) return list.slice();\n const next = list.slice();\n next.splice(from, 1);\n next.splice(to, 0, id);\n return next;\n}\n\n/**\n * Moves a visible column one step earlier (`-1`) or later (`1`) inside its own\n * zone: start-pinned, center or end-pinned. A column does not jump across\n * pinning; use `setPinning` for that. Hidden columns are skipped over.\n */\nexport function moveColumn<Row>(\n columns: readonly ColumnDef<Row>[],\n state: Pick<GridViewState, \"columnOrder\" | \"columnVisibility\" | \"columnPinning\">,\n id: string,\n delta: -1 | 1,\n): Pick<GridViewState, \"columnOrder\" | \"columnPinning\"> {\n const layout = layoutColumns(columns, state);\n const order = resolveColumnOrder(columns, state.columnOrder);\n const unchanged = { columnOrder: order, columnPinning: state.columnPinning };\n\n const zone = layout.start.includes(id) ? \"start\" : layout.end.includes(id) ? \"end\" : layout.center.includes(id) ? \"center\" : null;\n if (zone === null) return unchanged;\n const ids = layout[zone];\n const target = ids[ids.indexOf(id) + delta];\n if (target === undefined) return unchanged;\n\n if (zone === \"center\") return { columnOrder: moveWithin(order, id, target), columnPinning: state.columnPinning };\n const pinning = { start: state.columnPinning.start.slice(), end: state.columnPinning.end.slice() };\n pinning[zone] = moveWithin(pinning[zone], id, target);\n return { columnOrder: order, columnPinning: pinning };\n}\n\n/**\n * Moves a visible column to just before or after another one: what dropping a\n * dragged header does. Like `moveColumn` it stays inside its zone (start-pinned,\n * center or end-pinned); a target in another zone changes nothing.\n */\nexport function moveColumnTo<Row>(\n columns: readonly ColumnDef<Row>[],\n state: Pick<GridViewState, \"columnOrder\" | \"columnVisibility\" | \"columnPinning\">,\n id: string,\n targetId: string,\n placement: \"before\" | \"after\",\n): Pick<GridViewState, \"columnOrder\" | \"columnPinning\"> {\n const layout = layoutColumns(columns, state);\n const order = resolveColumnOrder(columns, state.columnOrder);\n const unchanged = { columnOrder: order, columnPinning: state.columnPinning };\n\n const zoneOf = (columnId: string) =>\n layout.start.includes(columnId) ? \"start\" : layout.end.includes(columnId) ? \"end\" : layout.center.includes(columnId) ? \"center\" : null;\n const zone = zoneOf(id);\n if (zone === null || id === targetId || zone !== zoneOf(targetId)) return unchanged;\n\n const place = (list: readonly string[]): string[] | null => {\n if (!list.includes(id) || !list.includes(targetId)) return null;\n const rest = list.filter((entry) => entry !== id);\n rest.splice(rest.indexOf(targetId) + (placement === \"after\" ? 1 : 0), 0, id);\n return rest;\n };\n\n if (zone === \"center\") {\n const next = place(order);\n return next === null ? unchanged : { columnOrder: next, columnPinning: state.columnPinning };\n }\n const next = place(state.columnPinning[zone]);\n if (next === null) return unchanged;\n return { columnOrder: order, columnPinning: { ...state.columnPinning, [zone]: next } };\n}\n\n/** Sets the width of a column, clamped to its `minWidth` and `maxWidth`. */\nexport function resizeColumn<Row>(\n columns: readonly ColumnDef<Row>[],\n sizing: Readonly<Record<string, number>>,\n id: string,\n width: number,\n): Record<string, number> {\n const column = indexColumns(columns).get(id);\n if (column === undefined) return { ...sizing };\n return { ...sizing, [id]: clampColumnWidth(column, width) };\n}\n","import { getColumnValue } from \"./columns\";\nimport { createCellFormatter, type FormatContext } from \"./formatters\";\nimport type { ColumnDef } from \"./types\";\nimport { isEmptyValue, toText } from \"./values\";\n\nexport interface DelimitedOptions extends FormatContext {\n /** Field separator. Defaults to `,` for CSV and a tab for TSV. */\n delimiter?: string;\n /** Row separator. Defaults to CRLF for CSV (RFC 4180) and LF for TSV. */\n eol?: string;\n /** Write the column headers as the first line. Default `true`. */\n header?: boolean;\n /**\n * `formatted` writes what the grid shows (\"$1,234.50\", \"Mar 5, 2024\"); `raw`\n * writes the stored value (1234.5, an ISO date). Default `formatted`.\n */\n values?: \"formatted\" | \"raw\";\n /**\n * Prefix cells that a spreadsheet would run as a formula (a leading `=`,\n * `@`, tab, or a `+`/`-` that is not a plain number) with an apostrophe, so\n * an exported cell cannot execute. Default `true` for CSV, `false` for TSV.\n */\n sanitizeFormulas?: boolean;\n /** Write a UTF-8 byte order mark first, which Excel needs to read non-ASCII CSV. CSV only. */\n bom?: boolean;\n}\n\nconst PLAIN_NUMBER = /^[+-][\\p{Sc}\\s\\d.,%()]*$/u;\n\n/** Quotes a field when it holds the delimiter, a quote or a line break. */\nexport function escapeDelimitedField(text: string, delimiter = \",\"): string {\n if (text === \"\") return \"\";\n const needsQuotes =\n text.includes(delimiter) || text.includes('\"') || text.includes(\"\\n\") || text.includes(\"\\r\");\n return needsQuotes ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\n/** Escapes one CSV field per RFC 4180. */\nexport function escapeCsvField(text: string, delimiter = \",\"): string {\n return escapeDelimitedField(text, delimiter);\n}\n\nfunction neutralizeFormula(text: string): string {\n if (text === \"\") return text;\n const first = text.charAt(0);\n if (first === \"=\" || first === \"@\" || first === \"\\t\" || first === \"\\r\") return `'${text}`;\n if ((first === \"+\" || first === \"-\") && !PLAIN_NUMBER.test(text)) return `'${text}`;\n return text;\n}\n\nfunction rawText(value: unknown): string {\n if (isEmptyValue(value)) return \"\";\n return toText(value);\n}\n\n/** Columns that hold data. `actions` columns carry buttons, not values. */\nexport function exportableColumns<Row>(columns: readonly ColumnDef<Row>[]): ColumnDef<Row>[] {\n return columns.filter((column) => column.cellType !== \"actions\");\n}\n\nfunction toDelimited<Row>(\n rows: readonly Row[],\n columns: readonly ColumnDef<Row>[],\n options: DelimitedOptions,\n defaults: { delimiter: string; eol: string; sanitize: boolean },\n): string {\n const delimiter = options.delimiter ?? defaults.delimiter;\n const eol = options.eol ?? defaults.eol;\n const sanitize = options.sanitizeFormulas ?? defaults.sanitize;\n const formatted = (options.values ?? \"formatted\") === \"formatted\";\n const fields = exportableColumns(columns).map((column) => ({\n column,\n format: formatted ? createCellFormatter(column, options) : null,\n }));\n\n const cell = (text: string) => escapeDelimitedField(sanitize ? neutralizeFormula(text) : text, delimiter);\n const lines: string[] = [];\n if (options.header !== false) {\n lines.push(fields.map(({ column }) => cell(column.header)).join(delimiter));\n }\n for (const row of rows) {\n lines.push(\n fields\n .map(({ column, format }) => {\n const value = getColumnValue(column, row);\n return cell(format === null ? rawText(value) : format(value, row));\n })\n .join(delimiter),\n );\n }\n return lines.join(eol);\n}\n\n/**\n * Serializes rows to CSV, one column per given column, in the given order.\n * Pass the visible columns to export \"the current view\". Values go through the\n * column formatters unless `values: \"raw\"`. Quotes, delimiters and line breaks\n * are escaped, and formula-looking cells are neutralized. `actions` columns are\n * skipped. The result has no trailing line break.\n */\nexport function gridToCsv<Row>(\n rows: readonly Row[],\n columns: readonly ColumnDef<Row>[],\n options: DelimitedOptions = {},\n): string {\n const body = toDelimited(rows, columns, options, { delimiter: \",\", eol: \"\\r\\n\", sanitize: true });\n return options.bom === true ? `\\uFEFF${body}` : body;\n}\n\n/** Tab-separated text, the format spreadsheets paste. Used by \"copy selection\". */\nexport function gridToTsv<Row>(\n rows: readonly Row[],\n columns: readonly ColumnDef<Row>[],\n options: DelimitedOptions = {},\n): string {\n return toDelimited(rows, columns, options, { delimiter: \"\\t\", eol: \"\\n\", sanitize: false });\n}\n\n/** Reads CSV or TSV back into rows of text. Handles quoted fields, escaped quotes and line breaks. */\nexport function parseDelimited(text: string, delimiter = \",\"): string[][] {\n const source = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n const rows: string[][] = [];\n let row: string[] = [];\n let field = \"\";\n let quoted = false;\n for (let i = 0; i < source.length; i += 1) {\n const char = source.charAt(i);\n if (quoted) {\n if (char === '\"') {\n if (source.charAt(i + 1) === '\"') {\n field += '\"';\n i += 1;\n } else quoted = false;\n } else field += char;\n } else if (char === '\"') quoted = true;\n else if (char === delimiter) {\n row.push(field);\n field = \"\";\n } else if (char === \"\\n\" || char === \"\\r\") {\n if (char === \"\\r\" && source.charAt(i + 1) === \"\\n\") i += 1;\n row.push(field);\n rows.push(row);\n row = [];\n field = \"\";\n } else field += char;\n }\n if (field !== \"\" || row.length > 0) {\n row.push(field);\n rows.push(row);\n }\n return rows;\n}\n","import { indexColumns } from \"./columns\";\nimport {\n createViewState,\n resolveColumnOrder,\n type GridViewState,\n} from \"./state\";\nimport {\n FILTER_OPERATORS,\n SAVED_VIEW_VERSION,\n type ColumnDef,\n type ColumnState,\n type SavedView,\n} from \"./types\";\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isOptionalNumber = (value: unknown) =>\n value === undefined || (typeof value === \"number\" && Number.isFinite(value));\n\n/**\n * Reads a saved view from untrusted JSON (storage, a URL, a server). Returns\n * `null` when the value is not a view this version understands, so a bad or\n * newer record is ignored instead of crashing the grid.\n */\nexport function parseSavedView(value: unknown): SavedView | null {\n if (!isRecord(value) || value.version !== SAVED_VIEW_VERSION) return null;\n if (value.name !== undefined && typeof value.name !== \"string\") return null;\n\n const { columns, sort, filter, group } = value;\n if (!Array.isArray(columns) || !Array.isArray(sort) || !Array.isArray(filter)) return null;\n if (group !== undefined && !Array.isArray(group)) return null;\n\n for (const column of columns) {\n if (!isRecord(column) || typeof column.id !== \"string\") return null;\n if (!isOptionalNumber(column.width)) return null;\n if (column.hidden !== undefined && typeof column.hidden !== \"boolean\") return null;\n if (column.pinned !== undefined && column.pinned !== \"start\" && column.pinned !== \"end\") {\n return null;\n }\n }\n for (const item of sort) {\n if (!isRecord(item) || typeof item.field !== \"string\") return null;\n if (item.direction !== \"asc\" && item.direction !== \"desc\") return null;\n }\n for (const item of filter) {\n if (!isRecord(item) || typeof item.field !== \"string\") return null;\n if (!(FILTER_OPERATORS as readonly unknown[]).includes(item.operator)) return null;\n }\n for (const item of group ?? []) {\n if (!isRecord(item) || typeof item.field !== \"string\") return null;\n }\n\n return value as unknown as SavedView;\n}\n\n/** One saved view in a list, without loading its body. */\nexport interface SavedViewSummary {\n id: string;\n name?: string;\n}\n\n/**\n * Where an app keeps saved views. The grid does not care: pass any\n * implementation (local storage, your API, `@x12i/flowix-ui`'s Flowix adapter).\n */\nexport interface SavedViewStore {\n list(): Promise<SavedViewSummary[]>;\n /** `null` when the id does not exist or holds something `parseSavedView` rejects. */\n load(id: string): Promise<SavedView | null>;\n save(id: string, view: SavedView): Promise<void>;\n delete(id: string): Promise<void>;\n}\n\nexport interface CaptureViewOptions {\n name?: string;\n}\n\n/**\n * Snapshots the view state into a `SavedView`. Columns are written in display\n * order (start-pinned, center, end-pinned) with their width, `hidden` and `pinned`.\n */\nexport function captureView<Row>(\n state: GridViewState,\n columns: readonly ColumnDef<Row>[],\n options: CaptureViewOptions = {},\n): SavedView {\n const known = indexColumns(columns);\n const pinnedStart = state.columnPinning.start.filter((id) => known.has(id));\n const pinnedEnd = state.columnPinning.end.filter((id) => known.has(id) && !pinnedStart.includes(id));\n const pinned = new Set([...pinnedStart, ...pinnedEnd]);\n const center = resolveColumnOrder(columns, state.columnOrder).filter((id) => !pinned.has(id));\n\n const entry = (id: string, pin?: \"start\" | \"end\"): ColumnState => {\n const out: ColumnState = { id };\n const width = state.columnSizing[id];\n if (width !== undefined) out.width = width;\n if (state.columnVisibility[id] === false) out.hidden = true;\n if (pin !== undefined) out.pinned = pin;\n return out;\n };\n\n const view: SavedView = {\n version: SAVED_VIEW_VERSION,\n columns: [\n ...pinnedStart.map((id) => entry(id, \"start\")),\n ...center.map((id) => entry(id)),\n ...pinnedEnd.map((id) => entry(id, \"end\")),\n ],\n sort: state.sort.filter((item) => known.has(item.field)).map((item) => ({ ...item })),\n filter: state.filter.filter((item) => known.has(item.field)).map((item) => ({ ...item })),\n };\n if (options.name !== undefined) view.name = options.name;\n if (state.group.length > 0) view.group = state.group.filter((item) => known.has(item.field)).map((item) => ({ ...item }));\n return view;\n}\n\n/**\n * Turns a saved view back into view state for the given columns. Ids the grid\n * does not have are ignored; columns the view does not mention keep their\n * defaults and follow in definition order. The result never throws on a view\n * saved against different columns, which is the normal case after a release.\n */\nexport function applySavedView<Row>(view: SavedView, columns: readonly ColumnDef<Row>[]): GridViewState {\n const defaults = createViewState(columns);\n const known = indexColumns(columns);\n const inView = view.columns.filter((column) => known.has(column.id));\n const mentioned = new Set(inView.map((column) => column.id));\n\n const visibility: Record<string, boolean> = {};\n for (const column of columns) {\n if (!mentioned.has(column.id) && defaults.columnVisibility[column.id] === false) visibility[column.id] = false;\n }\n const sizing: Record<string, number> = {};\n const pinning = { start: [] as string[], end: [] as string[] };\n for (const column of inView) {\n if (column.hidden === true) visibility[column.id] = false;\n if (column.width !== undefined) sizing[column.id] = column.width;\n if (column.pinned === \"start\") pinning.start.push(column.id);\n if (column.pinned === \"end\") pinning.end.push(column.id);\n }\n for (const column of columns) {\n if (mentioned.has(column.id)) continue;\n if (column.pinned === \"start\") pinning.start.push(column.id);\n if (column.pinned === \"end\") pinning.end.push(column.id);\n }\n\n return {\n sort: view.sort.filter((item) => known.has(item.field)).map((item) => ({ ...item })),\n filter: view.filter.filter((item) => known.has(item.field)).map((item) => ({ ...item })),\n group: (view.group ?? []).filter((item) => known.has(item.field)).map((item) => ({ ...item })),\n columnOrder: resolveColumnOrder(\n columns,\n inView.map((column) => column.id),\n ),\n columnVisibility: visibility,\n columnSizing: sizing,\n columnPinning: pinning,\n };\n}\n\n/** A saved-view store that keeps views in memory. Handy for tests and demos. */\nexport function createMemorySavedViewStore(initial: Record<string, SavedView> = {}): SavedViewStore {\n const views = new Map<string, SavedView>(Object.entries(initial));\n return {\n list: async () =>\n [...views.entries()].map(([id, view]) => (view.name === undefined ? { id } : { id, name: view.name })),\n load: async (id) => {\n const view = views.get(id);\n return view === undefined ? null : parseSavedView(JSON.parse(JSON.stringify(view)));\n },\n save: async (id, view) => {\n views.set(id, JSON.parse(JSON.stringify(view)) as SavedView);\n },\n delete: async (id) => {\n views.delete(id);\n },\n };\n}\n\n/** The slice of `Storage` the local-storage store needs. */\nexport interface StorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nexport interface LocalStorageSavedViewStoreOptions {\n /** The key holding every view as one JSON object. Default `x12i-data-views`. */\n key?: string;\n /** Defaults to `localStorage`. Falls back to memory where there is none (SSR, private mode). */\n storage?: StorageLike;\n}\n\n/**\n * A saved-view store backed by `localStorage`, one JSON object under one key.\n * Reads go through `parseSavedView`, so a corrupted or newer record is skipped.\n */\nexport function createLocalStorageSavedViewStore(options: LocalStorageSavedViewStoreOptions = {}): SavedViewStore {\n const key = options.key ?? \"x12i-data-views\";\n const fallback = new Map<string, string>();\n const resolve = (): StorageLike => {\n if (options.storage !== undefined) return options.storage;\n try {\n const candidate = (globalThis as { localStorage?: StorageLike }).localStorage;\n if (candidate !== undefined) return candidate;\n } catch {\n // Access to localStorage can throw (blocked cookies); use memory.\n }\n return { getItem: (k) => fallback.get(k) ?? null, setItem: (k, v) => void fallback.set(k, v) };\n };\n\n const read = (): Record<string, unknown> => {\n try {\n const parsed: unknown = JSON.parse(resolve().getItem(key) ?? \"{}\");\n return isRecord(parsed) ? parsed : {};\n } catch {\n return {};\n }\n };\n\n return {\n list: async () => {\n const out: SavedViewSummary[] = [];\n for (const [id, value] of Object.entries(read())) {\n const view = parseSavedView(value);\n if (view !== null) out.push(view.name === undefined ? { id } : { id, name: view.name });\n }\n return out;\n },\n load: async (id) => parseSavedView(read()[id]),\n save: async (id, view) => {\n resolve().setItem(key, JSON.stringify({ ...read(), [id]: view }));\n },\n delete: async (id) => {\n const all = read();\n delete all[id];\n resolve().setItem(key, JSON.stringify(all));\n },\n };\n}\n","import { columnFieldName } from \"./columns\";\nimport { computeViewIndexes } from \"./view\";\nimport type {\n ColumnDef,\n FilterModelItem,\n GetRowsRequest,\n GetRowsResult,\n GroupModelItem,\n ServerDataSource,\n SortModelItem,\n} from \"./types\";\n\n/** What a server query depends on. A change to any part throws the cached rows out of date. */\nexport interface ServerQuery {\n sort: SortModelItem[];\n filter: FilterModelItem[];\n group: GroupModelItem[];\n quickFilter?: string;\n}\n\n/** An abort error: what a data source should reject with when its `signal` aborts. */\nexport function createAbortError(message = \"Aborted\"): Error {\n if (typeof DOMException === \"function\") return new DOMException(message, \"AbortError\");\n const error = new Error(message);\n error.name = \"AbortError\";\n return error;\n}\n\nexport function isAbortError(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && (error as { name?: unknown }).name === \"AbortError\";\n}\n\nfunction mapFields<T extends { field: string }>(items: readonly T[], map: ReadonlyMap<string, string>): T[] {\n return items.map((item) => ({ ...item, field: map.get(item.field) ?? item.field }));\n}\n\n/**\n * Translates a grid query (which names columns by `id`) into what a server\n * sees: the data field of each column (`column.field ?? column.id`).\n */\nexport function toServerQuery<Row>(columns: readonly ColumnDef<Row>[], query: ServerQuery): ServerQuery {\n const map = new Map(columns.map((column) => [column.id, columnFieldName(column)] as const));\n const out: ServerQuery = {\n sort: mapFields(query.sort, map),\n filter: mapFields(query.filter, map),\n group: mapFields(query.group, map),\n };\n if (query.quickFilter !== undefined && query.quickFilter !== \"\") out.quickFilter = query.quickFilter;\n return out;\n}\n\n/** The inverse of `toServerQuery`, for data sources that reuse the headless engine. */\nexport function fromServerQuery<Row>(columns: readonly ColumnDef<Row>[], query: ServerQuery): ServerQuery {\n const map = new Map(columns.map((column) => [columnFieldName(column), column.id] as const));\n const out: ServerQuery = {\n sort: mapFields(query.sort, map),\n filter: mapFields(query.filter, map),\n group: mapFields(query.group, map),\n };\n if (query.quickFilter !== undefined) out.quickFilter = query.quickFilter;\n return out;\n}\n\nexport interface ClientDataSourceOptions {\n /** Simulated network delay in milliseconds, or a function returning one. Default 0. */\n latency?: number | (() => number);\n locale?: string;\n /** Throw this for requests the function accepts, to exercise error states. */\n fail?: (request: GetRowsRequest) => unknown;\n}\n\nfunction delay(ms: number, signal: AbortSignal | undefined): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted === true) {\n reject(createAbortError());\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(createAbortError());\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/**\n * A `ServerDataSource` over an in-memory array: it filters, sorts and pages with\n * the headless engine. Use it to try server mode without a backend, in tests,\n * and in demos. It honors the `signal` like a real fetch.\n */\nexport function createClientDataSource<Row>(\n rows: readonly Row[],\n columns: readonly ColumnDef<Row>[],\n options: ClientDataSourceOptions = {},\n): ServerDataSource<Row> {\n return {\n async getRows(request, requestOptions) {\n const latency = typeof options.latency === \"function\" ? options.latency() : (options.latency ?? 0);\n await delay(latency, requestOptions?.signal);\n const failure = options.fail?.(request);\n if (failure !== undefined && failure !== false && failure !== null) {\n throw failure instanceof Error ? failure : new Error(String(failure));\n }\n const local = fromServerQuery(columns, request);\n const indexes = computeViewIndexes(rows, columns, {\n sort: local.sort,\n filter: local.filter,\n ...(local.quickFilter === undefined ? {} : { quickFilter: local.quickFilter }),\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n });\n const slice = indexes.slice(request.startRow, request.endRow);\n const result: GetRowsResult<Row> = { rows: slice.map((index) => rows[index] as Row), total: indexes.length };\n return result;\n },\n };\n}\n\n// --------------------------------------------------------------------------------\n// Block store\n\nexport type BlockStatus = \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\nexport interface ServerStoreSnapshot {\n /** Changes whenever anything the grid could show changes. */\n readonly version: number;\n /** Total rows matching the query, or `null` before the first answer. */\n readonly total: number | null;\n /** At least one request is in flight. */\n readonly loading: boolean;\n /** The error of the most recent failed request, or `null`. */\n readonly error: unknown;\n /**\n * What is on screen came from before the last query change and is being\n * replaced: the total, or a block in the rows last asked for. Blocks outside\n * that window stay stale quietly until they are scrolled to.\n */\n readonly stale: boolean;\n}\n\nexport interface ServerRowStoreOptions<Row> {\n dataSource: ServerDataSource<Row>;\n /** Rows per request. In paged mode use the page size. */\n blockSize: number;\n query?: ServerQuery;\n}\n\nexport interface ServerRowStore<Row> {\n subscribe(listener: () => void): () => void;\n getSnapshot(): ServerStoreSnapshot;\n /**\n * Changes what the server is asked for. Requests in flight are aborted. Rows\n * already loaded stay visible and flagged stale until fresh blocks replace them\n * (stale-while-revalidate). Returns `false` when the query is unchanged.\n */\n setQuery(query: ServerQuery): boolean;\n /** Changes the rows per request. Cached rows no longer line up, so they are dropped. */\n setBlockSize(size: number): void;\n /** Makes sure every block overlapping `[startRow, endRow)` is loaded or loading. */\n request(startRow: number, endRow: number): void;\n /** The row at an index, or `undefined` while it is not loaded. Stale rows are returned. */\n getRow(index: number): Row | undefined;\n getBlockStatus(index: number): BlockStatus;\n /** Whether the row at an index is from before the last query change. */\n isStale(index: number): boolean;\n /** Requests again every block that failed. */\n retry(): void;\n /** Drops everything and loads again from the first block on the next `request`. */\n reset(): void;\n /** Aborts requests and stops notifying. */\n destroy(): void;\n}\n\ninterface Block<Row> {\n status: BlockStatus;\n rows: Row[];\n stale: boolean;\n controller: AbortController | null;\n}\n\n/**\n * The cache behind server mode: fixed-size blocks, one request per block, an\n * `AbortSignal` per request, stale-while-revalidate on query changes and retry\n * for failed blocks. It also follows cursor-paged APIs: when an answer carries\n * `nextCursor`, later blocks are requested one after another with that cursor.\n *\n * It is framework free; React reads it with `useSyncExternalStore`.\n */\nexport function createServerRowStore<Row>(options: ServerRowStoreOptions<Row>): ServerRowStore<Row> {\n const { dataSource } = options;\n let blockSize = Math.max(1, Math.floor(options.blockSize));\n let query: ServerQuery = options.query ?? { sort: [], filter: [], group: [] };\n let queryKey = JSON.stringify(query);\n const blocks = new Map<number, Block<Row>>();\n const cursors = new Map<number, string | null>();\n let cursorMode = false;\n let total: number | null = null;\n // `total` came from before the last query change and no answer to the new query has arrived.\n let totalStale = false;\n let lastError: unknown = null;\n let version = 0;\n let destroyed = false;\n // The rows the grid last asked for. Only stale blocks in this window count as \"stale on screen\";\n // the others stay as they are until they are scrolled to.\n let windowStart = 0;\n let windowEnd = 0;\n const listeners = new Set<() => void>();\n\n const compute = (): ServerStoreSnapshot => {\n let loading = false;\n let stale = totalStale;\n const first = Math.floor(windowStart / blockSize);\n const last = Math.floor((windowEnd - 1) / blockSize);\n for (const [index, block] of blocks) {\n if (block.status === \"loading\") loading = true;\n if (block.stale && index >= first && index <= last) stale = true;\n }\n return { version, total, loading, error: lastError, stale };\n };\n let snapshot = compute();\n\n const emit = () => {\n version += 1;\n snapshot = compute();\n for (const listener of [...listeners]) listener();\n };\n\n const abortAll = () => {\n for (const block of blocks.values()) {\n block.controller?.abort();\n block.controller = null;\n }\n };\n\n const load = (index: number): Promise<void> => {\n const existing = blocks.get(index);\n const block: Block<Row> = existing ?? { status: \"idle\", rows: [], stale: false, controller: null };\n blocks.set(index, block);\n block.controller?.abort();\n const controller = new AbortController();\n block.controller = controller;\n block.status = \"loading\";\n const request: GetRowsRequest = {\n startRow: index * blockSize,\n endRow: (index + 1) * blockSize,\n sort: query.sort,\n filter: query.filter,\n group: query.group,\n };\n if (query.quickFilter !== undefined && query.quickFilter !== \"\") request.quickFilter = query.quickFilter;\n if (cursorMode) request.cursor = index === 0 ? null : (cursors.get(index) ?? null);\n\n return dataSource.getRows(request, { signal: controller.signal }).then(\n (result) => {\n if (destroyed || block.controller !== controller || controller.signal.aborted) return;\n block.controller = null;\n block.status = \"loaded\";\n block.rows = result.rows;\n block.stale = false;\n total = result.total;\n totalStale = false;\n lastError = null;\n if (result.nextCursor !== undefined) {\n cursorMode = true;\n cursors.set(index + 1, result.nextCursor);\n }\n emit();\n },\n (error: unknown) => {\n if (destroyed || block.controller !== controller || controller.signal.aborted || isAbortError(error)) return;\n block.controller = null;\n block.status = \"error\";\n lastError = error;\n emit();\n },\n );\n };\n\n // In cursor mode block N needs the cursor from block N-1, so the chain loads in order.\n const loadWithCursors = async (index: number): Promise<void> => {\n let start = index;\n while (start > 0 && !cursors.has(start)) start -= 1;\n for (let next = start; next <= index; next += 1) {\n const block = blocks.get(next);\n if (block !== undefined && block.status === \"loaded\" && !block.stale) continue;\n await load(next);\n if (blocks.get(next)?.status !== \"loaded\") return;\n }\n };\n\n const needsLoad = (block: Block<Row> | undefined): boolean =>\n block === undefined || block.status === \"idle\" || (block.status === \"loaded\" && block.stale);\n\n return {\n subscribe(listener) {\n listeners.add(listener);\n return () => void listeners.delete(listener);\n },\n getSnapshot: () => snapshot,\n setQuery(next) {\n const key = JSON.stringify(next);\n if (key === queryKey) return false;\n queryKey = key;\n query = next;\n abortAll();\n cursors.clear();\n for (const [index, block] of [...blocks.entries()]) {\n if (block.status === \"loaded\") {\n block.stale = true;\n block.status = \"idle\";\n } else {\n blocks.delete(index);\n }\n }\n lastError = null;\n totalStale = total !== null;\n emit();\n return true;\n },\n setBlockSize(size) {\n const next = Math.max(1, Math.floor(size));\n if (next === blockSize) return;\n blockSize = next;\n abortAll();\n blocks.clear();\n cursors.clear();\n total = null;\n totalStale = false;\n lastError = null;\n emit();\n },\n request(startRow, endRow) {\n if (destroyed || endRow <= startRow) return;\n windowStart = Math.max(0, startRow);\n windowEnd = endRow;\n const first = Math.floor(Math.max(0, startRow) / blockSize);\n const last = Math.floor((endRow - 1) / blockSize);\n for (let index = first; index <= last; index += 1) {\n if (!needsLoad(blocks.get(index))) continue;\n if (cursorMode && index > 0) {\n if (cursors.has(index)) void load(index);\n else void loadWithCursors(index);\n } else {\n void load(index);\n }\n }\n const next = compute();\n if (snapshot.loading !== next.loading || snapshot.stale !== next.stale) emit();\n },\n getRow(index) {\n const block = blocks.get(Math.floor(index / blockSize));\n return block?.rows[index % blockSize];\n },\n getBlockStatus(index) {\n const block = blocks.get(Math.floor(index / blockSize));\n if (block === undefined) return \"idle\";\n return block.stale && block.status === \"idle\" ? \"loaded\" : block.status;\n },\n isStale(index) {\n return blocks.get(Math.floor(index / blockSize))?.stale === true;\n },\n retry() {\n const failed = [...blocks.entries()].filter(([, block]) => block.status === \"error\").map(([index]) => index);\n if (failed.length === 0) return;\n lastError = null;\n for (const index of failed) {\n if (cursorMode && index > 0 && !cursors.has(index)) void loadWithCursors(index);\n else void load(index);\n }\n emit();\n },\n reset() {\n abortAll();\n blocks.clear();\n cursors.clear();\n total = null;\n totalStale = false;\n lastError = null;\n emit();\n },\n destroy() {\n destroyed = true;\n abortAll();\n listeners.clear();\n },\n };\n}","export type MessageValues = Readonly<Record<string, string | number>>;\n\n/**\n * The ICU MessageFormat subset the grid's messages use:\n *\n * - `{name}`: the value; numbers are formatted for the locale.\n * - `{count, plural, =0 {none} one {# row} other {# rows}}`: plural categories\n * from `Intl.PluralRules`, exact `=N` matches, and `#` for the number.\n * - `{kind, select, a {...} other {...}}`: choose by string value.\n *\n * Apostrophes are plain characters; there is no quoting. A missing value renders\n * as an empty string rather than throwing.\n */\nexport function formatMessage(template: string, values: MessageValues = {}, locale?: string): string {\n return render(template, values, locale, undefined);\n}\n\nfunction formatNumber(value: number, locale: string | undefined): string {\n try {\n return new Intl.NumberFormat(locale).format(value);\n } catch {\n return String(value);\n }\n}\n\nfunction formatValue(value: string | number | undefined, locale: string | undefined): string {\n if (value === undefined) return \"\";\n return typeof value === \"number\" ? formatNumber(value, locale) : value;\n}\n\n/** Index of the `}` that closes the `{` at `open`, or -1. */\nfunction closingBrace(text: string, open: number): number {\n let depth = 0;\n for (let i = open; i < text.length; i += 1) {\n const char = text.charAt(i);\n if (char === \"{\") depth += 1;\n else if (char === \"}\") {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\nfunction render(\n template: string,\n values: MessageValues,\n locale: string | undefined,\n pluralValue: number | undefined,\n): string {\n let out = \"\";\n let i = 0;\n while (i < template.length) {\n const char = template.charAt(i);\n if (char === \"{\") {\n const end = closingBrace(template, i);\n if (end < 0) {\n out += template.slice(i);\n break;\n }\n out += evaluate(template.slice(i + 1, end), values, locale);\n i = end + 1;\n } else if (char === \"#\" && pluralValue !== undefined) {\n out += formatNumber(pluralValue, locale);\n i += 1;\n } else {\n out += char;\n i += 1;\n }\n }\n return out;\n}\n\nfunction evaluate(body: string, values: MessageValues, locale: string | undefined): string {\n const firstComma = body.indexOf(\",\");\n if (firstComma < 0) return formatValue(values[body.trim()], locale);\n\n const name = body.slice(0, firstComma).trim();\n const rest = body.slice(firstComma + 1);\n const secondComma = rest.indexOf(\",\");\n if (secondComma < 0) return formatValue(values[name], locale);\n const kind = rest.slice(0, secondComma).trim();\n const branchesSource = rest.slice(secondComma + 1);\n\n const branches = new Map<string, string>();\n let i = 0;\n while (i < branchesSource.length) {\n while (i < branchesSource.length && /\\s/.test(branchesSource.charAt(i))) i += 1;\n let selector = \"\";\n while (i < branchesSource.length && !/[\\s{]/.test(branchesSource.charAt(i))) {\n selector += branchesSource.charAt(i);\n i += 1;\n }\n while (i < branchesSource.length && /\\s/.test(branchesSource.charAt(i))) i += 1;\n if (branchesSource.charAt(i) !== \"{\") break;\n const end = closingBrace(branchesSource, i);\n if (end < 0) break;\n branches.set(selector, branchesSource.slice(i + 1, end));\n i = end + 1;\n }\n\n const value = values[name];\n if (kind === \"plural\") {\n const count = typeof value === \"number\" ? value : Number(value);\n if (Number.isNaN(count)) return \"\";\n let category = \"other\";\n try {\n category = new Intl.PluralRules(locale).select(count);\n } catch {\n // Unknown locale: fall back to the \"other\" branch.\n }\n const chosen = branches.get(`=${count}`) ?? branches.get(category) ?? branches.get(\"other\") ?? \"\";\n return render(chosen, values, locale, count);\n }\n if (kind === \"select\") {\n const chosen = branches.get(String(value)) ?? branches.get(\"other\") ?? \"\";\n return render(chosen, values, locale, undefined);\n }\n return formatValue(value, locale);\n}\n","import type { FilterOperator } from \"./types\";\n\n/**\n * Every user-facing string of the DataGrid and Pagination. Components contain\n * no English: they read these. Templates use ICU MessageFormat (`{name}`,\n * `{count, plural, one {# row} other {# rows}}`); see `formatMessage`.\n */\nexport interface DataGridMessages {\n // States\n loading: string;\n loadingMore: string;\n empty: string;\n emptyFiltered: string;\n error: string;\n retry: string;\n clearFilters: string;\n\n // Toolbar\n toolbarLabel: string;\n quickSearch: string;\n quickSearchPlaceholder: string;\n clearSearch: string;\n columns: string;\n columnsMenuLabel: string;\n showAllColumns: string;\n exportCsv: string;\n copySelection: string;\n copied: string;\n copyFailed: string;\n\n // Selection\n selectedCount: string;\n allSelected: string;\n clearSelection: string;\n selectAll: string;\n selectRow: string;\n\n // Header\n sortAscending: string;\n sortDescending: string;\n clearSort: string;\n filterColumn: string;\n columnMenu: string;\n hideColumn: string;\n pinStart: string;\n pinEnd: string;\n unpin: string;\n moveEarlier: string;\n moveLater: string;\n groupBy: string;\n ungroup: string;\n resizeColumn: string;\n sortRank: string;\n\n // Filters\n filterOperator: string;\n filterValue: string;\n filterFrom: string;\n filterTo: string;\n filterApply: string;\n filterClear: string;\n filterAny: string;\n filterNoOptions: string;\n filterBlank: string;\n operators: Record<FilterOperator, string>;\n activeFilters: string;\n filterSummary: string;\n removeFilter: string;\n clearAllFilters: string;\n groupedBy: string;\n removeGrouping: string;\n\n // Rows and cells\n expandRow: string;\n collapseRow: string;\n expandGroup: string;\n collapseGroup: string;\n groupLabel: string;\n rowActions: string;\n detailRegion: string;\n totals: string;\n yes: string;\n no: string;\n moreTags: string;\n progressLabel: string;\n\n // Editing\n editCell: string;\n cellEditFailed: string;\n cellSaved: string;\n invalidNumber: string;\n invalidDate: string;\n\n // Live announcements\n announceSorted: string;\n announceSortCleared: string;\n announceFiltered: string;\n announceFilterCleared: string;\n announceGrouped: string;\n announceColumnMoved: string;\n announceColumnHidden: string;\n announceColumnResized: string;\n announcePinned: string;\n announceSelection: string;\n\n // Server mode\n rowLoading: string;\n rowFailed: string;\n\n // Pagination\n paginationLabel: string;\n pageSize: string;\n firstPage: string;\n previousPage: string;\n nextPage: string;\n lastPage: string;\n pageRange: string;\n pageStatus: string;\n}\n\nexport type DataGridMessageOverrides = Partial<Omit<DataGridMessages, \"operators\">> & {\n operators?: Partial<Record<FilterOperator, string>>;\n};\n\n/** The English messages. Pass a translated subset through the `messages` prop. */\nexport const defaultMessages: DataGridMessages = {\n loading: \"Loading rows\",\n loadingMore: \"Loading more rows\",\n empty: \"No rows to show\",\n emptyFiltered: \"No rows match the current filters\",\n error: \"Could not load rows\",\n retry: \"Try again\",\n clearFilters: \"Clear filters\",\n\n toolbarLabel: \"Grid tools\",\n quickSearch: \"Search rows\",\n quickSearchPlaceholder: \"Search\",\n clearSearch: \"Clear search\",\n columns: \"Columns\",\n columnsMenuLabel: \"Show or hide columns\",\n showAllColumns: \"Show all columns\",\n exportCsv: \"Export CSV\",\n copySelection: \"Copy\",\n copied: \"{count, plural, one {Copied # row} other {Copied # rows}}\",\n copyFailed: \"Could not copy to the clipboard\",\n\n selectedCount: \"{count, plural, one {# row selected} other {# rows selected}}\",\n allSelected: \"All {count, plural, one {# row} other {# rows}} selected\",\n clearSelection: \"Clear selection\",\n selectAll: \"Select all rows\",\n selectRow: \"Select row\",\n\n sortAscending: \"Sort ascending\",\n sortDescending: \"Sort descending\",\n clearSort: \"Clear sort\",\n filterColumn: \"Filter {column}\",\n columnMenu: \"Options for {column}\",\n hideColumn: \"Hide column\",\n pinStart: \"Pin to start\",\n pinEnd: \"Pin to end\",\n unpin: \"Unpin\",\n moveEarlier: \"Move earlier\",\n moveLater: \"Move later\",\n groupBy: \"Group by {column}\",\n ungroup: \"Stop grouping by {column}\",\n resizeColumn: \"Resize {column}\",\n sortRank: \"Sort priority {rank}\",\n\n filterOperator: \"Operator\",\n filterValue: \"Value\",\n filterFrom: \"From\",\n filterTo: \"To\",\n filterApply: \"Apply\",\n filterClear: \"Clear\",\n filterAny: \"Any\",\n filterNoOptions: \"No values to choose from\",\n filterBlank: \"(Blank)\",\n operators: {\n contains: \"contains\",\n \"not-contains\": \"does not contain\",\n \"starts-with\": \"starts with\",\n equals: \"is\",\n \"not-equals\": \"is not\",\n gt: \"is greater than\",\n gte: \"is at least\",\n lt: \"is less than\",\n lte: \"is at most\",\n between: \"is between\",\n in: \"is one of\",\n before: \"is before\",\n after: \"is after\",\n \"is-empty\": \"is empty\",\n \"is-not-empty\": \"is not empty\",\n },\n activeFilters: \"Active filters\",\n filterSummary: \"{column} {operator} {value}\",\n removeFilter: \"Remove filter {summary}\",\n clearAllFilters: \"Clear all\",\n groupedBy: \"Grouped by {column}\",\n removeGrouping: \"Stop grouping by {column}\",\n\n expandRow: \"Expand row\",\n collapseRow: \"Collapse row\",\n expandGroup: \"Expand group\",\n collapseGroup: \"Collapse group\",\n groupLabel: \"{value} ({count})\",\n rowActions: \"Row actions\",\n detailRegion: \"Row details\",\n totals: \"Total\",\n yes: \"Yes\",\n no: \"No\",\n moreTags: \"+{count}\",\n progressLabel: \"{value} complete\",\n\n editCell: \"Edit {column}\",\n cellEditFailed: \"Could not save {column}. The change was undone.\",\n cellSaved: \"{column} saved\",\n invalidNumber: \"Enter a number\",\n invalidDate: \"Enter a valid date\",\n\n announceSorted:\n \"Sorted by {column}, {direction, select, desc {descending} other {ascending}}. {count, plural, one {# row} other {# rows}}.\",\n announceSortCleared: \"Sorting cleared. {count, plural, one {# row} other {# rows}}.\",\n announceFiltered: \"{count, plural, =0 {No rows match} one {# row matches} other {# rows match}} the filters.\",\n announceFilterCleared: \"Filters cleared. {count, plural, one {# row} other {# rows}}.\",\n announceGrouped: \"Grouped by {column}.\",\n announceColumnMoved: \"{column} moved to position {position} of {total}.\",\n announceColumnHidden: \"{column} hidden.\",\n announceColumnResized: \"{column} width {width} pixels.\",\n announcePinned: \"{column} pinned to the {side, select, end {end} other {start}}.\",\n announceSelection: \"{count, plural, one {# row selected} other {# rows selected}}.\",\n\n rowLoading: \"Loading row\",\n rowFailed: \"Row could not be loaded\",\n\n paginationLabel: \"Pagination\",\n pageSize: \"Rows per page\",\n firstPage: \"First page\",\n previousPage: \"Previous page\",\n nextPage: \"Next page\",\n lastPage: \"Last page\",\n pageRange: \"{start}–{end} of {total}\",\n pageStatus: \"Page {page} of {pages}\",\n};\n\n/** Merges overrides onto the English defaults. Missing keys keep their English text. */\nexport function resolveMessages(overrides?: DataGridMessageOverrides): DataGridMessages {\n if (overrides === undefined) return defaultMessages;\n const { operators, ...rest } = overrides;\n const merged: Record<string, unknown> = { ...defaultMessages };\n for (const [key, value] of Object.entries(rest)) if (value !== undefined) merged[key] = value;\n return {\n ...(merged as unknown as DataGridMessages),\n operators: { ...defaultMessages.operators, ...operators },\n };\n}\n"],"mappings":"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","names":["formatNumber","next"]}
|