@gridkitjs/core 0.10.0 → 0.12.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/dist/index.d.ts +2012 -22
- package/dist/index.js +3197 -853
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/util/grid.ts","../src/util/navigation.ts","../src/util/ordering.ts","../src/util/selection.ts","../src/util/sizing.ts","../src/util/sorting.ts","../src/util/filtering.ts","../src/util/grouping.ts","../src/util/rows.ts","../src/util/paging.ts","../src/util/paginationWindow.ts","../src/util/aggregation.ts","../src/util/virtualization.ts"],"sourcesContent":["import type { ColumnAlignment, ColumnDefinition, ColumnType } from \"../types\";\n\n/**\n * Narrows to a value worth drilling into. Mirrors the `LeafValue` union in\n * `../types`: arrays and `Date`s are cell values rather than groups of\n * columns, and `null` cannot be introspected. Keep the two in sync.\n */\nfunction isNested(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value instanceof Date)\n );\n}\n\nfunction getType(value: unknown): ColumnType {\n if (value instanceof Date) return \"dateTime\";\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"bigint\") return \"number\";\n if (typeof value === \"symbol\") return \"string\";\n return \"string\";\n}\n\n/**\n * How a column of `type` aligns by default. Numeric types align right so that\n * their digits line up by place value; everything else reads from the left.\n */\nexport function alignmentForType(type: ColumnType): ColumnAlignment {\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return \"right\";\n default:\n return \"left\";\n }\n}\n\nfunction getAlignment(value: unknown): ColumnAlignment {\n return alignmentForType(getType(value));\n}\n\n/**\n * Derives one column per field across `rows`, in the order each field is first\n * seen — so a key that only appears in a later row still gets a column,\n * appended at the end. Nested objects contribute their non-object properties\n * as `\"Parent.Child\"`; anything deeper is skipped, as is the nested object\n * itself.\n *\n * Order follows `Object.entries`, which lists integer-like keys first\n * regardless of the order they were written in.\n */\nexport function defineColumnsFromRows<Row>(\n rows: readonly Row[],\n): readonly ColumnDefinition<Row>[] {\n const columns: ColumnDefinition<Row>[] = [];\n const seen = new Set<string>();\n\n function add(field: string, value: unknown): void {\n if (seen.has(field)) {\n return;\n }\n seen.add(field);\n columns.push({\n field,\n type: getType(value),\n alignment: getAlignment(value),\n });\n }\n\n for (const row of rows) {\n if (!isNested(row)) {\n continue;\n }\n for (const [key, value] of Object.entries(row)) {\n if (!isNested(value)) {\n add(key, value);\n continue;\n }\n for (const [nestedKey, nestedValue] of Object.entries(value)) {\n if (!isNested(nestedValue)) {\n add(`${key}.${nestedKey}`, nestedValue);\n }\n }\n }\n }\n\n return columns;\n}\n\n/**\n * The key state about a column is stored under, and the key it renders with.\n * Every such lookup goes through here so the two can never disagree.\n */\nexport function getColumnId<Row>(\n column: ColumnDefinition<Row, unknown>,\n): string {\n return column.id ?? column.field;\n}\n\n/**\n * The key state about a row is stored under, and the key it renders with — the\n * row's counterpart to `getColumnId`, and for the same reason: every such\n * lookup goes through here so no two can disagree.\n *\n * Falls back to the position so a grid given no `getRowId` still works. That\n * fallback ties a selection to where a row sits rather than to the row, so\n * anything that sorts, filters or pages its data has to supply one — otherwise\n * a re-sort leaves the same positions selected under different rows.\n */\nexport function resolveRowId<Row>(\n row: Row,\n index: number,\n getRowId?: (row: Row, index: number) => string,\n): string {\n return getRowId?.(row, index) ?? String(index);\n}\n\n/**\n * What a column's header shows: its own `headerTemplate`, called first if it is\n * a function, or else a label read off the field path — `\"Application.Id\"`\n * reading as `\"Application Id\"`.\n */\nexport function resolveColumnLabel<Row, Node>(\n column: ColumnDefinition<Row, Node>,\n): Node | string {\n const { headerTemplate } = column;\n if (headerTemplate === undefined) {\n return column.field.split(\".\").join(\" \");\n }\n // `Node` is open, so it could itself be a function type and the `typeof`\n // check cannot narrow on its own. A header that is callable is the lazy\n // form by definition — no adapter binds `Node` to a function.\n return typeof headerTemplate === \"function\"\n ? (headerTemplate as () => Node)()\n : headerTemplate;\n}\n\n/** Which of a column header's keyboard interactions to announce. */\nexport interface KeyShortcutCapabilities {\n reorderable: boolean;\n resizable: boolean;\n sortable: boolean;\n groupable: boolean;\n}\n\n/**\n * The `aria-keyshortcuts` string for a column header, naming only the keys\n * that column actually responds to — so the keys are discoverable, since\n * none of them is a convention a user would try unprompted.\n */\nexport function buildKeyShortcuts(\n capabilities: KeyShortcutCapabilities,\n): string {\n return [\n capabilities.reorderable ? \"Control+ArrowLeft Control+ArrowRight\" : \"\",\n // Alt+Enter is the keyboard equivalent of double-clicking the resize\n // handle to size the column to its content — same gate as the nudge\n // shortcuts, since both are resize actions.\n capabilities.resizable ? \"Alt+ArrowLeft Alt+ArrowRight Alt+Enter\" : \"\",\n capabilities.sortable ? \"Alt+ArrowUp\" : \"\",\n // Down rather than reusing Up: it reads as \"drill into groups\", and Up is\n // already sort's own mnemonic on the same header.\n capabilities.groupable ? \"Alt+ArrowDown\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\n/**\n * Accesses a value at a dotted path, e.g. `foo.bar.baz`.\n *\n * @param obj The object to access\n * @param path Path to the value, e.g. `\"foo.bar\"`\n * @returns The value at `path`, or `undefined` if it doesn't exist\n */\nexport function accessDotted(obj: unknown, path: string): unknown {\n return path\n .split(\".\")\n .reduce((value, key) => (isNested(value) ? value[key] : undefined), obj);\n}\n","/**\n * The header's row index. One coordinate space covers the header and the body\n * so that arrowing up out of the first row reaches the header without a case\n * of its own, and every other move is plain arithmetic.\n */\nexport const HEADER_ROW = -1;\n\n/** The cell the grid's single tab stop sits on. */\nexport interface GridFocus {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\n/** The modifier keys held with a navigation key press. */\nexport interface NavigationModifiers {\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly altKey: boolean;\n readonly shiftKey: boolean;\n}\n\n/**\n * Holds a coordinate inside the grid, so that a focus surviving a column\n * removal or a shorter page never leaves the grid with no tab stop at all —\n * which is a grid a keyboard cannot reach.\n */\nexport function clampFocus(\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n): GridFocus {\n return {\n rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),\n columnIndex: Math.min(\n Math.max(focus.columnIndex, 0),\n Math.max(columnCount - 1, 0),\n ),\n };\n}\n\n/** Never treats any row as unreachable — the default when a caller has no skippable rows at all. */\nfunction noRowsSkippable(): boolean {\n return false;\n}\n\n/**\n * `rowIndex` moved forward one row at a time in `direction` (`1` or `-1`)\n * until it lands on a row `isSkippableRow` says is reachable, or would run\n * off the grid's own bounds (`HEADER_ROW` to `rowCount - 1`) trying — in\n * which case it returns `fallback` (the position before this move started)\n * instead of an out-of-range index.\n *\n * Deliberately not \"step one past the bound\" the way an ordinary move here\n * left unclamped would: `clampFocus` downstream holds any out-of-range\n * `rowIndex` at the nearest in-range one, and if that nearest row happens\n * to be the very one that was skippable (the grid's actual last row is a\n * group's own summary row, say), clamping back onto it would silently\n * defeat the skip. Staying at `fallback` is what a \"there is nowhere valid\n * to move to\" press should do instead — the same way `ArrowLeft` at column\n * 0 already leaves `rowIndex`/`columnIndex` exactly where they were,\n * `clampFocus` is left with nothing to correct either way, and a caller\n * that still wants to detect \"did this move go anywhere\" can compare the\n * result to `focus` itself.\n */\nfunction skipSkippableRows(\n rowIndex: number,\n direction: 1 | -1,\n rowCount: number,\n isSkippableRow: (rowIndex: number) => boolean,\n fallback: number,\n): number {\n let next = rowIndex;\n // The header (HEADER_ROW) and anything already out of the body's own\n // [0, rowCount) range are never skippable — an ordinary PageUp/ArrowUp\n // overshoot past the header, in particular, has nothing to skip past, so\n // this function has nothing to do; `clampFocus` downstream still handles\n // holding it in bounds as it always has.\n while (next >= 0 && next < rowCount && isSkippableRow(next)) {\n const stepped = next + direction;\n // Landing on the header itself (moving up from row 0) is always valid —\n // only a step that would leave the header *and* the body's own range\n // behind (moving down past the last row) has nowhere left to go.\n if (stepped < HEADER_ROW || stepped >= rowCount) {\n return fallback;\n }\n next = stepped;\n }\n return next;\n}\n\n/**\n * The focus a navigation key press moves to, or `null` when the key isn't\n * this grid's to handle — left for the browser or another handler.\n *\n * `pageSize` is a pre-measured row count rather than a callback: this\n * function takes plain data only, so a caller measures the viewport once and\n * hands over the number.\n *\n * `isSkippableRow` names rows the vertical moves (`ArrowUp`/`ArrowDown`/\n * `PageUp`/`PageDown`/`Ctrl+End`) never land a tab stop on — a group's own\n * summary row (`groupAggregateDisplay: \"row\"`), which still occupies a real\n * row slot for `rowCount`/`aria-rowindex` purposes but is presentational,\n * not a stop of its own. Left/right and plain `Home`/`End` stay row-scoped\n * and so never consult it. Defaults to skipping nothing, so every existing\n * caller (and every horizontal move) is unaffected.\n */\nexport function nextFocusForKey(\n key: string,\n modifiers: NavigationModifiers,\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n pageSize: number,\n isSkippableRow: (rowIndex: number) => boolean = noRowsSkippable,\n): GridFocus | null {\n // Alt on an arrow resizes and Ctrl on one reorders; the header claims both\n // before this runs, and elsewhere they belong to the browser.\n if (modifiers.altKey) {\n return null;\n }\n\n const { rowIndex, columnIndex } = focus;\n\n switch (key) {\n case \"ArrowLeft\":\n if (modifiers.ctrlKey) return null;\n return { rowIndex, columnIndex: columnIndex - 1 };\n case \"ArrowRight\":\n if (modifiers.ctrlKey) return null;\n return { rowIndex, columnIndex: columnIndex + 1 };\n case \"ArrowUp\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex - 1,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n case \"ArrowDown\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex + 1,\n 1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n // Ctrl takes Home and End to the grid's ends rather than the row's, which\n // is the one place Ctrl is navigation rather than reorder.\n case \"Home\":\n return modifiers.ctrlKey\n ? { rowIndex: HEADER_ROW, columnIndex: 0 }\n : { rowIndex, columnIndex: 0 };\n case \"End\":\n return modifiers.ctrlKey\n ? {\n rowIndex: skipSkippableRows(\n rowCount - 1,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex: columnCount - 1,\n }\n : { rowIndex, columnIndex: columnCount - 1 };\n case \"PageUp\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex - pageSize,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n case \"PageDown\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex + pageSize,\n 1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n default:\n return null;\n }\n}\n","import type { ColumnDefinition, ColumnOrderState, DropSide } from \"../types\";\nimport { getColumnId } from \"./grid\";\n\n/**\n * Puts `columns` in the order `order` gives. Ids it lists come first, in that\n * order; columns it omits keep their position among the definitions and\n * follow. Ids naming no column are ignored.\n *\n * Tolerating both gaps is what lets a stored order outlive the column list it\n * was made against.\n */\nexport function applyColumnOrder<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n order: ColumnOrderState,\n): readonly ColumnDefinition<Row, Node>[] {\n if (order.length === 0) {\n return columns;\n }\n\n const byId = new Map(columns.map((column) => [getColumnId(column), column]));\n const listed = order\n .map((id) => byId.get(id))\n .filter((column) => column !== undefined);\n const taken = new Set(listed.map((column) => getColumnId(column)));\n\n return [\n ...listed,\n ...columns.filter((column) => !taken.has(getColumnId(column))),\n ];\n}\n\n/**\n * The order with `movedId` lifted out and put back in front of `beforeId`, or\n * at the end when that is `null`.\n *\n * Returns `orderedIds` itself when the move changes nothing, so callers can\n * treat an unchanged reference as \"no move happened\".\n */\nexport function moveColumnBefore(\n orderedIds: ColumnOrderState,\n movedId: string,\n beforeId: string | null,\n): ColumnOrderState {\n if (movedId === beforeId || !orderedIds.includes(movedId)) {\n return orderedIds;\n }\n\n const without = orderedIds.filter((id) => id !== movedId);\n // Taken after the removal: an index read before it would be one too far\n // right for every move that travels rightwards.\n const target = beforeId === null ? without.length : without.indexOf(beforeId);\n if (target === -1) {\n return orderedIds;\n }\n\n const next = [...without];\n next.splice(target, 0, movedId);\n return next.every((id, index) => id === orderedIds[index])\n ? orderedIds\n : next;\n}\n\n/**\n * Whether moving `movedId` in front of `beforeId` would rearrange anything, so\n * that a drop indicator promises exactly the moves that happen.\n *\n * Defined against `moveColumnBefore` rather than restating its conditions, so\n * the two cannot disagree about what a no-op is.\n */\nexport function movesColumn(\n orderedIds: ColumnOrderState,\n movedId: string,\n beforeId: string | null,\n): boolean {\n return moveColumnBefore(orderedIds, movedId, beforeId) !== orderedIds;\n}\n\n/**\n * The id a drop on `side` of `targetId` lands in front of, which is `null`\n * past the last column.\n *\n * \"After C\" and \"before D\" name the same gap, so collapsing both to one id\n * keeps a drop target a single nullable string.\n */\nexport function resolveDropBefore(\n orderedIds: ColumnOrderState,\n targetId: string,\n side: DropSide,\n): string | null {\n if (side === \"before\") {\n return targetId;\n }\n const index = orderedIds.indexOf(targetId);\n return index === -1 ? null : (orderedIds[index + 1] ?? null);\n}\n\n/**\n * The `beforeId` a keyboard nudge on `columnId` produces, for `onDrop` to\n * apply the same way a pointer drop does — or `undefined` when the nudge is a\n * no-op: `columnId` is not in `orderedIds`, or the nudge would move it left\n * of the start.\n *\n * `null` is a real answer here, not \"no-op\": it means append to the end, the\n * same convention `moveColumnBefore` uses.\n */\nexport function resolveKeyboardDropTarget(\n orderedIds: ColumnOrderState,\n columnId: string,\n direction: -1 | 1,\n): string | null | undefined {\n const index = orderedIds.indexOf(columnId);\n if (index === -1) {\n return undefined;\n }\n\n /**\n * Moving right lands in front of the id two along: the gap immediately\n * after a column is the one it already sits in.\n */\n const targetIndex = direction === -1 ? index - 1 : index + 2;\n if (targetIndex < 0) {\n return undefined;\n }\n\n return orderedIds[targetIndex] ?? null;\n}\n","import type {\n CellSelectionMode,\n CellSelectionState,\n SelectedCellRef,\n SelectIntent,\n SelectionDiff,\n SelectionMode,\n SelectionState,\n} from \"../types\";\n\n/** Nothing changed, so nothing to report — shared to save an allocation. */\nconst NO_CHANGE: SelectionDiff = { added: [], removed: [] };\n\n/**\n * Whether two selections hold the same ids in the same order.\n *\n * Order counts because the selection's own order is what makes `at(-1)` the\n * most recently selected; a comparison that ignored it would have a transform\n * return the old reference after a reordering that a consumer can observe.\n */\nfunction sameSelection(a: SelectionState, b: SelectionState): boolean {\n return a.length === b.length && a.every((id, index) => id === b[index]);\n}\n\n/**\n * The selection with `id` added if absent and removed if present — a\n * Ctrl-click, or Space on the focused member.\n *\n * The mode is enforced here rather than by each caller, so `\"single\"` cannot\n * accumulate no matter which interaction reaches it. Returns `selection`\n * itself when `mode` is `false`, keeping the unchanged-reference contract\n * `moveColumnBefore` set: a caller treats an unchanged reference as \"nothing\n * happened\" and neither renders nor reports.\n */\nexport function toggleSelection(\n selection: SelectionState,\n id: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode === false) {\n return selection;\n }\n if (selection.includes(id)) {\n return selection.filter((selectedId) => selectedId !== id);\n }\n return mode === \"single\" ? [id] : [...selection, id];\n}\n\n/**\n * The selection reduced to `id` alone — a plain click, which discards what\n * came before rather than adding to it.\n *\n * Never deselects, so clicking the one selected row leaves it selected.\n * Letting go of it is Ctrl-click's job, and `toggleSelection`'s.\n */\nexport function selectOnly(\n selection: SelectionState,\n id: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode === false) {\n return selection;\n }\n return selection.length === 1 && selection[0] === id ? selection : [id];\n}\n\n/**\n * The selection replaced by every id from `anchorId` to `focusId` inclusive — a\n * Shift-click. The two may be given in either order.\n *\n * Spans `orderedIds`, the order as displayed, rather than the selection's own:\n * the range a user drew across the screen is the range they mean, whatever\n * order they clicked its ends in. Degrades to `selectOnly` under `\"single\"`,\n * where a range has nowhere to go.\n */\nexport function selectRange(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string,\n focusId: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode !== \"multiple\") {\n return selectOnly(selection, focusId, mode);\n }\n\n const anchor = orderedIds.indexOf(anchorId);\n const focus = orderedIds.indexOf(focusId);\n if (anchor === -1 || focus === -1) {\n return selection;\n }\n\n const next = orderedIds.slice(\n Math.min(anchor, focus),\n Math.max(anchor, focus) + 1,\n );\n return sameSelection(selection, next) ? selection : next;\n}\n\n/**\n * Every id in `orderedIds`, or `selection` untouched under any mode but\n * `\"multiple\"` — there is no selecting all of one thing.\n */\nexport function selectAll(\n selection: SelectionState,\n orderedIds: readonly string[],\n mode: SelectionMode,\n): SelectionState {\n if (mode !== \"multiple\") {\n return selection;\n }\n return sameSelection(selection, orderedIds) ? selection : orderedIds;\n}\n\nexport function clearSelection(selection: SelectionState): SelectionState {\n return selection.length === 0 ? selection : [];\n}\n\n/**\n * What one transition added and what it removed.\n *\n * Defined here rather than in an adapter so that every callback reporting a\n * selection change reads one answer, and a select and a deselect fired for the\n * same interaction cannot disagree about which it was.\n */\nexport function diffSelection(\n previous: SelectionState,\n next: SelectionState,\n): SelectionDiff {\n if (previous === next) {\n return NO_CHANGE;\n }\n\n const before = new Set(previous);\n const after = new Set(next);\n return {\n added: next.filter((id) => !before.has(id)),\n removed: previous.filter((id) => !after.has(id)),\n };\n}\n\nexport function isSameCell(\n a: CellSelectionState,\n b: CellSelectionState,\n): boolean {\n if (a === null || b === null) {\n return a === b;\n }\n return a.rowId === b.rowId && a.columnId === b.columnId;\n}\n\n/**\n * The cell selection moved to `cell` — a plain click. Idempotent: clicking the\n * selected cell again leaves it selected, matching `selectOnly`.\n */\nexport function selectCell(\n selection: CellSelectionState,\n cell: SelectedCellRef,\n mode: CellSelectionMode,\n): CellSelectionState {\n if (mode === false || isSameCell(selection, cell)) {\n return selection;\n }\n return cell;\n}\n\n/**\n * The cell selection moved to `cell`, or cleared when it is already there — a\n * Ctrl-click, matching `toggleSelection`.\n */\nexport function toggleCellSelection(\n selection: CellSelectionState,\n cell: SelectedCellRef,\n mode: CellSelectionMode,\n): CellSelectionState {\n if (mode === false) {\n return selection;\n }\n return isSameCell(selection, cell) ? null : cell;\n}\n\n/** The intent a click or key press carries, by the modifiers held with it. */\nexport function intentOf(event: {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n}): SelectIntent {\n if (event.shiftKey) {\n return \"range\";\n }\n // Cmd on a Mac is Ctrl everywhere else, and both mean the same thing here.\n return event.ctrlKey || event.metaKey ? \"toggle\" : \"replace\";\n}\n\n/**\n * The transform an intent asks for. A function rather than a branch inside\n * each caller, so a row and a column cannot come to mean different things by\n * the same click.\n */\nexport function applySelectionIntent(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string | null,\n id: string,\n intent: SelectIntent,\n mode: SelectionMode,\n): SelectionState {\n switch (intent) {\n case \"toggle\":\n return toggleSelection(selection, id, mode);\n // A range with no anchor yet spans from the id to itself, which is the\n // plain click a first Shift-click may as well be.\n case \"range\":\n return selectRange(selection, orderedIds, anchorId ?? id, id, mode);\n default:\n return selectOnly(selection, id, mode);\n }\n}\n","import type {\n ColumnConstraints,\n ColumnDefinition,\n ColumnResizeSession,\n ColumnResolveOptions,\n ColumnSizeDefaults,\n ColumnSizingState,\n ResolvedColumn,\n} from \"../types\";\nimport { alignmentForType, getColumnId, resolveColumnLabel } from \"./grid\";\n\n/**\n * Applied to any column that does not size itself. The minimum is a width a\n * header stays legible at rather than a measured value — a column dragged\n * narrower than this reads as a rendering fault.\n */\nexport const DEFAULT_COLUMN_SIZES: ColumnSizeDefaults = {\n width: 150,\n minWidth: 40,\n maxWidth: Number.POSITIVE_INFINITY,\n};\n\n/** How far one arrow key press moves a column edge. */\nexport const KEYBOARD_STEP = 10;\n\nfunction withDefaults(\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnSizeDefaults {\n return { ...DEFAULT_COLUMN_SIZES, ...defaults };\n}\n\n/**\n * The bounds `column` may be sized between. Resolved in one place so that a\n * drag, a clamp and an auto-fit cannot disagree about a column's limits.\n */\nexport function resolveColumnConstraints<Row>(\n column: ColumnDefinition<Row, unknown>,\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnConstraints {\n const resolved = withDefaults(defaults);\n return {\n minWidth: column.minWidth ?? resolved.minWidth,\n maxWidth: column.maxWidth ?? resolved.maxWidth,\n };\n}\n\n/** Holds `width` within `constraints`. */\nexport function clampColumnWidth(\n width: number,\n constraints: ColumnConstraints,\n): number {\n return Math.min(Math.max(width, constraints.minWidth), constraints.maxWidth);\n}\n\n/**\n * Pairs each column with everything needed to render it — the width it sits\n * at, the label its header shows, whether it may be resized and how its cells\n * align. Widths take the first of the sizing state, the column's own `width`,\n * and the default, then clamp.\n *\n * The sizing state winning means a user's drag outlives a re-render; a column\n * absent from it still tracks a `width` edited in the definition.\n */\nexport function resolveColumnWidths<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n sizing: ColumnSizingState,\n options?: ColumnResolveOptions,\n): readonly ResolvedColumn<Row, Node>[] {\n const resolved = withDefaults(options?.sizes);\n\n return columns.map((column) => {\n const id = getColumnId(column);\n const stored = sizing[id];\n\n return {\n column,\n id,\n sized: stored !== undefined,\n width: clampColumnWidth(\n stored ?? column.width ?? resolved.width,\n resolveColumnConstraints(column, resolved),\n ),\n label: resolveColumnLabel(column),\n resizable: column.resizable ?? options?.resizable ?? false,\n reorderable: column.reorderable ?? options?.reorderable ?? false,\n groupByDraggable:\n column.groupByDraggable ?? options?.groupByDraggable ?? false,\n alignment: column.alignment ?? alignmentForType(column.type ?? \"string\"),\n };\n });\n}\n\nexport function totalColumnWidth<Row, Node>(\n resolved: readonly ResolvedColumn<Row, Node>[],\n): number {\n return resolved.reduce((total, entry) => total + entry.width, 0);\n}\n\n/**\n * Opens a resize. The session captures its constraints and starting point up\n * front, so applying a pointer position later is arithmetic on numbers alone —\n * which is what keeps the drag testable without a DOM.\n *\n * @param startPosition Where the pointer went down, on the axis being dragged.\n */\nexport function beginColumnResize<Row>(\n column: ColumnDefinition<Row, unknown>,\n startWidth: number,\n startPosition: number,\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnResizeSession {\n return {\n columnId: getColumnId(column),\n startWidth,\n startPosition,\n constraints: resolveColumnConstraints(column, defaults),\n };\n}\n\n/**\n * The width the dragged column takes with the pointer at `position`. The delta\n * is signed, so a right-to-left adapter negates it and nothing else changes.\n */\nexport function applyColumnResize(\n session: ColumnResizeSession,\n position: number,\n): number {\n return clampColumnWidth(\n session.startWidth + (position - session.startPosition),\n session.constraints,\n );\n}\n\ninterface SizingEntry<Row, Node> {\n entry: ResolvedColumn<Row, Node>;\n width: number;\n bound: number;\n adjustable: boolean;\n}\n\n/**\n * Whether `item` has reached `bound` in the direction it moves toward — above\n * it for a column growing to a `maxWidth`, below it for one shrinking to a\n * `minWidth`.\n */\nfunction reachedBound<Row, Node>(\n width: number,\n item: SizingEntry<Row, Node>,\n): boolean {\n return item.bound > item.width ? width >= item.bound : width <= item.bound;\n}\n\n/**\n * Moves every adjustable entry's `width` toward `bound` by its proportional\n * share of `remaining`'s current surplus or deficit, looping so a column\n * clamped at its bound in one pass frees the remainder for the others to\n * absorb in the next.\n */\nfunction redistribute<Row, Node>(\n entries: readonly SizingEntry<Row, Node>[],\n remaining: (sum: number) => number,\n): void {\n for (;;) {\n const movable = entries.filter(\n (item) => item.adjustable && !reachedBound(item.width, item),\n );\n const left = remaining(entries.reduce((t, i) => t + i.width, 0));\n if (left <= 0 || movable.length === 0) {\n break;\n }\n\n const base = movable.reduce((total, item) => total + item.width, 0);\n let clamped = false;\n\n for (const item of movable) {\n const share =\n base === 0 ? left / movable.length : (left * item.width) / base;\n const next = item.width + (item.bound > item.width ? share : -share);\n\n if (reachedBound(next, item)) {\n item.width = item.bound;\n clamped = true;\n } else {\n item.width = next;\n }\n }\n\n if (!clamped) {\n break;\n }\n }\n}\n\n/**\n * Fits columns to `availableWidth`: grows them to fill leftover space, or\n * shrinks them to relieve an overflow, in both cases proportionally to each\n * column's current width. Columns the user has sized are left alone in\n * either direction, so dragging one column neither rubber-bands it back nor\n * has it absorb a squeeze meant for the rest.\n *\n * Growing stops at each column's `maxWidth`; shrinking stops at its\n * `minWidth`. If shrinking every adjustable column to its floor still does\n * not reach `availableWidth`, the columns are returned untouched and the\n * container scrolls rather than crushing them further.\n */\nexport function fitColumnsToWidth<Row, Node>(\n resolved: readonly ResolvedColumn<Row, Node>[],\n availableWidth: number,\n defaults?: Partial<ColumnSizeDefaults>,\n): readonly ResolvedColumn<Row, Node>[] {\n const target = Math.floor(availableWidth);\n const total = totalColumnWidth(resolved);\n if (resolved.length === 0 || total === target) {\n return resolved;\n }\n\n const growing = total < target;\n const entries: SizingEntry<Row, Node>[] = resolved.map((entry) => {\n const constraints = resolveColumnConstraints(entry.column, defaults);\n return {\n entry,\n width: entry.width,\n bound: growing ? constraints.maxWidth : constraints.minWidth,\n adjustable: !entry.sized,\n };\n });\n\n if (!growing) {\n // Only unsized columns can be shrunk, so if they alone cannot reach the\n // target the grid genuinely cannot fit and should scroll, unchanged.\n const floor = entries.reduce(\n (sum, item) => sum + (item.adjustable ? item.bound : item.width),\n 0,\n );\n if (floor > target) {\n return resolved;\n }\n }\n\n redistribute(entries, (sum) => (growing ? target - sum : sum - target));\n\n // Fractional widths would leave the table a sub-pixel off its container and\n // show a scrollbar that never goes away, so round every column toward the\n // target and hand the remaining pixels back out (growing) or claw them\n // back (shrinking) one at a time.\n const rounded = entries.map((item) =>\n growing ? Math.floor(item.width) : Math.ceil(item.width),\n );\n let remainder = target - rounded.reduce((total, width) => total + width, 0);\n\n return entries.map((item, index) => {\n let width = rounded[index] ?? item.width;\n // Rounding toward the target can only ever leave it short when growing\n // (floor) or over when shrinking (ceil), so only one direction is ever\n // live here — but each still needs room left before its own bound.\n const hasRoom = growing ? width < item.bound : width > item.bound;\n\n if (remainder !== 0 && item.adjustable && hasRoom) {\n width += growing ? 1 : -1;\n remainder += growing ? -1 : 1;\n }\n\n return { ...item.entry, width };\n });\n}\n\n/**\n * The width a column needs to show `measuredWidth` of content.\n *\n * `padding` is an allowance on top of the measurement, since a column sized to\n * exactly its content can still round down into an ellipsis.\n */\nexport function sizeColumnToContent(\n measuredWidth: number,\n constraints: ColumnConstraints,\n padding = 2,\n): number {\n return clampColumnWidth(Math.ceil(measuredWidth + padding), constraints);\n}\n\n/**\n * `current` with `columnId` reverted to its width in `base` — or omitted\n * entirely if `base` had none — for Escape to restore a resize in progress.\n *\n * A column with no stored width in `base` is correctly omitted by deleting\n * the key rather than merging its `base` width back in, which would\n * otherwise leave it pinned and hidden from auto-fit.\n */\nexport function revertColumnSize(\n current: ColumnSizingState,\n base: ColumnSizingState,\n columnId: string,\n): ColumnSizingState {\n const next = Object.fromEntries(\n Object.entries(current).filter(([id]) => id !== columnId),\n );\n if (columnId in base) {\n next[columnId] = base[columnId] as number;\n }\n return next;\n}\n","import type {\n ColumnSortState,\n ColumnType,\n ResolvedColumn,\n ResolvedRow,\n SortDirection,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/** A date/time value converted to a comparable instant. */\nfunction toTime(value: unknown): number {\n return value instanceof Date\n ? value.getTime()\n : new Date(String(value)).getTime();\n}\n\n/**\n * Compares two cell values the way `type` implies — numerically for the\n * numeric types, chronologically for the date/time types, lexically\n * otherwise. Defaults to string comparison when `type` is absent, mirroring\n * `ColumnDefinition.type`'s own default.\n *\n * `null`/`undefined` sort after every value on both sides. Used directly,\n * that ordering is fixed; `sortRows` applies it directionally without\n * disturbing it — see its own doc comment.\n */\nexport function compareValues(\n a: unknown,\n b: unknown,\n type?: ColumnType,\n): number {\n if (isEmpty(a)) {\n return isEmpty(b) ? 0 : 1;\n }\n if (isEmpty(b)) {\n return -1;\n }\n\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return Number(a) - Number(b);\n case \"boolean\":\n return Number(Boolean(a)) - Number(Boolean(b));\n case \"date\":\n case \"dateTime\":\n case \"time\":\n return toTime(a) - toTime(b);\n default:\n return String(a).localeCompare(String(b));\n }\n}\n\n/** This column's direction in `sort`, or `null` outside it. */\nexport function sortDirectionFor(\n sort: ColumnSortState,\n columnId: string,\n): SortDirection | null {\n return sort.find((entry) => entry.columnId === columnId)?.direction ?? null;\n}\n\n/** This column's 1-based place in `sort`, or `null` outside it. */\nexport function sortPriorityFor(\n sort: ColumnSortState,\n columnId: string,\n): number | null {\n const index = sort.findIndex((entry) => entry.columnId === columnId);\n return index === -1 ? null : index + 1;\n}\n\n/**\n * The sort with `columnId` cycled to its next direction — none → asc → desc →\n * none.\n *\n * `stack: false` (a plain click) means \"sort by only this column\": unless\n * `columnId` is already the sole entry, in which case its own cycle just\n * continues, it collapses `sort` down to `columnId` alone at `\"asc\"`,\n * regardless of any direction it held as part of a larger stack.\n *\n * `stack: true` (a Shift-click) cycles or appends `columnId` in place without\n * disturbing the rest of the stack; cycling it back to `\"none\"` removes it\n * and closes the gap, leaving the others in their existing order.\n */\nexport function toggleColumnSort(\n sort: ColumnSortState,\n columnId: string,\n options: { readonly stack: boolean },\n): ColumnSortState {\n const index = sort.findIndex((entry) => entry.columnId === columnId);\n const isSoleEntry = sort.length === 1 && index === 0;\n\n if (!options.stack && !isSoleEntry) {\n return [{ columnId, direction: \"asc\" }];\n }\n\n const current = index === -1 ? undefined : sort[index]?.direction;\n const next: SortDirection | null =\n current === undefined ? \"asc\" : current === \"asc\" ? \"desc\" : null;\n\n if (next === null) {\n return sort.filter((entry) => entry.columnId !== columnId);\n }\n if (index === -1) {\n return [...sort, { columnId, direction: next }];\n }\n return sort.map((entry, i) =>\n i === index ? { columnId, direction: next } : entry,\n );\n}\n\n/**\n * `rows` ordered by `sort` — each entry read against `columns` for its\n * `field` and `type` — with `rowIndex` renumbered to match the new\n * positions, the invariant the rest of the grid relies on for keyboard\n * navigation and `aria-rowindex`.\n *\n * Stable (`Array.prototype.sort` has been stable since ES2019), so rows\n * equal under every active key keep their relative order. A `null`/\n * `undefined` value sorts last under either direction — resolved before\n * `compareValues` is asked, and left out of the direction flip below, so\n * that toggling a column reorders the values it holds rather than moving its\n * gaps to the front.\n *\n * Returns `rows` itself, untouched, when `sort` is empty or names only\n * columns absent from `columns` — a stored sort tolerates a column removed\n * from the definition the same way a stored `ColumnOrderState` does.\n */\nexport function sortRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n sort: ColumnSortState,\n columns: readonly ResolvedColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n if (sort.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = sort.filter((entry) => byId.has(entry.columnId));\n if (active.length === 0) {\n return rows;\n }\n\n const sorted = [...rows].sort((a, b) => {\n for (const { columnId, direction } of active) {\n const column = byId.get(columnId);\n if (column === undefined) {\n continue;\n }\n const left = accessDotted(a.row, column.field);\n const right = accessDotted(b.row, column.field);\n const leftEmpty = isEmpty(left);\n const rightEmpty = isEmpty(right);\n if (leftEmpty || rightEmpty) {\n if (leftEmpty && rightEmpty) {\n continue;\n }\n return leftEmpty ? 1 : -1;\n }\n\n const result = compareValues(left, right, column.type);\n if (result !== 0) {\n return direction === \"asc\" ? result : -result;\n }\n }\n return 0;\n });\n\n return sorted.map((row, index) =>\n row.rowIndex === index ? row : { ...row, rowIndex: index },\n );\n}\n","import type {\n ColumnDefinition,\n ColumnType,\n FieldPath,\n FilterEntry,\n FilterState,\n ResolvedColumn,\n ResolvedRow,\n TextFilterEntry,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\n\ninterface FilterPattern {\n mode: \"exact\" | \"contains\" | \"startsWith\" | \"endsWith\";\n text: string; // anchors stripped, lowercased once\n}\n\n/**\n * Reads a query's leading/trailing `%` into a match mode — see\n * `TextFilterEntry`'s own doc comment for the four shapes. Only the first\n * and last characters are read as anchors — a `%` anywhere else in the\n * query is a literal character, not a wildcard.\n */\nfunction parseFilterPattern(query: string): FilterPattern {\n const start = query.startsWith(\"%\");\n const end = query.endsWith(\"%\");\n let text = query;\n if (start) {\n text = text.slice(1);\n }\n if (end) {\n text = text.slice(0, -1);\n }\n text = text.toLowerCase();\n\n if (start && end) {\n return { mode: \"contains\", text };\n }\n if (start) {\n return { mode: \"endsWith\", text };\n }\n if (end) {\n return { mode: \"startsWith\", text };\n }\n return { mode: \"exact\", text };\n}\n\nfunction isEmptyValue(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/**\n * `parseFilterPattern`, compiled to a reusable test — parsed once, reused\n * per row, unlike a per-call `matchesQuery`.\n */\nfunction compileFilterQuery(query: string): (value: unknown) => boolean {\n const { mode, text } = parseFilterPattern(query);\n return (value: unknown) => {\n const candidate = (isEmptyValue(value) ? \"\" : String(value)).toLowerCase();\n switch (mode) {\n case \"exact\":\n return candidate === text;\n case \"contains\":\n return candidate.includes(text);\n case \"startsWith\":\n return candidate.startsWith(text);\n case \"endsWith\":\n return candidate.endsWith(text);\n }\n };\n}\n\n/**\n * Whether `target` (a `ValueFilterEntry`'s value) equals `value` under\n * `type` — `false` whenever `type` doesn't agree with `target`'s own kind,\n * so a number filter never silently matches a string column.\n */\nfunction matchesTypedValue(\n value: unknown,\n target: number | boolean | Date,\n type: ColumnType | undefined,\n): boolean {\n if (typeof target === \"number\") {\n if (\n type !== \"number\" &&\n type !== \"decimal\" &&\n type !== \"currency\" &&\n type !== \"percent\"\n ) {\n return false;\n }\n return typeof value === \"number\" && value === target;\n }\n if (typeof target === \"boolean\") {\n if (type !== \"boolean\") {\n return false;\n }\n return typeof value === \"boolean\" && value === target;\n }\n if (type !== \"date\" && type !== \"dateTime\" && type !== \"time\") {\n return false;\n }\n return value instanceof Date && value.getTime() === target.getTime();\n}\n\n/**\n * Whether a non-group entry names a column present in `byId` (or names\n * none at all) — lets a stored filter tolerate a column removed from the\n * definition the same way a stored `ColumnSortState` does, by dropping only\n * the entries that reference it.\n *\n * A `GroupFilterEntry` is always usable, regardless of its own contents:\n * its vacuous truth value under an empty or fully-unusable `entries` list\n * depends on its own `combinator` (`\"and\"` vacuously matches everything,\n * `\"or\"` vacuously matches nothing) — a group can't be dropped from its\n * parent's list the way an unusable simple entry can, since whether\n * dropping it would be safe depends on the *parent's* combinator too,\n * which this check has no way to know. Compiling it and letting `.every()`/\n * `.some()` resolve the vacuous case naturally is what stays correct in\n * every context; deciding upfront here is not.\n */\nfunction isEntryUsable<Row>(\n entry: FilterEntry<Row>,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n): boolean {\n if (\"combinator\" in entry) {\n return true;\n }\n return entry.columnId === undefined || byId.has(entry.columnId);\n}\n\n/**\n * One compiled test per usable `FilterEntry`, closing over its column\n * lookup so `filterRows`'s row loop is just `.every(test)`.\n */\nfunction compileFilterEntry<Row>(\n entry: FilterEntry<Row>,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n columns: readonly ResolvedColumn<Row, unknown>[],\n): (row: ResolvedRow<Row>) => boolean {\n if (\"combinator\" in entry) {\n const tests = entry.entries\n .filter((nested) => isEntryUsable(nested, byId))\n .map((nested) => compileFilterEntry(nested, byId, columns));\n return entry.combinator === \"and\"\n ? (row) => tests.every((test) => test(row))\n : (row) => tests.some((test) => test(row));\n }\n\n if (\"predicate\" in entry) {\n const { columnId, predicate } = entry;\n const column = columnId === undefined ? undefined : byId.get(columnId);\n return (row) =>\n predicate(\n column === undefined ? undefined : accessDotted(row.row, column.field),\n row.row,\n );\n }\n\n if (\"value\" in entry) {\n const { columnId, value } = entry;\n if (columnId !== undefined) {\n const column = byId.get(columnId);\n if (column === undefined) {\n return () => false;\n }\n return (row) =>\n matchesTypedValue(\n accessDotted(row.row, column.field),\n value,\n column.type,\n );\n }\n return (row) =>\n columns.some((entry) =>\n matchesTypedValue(\n accessDotted(row.row, entry.column.field),\n value,\n entry.column.type,\n ),\n );\n }\n\n const { columnId, query } = entry;\n const test = compileFilterQuery(query);\n if (columnId !== undefined) {\n const column = byId.get(columnId);\n if (column === undefined) {\n return () => false;\n }\n return (row) => test(accessDotted(row.row, column.field));\n }\n return (row) =>\n columns.some((entry) => test(accessDotted(row.row, entry.column.field)));\n}\n\n/**\n * Whether `value`, stringified, matches `query`'s SQL LIKE-style pattern —\n * case-insensitive always. A bare query is an exact match; `%text%` is\n * contains; `text%` is starts-with; `%text` is ends-with. `null`/`undefined`\n * stringify to `\"\"`.\n *\n * A one-shot convenience: parses `query` fresh on every call. `filterRows`\n * does not call this per cell — it compiles each `TextFilterEntry` once,\n * outside its row loop.\n */\nexport function matchesQuery(value: unknown, query: string): boolean {\n return compileFilterQuery(query)(value);\n}\n\n/**\n * This column's current text query, or the global entry's when `columnId`\n * is omitted; `null` if no `TextFilterEntry` names it — including when the\n * entry that exists for that key is a `ValueFilterEntry`/\n * `PredicateFilterEntry`/`GroupFilterEntry` instead, since none of those\n * hold a query string to report.\n */\nexport function filterQueryFor<Row>(\n filter: FilterState<Row>,\n columnId?: FieldPath<Row> | (string & {}),\n): string | null {\n const entry = filter.find(\n (candidate): candidate is TextFilterEntry<Row> =>\n \"query\" in candidate && candidate.columnId === columnId,\n );\n return entry?.query ?? null;\n}\n\n/**\n * The filter with the `TextFilterEntry` for `columnId` (or the global\n * entry, when `columnId` is omitted) set to `query` — replacing whatever\n * entry already holds that key, of any variant, if present; appending a new\n * `TextFilterEntry` if not. An empty `query` removes the entry instead of\n * storing a filter that can never usefully match.\n *\n * Returns `filter` itself, unchanged, when the result would be a no-op: an\n * empty `query` naming a key with no existing entry, or a `query` equal to\n * an existing `TextFilterEntry`'s.\n */\nexport function setColumnFilter<Row>(\n filter: FilterState<Row>,\n columnId: (FieldPath<Row> | (string & {})) | undefined,\n query: string,\n): FilterState<Row> {\n const index = filter.findIndex(\n (entry) => !(\"combinator\" in entry) && entry.columnId === columnId,\n );\n\n if (query === \"\") {\n return index === -1 ? filter : filter.filter((_entry, i) => i !== index);\n }\n\n const next: TextFilterEntry<Row> =\n columnId === undefined ? { query } : { columnId, query };\n\n if (index === -1) {\n return [...filter, next];\n }\n const existing = filter[index];\n if (\n existing !== undefined &&\n \"query\" in existing &&\n existing.query === query\n ) {\n return filter;\n }\n return filter.map((entry, i) => (i === index ? next : entry));\n}\n\n/** `filter` reduced to empty. Returns `filter` itself when already empty. */\nexport function clearAllFilters<Row>(\n filter: FilterState<Row>,\n): FilterState<Row> {\n return filter.length === 0 ? filter : [];\n}\n\n/**\n * `rows` reduced to those matching every entry in `filter` (AND at the top\n * level — nest a `GroupFilterEntry` for OR). `rowIndex` is renumbered to\n * match the retained positions — the same invariant `sortRows` keeps,\n * needed here independently since `filterRows` runs before `sortRows` in\n * the composed pipeline (see `resolveShownRows`).\n *\n * Order-preserving: surviving rows keep their relative order, which is what\n * makes running this before a sort produce the identical final order a\n * sort-then-filter would — only the cost differs.\n *\n * Every entry is compiled once, before the row loop.\n *\n * Returns `rows` itself, untouched, when `filter` is empty or names only\n * columns absent from `columns` — a stored filter tolerates a column\n * removed from the definition the same way a stored `ColumnSortState` does.\n */\nexport function filterRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n filter: FilterState<Row>,\n columns: readonly ResolvedColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n if (filter.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = filter.filter((entry) => isEntryUsable(entry, byId));\n if (active.length === 0) {\n return rows;\n }\n\n const compiled = active.map((entry) =>\n compileFilterEntry(entry, byId, columns),\n );\n const filtered = rows.filter((row) => compiled.every((test) => test(row)));\n\n return filtered.map((row, index) =>\n row.rowIndex === index ? row : { ...row, rowIndex: index },\n );\n}\n","import type {\n ColumnDefinition,\n DisplayRow,\n GroupByEntry,\n GroupByState,\n GroupExpansionState,\n ResolvedColumn,\n ResolvedGroupRow,\n ResolvedRow,\n SortDirection,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { compareValues } from \"./sorting\";\n\n/**\n * This group's id, from its path. Every group-id producer/consumer in this\n * package goes through this — never join `path` by hand elsewhere.\n *\n * `JSON.stringify` rather than a delimiter join: a delimiter would have to be\n * escaped in every segment to stay collision-free against a value that\n * legitimately contains it, and `JSON.stringify` already draws that\n * boundary between array entries for free.\n */\nexport function groupRowId(path: readonly unknown[]): string {\n return JSON.stringify(path);\n}\n\ninterface ValueGroup<Row> {\n value: unknown;\n rows: ResolvedRow<Row>[];\n}\n\n/**\n * A key `accessDotted`'s result can be bucketed by, distinguishing values\n * that `compareValues`/`===` would treat as equal-but-not-identical (two\n * `Date` instances for the same instant) while keeping values of different\n * types apart (the number `1` and the string `\"1\"`).\n *\n * Exported for `aggregation.ts`, which needs the identical notion of\n * \"same value\" to match a leaf row back against a group header's `path` —\n * two producers of the same key would drift apart silently otherwise.\n */\nexport function bucketKey(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\\0empty\";\n }\n if (value instanceof Date) {\n return `\\0date:${String(value.getTime())}`;\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return `\\0${typeof value}:${String(value)}`;\n case \"function\":\n return \"\\0function\";\n default:\n // Arrays, and anything else `accessDotted` could return.\n return `\\0object:${JSON.stringify(value)}`;\n }\n}\n\n/**\n * `rows` bucketed by `column`'s value, one bucket per distinct value in\n * first-seen order, then ordered by `direction` via `compareValues` — the\n * same comparator `sortRows` uses, so a grouped column and a sorted column\n * order their values identically.\n */\nfunction partitionByValue<Row>(\n rows: readonly ResolvedRow<Row>[],\n column: ColumnDefinition<Row, unknown>,\n direction: SortDirection,\n): readonly ValueGroup<Row>[] {\n const buckets = new Map<string, ValueGroup<Row>>();\n for (const row of rows) {\n const value = accessDotted(row.row, column.field);\n const key = bucketKey(value);\n const bucket = buckets.get(key);\n if (bucket === undefined) {\n buckets.set(key, { value, rows: [row] });\n } else {\n bucket.rows.push(row);\n }\n }\n\n const groups = [...buckets.values()];\n groups.sort((a, b) => {\n const result = compareValues(a.value, b.value, column.type);\n return direction === \"asc\" ? result : -result;\n });\n return groups;\n}\n\n/**\n * Depth-first builder behind `groupRows`: partitions `rows` by `levels[0]`,\n * appends a header per resulting group, and recurses into `levels.slice(1)`\n * for each — unless that group is collapsed, in which case only its header\n * is appended. `rows` with no levels left (either `levels` started empty, or\n * recursion exhausted it) are appended as plain data rows, keeping the\n * relative order filter/sort already gave them.\n */\nfunction buildLevel<Row>(\n rows: readonly ResolvedRow<Row>[],\n levels: readonly GroupByEntry[],\n parentPath: readonly unknown[],\n expansion: GroupExpansionState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n out: DisplayRow<Row>[],\n): void {\n const level = levels[0];\n if (level === undefined) {\n out.push(...rows);\n return;\n }\n\n // `levels` is pre-filtered to entries naming a column present in `byId`\n // (see `groupRows`), so this is always found.\n const column = byId.get(level.columnId);\n if (column === undefined) {\n out.push(...rows);\n return;\n }\n\n const rest = levels.slice(1);\n const groups = partitionByValue(rows, column, level.direction ?? \"asc\");\n\n for (const group of groups) {\n const path = [...parentPath, group.value];\n const groupId = groupRowId(path);\n const expanded = !expansion.includes(groupId);\n const header: ResolvedGroupRow = {\n kind: \"group\",\n groupId,\n level: parentPath.length,\n columnId: level.columnId,\n value: group.value,\n path,\n expanded,\n count: group.rows.length,\n // Renumbered globally once `groupRows` has the whole flattened array —\n // a header has no row of its own to carry a dataset position, so\n // `datasetIndex` takes the same renumbered value `rowIndex` does.\n rowIndex: -1,\n datasetIndex: -1,\n // Set by `withGroupAggregates`, downstream of grouping — empty here\n // since `groupRows` itself never knows about `AggregateState`.\n aggregates: new Map(),\n };\n out.push(header);\n if (expanded) {\n buildLevel(group.rows, rest, path, expansion, byId, out);\n }\n }\n}\n\n/**\n * `rows`, regrouped into `groupBy`'s stacked levels — a group header per\n * distinct value at each level, ordered by `compareValues` per that level's\n * own `direction`, followed depth-first by its nested groups and/or data\n * rows. A collapsed group (its `groupId` present in `expansion`) contributes\n * only its own header, nothing beneath it — but its `count` still reports\n * the group's full leaf-row count either way.\n *\n * Filter and sort are expected to have already run (see `resolveShownRows`):\n * this only reshapes their output, and never changes which rows appear or\n * their relative order within a group.\n *\n * `rowIndex` is renumbered across the whole flattened output, header rows\n * included — the same invariant `sortRows`/`filterRows` keep for\n * `ResolvedRow.rowIndex`, extended to `ResolvedGroupRow.rowIndex` since\n * `GridBody` addresses both kinds by the same flat position.\n *\n * Returns `rows` itself, untouched, when `groupBy` is empty or names only\n * columns absent from `columns` — a stored grouping tolerates a column\n * removed from the definition the same way a stored `ColumnSortState` does.\n */\nexport function groupRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n expansion: GroupExpansionState,\n columns: readonly ResolvedColumn<Row, unknown>[],\n): readonly DisplayRow<Row>[] {\n if (groupBy.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = groupBy.filter((entry) => byId.has(entry.columnId));\n if (active.length === 0) {\n return rows;\n }\n\n const out: DisplayRow<Row>[] = [];\n buildLevel(rows, active, [], expansion, byId, out);\n\n return out.map((entry, index) => {\n if (\"kind\" in entry) {\n return entry.rowIndex === index && entry.datasetIndex === index\n ? entry\n : { ...entry, rowIndex: index, datasetIndex: index };\n }\n return entry.rowIndex === index ? entry : { ...entry, rowIndex: index };\n });\n}\n\n/**\n * The expansion with `groupId` collapsed if it was expanded, or expanded if\n * it was collapsed.\n */\nexport function toggleGroupExpansion(\n expansion: GroupExpansionState,\n groupId: string,\n): GroupExpansionState {\n return expansion.includes(groupId)\n ? expansion.filter((id) => id !== groupId)\n : [...expansion, groupId];\n}\n\n/** `expansion` reduced to empty — every group expanded. Mirrors `clearAllFilters`. */\nexport function expandAllGroups(\n expansion: GroupExpansionState,\n): GroupExpansionState {\n return expansion.length === 0 ? expansion : [];\n}\n\n/**\n * Every group id present in `rows` — for collapsing every group currently\n * shown in one call. Operates on the already-grouped display, not the raw\n * grouping, so a group hidden beneath an already-collapsed ancestor (and so\n * absent from `rows`) keeps whatever expansion it already had rather than\n * being forced closed too; expanding that ancestor again reveals it exactly\n * as it was left.\n */\nexport function collapseAllGroups<Row>(\n rows: readonly DisplayRow<Row>[],\n): GroupExpansionState {\n return rows\n .filter((entry): entry is ResolvedGroupRow => \"kind\" in entry)\n .map((entry) => entry.groupId);\n}\n\n/**\n * `groupBy` with `columnId` positioned in front of `beforeColumnId` — or at\n * the end when that is `null` — inserting a fresh entry if `columnId` isn't\n * already part of the stack, or lifting its existing entry out and back in\n * if it is. The one function both a header dropped on the group-by bar and\n * a chip dragged within it need: the former's `columnId` is usually new to\n * the stack, the latter's never is, and this doesn't need to be told which.\n *\n * An existing entry keeps its own object (and so its own `direction`)\n * rather than being rebuilt, so a level merely repositioned stays\n * reference-equal at its new index — the same reason `moveColumnBefore`\n * moves ids rather than rebuilding them.\n *\n * Returns `groupBy` itself, untouched, when the move changes nothing: a\n * drop on the entry's own id, or back into the gap it already occupies, or\n * naming a `beforeColumnId` absent from the stack. Inserting a column not\n * yet in the stack is never a no-op.\n */\nexport function moveGroupByBefore(\n groupBy: GroupByState,\n columnId: string,\n beforeColumnId: string | null,\n): GroupByState {\n if (columnId === beforeColumnId) {\n return groupBy;\n }\n\n const without = groupBy.filter((entry) => entry.columnId !== columnId);\n const moved = groupBy.find((entry) => entry.columnId === columnId) ?? {\n columnId,\n };\n const target =\n beforeColumnId === null\n ? without.length\n : without.findIndex((entry) => entry.columnId === beforeColumnId);\n if (target === -1) {\n return groupBy;\n }\n\n const next = [...without];\n next.splice(target, 0, moved);\n return next.length === groupBy.length &&\n next.every((entry, index) => entry === groupBy[index])\n ? groupBy\n : next;\n}\n\n/**\n * Whether moving `columnId` in front of `beforeColumnId` would change\n * `groupBy` at all, so that a drop indicator promises exactly the move that\n * happens. Defined against `moveGroupByBefore` rather than restating its\n * conditions, the same relationship `movesColumn` keeps with\n * `moveColumnBefore`.\n */\nexport function movesGroupBy(\n groupBy: GroupByState,\n columnId: string,\n beforeColumnId: string | null,\n): boolean {\n return moveGroupByBefore(groupBy, columnId, beforeColumnId) !== groupBy;\n}\n","import type {\n ColumnSortState,\n FilterState,\n ResolvedColumn,\n ResolvedRow,\n SelectedCell,\n SelectedCellRef,\n SelectedColumn,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { filterRows } from \"./filtering\";\nimport { sortRows } from \"./sorting\";\n\n/**\n * `rows`, filtered then sorted — the one function `DataGrid.tsx` (and any\n * future framework binding) calls instead of composing `filterRows`/\n * `sortRows` itself.\n *\n * Filter always runs first: an O(n) pass that shrinks what the O(n log n)\n * sort has to touch whenever a filter is active, free when it isn't. This\n * is a performance choice, not a correctness one — filtering is an\n * order-preserving predicate and sort is a stable total order over whatever\n * it's handed, so the final order is identical either way.\n */\nexport function resolveShownRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n filter: FilterState<Row>,\n sort: ColumnSortState,\n columns: readonly ResolvedColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n return sortRows(filterRows(rows, filter, columns), sort, columns);\n}\n\n/**\n * `ids` resolved back to the rows behind them, keyed by `rowsById`.\n *\n * An id with no row behind it is dropped rather than left `undefined`: a\n * selection outlives a change to the data, so that filtering a row out and\n * back leaves it selected, and only what still exists can be handed to a\n * callback.\n */\nexport function resolveRows<Row>(\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n ids: readonly string[],\n): readonly ResolvedRow<Row>[] {\n return ids.map((id) => rowsById.get(id)).filter((row) => row !== undefined);\n}\n\n/**\n * `ids` resolved back to the columns behind them, paired with the position\n * each holds in `columns` — a stale id is dropped, matching `resolveRows`.\n */\nexport function resolveColumns<Row, Node>(\n columns: readonly ResolvedColumn<Row, Node>[],\n ids: readonly string[],\n): readonly SelectedColumn<Row, Node>[] {\n return ids\n .map((id) => {\n const columnIndex = columns.findIndex((entry) => entry.id === id);\n const column = columns[columnIndex];\n return column === undefined\n ? undefined\n : { columnId: id, column, columnIndex };\n })\n .filter((column) => column !== undefined);\n}\n\n/**\n * `cell` resolved down to the row, column and value it addresses — `null`\n * when there is no cell, or when either half of it names a row or column\n * that no longer exists.\n */\nexport function resolveCell<Row, Node>(\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n columns: readonly ResolvedColumn<Row, Node>[],\n cell: SelectedCellRef | null,\n): SelectedCell<Row, Node> | null {\n if (cell === null) {\n return null;\n }\n const entry = rowsById.get(cell.rowId);\n const columnIndex = columns.findIndex(\n (candidate) => candidate.id === cell.columnId,\n );\n const column = columns[columnIndex];\n if (entry === undefined || column === undefined) {\n return null;\n }\n return {\n rowId: cell.rowId,\n columnId: cell.columnId,\n row: entry.row,\n column,\n rowIndex: entry.rowIndex,\n columnIndex,\n value: accessDotted(entry.row, column.column.field),\n };\n}\n","import type { DisplayRow, PaginationState } from \"../types\";\n\nexport interface PaginatedRows<Row> {\n readonly rows: readonly DisplayRow<Row>[];\n readonly pageCount: number;\n /**\n * `pagination.pageIndex` clamped into `[0, pageCount - 1]` (or `0` when\n * `pageCount` is `0`) — read this back rather than trusting the input\n * verbatim, the same way `sortRows`/`filterRows` tolerate a stale stored\n * state.\n */\n readonly pageIndex: number;\n}\n\n/** A contiguous run of `rows` that pagination treats as one unit — a top-level group's header plus every entry beneath it, or a single bare data row. */\ninterface Unit {\n readonly start: number;\n readonly end: number; // exclusive\n}\n\n/**\n * `rows` split into pagination units: a top-level (`level === 0`) group\n * header together with every entry up to (not including) the next unit\n * boundary, or a single bare data row of its own. A nested group (`level >\n * 0`) and the data rows beneath it contribute no boundary — they're carried\n * along inside their top-level ancestor's span, which is what keeps a page\n * from ever splitting a group. A bare data row *outside* any top-level\n * group's span starts (and immediately ends) its own unit, which is what\n * makes an entirely ungrouped `rows` produce one unit per row rather than\n * collapsing into a single unit for the whole array.\n *\n * A `\"group-summary\"` row (`groupAggregateDisplay: \"row\"`) never opens a\n * boundary of its own, at any level — including a top-level one, despite\n * carrying that same `level: 0` a top-level header does. It always belongs\n * to the unit its own group already opened, the same way a nested header\n * and the data rows beneath it do.\n *\n * `openedByGroup` tracks whether the unit currently being built started at a\n * top-level header (in which case everything until the next one, headers and\n * bare rows alike, belongs to it) or at a bare row (in which case it holds\n * exactly that one row).\n */\nfunction unitsOf<Row>(rows: readonly DisplayRow<Row>[]): readonly Unit[] {\n const units: Unit[] = [];\n let start = 0;\n let openedByGroup = false;\n for (let index = 0; index < rows.length; index++) {\n const entry = rows[index];\n if (entry === undefined) {\n continue;\n }\n const isTopLevelHeader =\n \"kind\" in entry && entry.kind === \"group\" && entry.level === 0;\n const isBoundary = index !== start && (isTopLevelHeader || !openedByGroup);\n if (isBoundary) {\n units.push({ start, end: index });\n start = index;\n openedByGroup = isTopLevelHeader;\n } else if (index === start) {\n openedByGroup = isTopLevelHeader;\n }\n }\n if (start < rows.length) {\n units.push({ start, end: rows.length });\n }\n return units;\n}\n\n/**\n * `rows` sliced into pages of `pagination.pageSize` units — see `unitsOf`\n * for what a unit is. `pageIndex` is clamped into range, `pageSize <= 0` is\n * clamped to `1` (this codebase's general tolerance for stale/odd stored\n * state, matching `sortRows`/`filterRows`), and the returned page's\n * `rowIndex` is renumbered to be page-relative — 0-based from the top of the\n * page, header rows included, mirroring `groupRows`'s own renumbering\n * invariant. `datasetIndex` is left untouched: it is assigned once, ahead of\n * filter/sort/group/paginate, and reports each row's position in the whole\n * dataset regardless of which page is showing.\n */\nexport function paginateRows<Row>(\n rows: readonly DisplayRow<Row>[],\n pagination: PaginationState,\n): PaginatedRows<Row> {\n const pageSize = Math.max(1, pagination.pageSize);\n const units = unitsOf(rows);\n const pageCount = Math.ceil(units.length / pageSize);\n\n if (pageCount === 0) {\n return { rows: [], pageCount: 0, pageIndex: 0 };\n }\n\n const pageIndex = Math.min(Math.max(pagination.pageIndex, 0), pageCount - 1);\n const firstUnit = units[pageIndex * pageSize];\n const lastUnit =\n units[Math.min(pageIndex * pageSize + pageSize, units.length) - 1];\n if (firstUnit === undefined || lastUnit === undefined) {\n return { rows: [], pageCount, pageIndex };\n }\n\n const page = rows.slice(firstUnit.start, lastUnit.end);\n const renumbered = page.map((entry, index) =>\n entry.rowIndex === index ? entry : { ...entry, rowIndex: index },\n );\n\n return { rows: renumbered, pageCount, pageIndex };\n}\n","export type PaginationWindowEntry = number | \"ellipsis\";\n\n/**\n * Which page numbers a numbered pager should show for `currentPage` of\n * `pageCount`, collapsing any gap wider than one page into a single\n * `\"ellipsis\"` entry — the boundary + sibling windowing MUI's\n * `usePagination` and antd's `Pagination` both use. Always includes the\n * first/last `boundaryCount` pages and `currentPage`'s `siblingCount`\n * neighbors on each side; a gap of exactly one page is filled in rather than\n * collapsed, since an ellipsis standing in for a single page saves no space.\n */\nexport function paginationWindow(\n currentPage: number,\n pageCount: number,\n options?: {\n boundaryCount?: number | undefined;\n siblingCount?: number | undefined;\n },\n): readonly PaginationWindowEntry[] {\n if (pageCount <= 0) {\n return [];\n }\n\n const boundaryCount = Math.max(0, options?.boundaryCount ?? 1);\n const siblingCount = Math.max(0, options?.siblingCount ?? 1);\n const current = Math.min(Math.max(currentPage, 1), pageCount);\n\n const pages = new Set<number>();\n for (let page = 1; page <= Math.min(boundaryCount, pageCount); page++) {\n pages.add(page);\n }\n for (\n let page = Math.max(pageCount - boundaryCount + 1, 1);\n page <= pageCount;\n page++\n ) {\n pages.add(page);\n }\n for (\n let page = Math.max(current - siblingCount, 1);\n page <= Math.min(current + siblingCount, pageCount);\n page++\n ) {\n pages.add(page);\n }\n\n const sorted = Array.from(pages).sort((a, b) => a - b);\n const entries: PaginationWindowEntry[] = [];\n let previous: number | undefined;\n for (const page of sorted) {\n if (previous !== undefined) {\n if (page - previous === 2) {\n entries.push(previous + 1);\n } else if (page - previous > 2) {\n entries.push(\"ellipsis\");\n }\n }\n entries.push(page);\n previous = page;\n }\n\n return entries;\n}\n","import type {\n AggregateResults,\n AggregateSpec,\n AggregateState,\n BuiltInAggregate,\n ColumnDefinition,\n DisplayRow,\n GroupAggregateDisplay,\n GroupByState,\n ResolvedColumn,\n ResolvedGroupRow,\n ResolvedGroupSummaryRow,\n ResolvedRow,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { bucketKey } from \"./grouping\";\nimport { compareValues } from \"./sorting\";\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/** A value's numeric reading for `sum`/`avg` — `NaN` is treated as absent, same as an empty value. */\nfunction toNumber(value: unknown): number {\n return Number(value);\n}\n\n/**\n * A key distinguishing `countDistinct`'s buckets — reuses `bucketKey`'s\n * approach in `grouping.ts` (distinct values bucketed by kind and content,\n * two `Date`s for the same instant collapsing together) rather than a\n * second implementation of the same idea.\n */\nfunction distinctKey(value: unknown): string {\n if (isEmpty(value)) {\n return \"\\0empty\";\n }\n if (value instanceof Date) {\n return `\\0date:${String(value.getTime())}`;\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return `\\0${typeof value}:${String(value)}`;\n case \"function\":\n return \"\\0function\";\n default:\n return `\\0object:${JSON.stringify(value)}`;\n }\n}\n\n/**\n * One built-in reducer over the raw values read off `rows` at `column`'s\n * field. `min`/`max` compare via `compareValues` so a `date`/`dateTime`\n * column orders chronologically rather than numerically; `sum`/`avg`\n * coerce numerically regardless of `column.type`, matching how a\n * `currency`/`decimal`/`percent`/`number` column is expected to be used.\n *\n * Null/undefined handling: `min`/`max` ignore empty entries entirely rather\n * than letting them win by `compareValues`'s own \"empty sorts last\"\n * convention — an aggregate that returned `undefined` merely because every\n * value happened to be null would be a worse answer than skipping them.\n * `count` counts every row in scope regardless of whether its value at this\n * column is empty (it answers \"how many rows\", not \"how many non-null\n * values\") — `countDistinct` excludes empty values from its distinct set,\n * since \"blank\" is not a value to count as one of the distinct ones.\n */\nfunction reduceBuiltIn<Row>(\n rows: readonly Row[],\n fn: BuiltInAggregate,\n column: ResolvedColumn<Row, unknown> | undefined,\n): unknown {\n if (fn === \"count\") {\n return rows.length;\n }\n\n const field = column?.column.field;\n const values =\n field === undefined ? [] : rows.map((row) => accessDotted(row, field));\n\n switch (fn) {\n case \"sum\": {\n let total = 0;\n for (const value of values) {\n if (isEmpty(value)) continue;\n total += toNumber(value);\n }\n return total;\n }\n case \"avg\": {\n const present = values.filter((value) => !isEmpty(value));\n if (present.length === 0) return undefined;\n const total = present.reduce(\n (acc: number, value) => acc + toNumber(value),\n 0,\n );\n return total / present.length;\n }\n case \"min\":\n case \"max\": {\n const type = column?.column.type;\n let result: unknown;\n for (const value of values) {\n if (isEmpty(value)) continue;\n if (result === undefined) {\n result = value;\n continue;\n }\n const comparison = compareValues(value, result, type);\n if (fn === \"min\" ? comparison < 0 : comparison > 0) {\n result = value;\n }\n }\n return result;\n }\n case \"countDistinct\": {\n const seen = new Set<string>();\n for (const value of values) {\n if (isEmpty(value)) continue;\n seen.add(distinctKey(value));\n }\n return seen.size;\n }\n }\n}\n\n/** This spec's result key — `id` when given, `columnId` otherwise. */\nfunction keyOf<Row>(spec: AggregateSpec<Row>): string {\n return spec.id ?? spec.columnId;\n}\n\n/**\n * `rows` reduced through every spec in `specs`, keyed by `spec.id ??\n * spec.columnId`. A custom `fn` (a plain function, not a `BuiltInAggregate`\n * name) is called once with the raw `rows` — no wrapping, no\n * pre-processing, so it sees exactly the same leaf set a built-in reducer\n * does.\n *\n * Two specs resolving to the same key: the later one wins, matching\n * `setColumnFilter`'s own silent-replace precedent for a key collision\n * rather than throwing.\n *\n * Returns a fresh empty `Map` for empty `rows` or empty `specs` — never a\n * shared singleton — matching this codebase's general avoidance of shared\n * mutable module state.\n */\nexport function computeAggregates<Row>(\n rows: readonly Row[],\n specs: AggregateState<Row>,\n columns: readonly ResolvedColumn<Row, unknown>[],\n): AggregateResults {\n const results = new Map<string, unknown>();\n if (specs.length === 0) {\n return results;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry]));\n for (const spec of specs) {\n const value =\n typeof spec.fn === \"function\"\n ? spec.fn(rows)\n : reduceBuiltIn(rows, spec.fn, byId.get(spec.columnId));\n results.set(keyOf(spec), value);\n }\n return results;\n}\n\n/**\n * A group header's full leaf-row descendant set, found by re-filtering\n * `flatRows` (the same pre-group, filtered/sorted rows `groupRows` itself\n * partitioned) against `header.path` — each ancestor level's value matched\n * via `bucketKey`, the identical notion of \"same value\" `groupRows` uses to\n * bucket in the first place.\n *\n * Deliberately independent of `displayRows`' own flattened shape: a\n * collapsed group's descendants are never emitted into `displayRows` at\n * all (see `buildLevel`'s `if (expanded)` guard), so a header's subtotal\n * has to be recomputed from the original row list rather than walked out\n * of the grouped-and-collapsed output — the only way a collapsed group's\n * header still gets a correct count regardless of its own collapse state.\n */\nfunction leafDescendantsOf<Row>(\n flatRows: readonly ResolvedRow<Row>[],\n path: readonly unknown[],\n groupBy: GroupByState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n): Row[] {\n const keys = path.map((value) => bucketKey(value));\n return flatRows\n .filter((row) =>\n keys.every((key, level) => {\n const columnId = groupBy[level]?.columnId;\n const column = columnId === undefined ? undefined : byId.get(columnId);\n if (column === undefined) return false;\n return bucketKey(accessDotted(row.row, column.field)) === key;\n }),\n )\n .map((row) => row.row);\n}\n\n/**\n * `displayRows` (already regrouped by `groupBy`, per `groupRows`) with\n * every group header's `aggregates` field set to `specs` computed over\n * that group's full leaf-row descendants, re-derived from `flatRows` (the\n * same pre-group rows `groupRows` was given) — regardless of the group's\n * own collapse state, since a collapsed group's header still needs a\n * correct subtotal and its descendants are otherwise absent from\n * `displayRows` entirely. Each level's `aggregates` comes from its own\n * full descendant set, computed independently rather than combined from\n * its children's already-computed results, so a non-associative custom\n * aggregate (median, distinct count) is never silently wrong at a nested\n * level.\n *\n * `display: \"row\"` additionally emits a `ResolvedGroupSummaryRow` right\n * after each group's last visible entry (its last nested group/data row,\n * or immediately after its own header when collapsed) — every level gets\n * its own, the same way every level already gets its own `aggregates`.\n * `display: \"inline\"` (the default) emits none; a header's `aggregates`\n * field is populated either way, since `GridGroupRow`'s own inline\n * rendering and a summary row both read from it.\n *\n * `rowIndex`/`datasetIndex` are renumbered across the whole output when a\n * row was inserted, the same invariant `groupRows` itself keeps.\n *\n * Returns `displayRows` itself, untouched, when `specs` is empty — the\n * same reference-equality no-op every other transform across\n * grouping/pagination uses.\n */\n/**\n * One pass over a contiguous run of `displayRows` sharing one parent — the\n * top-level call covers the whole array, and each group header found along\n * the way recurses into its own span (every entry up to the next one at\n * its level or shallower) the same way, so a group at any nesting depth\n * gets its own `aggregates` computed and, under `display: \"row\"`, its own\n * summary row appended right after everything beneath it.\n *\n * Returns the index just past the run this call consumed, so the caller\n * (itself, one level up, or `withGroupAggregates`) knows where to resume.\n */\nfunction appendAggregatedSpan<Row>(\n displayRows: readonly DisplayRow<Row>[],\n start: number,\n levelFloor: number | null,\n flatRows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n specs: AggregateState<Row>,\n columns: readonly ResolvedColumn<Row, unknown>[],\n display: GroupAggregateDisplay,\n out: DisplayRow<Row>[],\n): number {\n let index = start;\n while (index < displayRows.length) {\n const entry = displayRows[index];\n if (entry === undefined) {\n index++;\n continue;\n }\n if (\n levelFloor !== null &&\n \"kind\" in entry &&\n entry.kind === \"group\" &&\n entry.level <= levelFloor\n ) {\n // The next entry at this level or shallower ends the current span —\n // handled by the caller's own iteration, not this one.\n break;\n }\n index++;\n if (!(\"kind\" in entry) || entry.kind !== \"group\") {\n out.push(entry);\n continue;\n }\n\n const leaves = leafDescendantsOf(flatRows, entry.path, groupBy, byId);\n const aggregates = computeAggregates(leaves, specs, columns);\n const withAggregates: ResolvedGroupRow = { ...entry, aggregates };\n out.push(withAggregates);\n\n index = appendAggregatedSpan(\n displayRows,\n index,\n entry.level,\n flatRows,\n groupBy,\n byId,\n specs,\n columns,\n display,\n out,\n );\n\n if (display === \"row\") {\n const summary: ResolvedGroupSummaryRow = {\n kind: \"group-summary\",\n groupId: entry.groupId,\n level: entry.level,\n rowIndex: -1,\n datasetIndex: -1,\n aggregates,\n };\n out.push(summary);\n }\n }\n return index;\n}\n\nexport function withGroupAggregates<Row>(\n displayRows: readonly DisplayRow<Row>[],\n flatRows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n specs: AggregateState<Row>,\n columns: readonly ResolvedColumn<Row, unknown>[],\n display: GroupAggregateDisplay = \"inline\",\n): readonly DisplayRow<Row>[] {\n if (specs.length === 0) {\n return displayRows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const out: DisplayRow<Row>[] = [];\n appendAggregatedSpan(\n displayRows,\n 0,\n null,\n flatRows,\n groupBy,\n byId,\n specs,\n columns,\n display,\n out,\n );\n\n return out.map((entry, position) => {\n if (\"kind\" in entry) {\n return entry.rowIndex === position && entry.datasetIndex === position\n ? entry\n : { ...entry, rowIndex: position, datasetIndex: position };\n }\n return entry.rowIndex === position\n ? entry\n : { ...entry, rowIndex: position };\n });\n}\n","/**\n * One entry per row: its measured height once known, `undefined` until then.\n * A row never yet rendered (or rendered but not yet observed) falls back to\n * `visibleRange`'s own `estimatedHeight` argument.\n */\nexport type RowHeights = readonly (number | undefined)[];\n\nexport interface VisibleRange {\n readonly startIndex: number;\n readonly endIndex: number; // inclusive\n /** Total height of every row before `startIndex` — the leading spacer's height. */\n readonly offsetBefore: number;\n /** Total height of every row after `endIndex` — the trailing spacer's height. */\n readonly offsetAfter: number;\n}\n\n/**\n * Which rows of a dynamic-height, virtualized list fall within\n * `[scrollTop, scrollTop + viewportHeight)`, padded by `overscan` rows on\n * each side and clamped to the array's own bounds.\n *\n * Walks a cumulative-offset prefix sum built from `heights` (measured height\n * where known, `estimatedHeight` otherwise) rather than assuming a uniform\n * row height — this codebase's rows are not uniform (`.is-wrapped` cells,\n * group header/summary rows), so a fixed-height virtualizer would either\n * break wrapping or force it out of scope.\n *\n * `O(n)` in `heights.length`. Deliberately not a Fenwick tree or a\n * binary-searchable prefix-sum structure — that optimization belongs in the\n * mutable React-side cache that already owns mutability\n * (`useRowVirtualizer`), not in this pure function's contract, and is not\n * worth taking on until a profiled scenario actually shows it matters at\n * realistic row counts.\n */\nexport function visibleRange(\n heights: RowHeights,\n estimatedHeight: number,\n scrollTop: number,\n viewportHeight: number,\n overscan: number,\n): VisibleRange {\n const rowCount = heights.length;\n if (rowCount === 0) {\n return { startIndex: 0, endIndex: -1, offsetBefore: 0, offsetAfter: 0 };\n }\n\n function heightAt(index: number): number {\n return heights[index] ?? estimatedHeight;\n }\n\n const viewportBottom = scrollTop + viewportHeight;\n\n // The first row whose bottom edge crosses `scrollTop` — everything before\n // it is fully scrolled past. `top` tracks that row's own top edge (the\n // cumulative height of every row before it) as the walk advances. Stops at\n // the last row rather than walking off the end when `scrollTop` reaches or\n // exceeds the total height.\n let start = 0;\n let top = 0;\n while (start < rowCount - 1 && top + heightAt(start) <= scrollTop) {\n top += heightAt(start);\n start += 1;\n }\n const startTop = top;\n\n // From `start`, the last row whose top edge is still above `viewportBottom`\n // — the first row no longer even partially visible ends the walk one row\n // earlier than it, or the array itself runs out first. `bottom` tracks the\n // current row's own bottom edge.\n let end = start;\n let bottom = startTop + heightAt(start);\n while (end < rowCount - 1 && bottom < viewportBottom) {\n end += 1;\n bottom += heightAt(end);\n }\n\n const overscanStart = Math.max(0, start - overscan);\n const overscanEnd = Math.min(rowCount - 1, end + overscan);\n\n let offsetBefore = 0;\n for (let index = 0; index < overscanStart; index++) {\n offsetBefore += heightAt(index);\n }\n let offsetAfter = 0;\n for (let index = overscanEnd + 1; index < rowCount; index++) {\n offsetAfter += heightAt(index);\n }\n\n return {\n startIndex: overscanStart,\n endIndex: overscanEnd,\n offsetBefore,\n offsetAfter,\n };\n}\n"],"mappings":"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","names":["total","test","columnId","entry","isEmpty"]}
|
|
1
|
+
{"version":3,"sources":["../src/util/grid.ts","../src/util/sorting.ts","../src/util/grouping.ts","../src/util/memoize.ts","../src/util/ordering.ts","../src/util/paging.ts","../src/util/report.ts","../src/util/filterOperators.ts","../src/util/serialize.ts","../src/util/sizing.ts","../src/util/aggregation.ts","../src/util/filtering.ts","../src/util/rows.ts","../src/util/visibility.ts","../src/util/view.ts","../src/controller/changes.ts","../src/util/selection.ts","../src/controller/selectionEvents.ts","../src/controller/selectionActions.ts","../src/controller/createGridController.ts","../src/commands/context.ts","../src/commands/builtInCommands.ts","../src/commands/registry.ts","../src/menu/resolveMenu.ts","../src/menu/contextMenu.ts","../src/menu/navigation.ts","../src/toolbar/options.ts","../src/toolbar/resolveToolbar.ts","../src/toolbar/overflow.ts","../src/toolbar/search.ts","../src/util/navigation.ts","../src/util/paginationWindow.ts","../src/util/columnChooser.ts","../src/messages.ts","../src/util/format.ts","../src/util/filterEditor.ts","../src/util/virtualization.ts"],"sourcesContent":["import type { ColumnAlignment, ColumnDefinition, ColumnType } from \"../types\";\n\n/**\n * Narrows to a value worth drilling into. Mirrors the `LeafValue` union in\n * `../types`: arrays and `Date`s are cell values rather than groups of\n * columns, and `null` cannot be introspected. Keep the two in sync.\n */\nfunction isNested(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value instanceof Date)\n );\n}\n\nfunction getType(value: unknown): ColumnType {\n if (value instanceof Date) return \"dateTime\";\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (typeof value === \"bigint\") return \"number\";\n if (typeof value === \"symbol\") return \"string\";\n return \"string\";\n}\n\n/**\n * How a column of `type` aligns by default. Numeric types align right so that\n * their digits line up by place value; everything else reads from the left.\n */\nexport function alignmentForType(type: ColumnType): ColumnAlignment {\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return \"right\";\n default:\n return \"left\";\n }\n}\n\nfunction getAlignment(value: unknown): ColumnAlignment {\n return alignmentForType(getType(value));\n}\n\n/**\n * Derives one column per field across `rows`, in the order each field is first\n * seen — so a key that only appears in a later row still gets a column,\n * appended at the end. Nested objects contribute their non-object properties\n * as `\"Parent.Child\"`; anything deeper is skipped, as is the nested object\n * itself.\n *\n * Order follows `Object.entries`, which lists integer-like keys first\n * regardless of the order they were written in.\n *\n * `Node` is whatever the caller's renderer draws: an inferred column sets no\n * template, so it suits any.\n */\nexport function defineColumnsFromRows<Row, Node = string>(\n rows: readonly Row[],\n): readonly ColumnDefinition<Row, Node>[] {\n const columns: ColumnDefinition<Row, Node>[] = [];\n const seen = new Set<string>();\n\n function add(field: string, value: unknown): void {\n if (seen.has(field)) {\n return;\n }\n seen.add(field);\n columns.push({\n field,\n type: getType(value),\n alignment: getAlignment(value),\n });\n }\n\n for (const row of rows) {\n if (!isNested(row)) {\n continue;\n }\n for (const [key, value] of Object.entries(row)) {\n if (!isNested(value)) {\n add(key, value);\n continue;\n }\n for (const [nestedKey, nestedValue] of Object.entries(value)) {\n if (!isNested(nestedValue)) {\n add(`${key}.${nestedKey}`, nestedValue);\n }\n }\n }\n }\n\n return columns;\n}\n\n/**\n * The key state about a column is stored under, and the key it renders with.\n * Every such lookup goes through here so the two can never disagree.\n */\nexport function getColumnId<Row>(\n column: ColumnDefinition<Row, unknown>,\n): string {\n return column.id ?? column.field;\n}\n\n/**\n * The key state about a row is stored under, and the key it renders with — the\n * row's counterpart to `getColumnId`, and for the same reason: every such\n * lookup goes through here so no two can disagree.\n *\n * Falls back to the position so a grid given no `getRowId` still works. That\n * fallback ties a selection to where a row sits rather than to the row, so\n * anything that sorts, filters or pages its data has to supply one — otherwise\n * a re-sort leaves the same positions selected under different rows.\n */\nexport function resolveRowId<Row>(\n row: Row,\n index: number,\n getRowId?: (row: Row, index: number) => string,\n): string {\n return getRowId?.(row, index) ?? String(index);\n}\n\n/** A label read off the field path — `\"Application.Id\"` reading as `\"Application Id\"`. */\nfunction labelFromField(field: string): string {\n return field.split(\".\").join(\" \");\n}\n\n/**\n * What a column's header shows: its own `headerTemplate`, called first if it is\n * a function, or else its plain-text `header`, or else a label read off the\n * field path.\n */\nexport function resolveColumnLabel<Row, Node>(\n column: ColumnDefinition<Row, Node>,\n): Node | string {\n const { headerTemplate } = column;\n if (headerTemplate === undefined) {\n return column.header ?? labelFromField(column.field);\n }\n // `Node` is open, so it could itself be a function type and the `typeof`\n // check cannot narrow on its own. A header that is callable is the lazy\n // form by definition — no adapter binds `Node` to a function.\n return typeof headerTemplate === \"function\"\n ? (headerTemplate as () => Node)()\n : headerTemplate;\n}\n\n/**\n * A column's name as text, for wherever markup will not do — an\n * announcement, an export. Its `header` first, even beside a\n * `headerTemplate`, since a template's output need not be text; then the\n * label `resolveColumnLabel` gives, when that is a string; then the label\n * read off the field path.\n */\nexport function resolveColumnHeaderText<Row>(\n column: ColumnDefinition<Row, unknown>,\n): string {\n if (column.header !== undefined) {\n return column.header;\n }\n const label = resolveColumnLabel(column);\n return typeof label === \"string\" ? label : labelFromField(column.field);\n}\n\n/** Which of a column header's keyboard interactions to announce. */\nexport interface KeyShortcutCapabilities {\n reorderable: boolean;\n resizable: boolean;\n sortable: boolean;\n groupable: boolean;\n /** Whether the header opens the grid's context menu. Defaults to `false`. */\n contextMenu?: boolean | undefined;\n}\n\n/**\n * The `aria-keyshortcuts` string for a column header, naming only the keys\n * that column actually responds to — so the keys are discoverable, since\n * none of them is a convention a user would try unprompted.\n */\nexport function buildKeyShortcuts(\n capabilities: KeyShortcutCapabilities,\n): string {\n return [\n capabilities.reorderable ? \"Control+ArrowLeft Control+ArrowRight\" : \"\",\n // Alt+Enter is the keyboard equivalent of double-clicking the resize\n // handle to size the column to its content — same gate as the nudge\n // shortcuts, since both are resize actions.\n capabilities.resizable ? \"Alt+ArrowLeft Alt+ArrowRight Alt+Enter\" : \"\",\n capabilities.sortable ? \"Alt+ArrowUp\" : \"\",\n // Down rather than reusing Up: it reads as \"drill into groups\", and Up is\n // already sort's own mnemonic on the same header.\n capabilities.groupable ? \"Alt+ArrowDown\" : \"\",\n // The ContextMenu key needs no mention: it says what it does on its face.\n capabilities.contextMenu === true ? \"Shift+F10\" : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n}\n\n/**\n * Accesses a value at a dotted path, e.g. `foo.bar.baz`.\n *\n * @param obj The object to access\n * @param path Path to the value, e.g. `\"foo.bar\"`\n * @returns The value at `path`, or `undefined` if it doesn't exist\n */\nexport function accessDotted(obj: unknown, path: string): unknown {\n return path\n .split(\".\")\n .reduce((value, key) => (isNested(value) ? value[key] : undefined), obj);\n}\n","import type {\n ColumnSortState,\n ColumnType,\n DataColumn,\n ResolvedRow,\n SortDirection,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/** A date/time value converted to a comparable instant. */\nfunction toTime(value: unknown): number {\n return value instanceof Date\n ? value.getTime()\n : new Date(String(value)).getTime();\n}\n\n/**\n * Compares two cell values the way `type` implies — numerically for the\n * numeric types, chronologically for the date/time types, lexically\n * otherwise. Defaults to string comparison when `type` is absent, mirroring\n * `ColumnDefinition.type`'s own default.\n *\n * `null`/`undefined` sort after every value on both sides. Used directly,\n * that ordering is fixed; `sortRows` applies it directionally without\n * disturbing it — see its own doc comment.\n */\nexport function compareValues(\n a: unknown,\n b: unknown,\n type?: ColumnType,\n): number {\n if (isEmpty(a)) {\n return isEmpty(b) ? 0 : 1;\n }\n if (isEmpty(b)) {\n return -1;\n }\n\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return Number(a) - Number(b);\n case \"boolean\":\n return Number(Boolean(a)) - Number(Boolean(b));\n case \"date\":\n case \"dateTime\":\n case \"time\":\n return toTime(a) - toTime(b);\n default:\n return String(a).localeCompare(String(b));\n }\n}\n\n/** This column's direction in `sort`, or `null` outside it. */\nexport function sortDirectionFor(\n sort: ColumnSortState,\n columnId: string,\n): SortDirection | null {\n return sort.find((entry) => entry.columnId === columnId)?.direction ?? null;\n}\n\n/** This column's 1-based place in `sort`, or `null` outside it. */\nexport function sortPriorityFor(\n sort: ColumnSortState,\n columnId: string,\n): number | null {\n const index = sort.findIndex((entry) => entry.columnId === columnId);\n return index === -1 ? null : index + 1;\n}\n\n/**\n * The sort with `columnId` cycled to its next direction — none → asc → desc →\n * none.\n *\n * `stack: false` (a plain click) means \"sort by only this column\": unless\n * `columnId` is already the sole entry, in which case its own cycle just\n * continues, it collapses `sort` down to `columnId` alone at `\"asc\"`,\n * regardless of any direction it held as part of a larger stack.\n *\n * `stack: true` (a Shift-click) cycles or appends `columnId` in place without\n * disturbing the rest of the stack; cycling it back to `\"none\"` removes it\n * and closes the gap, leaving the others in their existing order.\n */\nexport function toggleColumnSort(\n sort: ColumnSortState,\n columnId: string,\n options: { readonly stack: boolean },\n): ColumnSortState {\n const index = sort.findIndex((entry) => entry.columnId === columnId);\n const isSoleEntry = sort.length === 1 && index === 0;\n\n if (!options.stack && !isSoleEntry) {\n return [{ columnId, direction: \"asc\" }];\n }\n\n const current = index === -1 ? undefined : sort[index]?.direction;\n const next: SortDirection | null =\n current === undefined ? \"asc\" : current === \"asc\" ? \"desc\" : null;\n\n if (next === null) {\n return sort.filter((entry) => entry.columnId !== columnId);\n }\n if (index === -1) {\n return [...sort, { columnId, direction: next }];\n }\n return sort.map((entry, i) =>\n i === index ? { columnId, direction: next } : entry,\n );\n}\n\n/**\n * `rows` ordered by `sort` — each entry read against `columns` for its\n * `field` and `type` — with `rowIndex` renumbered to match the new\n * positions, the invariant the rest of the grid relies on for keyboard\n * navigation and `aria-rowindex`.\n *\n * Stable (`Array.prototype.sort` has been stable since ES2019), so rows\n * equal under every active key keep their relative order. A `null`/\n * `undefined` value sorts last under either direction — resolved before\n * `compareValues` is asked, and left out of the direction flip below, so\n * that toggling a column reorders the values it holds rather than moving its\n * gaps to the front.\n *\n * Returns `rows` itself, untouched, when `sort` is empty or names only\n * columns absent from `columns` — a stored sort tolerates a column removed\n * from the definition the same way a stored `ColumnOrderState` does.\n */\nexport function sortRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n sort: ColumnSortState,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n if (sort.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = sort.filter((entry) => byId.has(entry.columnId));\n if (active.length === 0) {\n return rows;\n }\n\n const sorted = [...rows].sort((a, b) => {\n for (const { columnId, direction } of active) {\n const column = byId.get(columnId);\n if (column === undefined) {\n continue;\n }\n const left = accessDotted(a.row, column.field);\n const right = accessDotted(b.row, column.field);\n const leftEmpty = isEmpty(left);\n const rightEmpty = isEmpty(right);\n if (leftEmpty || rightEmpty) {\n if (leftEmpty && rightEmpty) {\n continue;\n }\n return leftEmpty ? 1 : -1;\n }\n\n const result = compareValues(left, right, column.type);\n if (result !== 0) {\n return direction === \"asc\" ? result : -result;\n }\n }\n return 0;\n });\n\n return sorted.map((row, index) =>\n row.rowIndex === index ? row : { ...row, rowIndex: index },\n );\n}\n","import type {\n ColumnDefinition,\n DataColumn,\n DisplayRow,\n GroupByEntry,\n GroupByState,\n GroupExpansionState,\n ResolvedGroupRow,\n ResolvedRow,\n SortDirection,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { compareValues } from \"./sorting\";\n\n/**\n * This group's id, from its path. Every group-id producer/consumer in this\n * package goes through this — never join `path` by hand elsewhere.\n *\n * `JSON.stringify` rather than a delimiter join: a delimiter would have to be\n * escaped in every segment to stay collision-free against a value that\n * legitimately contains it, and `JSON.stringify` already draws that\n * boundary between array entries for free.\n */\nexport function groupRowId(path: readonly unknown[]): string {\n return JSON.stringify(path);\n}\n\ninterface ValueGroup<Row> {\n value: unknown;\n rows: ResolvedRow<Row>[];\n}\n\n/**\n * A key `accessDotted`'s result can be bucketed by, distinguishing values\n * that `compareValues`/`===` would treat as equal-but-not-identical (two\n * `Date` instances for the same instant) while keeping values of different\n * types apart (the number `1` and the string `\"1\"`).\n *\n * Exported for `aggregation.ts`, which needs the identical notion of\n * \"same value\" to match a leaf row back against a group header's `path` —\n * two producers of the same key would drift apart silently otherwise.\n */\nexport function bucketKey(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\\0empty\";\n }\n if (value instanceof Date) {\n return `\\0date:${String(value.getTime())}`;\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return `\\0${typeof value}:${String(value)}`;\n case \"function\":\n return \"\\0function\";\n default:\n // Arrays, and anything else `accessDotted` could return.\n return `\\0object:${JSON.stringify(value)}`;\n }\n}\n\n/**\n * `rows` bucketed by `column`'s value, one bucket per distinct value in\n * first-seen order, then ordered by `direction` via `compareValues` — the\n * same comparator `sortRows` uses, so a grouped column and a sorted column\n * order their values identically.\n */\nfunction partitionByValue<Row>(\n rows: readonly ResolvedRow<Row>[],\n column: ColumnDefinition<Row, unknown>,\n direction: SortDirection,\n): readonly ValueGroup<Row>[] {\n const buckets = new Map<string, ValueGroup<Row>>();\n for (const row of rows) {\n const value = accessDotted(row.row, column.field);\n const key = bucketKey(value);\n const bucket = buckets.get(key);\n if (bucket === undefined) {\n buckets.set(key, { value, rows: [row] });\n } else {\n bucket.rows.push(row);\n }\n }\n\n const groups = [...buckets.values()];\n groups.sort((a, b) => {\n const result = compareValues(a.value, b.value, column.type);\n return direction === \"asc\" ? result : -result;\n });\n return groups;\n}\n\n/**\n * Depth-first builder behind `groupRows`: partitions `rows` by `levels[0]`,\n * appends a header per resulting group, and recurses into `levels.slice(1)`\n * for each — unless that group is collapsed, in which case only its header\n * is appended. `rows` with no levels left (either `levels` started empty, or\n * recursion exhausted it) are appended as plain data rows, keeping the\n * relative order filter/sort already gave them.\n */\nfunction buildLevel<Row>(\n rows: readonly ResolvedRow<Row>[],\n levels: readonly GroupByEntry[],\n parentPath: readonly unknown[],\n expansion: GroupExpansionState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n out: DisplayRow<Row>[],\n): void {\n const level = levels[0];\n if (level === undefined) {\n out.push(...rows);\n return;\n }\n\n // `levels` is pre-filtered to entries naming a column present in `byId`\n // (see `groupRows`), so this is always found.\n const column = byId.get(level.columnId);\n if (column === undefined) {\n out.push(...rows);\n return;\n }\n\n const rest = levels.slice(1);\n const groups = partitionByValue(rows, column, level.direction ?? \"asc\");\n\n for (const group of groups) {\n const path = [...parentPath, group.value];\n const groupId = groupRowId(path);\n const expanded = !expansion.includes(groupId);\n const header: ResolvedGroupRow = {\n kind: \"group\",\n groupId,\n level: parentPath.length,\n columnId: level.columnId,\n value: group.value,\n path,\n expanded,\n count: group.rows.length,\n // Renumbered globally once `groupRows` has the whole flattened array —\n // a header has no row of its own to carry a dataset position, so\n // `datasetIndex` takes the same renumbered value `rowIndex` does.\n rowIndex: -1,\n datasetIndex: -1,\n // Set by `withGroupAggregates`, downstream of grouping — empty here\n // since `groupRows` itself never knows about `AggregateState`.\n aggregates: new Map(),\n };\n out.push(header);\n if (expanded) {\n buildLevel(group.rows, rest, path, expansion, byId, out);\n }\n }\n}\n\n/**\n * `rows`, regrouped into `groupBy`'s stacked levels — a group header per\n * distinct value at each level, ordered by `compareValues` per that level's\n * own `direction`, followed depth-first by its nested groups and/or data\n * rows. A collapsed group (its `groupId` present in `expansion`) contributes\n * only its own header, nothing beneath it — but its `count` still reports\n * the group's full leaf-row count either way.\n *\n * Filter and sort are expected to have already run (see `resolveShownRows`):\n * this only reshapes their output, and never changes which rows appear or\n * their relative order within a group.\n *\n * `rowIndex` is renumbered across the whole flattened output, header rows\n * included — the same invariant `sortRows`/`filterRows` keep for\n * `ResolvedRow.rowIndex`, extended to `ResolvedGroupRow.rowIndex` since\n * `GridBody` addresses both kinds by the same flat position.\n *\n * Returns `rows` itself, untouched, when `groupBy` is empty or names only\n * columns absent from `columns` — a stored grouping tolerates a column\n * removed from the definition the same way a stored `ColumnSortState` does.\n */\nexport function groupRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n expansion: GroupExpansionState,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly DisplayRow<Row>[] {\n if (groupBy.length === 0) {\n return rows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const active = groupBy.filter((entry) => byId.has(entry.columnId));\n if (active.length === 0) {\n return rows;\n }\n\n const out: DisplayRow<Row>[] = [];\n buildLevel(rows, active, [], expansion, byId, out);\n\n return out.map((entry, index) => {\n if (\"kind\" in entry) {\n return entry.rowIndex === index && entry.datasetIndex === index\n ? entry\n : { ...entry, rowIndex: index, datasetIndex: index };\n }\n return entry.rowIndex === index ? entry : { ...entry, rowIndex: index };\n });\n}\n\n/**\n * The expansion with `groupId` collapsed if it was expanded, or expanded if\n * it was collapsed.\n */\nexport function toggleGroupExpansion(\n expansion: GroupExpansionState,\n groupId: string,\n): GroupExpansionState {\n return expansion.includes(groupId)\n ? expansion.filter((id) => id !== groupId)\n : [...expansion, groupId];\n}\n\n/** `expansion` reduced to empty — every group expanded. Mirrors `clearAllFilters`. */\nexport function expandAllGroups(\n expansion: GroupExpansionState,\n): GroupExpansionState {\n return expansion.length === 0 ? expansion : [];\n}\n\n/**\n * Every group id present in `rows` — for collapsing every group currently\n * shown in one call. Operates on the already-grouped display, not the raw\n * grouping, so a group hidden beneath an already-collapsed ancestor (and so\n * absent from `rows`) keeps whatever expansion it already had rather than\n * being forced closed too; expanding that ancestor again reveals it exactly\n * as it was left.\n *\n * Group headers only: a summary row (`groupAggregateDisplay: \"row\"`) carries\n * its group's id too, and counting it would list that group twice.\n */\nexport function collapseAllGroups<Row>(\n rows: readonly DisplayRow<Row>[],\n): GroupExpansionState {\n return rows\n .filter(\n (entry): entry is ResolvedGroupRow =>\n \"kind\" in entry && entry.kind === \"group\",\n )\n .map((entry) => entry.groupId);\n}\n\n/**\n * `groupBy` with `columnId` positioned in front of `beforeColumnId` — or at\n * the end when that is `null` — inserting a fresh entry if `columnId` isn't\n * already part of the stack, or lifting its existing entry out and back in\n * if it is. The one function both a header dropped on the group-by bar and\n * a chip dragged within it need: the former's `columnId` is usually new to\n * the stack, the latter's never is, and this doesn't need to be told which.\n *\n * An existing entry keeps its own object (and so its own `direction`)\n * rather than being rebuilt, so a level merely repositioned stays\n * reference-equal at its new index — the same reason `moveColumnBefore`\n * moves ids rather than rebuilding them.\n *\n * Returns `groupBy` itself, untouched, when the move changes nothing: a\n * drop on the entry's own id, or back into the gap it already occupies, or\n * naming a `beforeColumnId` absent from the stack. Inserting a column not\n * yet in the stack is never a no-op.\n */\nexport function moveGroupByBefore(\n groupBy: GroupByState,\n columnId: string,\n beforeColumnId: string | null,\n): GroupByState {\n if (columnId === beforeColumnId) {\n return groupBy;\n }\n\n const without = groupBy.filter((entry) => entry.columnId !== columnId);\n const moved = groupBy.find((entry) => entry.columnId === columnId) ?? {\n columnId,\n };\n const target =\n beforeColumnId === null\n ? without.length\n : without.findIndex((entry) => entry.columnId === beforeColumnId);\n if (target === -1) {\n return groupBy;\n }\n\n const next = [...without];\n next.splice(target, 0, moved);\n return next.length === groupBy.length &&\n next.every((entry, index) => entry === groupBy[index])\n ? groupBy\n : next;\n}\n\n/**\n * Whether moving `columnId` in front of `beforeColumnId` would change\n * `groupBy` at all, so that a drop indicator promises exactly the move that\n * happens. Defined against `moveGroupByBefore` rather than restating its\n * conditions, the same relationship `movesColumn` keeps with\n * `moveColumnBefore`.\n */\nexport function movesGroupBy(\n groupBy: GroupByState,\n columnId: string,\n beforeColumnId: string | null,\n): boolean {\n return moveGroupByBefore(groupBy, columnId, beforeColumnId) !== groupBy;\n}\n","/**\n * `compute`, remembering its last arguments and result: called again with\n * every argument identical (`Object.is`), it hands back that same result\n * rather than recomputing. One slot is all a stage needs — the grid asks for\n * the current view, never an older one — and returning the same reference is\n * what lets each later stage, and a renderer, skip work of its own.\n */\nexport function memoizeLast<Args extends readonly unknown[], Result>(\n compute: (...args: Args) => Result,\n): (...args: Args) => Result {\n let last: { readonly args: Args; readonly result: Result } | undefined;\n return (...args) => {\n const previous = last;\n if (\n previous !== undefined &&\n args.every((arg, index) => Object.is(arg, previous.args[index]))\n ) {\n return previous.result;\n }\n const result = compute(...args);\n last = { args, result };\n return result;\n };\n}\n","import type {\n ColumnDefinition,\n ColumnOrderState,\n DataColumn,\n DropSide,\n} from \"../types\";\nimport { getColumnId } from \"./grid\";\n\n/**\n * Puts `columns` in the order `order` gives. Ids it lists come first, in that\n * order; columns it omits keep their position among the definitions and\n * follow. Ids naming no column are ignored.\n *\n * Tolerating both gaps is what lets a stored order outlive the column list it\n * was made against.\n */\nexport function applyColumnOrder<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n order: ColumnOrderState,\n): readonly ColumnDefinition<Row, Node>[] {\n if (order.length === 0) {\n return columns;\n }\n\n const byId = new Map(columns.map((column) => [getColumnId(column), column]));\n const listed = order\n .map((id) => byId.get(id))\n .filter((column) => column !== undefined);\n const taken = new Set(listed.map((column) => getColumnId(column)));\n\n return [\n ...listed,\n ...columns.filter((column) => !taken.has(getColumnId(column))),\n ];\n}\n\n/**\n * `columns` in the order `order` gives, each paired with its id — the\n * width-free column list the data stages (filter, sort, group, aggregate)\n * read. Ordered here, ahead of sizing, so every later stage sees the one\n * already-ordered list and no part of the grid has to know a reorder\n * happened.\n */\nexport function resolveDataColumns<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n order: ColumnOrderState,\n): readonly DataColumn<Row, Node>[] {\n return applyColumnOrder(columns, order).map((column) => ({\n id: getColumnId(column),\n column,\n }));\n}\n\n/**\n * The order with `movedId` lifted out and put back in front of `beforeId`, or\n * at the end when that is `null`.\n *\n * Returns `orderedIds` itself when the move changes nothing, so callers can\n * treat an unchanged reference as \"no move happened\".\n */\nexport function moveColumnBefore(\n orderedIds: ColumnOrderState,\n movedId: string,\n beforeId: string | null,\n): ColumnOrderState {\n if (movedId === beforeId || !orderedIds.includes(movedId)) {\n return orderedIds;\n }\n\n const without = orderedIds.filter((id) => id !== movedId);\n // Taken after the removal: an index read before it would be one too far\n // right for every move that travels rightwards.\n const target = beforeId === null ? without.length : without.indexOf(beforeId);\n if (target === -1) {\n return orderedIds;\n }\n\n const next = [...without];\n next.splice(target, 0, movedId);\n return next.every((id, index) => id === orderedIds[index])\n ? orderedIds\n : next;\n}\n\n/**\n * Whether moving `movedId` in front of `beforeId` would rearrange anything, so\n * that a drop indicator promises exactly the moves that happen.\n *\n * Defined against `moveColumnBefore` rather than restating its conditions, so\n * the two cannot disagree about what a no-op is.\n */\nexport function movesColumn(\n orderedIds: ColumnOrderState,\n movedId: string,\n beforeId: string | null,\n): boolean {\n return moveColumnBefore(orderedIds, movedId, beforeId) !== orderedIds;\n}\n\n/**\n * The id a drop on `side` of `targetId` lands in front of, which is `null`\n * past the last column.\n *\n * \"After C\" and \"before D\" name the same gap, so collapsing both to one id\n * keeps a drop target a single nullable string.\n */\nexport function resolveDropBefore(\n orderedIds: ColumnOrderState,\n targetId: string,\n side: DropSide,\n): string | null {\n if (side === \"before\") {\n return targetId;\n }\n const index = orderedIds.indexOf(targetId);\n return index === -1 ? null : (orderedIds[index + 1] ?? null);\n}\n\n/**\n * The `beforeId` a keyboard nudge on `columnId` produces, for `onDrop` to\n * apply the same way a pointer drop does — or `undefined` when the nudge is a\n * no-op: `columnId` is not in `orderedIds`, or the nudge would move it left\n * of the start.\n *\n * `null` is a real answer here, not \"no-op\": it means append to the end, the\n * same convention `moveColumnBefore` uses.\n */\nexport function resolveKeyboardDropTarget(\n orderedIds: ColumnOrderState,\n columnId: string,\n direction: -1 | 1,\n): string | null | undefined {\n const index = orderedIds.indexOf(columnId);\n if (index === -1) {\n return undefined;\n }\n\n /**\n * Moving right lands in front of the id two along: the gap immediately\n * after a column is the one it already sits in.\n */\n const targetIndex = direction === -1 ? index - 1 : index + 2;\n if (targetIndex < 0) {\n return undefined;\n }\n\n return orderedIds[targetIndex] ?? null;\n}\n","import type { DisplayRow, PaginationState } from \"../types\";\n\nexport interface PaginatedRows<Row> {\n readonly rows: readonly DisplayRow<Row>[];\n readonly pageCount: number;\n /**\n * `pagination.pageIndex` clamped into `[0, pageCount - 1]` (or `0` when\n * `pageCount` is `0`) — read this back rather than trusting the input\n * verbatim, the same way `sortRows`/`filterRows` tolerate a stale stored\n * state.\n */\n readonly pageIndex: number;\n}\n\n/** A contiguous run of `rows` that pagination treats as one unit — a top-level group's header plus every entry beneath it, or a single bare data row. */\ninterface Unit {\n readonly start: number;\n readonly end: number; // exclusive\n}\n\n/**\n * `rows` split into pagination units: a top-level (`level === 0`) group\n * header together with every entry up to (not including) the next unit\n * boundary, or a single bare data row of its own. A nested group (`level >\n * 0`) and the data rows beneath it contribute no boundary — they're carried\n * along inside their top-level ancestor's span, which is what keeps a page\n * from ever splitting a group. A bare data row *outside* any top-level\n * group's span starts (and immediately ends) its own unit, which is what\n * makes an entirely ungrouped `rows` produce one unit per row rather than\n * collapsing into a single unit for the whole array.\n *\n * A `\"group-summary\"` row (`groupAggregateDisplay: \"row\"`) never opens a\n * boundary of its own, at any level — including a top-level one, despite\n * carrying that same `level: 0` a top-level header does. It always belongs\n * to the unit its own group already opened, the same way a nested header\n * and the data rows beneath it do.\n *\n * `openedByGroup` tracks whether the unit currently being built started at a\n * top-level header (in which case everything until the next one, headers and\n * bare rows alike, belongs to it) or at a bare row (in which case it holds\n * exactly that one row).\n */\nfunction unitsOf<Row>(rows: readonly DisplayRow<Row>[]): readonly Unit[] {\n const units: Unit[] = [];\n let start = 0;\n let openedByGroup = false;\n for (let index = 0; index < rows.length; index++) {\n const entry = rows[index];\n if (entry === undefined) {\n continue;\n }\n const isTopLevelHeader =\n \"kind\" in entry && entry.kind === \"group\" && entry.level === 0;\n const isBoundary = index !== start && (isTopLevelHeader || !openedByGroup);\n if (isBoundary) {\n units.push({ start, end: index });\n start = index;\n openedByGroup = isTopLevelHeader;\n } else if (index === start) {\n openedByGroup = isTopLevelHeader;\n }\n }\n if (start < rows.length) {\n units.push({ start, end: rows.length });\n }\n return units;\n}\n\n/**\n * `rows` sliced into pages of `pagination.pageSize` units — see `unitsOf`\n * for what a unit is. `pageIndex` is clamped into range, `pageSize <= 0` is\n * clamped to `1` (this codebase's general tolerance for stale/odd stored\n * state, matching `sortRows`/`filterRows`), and the returned page's\n * `rowIndex` is renumbered to be page-relative — 0-based from the top of the\n * page, header rows included, mirroring `groupRows`'s own renumbering\n * invariant. `datasetIndex` is left untouched: it is assigned once, ahead of\n * filter/sort/group/paginate, and reports each row's position in the whole\n * dataset regardless of which page is showing.\n */\nexport function paginateRows<Row>(\n rows: readonly DisplayRow<Row>[],\n pagination: PaginationState,\n): PaginatedRows<Row> {\n const pageSize = Math.max(1, pagination.pageSize);\n const units = unitsOf(rows);\n const pageCount = Math.ceil(units.length / pageSize);\n\n if (pageCount === 0) {\n return { rows: [], pageCount: 0, pageIndex: 0 };\n }\n\n const pageIndex = Math.min(Math.max(pagination.pageIndex, 0), pageCount - 1);\n const firstUnit = units[pageIndex * pageSize];\n const lastUnit =\n units[Math.min(pageIndex * pageSize + pageSize, units.length) - 1];\n if (firstUnit === undefined || lastUnit === undefined) {\n return { rows: [], pageCount, pageIndex };\n }\n\n const page = rows.slice(firstUnit.start, lastUnit.end);\n const renumbered = page.map((entry, index) =>\n entry.rowIndex === index ? entry : { ...entry, rowIndex: index },\n );\n\n return { rows: renumbered, pageCount, pageIndex };\n}\n","/**\n * The one global this package touches. Declared here rather than taken from a\n * `lib`, which would bring the whole DOM (or Node) along with it: every\n * runtime core runs in has a `console`, and this is all of it core uses.\n */\ndeclare const console: { error: (message: string) => void };\n\n/**\n * Tells the developer about a mistake that does not stop the grid working —\n * two settings that contradict each other, state that cannot be saved — so it\n * is reported rather than thrown.\n */\nexport function reportError(message: string): void {\n console.error(`GridKit: ${message}`);\n}\n","import type { ColumnType, OperatorFilterEntry } from \"../types\";\nimport { bucketKey } from \"./grouping\";\nimport { compareValues } from \"./sorting\";\n\ntype CellTest = (value: unknown) => boolean;\n\ntype Operand = OperatorFilterEntry<unknown>[\"value\"];\n\n/**\n * Where a cell stands against one operand: below it, equal to it or above\n * it as `compareValues` orders them — or `undefined` when the two can't be\n * compared at all (an empty cell, a cell of another kind).\n */\ntype Comparison = (value: unknown) => number | undefined;\n\n/** How a column's values compare, which decides what an operand must be. */\ntype ValueKind = \"number\" | \"boolean\" | \"date\" | \"text\";\n\nconst matchNothing: CellTest = () => false;\n\nfunction kindOf(type: ColumnType | undefined): ValueKind {\n switch (type) {\n case \"number\":\n case \"decimal\":\n case \"currency\":\n case \"percent\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"date\":\n case \"dateTime\":\n case \"time\":\n return \"date\";\n default:\n return \"text\";\n }\n}\n\n/** Whether a column of `type` holds dates — what a saved string is revived for. */\nexport function isDateType(type: ColumnType | undefined): boolean {\n return kindOf(type) === \"date\";\n}\n\n/**\n * `null`, `undefined` and `\"\"` — the three a filter user calls blank. Wider\n * than the `null`/`undefined` a `TextFilterEntry` stringifies to `\"\"`,\n * because an empty string is just as blank to someone reading the grid.\n */\nexport function isEmptyCell(value: unknown): boolean {\n return value === null || value === undefined || value === \"\";\n}\n\n/**\n * `value` as a `Date`, when it is one or a string that reads as one —\n * `undefined` otherwise, an invalid date included, so an unparseable value\n * never compares as a date.\n */\nexport function toDate(value: unknown): Date | undefined {\n const date =\n value instanceof Date\n ? value\n : typeof value === \"string\"\n ? new Date(value)\n : undefined;\n return date === undefined || Number.isNaN(date.getTime()) ? undefined : date;\n}\n\n/**\n * `value` in the form `compareValues` compares under `kind`, or `undefined`\n * when it isn't of that kind. Text is lowercased here, once, so every text\n * comparison is case-insensitive the way a query is.\n */\nfunction comparable(value: unknown, kind: ValueKind): unknown {\n switch (kind) {\n case \"number\":\n return typeof value === \"number\" && !Number.isNaN(value)\n ? value\n : undefined;\n case \"boolean\":\n return typeof value === \"boolean\" ? value : undefined;\n case \"date\":\n return toDate(value);\n case \"text\":\n return String(value).toLowerCase();\n }\n}\n\n/** Whether an operand can stand for a value of `kind` at all. */\nfunction isOperandOfKind(operand: unknown, kind: ValueKind): boolean {\n if (kind !== \"text\") {\n return comparable(operand, kind) !== undefined;\n }\n return (\n typeof operand === \"string\" ||\n typeof operand === \"number\" ||\n typeof operand === \"boolean\"\n );\n}\n\n/**\n * Compares each cell against `operand` the way the column's `type` orders\n * values, or `undefined` when `operand` is of the wrong kind for the column\n * and so can be compared with nothing.\n */\nfunction compileComparison(\n operand: Operand,\n type: ColumnType | undefined,\n): Comparison | undefined {\n const kind = kindOf(type);\n if (!isOperandOfKind(operand, kind)) {\n return undefined;\n }\n const target = comparable(operand, kind);\n return (value) => {\n if (isEmptyCell(value)) {\n return undefined;\n }\n const cell = comparable(value, kind);\n return cell === undefined ? undefined : compareValues(cell, target, type);\n };\n}\n\n/** Whether an operand is a list — what `in` and `between` take. */\nexport function isScalarList<Scalar>(\n operand: Scalar | readonly Scalar[] | undefined,\n): operand is readonly Scalar[] {\n return Array.isArray(operand);\n}\n\nfunction compileOrdering(\n operator: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\",\n operand: Operand,\n type: ColumnType | undefined,\n): CellTest {\n const compare = compileComparison(operand, type);\n if (compare === undefined) {\n return matchNothing;\n }\n /** A cell that can't be compared satisfies no ordering. */\n const where =\n (holds: (result: number) => boolean): CellTest =>\n (value) => {\n const result = compare(value);\n return result !== undefined && holds(result);\n };\n switch (operator) {\n case \"eq\":\n return where((result) => result === 0);\n case \"ne\": {\n const equals = where((result) => result === 0);\n return (value) => !equals(value);\n }\n case \"gt\":\n return where((result) => result > 0);\n case \"gte\":\n return where((result) => result >= 0);\n case \"lt\":\n return where((result) => result < 0);\n case \"lte\":\n return where((result) => result <= 0);\n }\n}\n\nfunction compileBetween(\n operand: Operand,\n type: ColumnType | undefined,\n): CellTest {\n if (!isScalarList(operand) || operand.length !== 2) {\n return matchNothing;\n }\n const [low, high] = operand;\n const fromLow = compileComparison(low, type);\n const fromHigh = compileComparison(high, type);\n if (fromLow === undefined || fromHigh === undefined) {\n return matchNothing;\n }\n return (value) => {\n const aboveLow = fromLow(value);\n const belowHigh = fromHigh(value);\n return (\n aboveLow !== undefined &&\n belowHigh !== undefined &&\n aboveLow >= 0 &&\n belowHigh <= 0\n );\n };\n}\n\n/**\n * The key `in` matches by: grouping's own `bucketKey`, so two values are\n * \"the same\" exactly when grouping would put them in one group — except that\n * a date column reads a date string as the date it names, so a list saved as\n * `Date`s still matches cells that hold ISO strings, and the other way round.\n */\nexport function filterValueKey(\n value: unknown,\n type: ColumnType | undefined,\n): string {\n return bucketKey(isDateType(type) ? (toDate(value) ?? value) : value);\n}\n\nfunction compileIn(operand: Operand, type: ColumnType | undefined): CellTest {\n if (!isScalarList(operand)) {\n return matchNothing;\n }\n const keys = new Set(\n operand\n .filter((scalar) => !isEmptyCell(scalar))\n .map((scalar) => filterValueKey(scalar, type)),\n );\n return (value) =>\n !isEmptyCell(value) && keys.has(filterValueKey(value, type));\n}\n\nfunction compileText(\n operator: \"contains\" | \"notContains\" | \"startsWith\" | \"endsWith\",\n operand: Operand,\n): CellTest {\n if (!isOperandOfKind(operand, \"text\")) {\n return matchNothing;\n }\n const text = String(operand).toLowerCase();\n const read = (value: unknown) => String(value).toLowerCase();\n switch (operator) {\n case \"contains\":\n return (value) => !isEmptyCell(value) && read(value).includes(text);\n case \"notContains\":\n return (value) => isEmptyCell(value) || !read(value).includes(text);\n case \"startsWith\":\n return (value) => !isEmptyCell(value) && read(value).startsWith(text);\n case \"endsWith\":\n return (value) => !isEmptyCell(value) && read(value).endsWith(text);\n }\n}\n\n/**\n * One reusable test for an `OperatorFilterEntry`, given its column's `type`\n * — its operand read, checked and normalised once, so `filterRows`'s row\n * loop only reads the cell. See `OperatorFilterEntry` for what each\n * operator matches.\n */\nexport function compileOperatorEntry(\n entry: OperatorFilterEntry<unknown>,\n type: ColumnType | undefined,\n): CellTest {\n const { operator, value } = entry;\n switch (operator) {\n case \"isEmpty\":\n return isEmptyCell;\n case \"isNotEmpty\":\n return (cell) => !isEmptyCell(cell);\n case \"contains\":\n case \"notContains\":\n case \"startsWith\":\n case \"endsWith\":\n return compileText(operator, value);\n case \"between\":\n return compileBetween(value, type);\n case \"in\":\n return compileIn(value, type);\n case \"eq\":\n case \"ne\":\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\":\n return compileOrdering(operator, value, type);\n }\n}\n","import type {\n ColumnType,\n DataColumn,\n FilterEntry,\n FilterScalar,\n FilterState,\n GridState,\n OperatorFilterEntry,\n SerializedFilterEntry,\n SerializedFilterScalar,\n SerializedFilterState,\n SerializedGridState,\n SerializedOperatorFilterEntry,\n} from \"../types\";\nimport { isDateType, isScalarList, toDate } from \"./filterOperators\";\nimport { reportError } from \"./report\";\n\ntype Operand = Exclude<OperatorFilterEntry<unknown>[\"value\"], undefined>;\ntype SerializedOperand = Exclude<\n SerializedOperatorFilterEntry<unknown>[\"value\"],\n undefined\n>;\n\nfunction serializeScalar(scalar: FilterScalar): SerializedFilterScalar {\n return scalar instanceof Date ? scalar.toISOString() : scalar;\n}\n\nfunction serializeOperand(operand: Operand): SerializedOperand {\n return isScalarList(operand)\n ? operand.map(serializeScalar)\n : serializeScalar(operand);\n}\n\n/**\n * `entry` as JSON can hold it, or `undefined` when it cannot be written down\n * at all — a predicate, or a group left with nothing but predicates.\n */\nfunction serializeEntry<Row>(\n entry: FilterEntry<Row>,\n): SerializedFilterEntry<Row> | undefined {\n if (\"combinator\" in entry) {\n const entries = serializeFilter(entry.entries);\n // A group emptied by dropping its predicates would match everything (an\n // \"and\") or nothing (an \"or\") — neither what was saved — so it goes too.\n return entries.length === 0 && entry.entries.length > 0\n ? undefined\n : { combinator: entry.combinator, entries };\n }\n if (\"predicate\" in entry) {\n reportError(\n entry.columnId === undefined\n ? \"a predicate filter entry across every column cannot be serialised, so it is left out of the saved state.\"\n : `a predicate filter entry on \\`${entry.columnId}\\` cannot be serialised, so it is left out of the saved state.`,\n );\n return undefined;\n }\n if (\"operator\" in entry) {\n const { value, ...rest } = entry;\n return value === undefined\n ? rest\n : { ...rest, value: serializeOperand(value) };\n }\n if (\"value\" in entry) {\n const { value, ...rest } = entry;\n return {\n ...rest,\n value: value instanceof Date ? value.toISOString() : value,\n };\n }\n return entry;\n}\n\nfunction serializeFilter<Row>(\n filter: FilterState<Row>,\n): SerializedFilterState<Row> {\n return filter\n .map((entry) => serializeEntry(entry))\n .filter((entry) => entry !== undefined);\n}\n\n/**\n * `state` in a form that survives `JSON.stringify` and back unchanged, for\n * saving a layout — to local storage, a URL, a user's profile — and handing\n * it to `restoreState` later. Every slice is plain data already except the\n * filter: a `Date` value or operand is written as its ISO string, and a\n * predicate entry, being a function, cannot be written at all and is left\n * out with a `console.error` naming its column.\n */\nexport function serializeGridState<Row>(\n state: GridState<Row>,\n): SerializedGridState<Row> {\n return { ...state, filter: serializeFilter(state.filter) };\n}\n\n/** A saved scalar back as a `Date` when a date column's string reads as one. */\nfunction reviveScalar(\n scalar: FilterScalar,\n type: ColumnType | undefined,\n): FilterScalar {\n return isDateType(type) && typeof scalar === \"string\"\n ? (toDate(scalar) ?? scalar)\n : scalar;\n}\n\nfunction reviveOperand(\n operand: Operand | SerializedOperand,\n type: ColumnType | undefined,\n): Operand {\n return isScalarList(operand)\n ? operand.map((scalar) => reviveScalar(scalar, type))\n : reviveScalar(operand, type);\n}\n\nfunction reviveEntry<Row>(\n entry: FilterEntry<Row> | SerializedFilterEntry<Row>,\n typeOf: (columnId: string) => ColumnType | undefined,\n): FilterEntry<Row> {\n if (\"combinator\" in entry) {\n return {\n combinator: entry.combinator,\n entries: reviveEntries(entry.entries, typeOf),\n };\n }\n if (\"operator\" in entry) {\n const { value, ...rest } = entry;\n return value === undefined\n ? rest\n : { ...rest, value: reviveOperand(value, typeOf(entry.columnId)) };\n }\n if (\"value\" in entry) {\n const { value, ...rest } = entry;\n return {\n ...rest,\n value: typeof value === \"string\" ? new Date(value) : value,\n };\n }\n return entry;\n}\n\nfunction reviveEntries<Row>(\n filter: FilterState<Row> | SerializedFilterState<Row>,\n typeOf: (columnId: string) => ColumnType | undefined,\n): FilterState<Row> {\n return filter.map((entry) => reviveEntry(entry, typeOf));\n}\n\n/**\n * A filter as `serializeGridState` wrote it, back as a `FilterState`. A\n * value entry holding a string held a `Date`, since that is the only way one\n * comes to hold a string. An operator entry's strings are read as dates only\n * on a date, date-time or time column in `columns`, since elsewhere a string\n * is just a string. A filter that was never serialised passes through as it\n * is.\n */\nexport function reviveFilter<Row>(\n filter: FilterState<Row> | SerializedFilterState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): FilterState<Row> {\n const types = new Map(columns.map((entry) => [entry.id, entry.column.type]));\n return reviveEntries(filter, (columnId) => types.get(columnId));\n}\n","import type {\n ColumnConstraints,\n ColumnDefinition,\n ColumnResizeSession,\n ColumnResolveOptions,\n ColumnSizeDefaults,\n ColumnSizingState,\n ResolvedColumn,\n} from \"../types\";\nimport { alignmentForType, getColumnId, resolveColumnLabel } from \"./grid\";\n\n/**\n * Applied to any column that does not size itself. The minimum is a width a\n * header stays legible at rather than a measured value — a column dragged\n * narrower than this reads as a rendering fault.\n */\nexport const DEFAULT_COLUMN_SIZES: ColumnSizeDefaults = {\n width: 150,\n minWidth: 40,\n maxWidth: Number.POSITIVE_INFINITY,\n};\n\n/** How far one arrow key press moves a column edge. */\nexport const KEYBOARD_STEP = 10;\n\nfunction withDefaults(\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnSizeDefaults {\n return { ...DEFAULT_COLUMN_SIZES, ...defaults };\n}\n\n/**\n * The bounds `column` may be sized between. Resolved in one place so that a\n * drag, a clamp and an auto-fit cannot disagree about a column's limits.\n */\nexport function resolveColumnConstraints<Row>(\n column: ColumnDefinition<Row, unknown>,\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnConstraints {\n const resolved = withDefaults(defaults);\n return {\n minWidth: column.minWidth ?? resolved.minWidth,\n maxWidth: column.maxWidth ?? resolved.maxWidth,\n };\n}\n\n/** Holds `width` within `constraints`. */\nexport function clampColumnWidth(\n width: number,\n constraints: ColumnConstraints,\n): number {\n return Math.min(Math.max(width, constraints.minWidth), constraints.maxWidth);\n}\n\n/**\n * Pairs each column with everything needed to render it — the width it sits\n * at, the label its header shows, whether it may be resized and how its cells\n * align. Widths take the first of the sizing state, the column's own `width`,\n * and the default, then clamp.\n *\n * The sizing state winning means a user's drag outlives a re-render; a column\n * absent from it still tracks a `width` edited in the definition.\n */\nexport function resolveColumnWidths<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[],\n sizing: ColumnSizingState,\n options?: ColumnResolveOptions,\n): readonly ResolvedColumn<Row, Node>[] {\n const resolved = withDefaults(options?.sizes);\n\n return columns.map((column) => {\n const id = getColumnId(column);\n const stored = sizing[id];\n\n return {\n column,\n id,\n sized: stored !== undefined,\n width: clampColumnWidth(\n stored ?? column.width ?? resolved.width,\n resolveColumnConstraints(column, resolved),\n ),\n label: resolveColumnLabel(column),\n resizable: column.resizable ?? options?.resizable ?? false,\n reorderable: column.reorderable ?? options?.reorderable ?? false,\n groupByDraggable:\n column.groupByDraggable ?? options?.groupByDraggable ?? false,\n alignment: column.alignment ?? alignmentForType(column.type ?? \"string\"),\n };\n });\n}\n\nexport function totalColumnWidth<Row, Node>(\n resolved: readonly ResolvedColumn<Row, Node>[],\n): number {\n return resolved.reduce((total, entry) => total + entry.width, 0);\n}\n\n/**\n * Opens a resize. The session captures its constraints and starting point up\n * front, so applying a pointer position later is arithmetic on numbers alone —\n * which is what keeps the drag testable without a DOM.\n *\n * @param startPosition Where the pointer went down, on the axis being dragged.\n */\nexport function beginColumnResize<Row>(\n column: ColumnDefinition<Row, unknown>,\n startWidth: number,\n startPosition: number,\n defaults?: Partial<ColumnSizeDefaults>,\n): ColumnResizeSession {\n return {\n columnId: getColumnId(column),\n startWidth,\n startPosition,\n constraints: resolveColumnConstraints(column, defaults),\n };\n}\n\n/**\n * The width the dragged column takes with the pointer at `position`. The delta\n * is signed, so a right-to-left adapter negates it and nothing else changes.\n */\nexport function applyColumnResize(\n session: ColumnResizeSession,\n position: number,\n): number {\n return clampColumnWidth(\n session.startWidth + (position - session.startPosition),\n session.constraints,\n );\n}\n\ninterface SizingEntry<Row, Node> {\n entry: ResolvedColumn<Row, Node>;\n width: number;\n bound: number;\n adjustable: boolean;\n}\n\n/**\n * Whether `item` has reached `bound` in the direction it moves toward — above\n * it for a column growing to a `maxWidth`, below it for one shrinking to a\n * `minWidth`.\n */\nfunction reachedBound<Row, Node>(\n width: number,\n item: SizingEntry<Row, Node>,\n): boolean {\n return item.bound > item.width ? width >= item.bound : width <= item.bound;\n}\n\n/**\n * Moves every adjustable entry's `width` toward `bound` by its proportional\n * share of `remaining`'s current surplus or deficit, looping so a column\n * clamped at its bound in one pass frees the remainder for the others to\n * absorb in the next.\n */\nfunction redistribute<Row, Node>(\n entries: readonly SizingEntry<Row, Node>[],\n remaining: (sum: number) => number,\n): void {\n for (;;) {\n const movable = entries.filter(\n (item) => item.adjustable && !reachedBound(item.width, item),\n );\n const left = remaining(entries.reduce((t, i) => t + i.width, 0));\n if (left <= 0 || movable.length === 0) {\n break;\n }\n\n const base = movable.reduce((total, item) => total + item.width, 0);\n let clamped = false;\n\n for (const item of movable) {\n const share =\n base === 0 ? left / movable.length : (left * item.width) / base;\n const next = item.width + (item.bound > item.width ? share : -share);\n\n if (reachedBound(next, item)) {\n item.width = item.bound;\n clamped = true;\n } else {\n item.width = next;\n }\n }\n\n if (!clamped) {\n break;\n }\n }\n}\n\n/**\n * Fits columns to `availableWidth`: grows them to fill leftover space, or\n * shrinks them to relieve an overflow, in both cases proportionally to each\n * column's current width. Columns the user has sized are left alone in\n * either direction, so dragging one column neither rubber-bands it back nor\n * has it absorb a squeeze meant for the rest.\n *\n * Growing stops at each column's `maxWidth`; shrinking stops at its\n * `minWidth`. If shrinking every adjustable column to its floor still does\n * not reach `availableWidth`, the columns are returned untouched and the\n * container scrolls rather than crushing them further.\n */\nexport function fitColumnsToWidth<Row, Node>(\n resolved: readonly ResolvedColumn<Row, Node>[],\n availableWidth: number,\n defaults?: Partial<ColumnSizeDefaults>,\n): readonly ResolvedColumn<Row, Node>[] {\n const target = Math.floor(availableWidth);\n const total = totalColumnWidth(resolved);\n if (resolved.length === 0 || total === target) {\n return resolved;\n }\n\n const growing = total < target;\n const entries: SizingEntry<Row, Node>[] = resolved.map((entry) => {\n const constraints = resolveColumnConstraints(entry.column, defaults);\n return {\n entry,\n width: entry.width,\n bound: growing ? constraints.maxWidth : constraints.minWidth,\n adjustable: !entry.sized,\n };\n });\n\n if (!growing) {\n // Only unsized columns can be shrunk, so if they alone cannot reach the\n // target the grid genuinely cannot fit and should scroll, unchanged.\n const floor = entries.reduce(\n (sum, item) => sum + (item.adjustable ? item.bound : item.width),\n 0,\n );\n if (floor > target) {\n return resolved;\n }\n }\n\n redistribute(entries, (sum) => (growing ? target - sum : sum - target));\n\n // Fractional widths would leave the table a sub-pixel off its container and\n // show a scrollbar that never goes away, so round every column toward the\n // target and hand the remaining pixels back out (growing) or claw them\n // back (shrinking) one at a time.\n const rounded = entries.map((item) =>\n growing ? Math.floor(item.width) : Math.ceil(item.width),\n );\n let remainder = target - rounded.reduce((total, width) => total + width, 0);\n\n return entries.map((item, index) => {\n let width = rounded[index] ?? item.width;\n // Rounding toward the target can only ever leave it short when growing\n // (floor) or over when shrinking (ceil), so only one direction is ever\n // live here — but each still needs room left before its own bound.\n const hasRoom = growing ? width < item.bound : width > item.bound;\n\n if (remainder !== 0 && item.adjustable && hasRoom) {\n width += growing ? 1 : -1;\n remainder += growing ? -1 : 1;\n }\n\n return { ...item.entry, width };\n });\n}\n\n/**\n * The width a column needs to show `measuredWidth` of content.\n *\n * `padding` is an allowance on top of the measurement, since a column sized to\n * exactly its content can still round down into an ellipsis.\n */\nexport function sizeColumnToContent(\n measuredWidth: number,\n constraints: ColumnConstraints,\n padding = 2,\n): number {\n return clampColumnWidth(Math.ceil(measuredWidth + padding), constraints);\n}\n\n/**\n * `current` with `columnId` reverted to its width in `base` — or omitted\n * entirely if `base` had none — for Escape to restore a resize in progress.\n *\n * A column with no stored width in `base` is correctly omitted by deleting\n * the key rather than merging its `base` width back in, which would\n * otherwise leave it pinned and hidden from auto-fit.\n */\nexport function revertColumnSize(\n current: ColumnSizingState,\n base: ColumnSizingState,\n columnId: string,\n): ColumnSizingState {\n const next = Object.fromEntries(\n Object.entries(current).filter(([id]) => id !== columnId),\n );\n if (columnId in base) {\n next[columnId] = base[columnId] as number;\n }\n return next;\n}\n","import type {\n AggregateResults,\n AggregateSpec,\n AggregateState,\n BuiltInAggregate,\n ColumnDefinition,\n DataColumn,\n DisplayRow,\n GroupAggregateDisplay,\n GroupByState,\n ResolvedGroupRow,\n ResolvedGroupSummaryRow,\n ResolvedRow,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { bucketKey } from \"./grouping\";\nimport { compareValues } from \"./sorting\";\n\nfunction isEmpty(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/** A value's numeric reading for `sum`/`avg` — `NaN` is treated as absent, same as an empty value. */\nfunction toNumber(value: unknown): number {\n return Number(value);\n}\n\n/**\n * A key distinguishing `countDistinct`'s buckets — reuses `bucketKey`'s\n * approach in `grouping.ts` (distinct values bucketed by kind and content,\n * two `Date`s for the same instant collapsing together) rather than a\n * second implementation of the same idea.\n */\nfunction distinctKey(value: unknown): string {\n if (isEmpty(value)) {\n return \"\\0empty\";\n }\n if (value instanceof Date) {\n return `\\0date:${String(value.getTime())}`;\n }\n switch (typeof value) {\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"bigint\":\n case \"symbol\":\n return `\\0${typeof value}:${String(value)}`;\n case \"function\":\n return \"\\0function\";\n default:\n return `\\0object:${JSON.stringify(value)}`;\n }\n}\n\n/**\n * One built-in reducer over the raw values read off `rows` at `column`'s\n * field. `min`/`max` compare via `compareValues` so a `date`/`dateTime`\n * column orders chronologically rather than numerically; `sum`/`avg`\n * coerce numerically regardless of `column.type`, matching how a\n * `currency`/`decimal`/`percent`/`number` column is expected to be used.\n *\n * Null/undefined handling: `min`/`max` ignore empty entries entirely rather\n * than letting them win by `compareValues`'s own \"empty sorts last\"\n * convention — an aggregate that returned `undefined` merely because every\n * value happened to be null would be a worse answer than skipping them.\n * `count` counts every row in scope regardless of whether its value at this\n * column is empty (it answers \"how many rows\", not \"how many non-null\n * values\") — `countDistinct` excludes empty values from its distinct set,\n * since \"blank\" is not a value to count as one of the distinct ones.\n */\nfunction reduceBuiltIn<Row>(\n rows: readonly Row[],\n fn: BuiltInAggregate,\n column: DataColumn<Row, unknown> | undefined,\n): unknown {\n if (fn === \"count\") {\n return rows.length;\n }\n\n const field = column?.column.field;\n const values =\n field === undefined ? [] : rows.map((row) => accessDotted(row, field));\n\n switch (fn) {\n case \"sum\": {\n let total = 0;\n for (const value of values) {\n if (isEmpty(value)) continue;\n total += toNumber(value);\n }\n return total;\n }\n case \"avg\": {\n const present = values.filter((value) => !isEmpty(value));\n if (present.length === 0) return undefined;\n const total = present.reduce(\n (acc: number, value) => acc + toNumber(value),\n 0,\n );\n return total / present.length;\n }\n case \"min\":\n case \"max\": {\n const type = column?.column.type;\n let result: unknown;\n for (const value of values) {\n if (isEmpty(value)) continue;\n if (result === undefined) {\n result = value;\n continue;\n }\n const comparison = compareValues(value, result, type);\n if (fn === \"min\" ? comparison < 0 : comparison > 0) {\n result = value;\n }\n }\n return result;\n }\n case \"countDistinct\": {\n const seen = new Set<string>();\n for (const value of values) {\n if (isEmpty(value)) continue;\n seen.add(distinctKey(value));\n }\n return seen.size;\n }\n }\n}\n\n/** This spec's result key — `id` when given, `columnId` otherwise. */\nfunction keyOf<Row>(spec: AggregateSpec<Row>): string {\n return spec.id ?? spec.columnId;\n}\n\n/**\n * `rows` reduced through every spec in `specs`, keyed by `spec.id ??\n * spec.columnId`. A custom `fn` (a plain function, not a `BuiltInAggregate`\n * name) is called once with the raw `rows` — no wrapping, no\n * pre-processing, so it sees exactly the same leaf set a built-in reducer\n * does.\n *\n * Two specs resolving to the same key: the later one wins, matching\n * `setColumnFilter`'s own silent-replace precedent for a key collision\n * rather than throwing.\n *\n * Returns a fresh empty `Map` for empty `rows` or empty `specs` — never a\n * shared singleton — matching this codebase's general avoidance of shared\n * mutable module state.\n */\nexport function computeAggregates<Row>(\n rows: readonly Row[],\n specs: AggregateState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): AggregateResults {\n const results = new Map<string, unknown>();\n if (specs.length === 0) {\n return results;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry]));\n for (const spec of specs) {\n const value =\n typeof spec.fn === \"function\"\n ? spec.fn(rows)\n : reduceBuiltIn(rows, spec.fn, byId.get(spec.columnId));\n results.set(keyOf(spec), value);\n }\n return results;\n}\n\n/**\n * A group header's full leaf-row descendant set, found by re-filtering\n * `flatRows` (the same pre-group, filtered/sorted rows `groupRows` itself\n * partitioned) against `header.path` — each ancestor level's value matched\n * via `bucketKey`, the identical notion of \"same value\" `groupRows` uses to\n * bucket in the first place.\n *\n * Deliberately independent of `displayRows`' own flattened shape: a\n * collapsed group's descendants are never emitted into `displayRows` at\n * all (see `buildLevel`'s `if (expanded)` guard), so a header's subtotal\n * has to be recomputed from the original row list rather than walked out\n * of the grouped-and-collapsed output — the only way a collapsed group's\n * header still gets a correct count regardless of its own collapse state.\n */\nfunction leafDescendantsOf<Row>(\n flatRows: readonly ResolvedRow<Row>[],\n path: readonly unknown[],\n groupBy: GroupByState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n): Row[] {\n const keys = path.map((value) => bucketKey(value));\n return flatRows\n .filter((row) =>\n keys.every((key, level) => {\n const columnId = groupBy[level]?.columnId;\n const column = columnId === undefined ? undefined : byId.get(columnId);\n if (column === undefined) return false;\n return bucketKey(accessDotted(row.row, column.field)) === key;\n }),\n )\n .map((row) => row.row);\n}\n\n/**\n * `displayRows` (already regrouped by `groupBy`, per `groupRows`) with\n * every group header's `aggregates` field set to `specs` computed over\n * that group's full leaf-row descendants, re-derived from `flatRows` (the\n * same pre-group rows `groupRows` was given) — regardless of the group's\n * own collapse state, since a collapsed group's header still needs a\n * correct subtotal and its descendants are otherwise absent from\n * `displayRows` entirely. Each level's `aggregates` comes from its own\n * full descendant set, computed independently rather than combined from\n * its children's already-computed results, so a non-associative custom\n * aggregate (median, distinct count) is never silently wrong at a nested\n * level.\n *\n * `display: \"row\"` additionally emits a `ResolvedGroupSummaryRow` right\n * after each group's last visible entry (its last nested group/data row,\n * or immediately after its own header when collapsed) — every level gets\n * its own, the same way every level already gets its own `aggregates`.\n * `display: \"inline\"` (the default) emits none; a header's `aggregates`\n * field is populated either way, since `GridGroupRow`'s own inline\n * rendering and a summary row both read from it.\n *\n * `rowIndex`/`datasetIndex` are renumbered across the whole output when a\n * row was inserted, the same invariant `groupRows` itself keeps.\n *\n * Returns `displayRows` itself, untouched, when `specs` is empty — the\n * same reference-equality no-op every other transform across\n * grouping/pagination uses.\n */\n/**\n * One pass over a contiguous run of `displayRows` sharing one parent — the\n * top-level call covers the whole array, and each group header found along\n * the way recurses into its own span (every entry up to the next one at\n * its level or shallower) the same way, so a group at any nesting depth\n * gets its own `aggregates` computed and, under `display: \"row\"`, its own\n * summary row appended right after everything beneath it.\n *\n * Returns the index just past the run this call consumed, so the caller\n * (itself, one level up, or `withGroupAggregates`) knows where to resume.\n */\nfunction appendAggregatedSpan<Row>(\n displayRows: readonly DisplayRow<Row>[],\n start: number,\n levelFloor: number | null,\n flatRows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n specs: AggregateState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n display: GroupAggregateDisplay,\n out: DisplayRow<Row>[],\n): number {\n let index = start;\n while (index < displayRows.length) {\n const entry = displayRows[index];\n if (entry === undefined) {\n index++;\n continue;\n }\n if (\n levelFloor !== null &&\n \"kind\" in entry &&\n entry.kind === \"group\" &&\n entry.level <= levelFloor\n ) {\n // The next entry at this level or shallower ends the current span —\n // handled by the caller's own iteration, not this one.\n break;\n }\n index++;\n if (!(\"kind\" in entry) || entry.kind !== \"group\") {\n out.push(entry);\n continue;\n }\n\n const leaves = leafDescendantsOf(flatRows, entry.path, groupBy, byId);\n const aggregates = computeAggregates(leaves, specs, columns);\n const withAggregates: ResolvedGroupRow = { ...entry, aggregates };\n out.push(withAggregates);\n\n index = appendAggregatedSpan(\n displayRows,\n index,\n entry.level,\n flatRows,\n groupBy,\n byId,\n specs,\n columns,\n display,\n out,\n );\n\n if (display === \"row\") {\n const summary: ResolvedGroupSummaryRow = {\n kind: \"group-summary\",\n groupId: entry.groupId,\n level: entry.level,\n rowIndex: -1,\n datasetIndex: -1,\n aggregates,\n };\n out.push(summary);\n }\n }\n return index;\n}\n\nexport function withGroupAggregates<Row>(\n displayRows: readonly DisplayRow<Row>[],\n flatRows: readonly ResolvedRow<Row>[],\n groupBy: GroupByState,\n specs: AggregateState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n display: GroupAggregateDisplay = \"inline\",\n): readonly DisplayRow<Row>[] {\n if (specs.length === 0) {\n return displayRows;\n }\n\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const out: DisplayRow<Row>[] = [];\n appendAggregatedSpan(\n displayRows,\n 0,\n null,\n flatRows,\n groupBy,\n byId,\n specs,\n columns,\n display,\n out,\n );\n\n return out.map((entry, position) => {\n if (\"kind\" in entry) {\n return entry.rowIndex === position && entry.datasetIndex === position\n ? entry\n : { ...entry, rowIndex: position, datasetIndex: position };\n }\n return entry.rowIndex === position\n ? entry\n : { ...entry, rowIndex: position };\n });\n}\n","import type {\n ColumnDefinition,\n ColumnType,\n DataColumn,\n FieldPath,\n FilterEntry,\n FilterState,\n ResolvedRow,\n TextFilterEntry,\n} from \"../types\";\nimport { compileOperatorEntry } from \"./filterOperators\";\nimport { accessDotted } from \"./grid\";\n\ninterface FilterPattern {\n mode: \"exact\" | \"contains\" | \"startsWith\" | \"endsWith\";\n text: string; // anchors stripped, lowercased once\n}\n\n/**\n * Reads a query's leading/trailing `%` into a match mode — see\n * `TextFilterEntry`'s own doc comment for the four shapes. Only the first\n * and last characters are read as anchors — a `%` anywhere else in the\n * query is a literal character, not a wildcard.\n */\nfunction parseFilterPattern(query: string): FilterPattern {\n const start = query.startsWith(\"%\");\n const end = query.endsWith(\"%\");\n let text = query;\n if (start) {\n text = text.slice(1);\n }\n if (end) {\n text = text.slice(0, -1);\n }\n text = text.toLowerCase();\n\n if (start && end) {\n return { mode: \"contains\", text };\n }\n if (start) {\n return { mode: \"endsWith\", text };\n }\n if (end) {\n return { mode: \"startsWith\", text };\n }\n return { mode: \"exact\", text };\n}\n\nfunction isEmptyValue(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\n/**\n * `parseFilterPattern`, compiled to a reusable test — parsed once, reused\n * per row, unlike a per-call `matchesQuery`.\n */\nfunction compileFilterQuery(query: string): (value: unknown) => boolean {\n const { mode, text } = parseFilterPattern(query);\n return (value: unknown) => {\n const candidate = (isEmptyValue(value) ? \"\" : String(value)).toLowerCase();\n switch (mode) {\n case \"exact\":\n return candidate === text;\n case \"contains\":\n return candidate.includes(text);\n case \"startsWith\":\n return candidate.startsWith(text);\n case \"endsWith\":\n return candidate.endsWith(text);\n }\n };\n}\n\n/**\n * Whether `target` (a `ValueFilterEntry`'s value) equals `value` under\n * `type` — `false` whenever `type` doesn't agree with `target`'s own kind,\n * so a number filter never silently matches a string column.\n */\nfunction matchesTypedValue(\n value: unknown,\n target: number | boolean | Date,\n type: ColumnType | undefined,\n): boolean {\n if (typeof target === \"number\") {\n if (\n type !== \"number\" &&\n type !== \"decimal\" &&\n type !== \"currency\" &&\n type !== \"percent\"\n ) {\n return false;\n }\n return typeof value === \"number\" && value === target;\n }\n if (typeof target === \"boolean\") {\n if (type !== \"boolean\") {\n return false;\n }\n return typeof value === \"boolean\" && value === target;\n }\n if (type !== \"date\" && type !== \"dateTime\" && type !== \"time\") {\n return false;\n }\n return value instanceof Date && value.getTime() === target.getTime();\n}\n\n/**\n * Whether a non-group entry names a column present in `byId` (or names\n * none at all) — lets a stored filter tolerate a column removed from the\n * definition the same way a stored `ColumnSortState` does, by dropping only\n * the entries that reference it.\n *\n * A `GroupFilterEntry` is always usable, regardless of its own contents:\n * its vacuous truth value under an empty or fully-unusable `entries` list\n * depends on its own `combinator` (`\"and\"` vacuously matches everything,\n * `\"or\"` vacuously matches nothing) — a group can't be dropped from its\n * parent's list the way an unusable simple entry can, since whether\n * dropping it would be safe depends on the *parent's* combinator too,\n * which this check has no way to know. Compiling it and letting `.every()`/\n * `.some()` resolve the vacuous case naturally is what stays correct in\n * every context; deciding upfront here is not.\n */\nfunction isEntryUsable<Row>(\n entry: FilterEntry<Row>,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n): boolean {\n if (\"combinator\" in entry) {\n return true;\n }\n return entry.columnId === undefined || byId.has(entry.columnId);\n}\n\n/**\n * One compiled test per usable `FilterEntry`, closing over its column\n * lookup so `filterRows`'s row loop is just `.every(test)`.\n */\nfunction compileFilterEntry<Row>(\n entry: FilterEntry<Row>,\n byId: ReadonlyMap<string, ColumnDefinition<Row, unknown>>,\n columns: readonly DataColumn<Row, unknown>[],\n): (row: Row) => boolean {\n if (\"combinator\" in entry) {\n const tests = entry.entries\n .filter((nested) => isEntryUsable(nested, byId))\n .map((nested) => compileFilterEntry(nested, byId, columns));\n return entry.combinator === \"and\"\n ? (row) => tests.every((test) => test(row))\n : (row) => tests.some((test) => test(row));\n }\n\n if (\"predicate\" in entry) {\n const { columnId, predicate } = entry;\n const column = columnId === undefined ? undefined : byId.get(columnId);\n return (row) =>\n predicate(\n column === undefined ? undefined : accessDotted(row, column.field),\n row,\n );\n }\n\n // Before the `value` check: an operator entry usually has a `value` too.\n if (\"operator\" in entry) {\n const column = byId.get(entry.columnId);\n if (column === undefined) {\n return () => false;\n }\n const test = compileOperatorEntry(entry, column.type);\n return (row) => test(accessDotted(row, column.field));\n }\n\n if (\"value\" in entry) {\n const { columnId, value } = entry;\n if (columnId !== undefined) {\n const column = byId.get(columnId);\n if (column === undefined) {\n return () => false;\n }\n return (row) =>\n matchesTypedValue(accessDotted(row, column.field), value, column.type);\n }\n return (row) =>\n columns.some((entry) =>\n matchesTypedValue(\n accessDotted(row, entry.column.field),\n value,\n entry.column.type,\n ),\n );\n }\n\n const { columnId, query } = entry;\n const test = compileFilterQuery(query);\n if (columnId !== undefined) {\n const column = byId.get(columnId);\n if (column === undefined) {\n return () => false;\n }\n return (row) => test(accessDotted(row, column.field));\n }\n return (row) =>\n columns.some((entry) => test(accessDotted(row, entry.column.field)));\n}\n\n/**\n * `filter` compiled to one test of a row, every entry ANDed as `filterRows`\n * applies them — or `undefined` when no entry applies to `columns`, so a\n * caller can skip the row loop. Entries naming a column absent from\n * `columns` are dropped, as `filterRows` drops them.\n */\nexport function compileFilter<Row>(\n filter: FilterState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): ((row: Row) => boolean) | undefined {\n const byId = new Map(columns.map((entry) => [entry.id, entry.column]));\n const compiled = filter\n .filter((entry) => isEntryUsable(entry, byId))\n .map((entry) => compileFilterEntry(entry, byId, columns));\n return compiled.length === 0\n ? undefined\n : (row) => compiled.every((test) => test(row));\n}\n\n/**\n * Whether `value`, stringified, matches `query`'s SQL LIKE-style pattern —\n * case-insensitive always. A bare query is an exact match; `%text%` is\n * contains; `text%` is starts-with; `%text` is ends-with. `null`/`undefined`\n * stringify to `\"\"`.\n *\n * A one-shot convenience: parses `query` fresh on every call. `filterRows`\n * does not call this per cell — it compiles each `TextFilterEntry` once,\n * outside its row loop.\n */\nexport function matchesQuery(value: unknown, query: string): boolean {\n return compileFilterQuery(query)(value);\n}\n\n/**\n * This column's current text query, or the global entry's when `columnId`\n * is omitted; `null` if no `TextFilterEntry` names it — including when the\n * entry that exists for that key is a `ValueFilterEntry`/\n * `PredicateFilterEntry`/`OperatorFilterEntry`/`GroupFilterEntry` instead,\n * since none of those hold a query string to report.\n */\nexport function filterQueryFor<Row>(\n filter: FilterState<Row>,\n columnId?: FieldPath<Row> | (string & {}),\n): string | null {\n const entry = filter.find(\n (candidate): candidate is TextFilterEntry<Row> =>\n \"query\" in candidate && candidate.columnId === columnId,\n );\n return entry?.query ?? null;\n}\n\n/**\n * The filter with the `TextFilterEntry` for `columnId` (or the global\n * entry, when `columnId` is omitted) set to `query` — replacing whatever\n * entry already holds that key, of any variant, if present; appending a new\n * `TextFilterEntry` if not. An empty `query` removes the entry instead of\n * storing a filter that can never usefully match.\n *\n * Returns `filter` itself, unchanged, when the result would be a no-op: an\n * empty `query` naming a key with no existing entry, or a `query` equal to\n * an existing `TextFilterEntry`'s.\n */\nexport function setColumnFilter<Row>(\n filter: FilterState<Row>,\n columnId: (FieldPath<Row> | (string & {})) | undefined,\n query: string,\n): FilterState<Row> {\n const index = filter.findIndex(\n (entry) => !(\"combinator\" in entry) && entry.columnId === columnId,\n );\n\n if (query === \"\") {\n return index === -1 ? filter : filter.filter((_entry, i) => i !== index);\n }\n\n const next: TextFilterEntry<Row> =\n columnId === undefined ? { query } : { columnId, query };\n\n if (index === -1) {\n return [...filter, next];\n }\n const existing = filter[index];\n if (\n existing !== undefined &&\n \"query\" in existing &&\n existing.query === query\n ) {\n return filter;\n }\n return filter.map((entry, i) => (i === index ? next : entry));\n}\n\n/** `filter` reduced to empty. Returns `filter` itself when already empty. */\nexport function clearAllFilters<Row>(\n filter: FilterState<Row>,\n): FilterState<Row> {\n return filter.length === 0 ? filter : [];\n}\n\n/**\n * `rows` reduced to those matching every entry in `filter` (AND at the top\n * level — nest a `GroupFilterEntry` for OR). `rowIndex` is renumbered to\n * match the retained positions — the same invariant `sortRows` keeps,\n * needed here independently since `filterRows` runs before `sortRows` in\n * the composed pipeline (see `resolveShownRows`).\n *\n * Order-preserving: surviving rows keep their relative order, which is what\n * makes running this before a sort produce the identical final order a\n * sort-then-filter would — only the cost differs.\n *\n * Every entry is compiled once, before the row loop.\n *\n * Returns `rows` itself, untouched, when `filter` is empty or names only\n * columns absent from `columns` — a stored filter tolerates a column\n * removed from the definition the same way a stored `ColumnSortState` does.\n */\nexport function filterRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n filter: FilterState<Row>,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n if (filter.length === 0) {\n return rows;\n }\n const test = compileFilter(filter, columns);\n if (test === undefined) {\n return rows;\n }\n\n const filtered = rows.filter((row) => test(row.row));\n\n return filtered.map((row, index) =>\n row.rowIndex === index ? row : { ...row, rowIndex: index },\n );\n}\n","import type {\n ColumnSortState,\n DataColumn,\n FilterState,\n ResolvedColumn,\n ResolvedRow,\n SelectedCell,\n SelectedCellRef,\n SelectedColumn,\n} from \"../types\";\nimport { accessDotted } from \"./grid\";\nimport { filterRows } from \"./filtering\";\nimport { sortRows } from \"./sorting\";\n\n/**\n * `rows`, filtered then sorted — the one function `DataGrid.tsx` (and any\n * future framework binding) calls instead of composing `filterRows`/\n * `sortRows` itself.\n *\n * Filter always runs first: an O(n) pass that shrinks what the O(n log n)\n * sort has to touch whenever a filter is active, free when it isn't. This\n * is a performance choice, not a correctness one — filtering is an\n * order-preserving predicate and sort is a stable total order over whatever\n * it's handed, so the final order is identical either way.\n */\nexport function resolveShownRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n filter: FilterState<Row>,\n sort: ColumnSortState,\n columns: readonly DataColumn<Row, unknown>[],\n): readonly ResolvedRow<Row>[] {\n return sortRows(filterRows(rows, filter, columns), sort, columns);\n}\n\n/**\n * `ids` resolved back to the rows behind them, keyed by `rowsById`.\n *\n * An id with no row behind it is dropped rather than left `undefined`: a\n * selection outlives a change to the data, so that filtering a row out and\n * back leaves it selected, and only what still exists can be handed to a\n * callback.\n */\nexport function resolveRows<Row>(\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n ids: readonly string[],\n): readonly ResolvedRow<Row>[] {\n return ids.map((id) => rowsById.get(id)).filter((row) => row !== undefined);\n}\n\n/**\n * `ids` resolved back to the columns behind them, paired with the position\n * each holds in `columns` — a stale id is dropped, matching `resolveRows`.\n */\nexport function resolveColumns<Row, Node>(\n columns: readonly ResolvedColumn<Row, Node>[],\n ids: readonly string[],\n): readonly SelectedColumn<Row, Node>[] {\n return ids\n .map((id) => {\n const columnIndex = columns.findIndex((entry) => entry.id === id);\n const column = columns[columnIndex];\n return column === undefined\n ? undefined\n : { columnId: id, column, columnIndex };\n })\n .filter((column) => column !== undefined);\n}\n\n/**\n * `cell` resolved down to the row, column and value it addresses — `null`\n * when there is no cell, or when either half of it names a row or column\n * that no longer exists.\n */\nexport function resolveCell<Row, Node>(\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n columns: readonly ResolvedColumn<Row, Node>[],\n cell: SelectedCellRef | null,\n): SelectedCell<Row, Node> | null {\n if (cell === null) {\n return null;\n }\n const entry = rowsById.get(cell.rowId);\n const columnIndex = columns.findIndex(\n (candidate) => candidate.id === cell.columnId,\n );\n const column = columns[columnIndex];\n if (entry === undefined || column === undefined) {\n return null;\n }\n return {\n rowId: cell.rowId,\n columnId: cell.columnId,\n row: entry.row,\n column,\n rowIndex: entry.rowIndex,\n columnIndex,\n value: accessDotted(entry.row, column.column.field),\n };\n}\n","import type {\n ColumnDefinition,\n ColumnVisibilityState,\n DataColumn,\n} from \"../types\";\nimport { getColumnId } from \"./grid\";\n\n/**\n * Whether `column` is shown: what the user last chose for it, if anything,\n * else what its definition says. The one place that precedence is decided,\n * so the view and an imperative \"is it showing?\" cannot disagree.\n */\nexport function isColumnVisible<Row>(\n column: ColumnDefinition<Row, unknown>,\n visibility: ColumnVisibilityState,\n): boolean {\n return visibility[getColumnId(column)] ?? column.hidden !== true;\n}\n\n/**\n * `columns` without the hidden ones, in the same order. `columns` itself when\n * every column is shown — the common case — so a stage memoised on this\n * output sees nothing change.\n */\nexport function applyColumnVisibility<Row, Node>(\n columns: readonly DataColumn<Row, Node>[],\n visibility: ColumnVisibilityState,\n): readonly DataColumn<Row, Node>[] {\n const visible = columns.filter((entry) =>\n isColumnVisible(entry.column, visibility),\n );\n return visible.length === columns.length ? columns : visible;\n}\n\n/**\n * `visibility` with each of `columnIds` shown (`visible: true`) or hidden.\n * Only a column whose visibility actually changes gets an entry, and ids\n * naming no column are ignored, so asking to show what is already showing\n * hands back `visibility` itself — the same reference, for a caller deciding\n * whether anything happened.\n */\nexport function setColumnVisibility<Row>(\n columns: readonly DataColumn<Row, unknown>[],\n visibility: ColumnVisibilityState,\n columnIds: readonly string[],\n visible: boolean,\n): ColumnVisibilityState {\n const requested = new Set(columnIds);\n const changed = columns.filter(\n (entry) =>\n requested.has(entry.id) &&\n isColumnVisible(entry.column, visibility) !== visible,\n );\n if (changed.length === 0) {\n return visibility;\n }\n return {\n ...visibility,\n ...Object.fromEntries(changed.map((entry) => [entry.id, visible])),\n };\n}\n","import type {\n AggregateResults,\n AggregateState,\n ColumnSizeDefaults,\n ColumnSizingState,\n DataColumn,\n DisplayRow,\n GridView,\n GridViewInput,\n PaginationState,\n ResizeMode,\n ResolvedColumn,\n ResolvedRow,\n} from \"../types\";\nimport { computeAggregates, withGroupAggregates } from \"./aggregation\";\nimport { resolveRowId } from \"./grid\";\nimport { groupRows } from \"./grouping\";\nimport { memoizeLast } from \"./memoize\";\nimport { resolveDataColumns } from \"./ordering\";\nimport { paginateRows, type PaginatedRows } from \"./paging\";\nimport { resolveShownRows } from \"./rows\";\nimport { fitColumnsToWidth, resolveColumnWidths } from \"./sizing\";\nimport { applyColumnVisibility } from \"./visibility\";\n\n/**\n * A stable empty fallback for omitted `aggregates` — a fresh `[]` per call\n * would change identity each time and defeat every stage memoised on it.\n */\nconst NO_AGGREGATES: AggregateState<never> = [];\n\n/**\n * The rows, each carrying the id everything downstream keys it by. Resolved\n * once here rather than per consumer so a row's id cannot come out\n * differently in two places — the same reason widths are resolved once ahead\n * of the header and the body.\n *\n * An array rather than a map keyed by id: two rows given the same id is a\n * caller's mistake, and one that should render twice and look wrong rather\n * than silently lose a row.\n */\nfunction identifyRows<Row>(\n rows: readonly Row[],\n getRowId: ((row: Row, index: number) => string) | undefined,\n): readonly ResolvedRow<Row>[] {\n return rows.map((row, rowIndex) => ({\n rowId: resolveRowId(row, rowIndex, getRowId),\n row,\n rowIndex,\n datasetIndex: rowIndex,\n }));\n}\n\n/**\n * The columns as rendered. Auto-fit is a derivation rather than a write back\n * into `sizing`, so that a `width` set in a column definition is never\n * overwritten and nothing chases its own output; `\"fixed\"` is then simply\n * the absence of it.\n *\n * The only stage that reads `sizing` or `viewportWidth`, and nothing reads\n * its output but the renderer: a resize re-runs this and leaves every data\n * stage alone. Handed the visible columns only, so the hidden ones take no\n * share of a fitted width.\n */\nfunction sizeColumns<Row, Node>(\n visibleColumns: readonly DataColumn<Row, Node>[],\n sizing: ColumnSizingState,\n sizes: Partial<ColumnSizeDefaults> | undefined,\n resizable: boolean | undefined,\n reorderable: boolean | undefined,\n groupByDraggable: boolean | undefined,\n resizeMode: ResizeMode,\n viewportWidth: number | null,\n): readonly ResolvedColumn<Row, Node>[] {\n const widths = resolveColumnWidths(\n visibleColumns.map((entry) => entry.column),\n sizing,\n { sizes, resizable, reorderable, groupByDraggable },\n );\n return resizeMode === \"fit\" && viewportWidth !== null\n ? fitColumnsToWidth(widths, viewportWidth, sizes)\n : widths;\n}\n\n/**\n * The grand total: every aggregate over the whole filtered/sorted dataset,\n * ungrouped. Computed from `rows` directly rather than combined from any\n * group's result, for the same reason a nested group's own subtotal is: a\n * non-associative custom aggregate would be wrong if combined from parts.\n */\nfunction totalAggregates<Row>(\n rows: readonly ResolvedRow<Row>[],\n aggregates: AggregateState<Row>,\n dataColumns: readonly DataColumn<Row, unknown>[],\n): AggregateResults {\n return computeAggregates(\n rows.map((entry) => entry.row),\n aggregates,\n dataColumns,\n );\n}\n\n/**\n * Always last, after grouping and aggregation, so a page never splits a\n * group and a subtotal never changes value depending on which page is\n * showing. Unpaginated, the grid is a single page over every row, and\n * `pageCount`/`pageIndex` report that (`1`/`0`) rather than whatever a\n * stored `pagination` might still carry.\n */\nfunction paginate<Row>(\n displayRows: readonly DisplayRow<Row>[],\n paginated: boolean,\n pagination: PaginationState,\n): PaginatedRows<Row> {\n return paginated\n ? paginateRows(displayRows, pagination)\n : { rows: displayRows, pageCount: 1, pageIndex: 0 };\n}\n\n/**\n * `pageRows` narrowed back to its data rows, in the same (possibly\n * regrouped, possibly paginated) order — what a range selection anchors\n * against, so that a Shift-click spans the rows adjacent on screen rather\n * than their pre-grouping, pre-pagination order. A collapsed group, or a row\n * on another page, contributes nothing here, so a range spanning its\n * position includes only what was visible when it was drawn.\n *\n * `rows` itself when nothing could have reshaped it, sparing the filter pass\n * on the common ungrouped, unpaginated grid.\n */\nfunction narrowToDataRows<Row>(\n pageRows: readonly DisplayRow<Row>[],\n rows: readonly ResolvedRow<Row>[],\n reshaped: boolean,\n): readonly ResolvedRow<Row>[] {\n return reshaped\n ? pageRows.filter((entry): entry is ResolvedRow<Row> => !(\"kind\" in entry))\n : rows;\n}\n\n/**\n * `resolveGridView`, memoised per stage: each stage remembers its last\n * inputs and returns its last output when none of them changed identity, so\n * a call that changes one slice of state recomputes only what depends on\n * it. The data stages (filter → sort → group → aggregate → paginate) read\n * `dataColumns`, which carry no width, so a resize or a viewport change\n * leaves `rows`, `displayRows`, `pageRows`, `displayDataRows` and\n * `grandTotal` reference-equal to the previous call's — only `columns` is\n * new. The view object itself is reused when every field is unchanged, so a\n * snapshot-based renderer sees nothing to re-render.\n *\n * Hold one resolver per grid and call it with the current input every time\n * the view is needed; the memo only pays off across calls to the same one.\n */\nexport function createGridViewResolver<Row, Node = string>(): (\n input: GridViewInput<Row, Node>,\n) => GridView<Row, Node> {\n const identify = memoizeLast(identifyRows<Row>);\n const orderColumns = memoizeLast(resolveDataColumns<Row, Node>);\n const showColumns = memoizeLast(applyColumnVisibility<Row, Node>);\n const size = memoizeLast(sizeColumns<Row, Node>);\n const filterAndSort = memoizeLast(resolveShownRows<Row>);\n const group = memoizeLast(groupRows<Row>);\n const aggregate = memoizeLast(withGroupAggregates<Row>);\n const total = memoizeLast(totalAggregates<Row>);\n const page = memoizeLast(paginate<Row>);\n const narrow = memoizeLast(narrowToDataRows<Row>);\n const assemble = memoizeLast(\n (\n dataColumns: readonly DataColumn<Row, Node>[],\n columns: readonly ResolvedColumn<Row, Node>[],\n rows: readonly ResolvedRow<Row>[],\n displayRows: readonly DisplayRow<Row>[],\n pageRows: readonly DisplayRow<Row>[],\n displayDataRows: readonly ResolvedRow<Row>[],\n pageCount: number,\n pageIndex: number,\n grandTotal: AggregateResults,\n ): GridView<Row, Node> => ({\n dataColumns,\n columns,\n rows,\n displayRows,\n pageRows,\n displayDataRows,\n pageCount,\n pageIndex,\n grandTotal,\n }),\n );\n\n return ({ rows: data, getRowId, columns: definitions, state, options }) => {\n const paginated = options.paginated ?? false;\n const aggregates =\n options.aggregates ?? (NO_AGGREGATES as AggregateState<Row>);\n\n const dataColumns = orderColumns(definitions, state.columnOrder);\n // Hidden after ordering, so a hidden column keeps its slot in the order\n // and comes back to it when shown; the data stages below still read\n // every column, so a sort or filter on a hidden one still applies.\n const columns = size(\n showColumns(dataColumns, state.columnVisibility),\n state.columnSizing,\n options.columnSizeDefaults,\n options.resizableColumns,\n options.reorderableColumns,\n options.groupByDraggableColumns,\n options.resizeMode ?? \"fit\",\n options.viewportWidth ?? null,\n );\n\n const rows = filterAndSort(\n identify(data, getRowId),\n state.filter,\n state.columnSort,\n dataColumns,\n );\n // `groupRows` and `withGroupAggregates` each hand back their input\n // untouched when there is nothing to do, so an ungrouped grid without\n // aggregates pays only those checks.\n const displayRows = aggregate(\n group(rows, state.groupBy, state.groupExpansion, dataColumns),\n rows,\n state.groupBy,\n aggregates,\n dataColumns,\n options.groupAggregateDisplay ?? \"inline\",\n );\n const {\n rows: pageRows,\n pageCount,\n pageIndex,\n } = page(displayRows, paginated, state.pagination);\n\n return assemble(\n dataColumns,\n columns,\n rows,\n displayRows,\n pageRows,\n narrow(pageRows, rows, state.groupBy.length > 0 || paginated),\n pageCount,\n pageIndex,\n total(rows, aggregates, dataColumns),\n );\n };\n}\n\n/**\n * What the user is looking at, derived from the rows, the columns, the\n * grid's state and its options in one call: rows filtered → sorted →\n * grouped → aggregated → paginated, and columns ordered → hidden → sized.\n * The one function a renderer, an export or a toolbar calls instead of\n * composing the stages itself, so none of them can disagree about what is\n * shown.\n *\n * Unmemoised — a one-off resolver. A renderer that derives the view on every\n * change holds a `createGridViewResolver()` instead.\n */\nexport function resolveGridView<Row, Node = string>(\n input: GridViewInput<Row, Node>,\n): GridView<Row, Node> {\n return createGridViewResolver<Row, Node>()(input);\n}\n","import type {\n FilterEntry,\n FilterState,\n OperatorFilterEntry,\n PaginationState,\n SortDirection,\n} from \"../types\";\nimport { isScalarList } from \"../util/filterOperators\";\n\n/** A sort or group-by level: a column, and which way it orders. */\ninterface ColumnEntry {\n readonly columnId: string;\n readonly direction?: SortDirection | undefined;\n}\n\n/**\n * The column a whole-stack change is about: the first level whose column or\n * direction differs between the two stacks. `undefined` when they are the\n * same, which is how a setter knows it has nothing to do.\n *\n * A change event names one column because the change it was made for — a\n * header toggle, a drop — touched one. A setter can touch several, and the\n * first is the most useful one to name; the whole stack is in the event.\n */\nexport function changedEntryColumnId(\n previous: readonly ColumnEntry[],\n next: readonly ColumnEntry[],\n): string | undefined {\n const length = Math.max(previous.length, next.length);\n for (let index = 0; index < length; index++) {\n const before = previous[index];\n const after = next[index];\n if (\n before?.columnId !== after?.columnId ||\n before?.direction !== after?.direction\n ) {\n return (after ?? before)?.columnId;\n }\n }\n return undefined;\n}\n\n/**\n * The first id whose position differs between two orders — the column a\n * whole-order change names, for the reason `changedEntryColumnId` gives.\n */\nexport function changedId(\n previous: readonly string[],\n next: readonly string[],\n): string | undefined {\n const length = Math.max(previous.length, next.length);\n for (let index = 0; index < length; index++) {\n if (previous[index] !== next[index]) {\n return next[index] ?? previous[index];\n }\n }\n return undefined;\n}\n\n/**\n * Every key whose value differs between two keyed states — those `next`\n * sets first, in its order, then those only `previous` had.\n */\nexport function changedKeys(\n previous: Readonly<Record<string, unknown>>,\n next: Readonly<Record<string, unknown>>,\n): readonly string[] {\n const keys = new Set([...Object.keys(next), ...Object.keys(previous)]);\n return [...keys].filter((key) => previous[key] !== next[key]);\n}\n\n/** Whether two lists hold the same items in the same order. */\nexport function sameItems<Item>(\n previous: readonly Item[],\n next: readonly Item[],\n): boolean {\n return (\n previous.length === next.length &&\n previous.every((item, index) => item === next[index])\n );\n}\n\nexport function samePagination(\n previous: PaginationState,\n next: PaginationState,\n): boolean {\n return (\n previous.pageIndex === next.pageIndex && previous.pageSize === next.pageSize\n );\n}\n\nfunction sameValue(previous: unknown, next: unknown): boolean {\n return previous instanceof Date && next instanceof Date\n ? previous.getTime() === next.getTime()\n : previous === next;\n}\n\n/** Whether two operator operands hold the same scalars, a list item by item. */\nfunction sameOperand(\n previous: OperatorFilterEntry<unknown>[\"value\"],\n next: OperatorFilterEntry<unknown>[\"value\"],\n): boolean {\n if (isScalarList(previous) || isScalarList(next)) {\n return (\n isScalarList(previous) &&\n isScalarList(next) &&\n previous.length === next.length &&\n previous.every((scalar, index) => sameValue(scalar, next[index]))\n );\n }\n return sameValue(previous, next);\n}\n\nfunction sameEntry<Row>(\n previous: FilterEntry<Row>,\n next: FilterEntry<Row>,\n): boolean {\n if (\"combinator\" in previous || \"combinator\" in next) {\n return (\n \"combinator\" in previous &&\n \"combinator\" in next &&\n previous.combinator === next.combinator &&\n sameFilter(previous.entries, next.entries)\n );\n }\n if (previous.columnId !== next.columnId) {\n return false;\n }\n if (\"predicate\" in previous || \"predicate\" in next) {\n return (\n \"predicate\" in previous &&\n \"predicate\" in next &&\n previous.predicate === next.predicate\n );\n }\n // Before the `value` check: an operator entry usually has a `value` too.\n if (\"operator\" in previous || \"operator\" in next) {\n return (\n \"operator\" in previous &&\n \"operator\" in next &&\n previous.operator === next.operator &&\n sameOperand(previous.value, next.value)\n );\n }\n if (\"value\" in previous || \"value\" in next) {\n return (\n \"value\" in previous &&\n \"value\" in next &&\n sameValue(previous.value, next.value)\n );\n }\n return previous.query === next.query;\n}\n\n/**\n * Whether two filters match the same rows by construction: the same entries,\n * in the same order, each asking the same thing — a `Date` value compared by\n * time, a predicate by identity. A filter read back from JSON is equal to the\n * one that was saved, though not one entry is the same object.\n */\nexport function sameFilter<Row>(\n previous: FilterState<Row>,\n next: FilterState<Row>,\n): boolean {\n return (\n previous.length === next.length &&\n previous.every((entry, index) => {\n const other = next[index];\n return other !== undefined && sameEntry(entry, other);\n })\n );\n}\n","import type {\n CellSelectionMode,\n CellSelectionState,\n SelectedCellRef,\n SelectIntent,\n SelectionDiff,\n SelectionMode,\n SelectionState,\n} from \"../types\";\n\n/** Nothing changed, so nothing to report — shared to save an allocation. */\nconst NO_CHANGE: SelectionDiff = { added: [], removed: [] };\n\n/**\n * Whether two selections hold the same ids in the same order.\n *\n * Order counts because the selection's own order is what makes `at(-1)` the\n * most recently selected; a comparison that ignored it would have a transform\n * return the old reference after a reordering that a consumer can observe.\n */\nfunction sameSelection(a: SelectionState, b: SelectionState): boolean {\n return a.length === b.length && a.every((id, index) => id === b[index]);\n}\n\n/**\n * The selection with `id` added if absent and removed if present — a\n * Ctrl-click, or Space on the focused member.\n *\n * The mode is enforced here rather than by each caller, so `\"single\"` cannot\n * accumulate no matter which interaction reaches it. Returns `selection`\n * itself when `mode` is `false`, keeping the unchanged-reference contract\n * `moveColumnBefore` set: a caller treats an unchanged reference as \"nothing\n * happened\" and neither renders nor reports.\n */\nexport function toggleSelection(\n selection: SelectionState,\n id: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode === false) {\n return selection;\n }\n if (selection.includes(id)) {\n return selection.filter((selectedId) => selectedId !== id);\n }\n return mode === \"single\" ? [id] : [...selection, id];\n}\n\n/**\n * The selection reduced to `id` alone — a plain click, which discards what\n * came before rather than adding to it.\n *\n * Never deselects, so clicking the one selected row leaves it selected.\n * Letting go of it is Ctrl-click's job, and `toggleSelection`'s.\n */\nexport function selectOnly(\n selection: SelectionState,\n id: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode === false) {\n return selection;\n }\n return selection.length === 1 && selection[0] === id ? selection : [id];\n}\n\n/**\n * The selection replaced by every id from `anchorId` to `focusId` inclusive — a\n * Shift-click. The two may be given in either order.\n *\n * Spans `orderedIds`, the order as displayed, rather than the selection's own:\n * the range a user drew across the screen is the range they mean, whatever\n * order they clicked its ends in. Degrades to `selectOnly` under `\"single\"`,\n * where a range has nowhere to go.\n */\nexport function selectRange(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string,\n focusId: string,\n mode: SelectionMode,\n): SelectionState {\n if (mode !== \"multiple\") {\n return selectOnly(selection, focusId, mode);\n }\n\n const anchor = orderedIds.indexOf(anchorId);\n const focus = orderedIds.indexOf(focusId);\n if (anchor === -1 || focus === -1) {\n return selection;\n }\n\n const next = orderedIds.slice(\n Math.min(anchor, focus),\n Math.max(anchor, focus) + 1,\n );\n return sameSelection(selection, next) ? selection : next;\n}\n\n/**\n * Every id in `orderedIds`, or `selection` untouched under any mode but\n * `\"multiple\"` — there is no selecting all of one thing.\n */\nexport function selectAll(\n selection: SelectionState,\n orderedIds: readonly string[],\n mode: SelectionMode,\n): SelectionState {\n if (mode !== \"multiple\") {\n return selection;\n }\n return sameSelection(selection, orderedIds) ? selection : orderedIds;\n}\n\nexport function clearSelection(selection: SelectionState): SelectionState {\n return selection.length === 0 ? selection : [];\n}\n\n/**\n * What one transition added and what it removed.\n *\n * Defined here rather than in an adapter so that every callback reporting a\n * selection change reads one answer, and a select and a deselect fired for the\n * same interaction cannot disagree about which it was.\n */\nexport function diffSelection(\n previous: SelectionState,\n next: SelectionState,\n): SelectionDiff {\n if (previous === next) {\n return NO_CHANGE;\n }\n\n const before = new Set(previous);\n const after = new Set(next);\n return {\n added: next.filter((id) => !before.has(id)),\n removed: previous.filter((id) => !after.has(id)),\n };\n}\n\nexport function isSameCell(\n a: CellSelectionState,\n b: CellSelectionState,\n): boolean {\n if (a === null || b === null) {\n return a === b;\n }\n return a.rowId === b.rowId && a.columnId === b.columnId;\n}\n\n/**\n * The cell selection moved to `cell` — a plain click. Idempotent: clicking the\n * selected cell again leaves it selected, matching `selectOnly`.\n */\nexport function selectCell(\n selection: CellSelectionState,\n cell: SelectedCellRef,\n mode: CellSelectionMode,\n): CellSelectionState {\n if (mode === false || isSameCell(selection, cell)) {\n return selection;\n }\n return cell;\n}\n\n/**\n * The cell selection moved to `cell`, or cleared when it is already there — a\n * Ctrl-click, matching `toggleSelection`.\n */\nexport function toggleCellSelection(\n selection: CellSelectionState,\n cell: SelectedCellRef,\n mode: CellSelectionMode,\n): CellSelectionState {\n if (mode === false) {\n return selection;\n }\n return isSameCell(selection, cell) ? null : cell;\n}\n\n/**\n * The intent a click or key press carries, by the modifiers held with it.\n *\n * `toggleOnClick` makes the unmodified press a toggle — the\n * `selectable.toggleOnClick` checklist behaviour — leaving Shift and Ctrl\n * to mean what they always do.\n */\nexport function intentOf(\n event: {\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n },\n options?: { toggleOnClick?: boolean | undefined },\n): SelectIntent {\n if (event.shiftKey) {\n return \"range\";\n }\n // Cmd on a Mac is Ctrl everywhere else, and both mean the same thing here.\n if (event.ctrlKey || event.metaKey) {\n return \"toggle\";\n }\n return options?.toggleOnClick === true ? \"toggle\" : \"replace\";\n}\n\n/**\n * The transform an intent asks for. A function rather than a branch inside\n * each caller, so a row and a column cannot come to mean different things by\n * the same click.\n */\nexport function applySelectionIntent(\n selection: SelectionState,\n orderedIds: readonly string[],\n anchorId: string | null,\n id: string,\n intent: SelectIntent,\n mode: SelectionMode,\n): SelectionState {\n switch (intent) {\n case \"toggle\":\n return toggleSelection(selection, id, mode);\n // A range with no anchor yet spans from the id to itself, which is the\n // plain click a first Shift-click may as well be.\n case \"range\":\n return selectRange(selection, orderedIds, anchorId ?? id, id, mode);\n default:\n return selectOnly(selection, id, mode);\n }\n}\n","import type { SelectionCallbacks } from \"../options\";\nimport type {\n CellSelectionState,\n ResolvedColumn,\n ResolvedRow,\n SelectionDiff,\n SelectionState,\n} from \"../types\";\nimport { resolveCell, resolveColumns, resolveRows } from \"../util/rows\";\nimport { diffSelection } from \"../util/selection\";\n\n/**\n * Fires every row selection callback for one change, from one diff of it, so\n * that no two can disagree about what the change did. Returns the diff by id,\n * which still counts ids no row on screen answers to — the resolved rows the\n * callbacks carry leave those out.\n */\nexport function reportRowSelection<Row, Node>(\n previous: SelectionState,\n next: SelectionState,\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n callbacks: SelectionCallbacks<Row, Node>,\n): SelectionDiff {\n const diff = diffSelection(previous, next);\n const added = resolveRows(rowsById, diff.added);\n const removed = resolveRows(rowsById, diff.removed);\n\n for (const row of added) {\n callbacks.onRowSelect?.({ row, selection: next });\n }\n if (added.length > 0) {\n callbacks.onRowsSelect?.({ rows: added, selection: next });\n }\n for (const row of removed) {\n callbacks.onRowDeselect?.({ row, selection: next });\n }\n if (removed.length > 0) {\n callbacks.onRowsDeselect?.({ rows: removed, selection: next });\n }\n callbacks.onRowSelectionChange?.({\n added,\n removed,\n selected: resolveRows(rowsById, next),\n selection: next,\n });\n return diff;\n}\n\n/** `reportRowSelection`, for the columns as rendered. */\nexport function reportColumnSelection<Row, Node>(\n previous: SelectionState,\n next: SelectionState,\n columns: readonly ResolvedColumn<Row, Node>[],\n callbacks: SelectionCallbacks<Row, Node>,\n): SelectionDiff {\n const diff = diffSelection(previous, next);\n const added = resolveColumns(columns, diff.added);\n const removed = resolveColumns(columns, diff.removed);\n\n for (const column of added) {\n callbacks.onColumnSelect?.({ column, selection: next });\n }\n if (added.length > 0) {\n callbacks.onColumnsSelect?.({ columns: added, selection: next });\n }\n for (const column of removed) {\n callbacks.onColumnDeselect?.({ column, selection: next });\n }\n if (removed.length > 0) {\n callbacks.onColumnsDeselect?.({ columns: removed, selection: next });\n }\n callbacks.onColumnSelectionChange?.({\n added,\n removed,\n selected: resolveColumns(columns, next),\n selection: next,\n });\n return diff;\n}\n\n/**\n * Fires the cell selection callbacks for one change. The cell left and the\n * cell arrived at are resolved together, so moving between two cells reports\n * the leaving and the arriving as one change.\n */\nexport function reportCellSelection<Row, Node>(\n previous: CellSelectionState,\n next: CellSelectionState,\n rowsById: ReadonlyMap<string, ResolvedRow<Row>>,\n columns: readonly ResolvedColumn<Row, Node>[],\n callbacks: SelectionCallbacks<Row, Node>,\n): void {\n const selected = resolveCell(rowsById, columns, next);\n const deselected = resolveCell(rowsById, columns, previous);\n\n if (deselected !== null) {\n callbacks.onCellDeselect?.({ cell: deselected, selection: next });\n }\n if (selected !== null) {\n callbacks.onCellSelect?.({ cell: selected, selection: next });\n }\n callbacks.onCellSelectionChange?.({\n selected,\n deselected,\n selection: next,\n });\n}\n","import type {\n CellSelectionState,\n GridState,\n GridView,\n ResolvedRow,\n SelectionState,\n} from \"../types\";\nimport { memoizeLast } from \"../util/memoize\";\nimport {\n applySelectionIntent,\n clearSelection,\n isSameCell,\n selectAll,\n selectCell,\n toggleCellSelection,\n toggleSelection,\n} from \"../util/selection\";\nimport { sameItems } from \"./changes\";\nimport type { GridController, GridControllerOptions } from \"./gridController\";\nimport {\n reportCellSelection,\n reportColumnSelection,\n reportRowSelection,\n} from \"./selectionEvents\";\n\n/** What the selection actions need of the controller they belong to. */\nexport interface SelectionContext<Row, Node> {\n readonly getState: () => GridState<Row>;\n readonly getOptions: () => GridControllerOptions<Row, Node>;\n readonly getView: () => GridView<Row, Node>;\n /** The controller's shared commit — see `createGridController`. */\n readonly commit: <K extends keyof GridState<Row>>(\n key: K,\n next: GridState<Row>[K],\n report: () => void,\n ) => void;\n}\n\ntype SelectionActions<Row, Node> = Pick<\n GridController<Row, Node>,\n | \"setRowSelection\"\n | \"selectRows\"\n | \"selectRow\"\n | \"selectAllRows\"\n | \"clearSelection\"\n | \"setColumnSelection\"\n | \"selectColumn\"\n | \"setCellSelection\"\n | \"selectCell\"\n>;\n\nfunction indexRows<Row>(\n rows: readonly ResolvedRow<Row>[],\n): ReadonlyMap<string, ResolvedRow<Row>> {\n return new Map(rows.map((entry) => [entry.rowId, entry]));\n}\n\n/** `ids` without repeats, each where it first appears. */\nfunction distinct(ids: readonly string[]): readonly string[] {\n return [...new Set(ids)];\n}\n\n/**\n * The row, column and cell selection actions of one controller. Kept in a\n * module of their own as the largest group of actions, and the only one with\n * memory beyond the state: the anchor a range is measured from.\n *\n * Rows are resolved against the data rows on the current page and columns\n * against the columns as rendered — what the user can see and click — so a\n * range spans what is adjacent on screen.\n */\nexport function createSelectionActions<Row, Node>(\n grid: SelectionContext<Row, Node>,\n): SelectionActions<Row, Node> {\n /**\n * Where a range is measured from: the last row or column selected by\n * anything but a range, so that repeated Shift-clicks re-draw one span\n * instead of walking the anchor along with them.\n */\n let rowAnchor: string | null = null;\n let columnAnchor: string | null = null;\n const rowsById = memoizeLast(indexRows<Row>);\n\n function modes() {\n const selectable = grid.getOptions().selectable;\n return {\n rows: selectable?.rows ?? false,\n columns: selectable?.columns ?? false,\n cells: selectable?.cells ?? false,\n };\n }\n\n function rowIds(): readonly string[] {\n return grid.getView().displayDataRows.map((entry) => entry.rowId);\n }\n\n function columnIds(): readonly string[] {\n return grid.getView().columns.map((entry) => entry.id);\n }\n\n function commitRows(next: SelectionState): void {\n const previous = grid.getState().rowSelection;\n grid.commit(\"rowSelection\", next, () => {\n const options = grid.getOptions();\n const diff = reportRowSelection(\n previous,\n next,\n rowsById(grid.getView().displayDataRows),\n options,\n );\n options.onSelectionDiff?.({ target: \"rows\", ...diff, selection: next });\n });\n }\n\n function commitColumns(next: SelectionState): void {\n const previous = grid.getState().columnSelection;\n grid.commit(\"columnSelection\", next, () => {\n const options = grid.getOptions();\n const diff = reportColumnSelection(\n previous,\n next,\n grid.getView().columns,\n options,\n );\n options.onSelectionDiff?.({\n target: \"columns\",\n ...diff,\n selection: next,\n });\n });\n }\n\n function commitCell(next: CellSelectionState): void {\n const previous = grid.getState().cellSelection;\n grid.commit(\"cellSelection\", next, () => {\n const view = grid.getView();\n reportCellSelection(\n previous,\n next,\n rowsById(view.displayDataRows),\n view.columns,\n grid.getOptions(),\n );\n });\n }\n\n return {\n setRowSelection(selection) {\n if (!sameItems(grid.getState().rowSelection, selection)) {\n commitRows(selection);\n }\n },\n selectRows(ids, intent = \"replace\") {\n const mode = modes().rows;\n const current = grid.getState().rowSelection;\n if (mode === false || ids.length === 0) {\n return;\n }\n const next =\n intent === \"toggle\"\n ? ids.reduce(\n (selection, id) => toggleSelection(selection, id, mode),\n current,\n )\n : mode === \"single\"\n ? ids.slice(-1)\n : distinct(ids);\n rowAnchor = ids.at(-1) ?? null;\n if (!sameItems(current, next)) {\n commitRows(next);\n }\n },\n selectRow(rowId, intent) {\n const next = applySelectionIntent(\n grid.getState().rowSelection,\n rowIds(),\n rowAnchor,\n rowId,\n intent,\n modes().rows,\n );\n if (intent !== \"range\") {\n rowAnchor = rowId;\n }\n commitRows(next);\n },\n selectAllRows() {\n commitRows(\n selectAll(grid.getState().rowSelection, rowIds(), modes().rows),\n );\n },\n clearSelection() {\n commitRows(clearSelection(grid.getState().rowSelection));\n commitColumns(clearSelection(grid.getState().columnSelection));\n commitCell(null);\n },\n\n setColumnSelection(selection) {\n if (!sameItems(grid.getState().columnSelection, selection)) {\n commitColumns(selection);\n }\n },\n selectColumn(columnId, intent) {\n const next = applySelectionIntent(\n grid.getState().columnSelection,\n columnIds(),\n columnAnchor,\n columnId,\n intent,\n modes().columns,\n );\n if (intent !== \"range\") {\n columnAnchor = columnId;\n }\n commitColumns(next);\n },\n\n setCellSelection(selection) {\n if (!isSameCell(grid.getState().cellSelection, selection)) {\n commitCell(selection);\n }\n },\n selectCell(cell, intent) {\n const current = grid.getState().cellSelection;\n const mode = modes().cells;\n commitCell(\n intent === \"toggle\"\n ? toggleCellSelection(current, cell, mode)\n : selectCell(current, cell, mode),\n );\n },\n };\n}\n","import type { GridOptions } from \"../options\";\nimport type {\n ColumnDefinition,\n ColumnSizingState,\n ColumnVisibilityState,\n GridState,\n GridView,\n GroupByState,\n GroupExpansionState,\n PaginationState,\n} from \"../types\";\nimport { defineColumnsFromRows } from \"../util/grid\";\nimport {\n collapseAllGroups as collapsedGroups,\n expandAllGroups as expandedGroups,\n moveGroupByBefore,\n toggleGroupExpansion as toggledGroupExpansion,\n} from \"../util/grouping\";\nimport { memoizeLast } from \"../util/memoize\";\nimport { moveColumnBefore } from \"../util/ordering\";\nimport { paginateRows } from \"../util/paging\";\nimport { reportError } from \"../util/report\";\nimport { reviveFilter } from \"../util/serialize\";\nimport { resolveColumnWidths, revertColumnSize } from \"../util/sizing\";\nimport { toggleColumnSort as toggledColumnSort } from \"../util/sorting\";\nimport { createGridViewResolver } from \"../util/view\";\nimport { setColumnVisibility as withColumnVisibility } from \"../util/visibility\";\nimport {\n changedEntryColumnId,\n changedId,\n changedKeys,\n sameFilter,\n sameItems,\n samePagination,\n} from \"./changes\";\nimport type { GridController, GridControllerOptions } from \"./gridController\";\nimport { createSelectionActions } from \"./selectionActions\";\n\n/** `pagination.pageSize` an uncontrolled grid starts at when `defaultPagination` omits one — a reasonable default for an ERP-grade dataset. */\nconst DEFAULT_PAGE_SIZE = 25;\n\n/**\n * Stable empty fallbacks: a fresh `[]` per call would change identity each\n * time and defeat every view stage memoised on it.\n */\nconst NO_ROWS: readonly never[] = [];\nconst NO_COLUMNS: readonly never[] = [];\n\ntype SliceKey = keyof GridState<unknown>;\n\nconst SLICE_KEYS = [\n \"columnSizing\",\n \"columnOrder\",\n \"columnVisibility\",\n \"columnSort\",\n \"filter\",\n \"groupBy\",\n \"groupExpansion\",\n \"pagination\",\n \"rowSelection\",\n \"columnSelection\",\n \"cellSelection\",\n] as const satisfies readonly SliceKey[];\n\n/** The option that seeds each slice while it is uncontrolled. */\nconst DEFAULT_OPTION: { readonly [K in SliceKey]: `default${Capitalize<K>}` } =\n {\n columnSizing: \"defaultColumnSizing\",\n columnOrder: \"defaultColumnOrder\",\n columnVisibility: \"defaultColumnVisibility\",\n columnSort: \"defaultColumnSort\",\n filter: \"defaultFilter\",\n groupBy: \"defaultGroupBy\",\n groupExpansion: \"defaultGroupExpansion\",\n pagination: \"defaultPagination\",\n rowSelection: \"defaultRowSelection\",\n columnSelection: \"defaultColumnSelection\",\n cellSelection: \"defaultCellSelection\",\n };\n\n/** The slices the controller keeps itself — those not controlled. */\ntype OwnState<Row> = { -readonly [K in SliceKey]: GridState<Row>[K] };\n\n/** The options read as controlled values: a slice given here is the caller's. */\ntype ControlledState<Row> = {\n readonly [K in SliceKey]?: GridState<Row>[K] | undefined;\n};\n\n/** The slices a filter, sort or grouping change sends back to the first page. */\ntype PagingInputs<Row> = Pick<\n GridState<Row>,\n \"filter\" | \"columnSort\" | \"groupBy\"\n>;\n\nfunction startingState<Row>(options: GridOptions<Row>): OwnState<Row> {\n return {\n columnSizing: options.defaultColumnSizing ?? {},\n columnOrder: options.defaultColumnOrder ?? [],\n columnVisibility: options.defaultColumnVisibility ?? {},\n columnSort: options.defaultColumnSort ?? [],\n filter: options.defaultFilter ?? [],\n groupBy: options.defaultGroupBy ?? [],\n groupExpansion: options.defaultGroupExpansion ?? [],\n pagination: options.defaultPagination ?? {\n pageIndex: 0,\n pageSize: DEFAULT_PAGE_SIZE,\n },\n rowSelection: options.defaultRowSelection ?? [],\n columnSelection: options.defaultColumnSelection ?? [],\n cellSelection: options.defaultCellSelection ?? null,\n };\n}\n\n/**\n * The columns the grid shows: the caller's, or — when it gives none — one per\n * field of the rows, re-inferred only when the rows change.\n */\nfunction definedColumns<Row, Node>(\n columns: readonly ColumnDefinition<Row, Node>[] | undefined,\n rows: readonly Row[] | undefined,\n): readonly ColumnDefinition<Row, Node>[] {\n if (columns !== undefined && columns.length > 0) {\n return columns;\n }\n if (rows !== undefined && rows.length > 0) {\n return defineColumnsFromRows<Row, Node>(rows);\n }\n return NO_COLUMNS;\n}\n\nfunction pagingInputsOf<Row>(state: GridState<Row>): PagingInputs<Row> {\n return {\n filter: state.filter,\n columnSort: state.columnSort,\n groupBy: state.groupBy,\n };\n}\n\n/**\n * Creates the state container for one grid — see `GridController`. Hold one\n * per grid for its whole life: it keeps the uncontrolled slices, and its view\n * is memoised across calls the way `createGridViewResolver`'s is.\n */\nexport function createGridController<Row, Node = string>(\n initial: GridControllerOptions<Row, Node>,\n): GridController<Row, Node> {\n let options = initial;\n const own = startingState(initial);\n const resolveView = createGridViewResolver<Row, Node>();\n const resolveColumns = memoizeLast(definedColumns<Row, Node>);\n const listeners = new Set<() => void>();\n /** Slices already reported as given both ways, so each is reported once. */\n const reportedConflicts = new Set<SliceKey>();\n /**\n * While `restoreState` applies its slices, the callbacks they would fire,\n * held back until every slice is in place.\n */\n let heldReports: (() => void)[] | undefined;\n\n let state = resolveSlices();\n let pagingInputs = pagingInputsOf(state);\n reportConflicts();\n\n function controlledValue<K extends SliceKey>(\n key: K,\n ): GridState<Row>[K] | undefined {\n const controlled: ControlledState<Row> = options;\n return controlled[key];\n }\n\n function isControlled(key: SliceKey): boolean {\n return controlledValue(key) !== undefined;\n }\n\n function resolveSlice<K extends SliceKey>(key: K): GridState<Row>[K] {\n const controlled = controlledValue(key);\n return controlled === undefined ? own[key] : controlled;\n }\n\n function resolveSlices(): GridState<Row> {\n return {\n columnSizing: resolveSlice(\"columnSizing\"),\n columnOrder: resolveSlice(\"columnOrder\"),\n columnVisibility: resolveSlice(\"columnVisibility\"),\n columnSort: resolveSlice(\"columnSort\"),\n filter: resolveSlice(\"filter\"),\n groupBy: resolveSlice(\"groupBy\"),\n groupExpansion: resolveSlice(\"groupExpansion\"),\n pagination: resolveSlice(\"pagination\"),\n rowSelection: resolveSlice(\"rowSelection\"),\n columnSelection: resolveSlice(\"columnSelection\"),\n cellSelection: resolveSlice(\"cellSelection\"),\n };\n }\n\n /**\n * A controlled value and its default together is a contradiction React's\n * own inputs report the same way: the controlled value wins, and the\n * default is never read.\n */\n function reportConflicts(): void {\n for (const key of SLICE_KEYS) {\n const defaultKey = DEFAULT_OPTION[key];\n if (\n reportedConflicts.has(key) ||\n !isControlled(key) ||\n options[defaultKey] === undefined\n ) {\n continue;\n }\n reportedConflicts.add(key);\n reportError(\n `\\`${key}\\` and \\`${defaultKey}\\` are both set — \\`${key}\\` is controlled, so \\`${defaultKey}\\` is ignored.`,\n );\n }\n }\n\n /**\n * Re-resolves every slice after a change, keeping the previous state object\n * when none differs, so a snapshot read twice is the same object.\n *\n * Applies the one rule linking slices: a user on page 7 of a result that\n * filtering, sorting or regrouping just shrank to 2 pages must not be left\n * on an empty page, so a change to any of the three sends an uncontrolled\n * pagination back to the first page. It is a consequence of that change,\n * not a page change of its own, so it reports nothing — the change that\n * caused it already did. A controlled pagination is the caller's to reset.\n */\n function refresh(): void {\n let next = resolveSlices();\n if (\n next.filter !== pagingInputs.filter ||\n next.columnSort !== pagingInputs.columnSort ||\n next.groupBy !== pagingInputs.groupBy\n ) {\n pagingInputs = pagingInputsOf(next);\n if (!isControlled(\"pagination\") && own.pagination.pageIndex !== 0) {\n own.pagination = { ...own.pagination, pageIndex: 0 };\n next = { ...next, pagination: own.pagination };\n }\n }\n state = SLICE_KEYS.every((key) => next[key] === state[key]) ? state : next;\n }\n\n function notify(): void {\n for (const listener of [...listeners]) {\n listener();\n }\n }\n\n /**\n * The shared tail of every action — see `GridController`. `report` fires\n * the slice's callback; it runs after the value is kept, so a callback\n * reading `getState()` or calling another action sees the change.\n */\n function commit<K extends SliceKey>(\n key: K,\n next: GridState<Row>[K],\n report: () => void,\n ): void {\n if (next === state[key]) {\n return;\n }\n if (!isControlled(key)) {\n own[key] = next;\n }\n if (heldReports !== undefined) {\n heldReports.push(report);\n return;\n }\n refresh();\n report();\n notify();\n }\n\n function getView(): GridView<Row, Node> {\n return resolveView({\n rows: options.dataSource ?? NO_ROWS,\n getRowId: options.getRowId,\n columns: resolveColumns(options.columns, options.dataSource),\n state,\n options: {\n paginated: options.paginated,\n aggregates: options.aggregates,\n groupAggregateDisplay: options.groupAggregateDisplay,\n columnSizeDefaults: options.columnSizeDefaults,\n resizableColumns: options.resizableColumns,\n reorderableColumns: options.reorderableColumns,\n groupByDraggableColumns: options.groupByDraggableColumns,\n resizeMode: options.resizeMode,\n viewportWidth: options.viewportWidth,\n },\n });\n }\n\n function commitColumnSizing(\n next: ColumnSizingState,\n columnId: string,\n width: number,\n phase: \"move\" | \"end\",\n ): void {\n commit(\"columnSizing\", next, () => {\n options.onColumnResize?.({ columnId, width, sizing: next, phase });\n });\n }\n\n /**\n * The width a column's definition gives it, before any user resize or fit\n * — what a column reverts to when its sizing entry goes.\n */\n function definedWidth(columnId: string): number {\n const entry = getView().dataColumns.find(\n (candidate) => candidate.id === columnId,\n );\n const [resolved] =\n entry === undefined\n ? []\n : resolveColumnWidths(\n [entry.column],\n {},\n {\n sizes: options.columnSizeDefaults,\n },\n );\n return resolved?.width ?? 0;\n }\n\n /**\n * Reported once per change, naming every column it touched in the order\n * they are shown, whatever order the caller named them in — and ids naming\n * no column last.\n */\n function commitColumnVisibility(next: ColumnVisibilityState): void {\n const previous = state.columnVisibility;\n commit(\"columnVisibility\", next, () => {\n const changed = new Set(changedKeys(previous, next));\n const shown = getView()\n .dataColumns.map((entry) => entry.id)\n .filter((id) => changed.delete(id));\n options.onColumnVisibilityChange?.({\n columnIds: [...shown, ...changed],\n visibility: next,\n });\n });\n }\n\n function changeColumnVisibility(\n columnIds: readonly string[],\n visible: boolean,\n ): void {\n commitColumnVisibility(\n withColumnVisibility(\n getView().dataColumns,\n state.columnVisibility,\n columnIds,\n visible,\n ),\n );\n }\n\n function commitGroupBy(next: GroupByState, columnId: string): void {\n commit(\"groupBy\", next, () => {\n options.onGroupByChange?.({ columnId, groupBy: next });\n });\n }\n\n function commitGroupExpansion(\n next: GroupExpansionState,\n groupId: string | null,\n ): void {\n commit(\"groupExpansion\", next, () => {\n options.onGroupExpansionChange?.({ groupId, expansion: next });\n });\n }\n\n /**\n * The page count reported is over every display row whether or not the\n * grid is paginated, which is what a pager built on the event shows. A\n * pagination equal to the current one — `nextPage` on the last page,\n * `goToPage` to the page shown — reports nothing.\n */\n function commitPagination(next: PaginationState): void {\n if (samePagination(state.pagination, next)) {\n return;\n }\n commit(\"pagination\", next, () => {\n options.onPaginationChange?.({\n pagination: next,\n pageCount: paginateRows(getView().displayRows, next).pageCount,\n });\n });\n }\n\n /**\n * `pageIndex` clamped into the pages that exist, by `paginateRows` itself\n * rather than by hand, so it can never disagree with the page the view\n * shows.\n */\n function goToPage(pageIndex: number): void {\n const current = state.pagination;\n const clamped = paginateRows(getView().displayRows, {\n ...current,\n pageIndex,\n }).pageIndex;\n commitPagination({ ...current, pageIndex: clamped });\n }\n\n /** The page shown, which may sit below a stored index past the last page. */\n function shownPageIndex(): number {\n return paginateRows(getView().displayRows, state.pagination).pageIndex;\n }\n\n const selection = createSelectionActions<Row, Node>({\n getState: () => state,\n getOptions: () => options,\n getView,\n commit,\n });\n\n const controller: GridController<Row, Node> = {\n ...selection,\n getOptions: () => options,\n setOptions(next) {\n options = next;\n reportConflicts();\n refresh();\n },\n getState: () => state,\n getView,\n restoreState(saved) {\n const reports: (() => void)[] = [];\n heldReports = reports;\n try {\n restoreSlices(saved);\n } finally {\n heldReports = undefined;\n }\n if (saved.pagination !== undefined) {\n // Taken as already seen, so the sort, filter or grouping this same\n // call restored does not send the restored page back to the first.\n pagingInputs = pagingInputsOf(resolveSlices());\n }\n refresh();\n for (const report of reports) {\n report();\n }\n if (reports.length > 0) {\n notify();\n }\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n\n setColumnSizing(sizing) {\n const [columnId] = changedKeys(state.columnSizing, sizing);\n if (columnId !== undefined) {\n commitColumnSizing(\n sizing,\n columnId,\n sizing[columnId] ?? definedWidth(columnId),\n \"end\",\n );\n }\n },\n resizeColumn(columnId, width, phase) {\n commitColumnSizing(\n { ...state.columnSizing, [columnId]: width },\n columnId,\n width,\n phase,\n );\n },\n cancelColumnResize(columnId, startSizing, startWidth) {\n commitColumnSizing(\n revertColumnSize(state.columnSizing, startSizing, columnId),\n columnId,\n startWidth,\n \"end\",\n );\n },\n\n setColumnOrder(order) {\n const columnId = changedId(state.columnOrder, order);\n if (columnId === undefined) {\n return;\n }\n commit(\"columnOrder\", order, () => {\n options.onColumnOrderChange?.({ columnId, order });\n });\n },\n /**\n * Applied to every id in display order rather than to the stored order,\n * which starts empty and may name only some columns, so would have\n * nothing to rearrange.\n */\n moveColumn(columnId, beforeId) {\n const orderedIds = getView().dataColumns.map((entry) => entry.id);\n const next = moveColumnBefore(orderedIds, columnId, beforeId);\n if (next === orderedIds) {\n return;\n }\n commit(\"columnOrder\", next, () => {\n options.onColumnOrderChange?.({ columnId, order: next });\n });\n },\n\n setColumnVisibility(visibility) {\n if (changedKeys(state.columnVisibility, visibility).length > 0) {\n commitColumnVisibility(visibility);\n }\n },\n showColumns(columnIds) {\n changeColumnVisibility(columnIds, true);\n },\n hideColumns(columnIds) {\n changeColumnVisibility(columnIds, false);\n },\n\n setFilter(filter) {\n if (sameFilter(state.filter, filter)) {\n return;\n }\n commit(\"filter\", filter, () => {\n options.onFilterChange?.({ filter });\n });\n },\n\n setColumnSort(sort) {\n const columnId = changedEntryColumnId(state.columnSort, sort);\n if (columnId === undefined) {\n return;\n }\n commit(\"columnSort\", sort, () => {\n options.onColumnSortChange?.({ columnId, sort });\n });\n },\n toggleColumnSort(columnId, { stack = false } = {}) {\n const next = toggledColumnSort(state.columnSort, columnId, { stack });\n commit(\"columnSort\", next, () => {\n options.onColumnSortChange?.({ columnId, sort: next });\n });\n },\n clearColumnSort(columnId) {\n const next = state.columnSort.filter(\n (entry) => entry.columnId !== columnId,\n );\n if (next.length === state.columnSort.length) {\n return;\n }\n commit(\"columnSort\", next, () => {\n options.onColumnSortChange?.({ columnId, sort: next });\n });\n },\n\n setGroupBy(groupBy) {\n const columnId = changedEntryColumnId(state.groupBy, groupBy);\n if (columnId !== undefined) {\n commitGroupBy(groupBy, columnId);\n }\n },\n toggleGroupBy(columnId) {\n const grouped = state.groupBy.some(\n (entry) => entry.columnId === columnId,\n );\n commitGroupBy(\n grouped\n ? state.groupBy.filter((entry) => entry.columnId !== columnId)\n : [...state.groupBy, { columnId }],\n columnId,\n );\n },\n moveGroupBy(columnId, beforeColumnId) {\n commitGroupBy(\n moveGroupByBefore(state.groupBy, columnId, beforeColumnId),\n columnId,\n );\n },\n\n setGroupExpansion(expansion) {\n if (!sameItems(state.groupExpansion, expansion)) {\n commitGroupExpansion(expansion, null);\n }\n },\n toggleGroupExpansion(groupId) {\n commitGroupExpansion(\n toggledGroupExpansion(state.groupExpansion, groupId),\n groupId,\n );\n },\n expandAllGroups() {\n commitGroupExpansion(expandedGroups(state.groupExpansion), null);\n },\n collapseAllGroups() {\n commitGroupExpansion(collapsedGroups(getView().displayRows), null);\n },\n\n setPagination: commitPagination,\n goToPage,\n nextPage() {\n goToPage(shownPageIndex() + 1);\n },\n previousPage() {\n goToPage(shownPageIndex() - 1);\n },\n setPageSize(pageSize) {\n const first = { pageIndex: 0, pageSize };\n commitPagination({\n ...first,\n pageIndex: paginateRows(getView().displayRows, first).pageIndex,\n });\n },\n };\n\n /** Each slice `saved` holds, through the action that sets it. */\n function restoreSlices(\n saved: Parameters<GridController<Row, Node>[\"restoreState\"]>[0],\n ): void {\n if (saved.columnSizing !== undefined) {\n controller.setColumnSizing(saved.columnSizing);\n }\n if (saved.columnOrder !== undefined) {\n controller.setColumnOrder(saved.columnOrder);\n }\n if (saved.columnVisibility !== undefined) {\n controller.setColumnVisibility(saved.columnVisibility);\n }\n if (saved.columnSort !== undefined) {\n controller.setColumnSort(saved.columnSort);\n }\n if (saved.filter !== undefined) {\n controller.setFilter(reviveFilter(saved.filter, getView().dataColumns));\n }\n if (saved.groupBy !== undefined) {\n controller.setGroupBy(saved.groupBy);\n }\n if (saved.groupExpansion !== undefined) {\n controller.setGroupExpansion(saved.groupExpansion);\n }\n if (saved.pagination !== undefined) {\n controller.setPagination(saved.pagination);\n }\n if (saved.rowSelection !== undefined) {\n controller.setRowSelection(saved.rowSelection);\n }\n if (saved.columnSelection !== undefined) {\n controller.setColumnSelection(saved.columnSelection);\n }\n if (saved.cellSelection !== undefined) {\n controller.setCellSelection(saved.cellSelection);\n }\n }\n\n return controller;\n}\n","import type { GridController } from \"../controller/gridController\";\nimport type { GridMessages } from \"../messages\";\nimport type { ResolvedRow, SelectionState } from \"../types\";\nimport type {\n GridCommandContext,\n GridCommandHost,\n GridCommandTarget,\n} from \"./types\";\n\n/** What `createCommandContext` builds a context from. */\nexport interface GridCommandContextInput<Row, Node> {\n readonly controller: GridController<Row, Node>;\n readonly target: GridCommandTarget;\n /** The grid's messages, already laid over the defaults — see `resolveMessages`. */\n readonly messages: GridMessages;\n readonly host: GridCommandHost;\n}\n\n/**\n * The rows in `rows` that `selection` names, in `rows`' order. An empty\n * selection — the common case — is answered without walking the rows.\n */\nfunction selectedRowsOf<Row>(\n rows: readonly ResolvedRow<Row>[],\n selection: SelectionState,\n): readonly ResolvedRow<Row>[] {\n if (selection.length === 0) {\n return [];\n }\n const selected = new Set(selection);\n return rows.filter((entry) => selected.has(entry.rowId));\n}\n\n/**\n * A command context for `target`, over the controller's state, view and\n * options as they are now. The controller itself serves as `actions`, typed\n * down to them, so a command cannot reach `setOptions`.\n *\n * `row` and `column` are looked up once here, against every filtered row and\n * every column, hidden ones included, so a target the API names off screen\n * still resolves.\n */\nexport function createCommandContext<Row, Node>({\n controller,\n target,\n messages,\n host,\n}: GridCommandContextInput<Row, Node>): GridCommandContext<Row> {\n const state = controller.getState();\n const view = controller.getView();\n let selectedRows: readonly ResolvedRow<Row>[] | undefined;\n\n return {\n target,\n state,\n view,\n options: controller.getOptions(),\n messages,\n actions: controller,\n host,\n row:\n target.area === \"cell\"\n ? (view.rows.find((entry) => entry.rowId === target.rowId) ?? null)\n : null,\n column:\n \"columnId\" in target\n ? (view.dataColumns.find((entry) => entry.id === target.columnId) ??\n null)\n : null,\n selectedRows: () =>\n (selectedRows ??= selectedRowsOf(view.rows, state.rowSelection)),\n };\n}\n","import type { DataColumn, SelectableConfig, SortDirection } from \"../types\";\nimport { resolveColumnHeaderText } from \"../util/grid\";\nimport { sortDirectionFor } from \"../util/sorting\";\nimport type {\n GridCommand,\n GridCommandContext,\n GridCommandTarget,\n} from \"./types\";\n\n/** The id of every command `builtInCommands` returns. */\nexport type BuiltInCommandId =\n | \"sort.ascending\"\n | \"sort.descending\"\n | \"sort.clear\"\n | \"sort.clearAll\"\n | \"group.add\"\n | \"group.remove\"\n | \"group.clearAll\"\n | \"group.expandAll\"\n | \"group.collapseAll\"\n | \"column.hide\"\n | \"column.autoFit\"\n | \"column.autoFitAll\"\n | \"column.choose\"\n | \"selection.selectAllRows\"\n | \"selection.clear\"\n | \"filter.clearAll\";\n\n/**\n * The icon keys the built-ins carry, which a renderer draws as icons of its\n * own. An app command may use them too, to look like the built-ins.\n */\nexport type BuiltInCommandIcon =\n \"sortAscending\" | \"sortDescending\" | \"group\" | \"hide\" | \"autoFit\";\n\ntype Area = GridCommandTarget[\"area\"];\ntype Column<Row> = DataColumn<Row, unknown>;\ntype Context<Row> = GridCommandContext<Row>;\n\n/**\n * Whether the command was asked for on one of `areas`. Each built-in acts on\n * a column, a row, a group or the whole grid, and is hidden on a target that\n * has none of what it needs — so any id can be listed in any menu unchecked.\n */\nfunction isOn<Row>(context: Context<Row>, areas: readonly Area[]): boolean {\n return areas.includes(context.target.area);\n}\n\n/** The target's column, when the target is one of `areas`. */\nfunction columnOn<Row>(\n context: Context<Row>,\n areas: readonly Area[],\n): Column<Row> | null {\n return isOn(context, areas) ? context.column : null;\n}\n\nfunction isGroupedBy<Row>(context: Context<Row>, columnId: string): boolean {\n return context.state.groupBy.some((entry) => entry.columnId === columnId);\n}\n\nfunction sortableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null &&\n (column.column.sortable ?? context.options.sortableColumns ?? false)\n ? column\n : null;\n}\n\n/** A header's column that may be grouped by, and is not yet. */\nfunction groupableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null &&\n (column.column.groupable ?? context.options.groupableColumns ?? false) &&\n !isGroupedBy(context, column.id)\n ? column\n : null;\n}\n\nfunction groupedColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\", \"group\"]);\n return column !== null && isGroupedBy(context, column.id) ? column : null;\n}\n\nfunction hideableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n return column !== null && column.column.hideable !== false ? column : null;\n}\n\n/**\n * Read off the columns as rendered, where resizability is settled against\n * the grid-level default — and where a hidden column, with no width to fit,\n * is not.\n */\nfunction resizableColumn<Row>(context: Context<Row>): Column<Row> | null {\n const column = columnOn(context, [\"header\"]);\n if (column === null) {\n return null;\n }\n return (\n context.view.columns.find(\n (entry) => entry.id === column.id && entry.resizable,\n ) ?? null\n );\n}\n\nfunction resizableColumnIds<Row>(context: Context<Row>): readonly string[] {\n return context.view.columns\n .filter((entry) => entry.resizable)\n .map((entry) => entry.id);\n}\n\nfunction isAnythingSelectable(\n selectable: SelectableConfig | undefined,\n): boolean {\n return [selectable?.rows, selectable?.columns, selectable?.cells].some(\n (mode) => mode !== undefined && mode !== false,\n );\n}\n\n/** The target's column by name, for a label that names it. */\nfunction columnName<Row>(context: Context<Row>): string {\n return context.column === null\n ? \"\"\n : resolveColumnHeaderText(context.column.column);\n}\n\n/** What a built-in acting on one column says about it. */\ninterface ColumnCommandSpec<Row> {\n readonly id: BuiltInCommandId;\n readonly label: (context: Context<Row>) => string;\n readonly icon?: BuiltInCommandIcon;\n /** The column the command acts on, or `null` where there is none — which hides it. */\n readonly find: (context: Context<Row>) => Column<Row> | null;\n readonly isEnabled?: (column: Column<Row>, context: Context<Row>) => boolean;\n readonly isChecked?: (column: Column<Row>, context: Context<Row>) => boolean;\n readonly execute: (column: Column<Row>, context: Context<Row>) => void;\n}\n\n/**\n * A built-in acting on the column `find` picks out. Every predicate and\n * `execute` look it up again rather than trusting an earlier answer, so each\n * holds up on its own when called with a context it was not resolved in.\n */\nfunction columnCommand<Row>({\n id,\n label,\n icon,\n find,\n isEnabled,\n isChecked,\n execute,\n}: ColumnCommandSpec<Row>): GridCommand<Row> {\n function test(\n predicate: (column: Column<Row>, context: Context<Row>) => boolean,\n ) {\n return (context: Context<Row>) => {\n const column = find(context);\n return column !== null && predicate(column, context);\n };\n }\n return {\n id,\n label,\n icon,\n isVisible: (context) => find(context) !== null,\n isEnabled: isEnabled === undefined ? undefined : test(isEnabled),\n isChecked: isChecked === undefined ? undefined : test(isChecked),\n execute: (context) => {\n const column = find(context);\n if (column !== null) {\n execute(column, context);\n }\n },\n };\n}\n\nfunction sortCommand<Row>(direction: SortDirection): GridCommand<Row> {\n return columnCommand({\n id: direction === \"asc\" ? \"sort.ascending\" : \"sort.descending\",\n label: ({ messages }) =>\n direction === \"asc\" ? messages.sortAscending : messages.sortDescending,\n icon: direction === \"asc\" ? \"sortAscending\" : \"sortDescending\",\n find: sortableColumn,\n isChecked: (column, { state }) =>\n sortDirectionFor(state.columnSort, column.id) === direction,\n execute: (column, { actions }) => {\n actions.setColumnSort([{ columnId: column.id, direction }]);\n },\n });\n}\n\n/**\n * The grid's own commands, one per action its menus and toolbar offer —\n * sorting, grouping, hiding, fitting and choosing columns, selecting and\n * clearing.\n * Labels come from `messages`, so they follow the grid's language.\n *\n * A function rather than a constant so each comes typed for the caller's\n * `Row`; the commands hold no state, and two calls build equal ones.\n */\nexport function builtInCommands<Row>(): readonly GridCommand<Row>[] {\n return [\n sortCommand(\"asc\"),\n sortCommand(\"desc\"),\n // Cleared rather than set, so the change reports this column — the one\n // the announcement names — rather than a key that moved up past it.\n columnCommand({\n id: \"sort.clear\",\n label: ({ messages }) => messages.clearSort,\n find: sortableColumn,\n isEnabled: (column, { state }) =>\n sortDirectionFor(state.columnSort, column.id) !== null,\n execute: (column, { actions }) => {\n actions.clearColumnSort(column.id);\n },\n }),\n {\n id: \"sort.clearAll\",\n label: ({ messages }) => messages.clearAllSorting,\n isVisible: (context) => isOn(context, [\"grid\", \"toolbar\", \"header\"]),\n isEnabled: ({ state }) => state.columnSort.length > 0,\n execute: ({ actions }) => {\n actions.setColumnSort([]);\n },\n },\n columnCommand({\n id: \"group.add\",\n label: (context) => context.messages.groupByColumn(columnName(context)),\n icon: \"group\",\n find: groupableColumn,\n execute: (column, { actions }) => {\n actions.toggleGroupBy(column.id);\n },\n }),\n // Toggled rather than set, so the change reports this column — the one\n // the announcement names — rather than the level that moved up.\n columnCommand({\n id: \"group.remove\",\n label: (context) => context.messages.removeGroupBy(columnName(context)),\n icon: \"group\",\n find: groupedColumn,\n execute: (column, { actions }) => {\n actions.toggleGroupBy(column.id);\n },\n }),\n {\n id: \"group.clearAll\",\n label: ({ messages }) => messages.ungroupAll,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\"]) && context.state.groupBy.length > 0,\n execute: ({ actions }) => {\n actions.setGroupBy([]);\n },\n },\n {\n id: \"group.expandAll\",\n label: ({ messages }) => messages.expandAllGroups,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\", \"group\", \"cell\"]) &&\n context.state.groupBy.length > 0,\n execute: ({ actions }) => {\n actions.expandAllGroups();\n },\n },\n {\n id: \"group.collapseAll\",\n label: ({ messages }) => messages.collapseAllGroups,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\", \"group\", \"cell\"]) &&\n context.state.groupBy.length > 0,\n execute: ({ actions }) => {\n actions.collapseAllGroups();\n },\n },\n columnCommand({\n id: \"column.hide\",\n label: ({ messages }) => messages.hideColumn,\n icon: \"hide\",\n find: hideableColumn,\n // The last column shown stays: a grid with none has no header left to\n // bring one back from.\n isEnabled: (column, { view }) =>\n view.columns.some((entry) => entry.id !== column.id),\n execute: (column, { actions }) => {\n actions.hideColumns([column.id]);\n },\n }),\n columnCommand({\n id: \"column.autoFit\",\n label: ({ messages }) => messages.autoFitColumn,\n icon: \"autoFit\",\n find: resizableColumn,\n execute: (column, { host }) => {\n host.autoFitColumns([column.id]);\n },\n }),\n {\n id: \"column.autoFitAll\",\n label: ({ messages }) => messages.autoFitAllColumns,\n icon: \"autoFit\",\n isVisible: (context) =>\n isOn(context, [\"grid\", \"toolbar\", \"header\"]) &&\n resizableColumnIds(context).length > 0,\n execute: (context) => {\n context.host.autoFitColumns(resizableColumnIds(context));\n },\n },\n // The target goes along, so the renderer opens the chooser where it was\n // asked for: beside the toolbar button, below the header, or at the\n // grid's corner for a call from nowhere in particular.\n {\n id: \"column.choose\",\n label: ({ messages }) => messages.chooseColumns,\n isVisible: (context) => isOn(context, [\"grid\", \"toolbar\", \"header\"]),\n execute: ({ host, target }) => {\n host.openPanel(\"columnChooser\", target);\n },\n },\n {\n id: \"selection.selectAllRows\",\n label: ({ messages }) => messages.selectAllRows,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"cell\"]) &&\n context.options.selectable?.rows === \"multiple\",\n isEnabled: ({ view }) => view.displayDataRows.length > 0,\n execute: ({ actions }) => {\n actions.selectAllRows();\n },\n },\n {\n id: \"selection.clear\",\n label: ({ messages }) => messages.clearSelection,\n isVisible: (context) =>\n isOn(context, [\"grid\", \"cell\", \"header\"]) &&\n isAnythingSelectable(context.options.selectable),\n isEnabled: ({ state }) =>\n state.rowSelection.length > 0 ||\n state.columnSelection.length > 0 ||\n state.cellSelection !== null,\n execute: ({ actions }) => {\n actions.clearSelection();\n },\n },\n {\n id: \"filter.clearAll\",\n label: ({ messages }) => messages.clearFilters,\n isVisible: (context) => isOn(context, [\"grid\", \"toolbar\", \"header\"]),\n isEnabled: ({ state }) => state.filter.length > 0,\n execute: ({ actions }) => {\n actions.setFilter([]);\n },\n },\n ];\n}\n","import { reportError } from \"../util/report\";\nimport { builtInCommands } from \"./builtInCommands\";\nimport type { GridCommand, GridCommandContext } from \"./types\";\n\n/** Whether `command` shows on `context`'s target. */\nexport function isCommandVisible<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): boolean {\n return command.isVisible?.(context) ?? true;\n}\n\n/** Whether `command` can run on `context`'s target. */\nexport function isCommandEnabled<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): boolean {\n return command.isEnabled?.(context) ?? true;\n}\n\n/**\n * Every command a grid knows, by id: the built-ins, then `commands` — an app\n * command with a built-in's id replacing it, so every menu and toolbar\n * listing that id gets the app's version (translated, gated by a privilege,\n * or doing something else) without being changed itself.\n *\n * A fresh map per call; a renderer resolves it once per change to\n * `commands`, not per menu.\n */\nexport function resolveCommands<Row>(\n commands: readonly GridCommand<Row>[] | undefined,\n): ReadonlyMap<string, GridCommand<Row>> {\n const registry = new Map(\n builtInCommands<Row>().map((command) => [command.id, command]),\n );\n for (const command of commands ?? []) {\n if (command.id === \"separator\") {\n reportError(\n \"a command cannot have the id `separator`, which a menu reads as a separator, so it is left out.\",\n );\n continue;\n }\n registry.set(command.id, command);\n }\n return registry;\n}\n\n/**\n * Runs `command` when it is visible and enabled on `context`'s target, and\n * says whether it did — so a renderer reports only a command that ran, and a\n * stale button or a call through the API cannot run one the grid's state no\n * longer allows.\n */\nexport function runCommand<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): boolean {\n if (\n !isCommandVisible(command, context) ||\n !isCommandEnabled(command, context)\n ) {\n return false;\n }\n command.execute(context);\n return true;\n}\n","import {\n isCommandEnabled,\n isCommandVisible,\n runCommand,\n} from \"../commands/registry\";\nimport type { GridCommand, GridCommandContext } from \"../commands/types\";\nimport { reportError } from \"../util/report\";\nimport type {\n MenuEntry,\n MenuItemEntry,\n MenuSubmenuEntry,\n ResolvedMenuEntry,\n ResolvedMenuItem,\n ResolvedMenuSubmenu,\n} from \"./types\";\n\n/** What `resolveMenu` resolves a menu's entries against. */\nexport interface MenuResolveOptions<Row> {\n /** Every command the grid knows, by id — see `resolveCommands`. */\n readonly commands: ReadonlyMap<string, GridCommand<Row>>;\n readonly context: GridCommandContext<Row>;\n}\n\n/**\n * Unknown ids already reported, per command map. A toolbar is resolved again\n * on every change to the grid, and one typo should say so once, not every\n * time; keyed weakly, so a map the renderer drops takes its ids with it.\n */\nconst reportedUnknownIds = new WeakMap<object, Set<string>>();\n\nfunction reportUnknownId(commands: object, id: string): void {\n let reported = reportedUnknownIds.get(commands);\n if (reported === undefined) {\n reported = new Set();\n reportedUnknownIds.set(commands, reported);\n }\n if (reported.has(id)) {\n return;\n }\n reported.add(id);\n reportError(\n `the menu or toolbar entry \\`${id}\\` names no command, so it is left out.`,\n );\n}\n\n/** A label or flag an entry gives outright, or as a function of the context. */\nfunction evaluate<Row, Value>(\n value: Value | ((context: GridCommandContext<Row>) => Value),\n context: GridCommandContext<Row>,\n): Value {\n // `Value` is never itself a function here — a label is a string, a flag a\n // boolean — so a function is always the form that reads the context.\n return typeof value === \"function\"\n ? (value as (context: GridCommandContext<Row>) => Value)(context)\n : value;\n}\n\nfunction commandItem<Row>(\n command: GridCommand<Row>,\n context: GridCommandContext<Row>,\n): ResolvedMenuItem | null {\n if (!isCommandVisible(command, context)) {\n return null;\n }\n return {\n type: \"item\",\n id: command.id,\n label: evaluate(command.label, context),\n icon: command.icon,\n shortcut: command.shortcut,\n disabled: !isCommandEnabled(command, context),\n checked: command.isChecked?.(context),\n run: () => runCommand(command, context),\n };\n}\n\nfunction inlineItem<Row>(\n entry: MenuItemEntry<Row>,\n context: GridCommandContext<Row>,\n): ResolvedMenuItem | null {\n if (evaluate(entry.hidden ?? false, context)) {\n return null;\n }\n const disabled = evaluate(entry.disabled ?? false, context);\n return {\n type: \"item\",\n id: entry.id,\n label: evaluate(entry.label, context),\n icon: entry.icon,\n shortcut: entry.shortcut,\n disabled,\n checked:\n entry.checked === undefined\n ? undefined\n : evaluate(entry.checked, context),\n run: () => {\n if (disabled) {\n return false;\n }\n entry.onSelect(context);\n return true;\n },\n };\n}\n\n/**\n * `entries` with no separator first, last, or next to another — what is\n * left once the items between two separators have all been dropped. An\n * entry `isEdge` picks out — a toolbar's spacer — already parts what is on\n * either side of it, so a separator next to one goes too, as at the ends.\n */\nexport function collapseSeparators<Entry extends { readonly type: string }>(\n entries: readonly Entry[],\n isEdge: (entry: Entry) => boolean = () => false,\n): readonly Entry[] {\n const collapsed: Entry[] = [];\n for (const entry of entries) {\n const previous = collapsed.at(-1);\n if (entry.type !== \"separator\") {\n if (isEdge(entry) && previous?.type === \"separator\") {\n collapsed.pop();\n }\n collapsed.push(entry);\n } else if (\n previous !== undefined &&\n previous.type !== \"separator\" &&\n !isEdge(previous)\n ) {\n collapsed.push(entry);\n }\n }\n if (collapsed.at(-1)?.type === \"separator\") {\n collapsed.pop();\n }\n return collapsed;\n}\n\n/**\n * One entry resolved, `null` when it shows nothing — what `resolveMenu` does\n * to each of its entries, and a toolbar to each it shares with menus.\n * `index` is the entry's place among those it was listed with, which keys a\n * separator.\n */\nexport function resolveMenuEntry<Row>(\n entry: MenuEntry<Row>,\n index: number,\n options: MenuResolveOptions<Row>,\n): ResolvedMenuEntry | null {\n const { commands, context } = options;\n if (entry === \"separator\") {\n return { type: \"separator\", key: `separator-${String(index)}` };\n }\n if (typeof entry === \"string\") {\n const command = commands.get(entry);\n if (command === undefined) {\n reportUnknownId(commands, entry);\n return null;\n }\n return commandItem(command, context);\n }\n return entry.type === \"item\"\n ? inlineItem(entry, context)\n : resolveSubmenu(entry, options);\n}\n\nfunction resolveSubmenu<Row>(\n entry: MenuSubmenuEntry<Row>,\n options: MenuResolveOptions<Row>,\n): ResolvedMenuSubmenu | null {\n const items = resolveMenu(entry.items, options);\n return items.length === 0\n ? null\n : {\n type: \"submenu\",\n id: entry.id,\n label: evaluate(entry.label, options.context),\n icon: entry.icon,\n items,\n };\n}\n\n/**\n * A menu's entries resolved against the grid as `context` sees it, ready to\n * draw:\n *\n * - A command id becomes its command's item, and a hidden command or item\n * is left out. An id naming no command is left out too, and reported once\n * per command map through `console.error`.\n * - Labels become strings and flags booleans; `checked` stays `undefined`\n * for an item that is not checkable.\n * - A submenu is resolved the same way, and left out when nothing in it\n * shows.\n * - Separators never lead, trail or double up, however the items around\n * them came and went.\n *\n * An empty result means there is nothing to show — no grid menu at all\n * here.\n */\nexport function resolveMenu<Row>(\n entries: readonly MenuEntry<Row>[],\n options: MenuResolveOptions<Row>,\n): readonly ResolvedMenuEntry[] {\n return collapseSeparators(\n entries\n .map((entry, index) => resolveMenuEntry(entry, index, options))\n .filter((entry) => entry !== null),\n );\n}\n","import type { BuiltInCommandId } from \"../commands/builtInCommands\";\nimport type { GridCommandContext, GridCommandTarget } from \"../commands/types\";\nimport type { MenuEntry } from \"./types\";\n\n/** The parts of a grid that open a context menu of their own. */\nexport type GridContextMenuArea = \"header\" | \"cell\" | \"group\" | \"body\";\n\n/**\n * Where a context menu opens: a command target in one of the context menu\n * areas — a column header, a data cell, a group header row, or empty space\n * in the body — or in `Area` alone.\n */\nexport type GridContextMenuTarget<\n Area extends GridContextMenuArea = GridContextMenuArea,\n> = Extract<GridCommandTarget, { readonly area: Area }>;\n\n/** What `onContextMenuOpenChange` is told as a context menu opens or closes. */\nexport interface ContextMenuOpenChangeEvent {\n readonly open: boolean;\n /** Where the menu opened, or where the one closing had. */\n readonly target: GridContextMenuTarget;\n}\n\n/** What a function given for an area is asked, each time its menu opens. */\nexport interface GridContextMenuRequest<\n Row,\n Area extends GridContextMenuArea = GridContextMenuArea,\n> {\n /** Where the menu opens. */\n readonly target: GridContextMenuTarget<Area>;\n /** The area's default entries, to keep, trim, reorder or add to. */\n readonly defaults: readonly MenuEntry<Row>[];\n /** The grid as the menu sees it — the context its items run in. */\n readonly context: GridCommandContext<Row>;\n}\n\n/**\n * An area's menu: its entries, or a function that works them out each time\n * the menu opens — from where it opens, the area's defaults and the grid's\n * state. A function giving `null` or `[]` shows no grid menu there, so the\n * browser's own menu shows.\n */\nexport type GridContextMenuEntries<\n Row,\n Area extends GridContextMenuArea = GridContextMenuArea,\n> =\n | readonly MenuEntry<Row>[]\n | ((\n request: GridContextMenuRequest<Row, Area>,\n ) => readonly MenuEntry<Row>[] | null);\n\n/**\n * A grid's context menus, by area, in the vocabulary every grid menu is\n * written in. An area left out shows its defaults; one given `[]` shows no\n * grid menu, so the browser's own menu shows there.\n */\nexport interface GridContextMenuOptions<Row> {\n /** A column header's menu. */\n readonly header?: GridContextMenuEntries<Row, \"header\"> | undefined;\n /** A data cell's menu, acting on its row and cell. */\n readonly cell?: GridContextMenuEntries<Row, \"cell\"> | undefined;\n /** A group header row's menu. */\n readonly group?: GridContextMenuEntries<Row, \"group\"> | undefined;\n /** The menu of the body's empty space, below the last row or in a grid with none. */\n readonly body?: GridContextMenuEntries<Row, \"body\"> | undefined;\n}\n\n/**\n * The menu each area shows unless the grid says otherwise — built-in\n * commands only, each hidden where it has nothing to act on, so the menu a\n * column header shows holds only what that column can do. The body has\n * none: empty space keeps the browser's menu until a grid gives it one.\n */\nexport const defaultContextMenu: {\n readonly [Area in GridContextMenuArea]: readonly (\n BuiltInCommandId | \"separator\"\n )[];\n} = {\n header: [\n \"sort.ascending\",\n \"sort.descending\",\n \"sort.clear\",\n \"separator\",\n \"group.add\",\n \"group.remove\",\n \"separator\",\n \"column.autoFit\",\n \"column.autoFitAll\",\n \"separator\",\n \"column.hide\",\n \"column.choose\",\n ],\n cell: [\n \"selection.selectAllRows\",\n \"selection.clear\",\n \"separator\",\n \"group.expandAll\",\n \"group.collapseAll\",\n ],\n group: [\"group.expandAll\", \"group.collapseAll\", \"separator\", \"group.remove\"],\n body: [],\n};\n\n/**\n * Whether the `contextMenu` option opens a grid menu on `area` at all: it is\n * on, and gives the area entries or a function rather than `[]`. A function\n * may still give no menu for one place or another; this answers for the\n * area, as a cell's `aria-keyshortcuts` needs to before anything is asked.\n */\nexport function hasContextMenu<Row>(\n contextMenu: boolean | GridContextMenuOptions<Row> | undefined,\n area: GridContextMenuArea,\n): boolean {\n if (contextMenu === undefined || contextMenu === false) {\n return false;\n }\n const entries =\n (contextMenu === true ? undefined : contextMenu[area]) ??\n defaultContextMenu[area];\n return typeof entries === \"function\" || entries.length > 0;\n}\n\n/** What an area's option gives one request: its defaults when left out. */\nfunction entriesFor<Row, Area extends GridContextMenuArea>(\n given: GridContextMenuEntries<Row, Area> | undefined,\n request: GridContextMenuRequest<Row, Area>,\n): readonly MenuEntry<Row>[] {\n if (given === undefined) {\n return request.defaults;\n }\n return typeof given === \"function\" ? (given(request) ?? []) : given;\n}\n\n/**\n * The entries a grid's `contextMenu` option gives the place `context.target`\n * names, to resolve with `resolveMenu` in that same context: none while the\n * option is off — left out or `false` — or for a target no context menu\n * opens on; the area's defaults under `true` or when the option leaves the\n * area out; the entries it lists; or what its function gives this request.\n * No entries means no grid menu there.\n */\nexport function contextMenuEntries<Row>(\n contextMenu: boolean | GridContextMenuOptions<Row> | undefined,\n context: GridCommandContext<Row>,\n): readonly MenuEntry<Row>[] {\n if (contextMenu === undefined || contextMenu === false) {\n return [];\n }\n const options: GridContextMenuOptions<Row> =\n contextMenu === true ? {} : contextMenu;\n const { target } = context;\n switch (target.area) {\n case \"header\":\n return entriesFor(options.header, {\n target,\n defaults: defaultContextMenu.header,\n context,\n });\n case \"cell\":\n return entriesFor(options.cell, {\n target,\n defaults: defaultContextMenu.cell,\n context,\n });\n case \"group\":\n return entriesFor(options.group, {\n target,\n defaults: defaultContextMenu.group,\n context,\n });\n case \"body\":\n return entriesFor(options.body, {\n target,\n defaults: defaultContextMenu.body,\n context,\n });\n default:\n return [];\n }\n}\n","import type { ResolvedMenuEntry } from \"./types\";\n\n/** Where an arrow, Home or End key moves a menu's focus. */\nexport type MenuMove = \"next\" | \"previous\" | \"first\" | \"last\";\n\n/** Where the search for the next item begins, before skipping separators. */\nfunction startIndex(count: number, from: number, move: MenuMove): number {\n const focused = from >= 0 && from < count;\n switch (move) {\n case \"first\":\n return 0;\n case \"last\":\n return count - 1;\n case \"next\":\n return focused ? from + 1 : 0;\n case \"previous\":\n return focused ? from - 1 : count - 1;\n }\n}\n\n/**\n * The index of the item focus moves to from `from` — `-1` when nothing is\n * focused yet, so `\"next\"` lands on the first item and `\"previous\"` on the\n * last. Separators are skipped and `\"next\"`/`\"previous\"` wrap round the\n * ends; disabled items count, since they stay focusable for a screen reader\n * to find. `-1` when there is no item at all.\n *\n * Takes anything with a `type`, so a behaviour that reads its items off the\n * page can pass `{ type: \"item\" }` for each.\n */\nexport function nextMenuIndex(\n entries: readonly Pick<ResolvedMenuEntry, \"type\">[],\n from: number,\n move: MenuMove,\n): number {\n const count = entries.length;\n const step = move === \"next\" || move === \"first\" ? 1 : -1;\n const start = startIndex(count, from, move);\n for (let offset = 0; offset < count; offset++) {\n const index = (((start + step * offset) % count) + count) % count;\n if (entries[index]?.type !== \"separator\") {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The index of the item `query` — what was typed, buffered for a moment —\n * picks, matched case-insensitively against the start of each label and\n * wrapping round the end; `-1` when none matches.\n *\n * `from` is the item focused now. A single letter, or the same letter\n * typed again and again, searches from the item after it, so repeating a\n * letter steps through every item it starts. A longer query searches from\n * `from` itself, so the item already found stays put while what is typed\n * still matches it.\n */\nexport function typeaheadIndex(\n labels: readonly string[],\n from: number,\n query: string,\n): number {\n const typed = query.toLowerCase();\n const firstCodePoint = typed.codePointAt(0);\n if (firstCodePoint === undefined) {\n return -1;\n }\n const first = String.fromCodePoint(firstCodePoint);\n const repeated = typed.replaceAll(first, \"\") === \"\";\n const prefix = repeated ? first : typed;\n const start = repeated ? from + 1 : Math.max(from, 0);\n for (let offset = 0; offset < labels.length; offset++) {\n const index = (start + offset) % labels.length;\n if (labels[index]?.toLowerCase().startsWith(prefix) === true) {\n return index;\n }\n }\n return -1;\n}\n","import type { BuiltInCommandId } from \"../commands/builtInCommands\";\nimport type { ToolbarEntry } from \"./types\";\n\n/** A grid's toolbar: what it lists, and what a screen reader calls it. */\nexport interface GridToolbarOptions<Row> {\n /** The toolbar's entries, in order. Left out, the defaults. */\n readonly items?: readonly ToolbarEntry<Row>[] | undefined;\n /** The toolbar's accessible name. Left out, `messages.toolbarLabel`. */\n readonly label?: string | undefined;\n}\n\n/**\n * What a toolbar lists unless the grid says otherwise: the search box, then\n * the free space, then \"Clear filters\" and \"Choose columns\" at the far end.\n */\nexport const defaultToolbar: readonly (\n BuiltInCommandId | \"search\" | \"spacer\"\n)[] = [\"search\", \"spacer\", \"filter.clearAll\", \"column.choose\"];\n\n/**\n * The entries a grid's `toolbar` option lists, to resolve with\n * `resolveToolbar`: none while it is off — left out or `false` — the\n * defaults under `true` or an object without `items`, else its `items`.\n * No entries means no toolbar.\n */\nexport function toolbarEntries<Row>(\n toolbar: boolean | GridToolbarOptions<Row> | undefined,\n): readonly ToolbarEntry<Row>[] {\n if (toolbar === undefined || toolbar === false) {\n return [];\n }\n return (toolbar === true ? undefined : toolbar.items) ?? defaultToolbar;\n}\n","import type { GridCommand, GridCommandContext } from \"../commands/types\";\nimport { collapseSeparators, resolveMenuEntry } from \"../menu/resolveMenu\";\nimport type {\n GridToolbarTarget,\n ResolvedToolbarItem,\n ToolbarEntry,\n} from \"./types\";\n\n/** What `resolveToolbar` resolves a toolbar's entries against. */\nexport interface ToolbarResolveOptions<Row> {\n /** Every command the grid knows, by id — see `resolveCommands`. */\n readonly commands: ReadonlyMap<string, GridCommand<Row>>;\n /**\n * The context an item resolves and runs in, for its target — the item\n * itself, or the dropdown an item in one is listed under. A command that\n * opens a panel anchors it there.\n */\n readonly contextFor: (target: GridToolbarTarget) => GridCommandContext<Row>;\n}\n\nfunction isSpacer(entry: ResolvedToolbarItem): boolean {\n return entry.type === \"spacer\";\n}\n\n/**\n * A toolbar's entries resolved against the grid, ready to draw, by the\n * rules `resolveMenu` follows:\n *\n * - A command id becomes its command's button, and an inline item a button\n * of its own; either is a toggle, with `pressed`, when it is checkable. A\n * hidden one is left out, and so is an id naming no command, reported\n * once per command map through `console.error`.\n * - A submenu becomes a dropdown, its items resolved as a menu's, and is\n * left out when nothing in it shows.\n * - `\"search\"`, `\"spacer\"` and custom entries stay as they are.\n * - Separators never lead, trail, double up or sit next to a spacer, which\n * already parts what is on either side of it.\n *\n * Resolve again whenever the grid changes, so each button's label, flags\n * and `run` follow its state.\n */\nexport function resolveToolbar<Row>(\n entries: readonly ToolbarEntry<Row>[],\n options: ToolbarResolveOptions<Row>,\n): readonly ResolvedToolbarItem[] {\n const { commands, contextFor } = options;\n\n function resolveEntry(\n entry: ToolbarEntry<Row>,\n index: number,\n ): ResolvedToolbarItem | null {\n if (entry === \"search\") {\n return { type: \"search\", key: \"search\" };\n }\n if (entry === \"spacer\") {\n return { type: \"spacer\", key: `spacer-${String(index)}` };\n }\n if (typeof entry === \"object\" && entry.type === \"custom\") {\n return { type: \"custom\", id: entry.id, key: entry.id };\n }\n if (entry === \"separator\") {\n return { type: \"separator\", key: `separator-${String(index)}` };\n }\n const resolved = resolveMenuEntry(entry, index, {\n commands,\n context: contextFor({\n area: \"toolbar\",\n itemId: typeof entry === \"string\" ? entry : entry.id,\n }),\n });\n if (resolved === null || resolved.type === \"separator\") {\n return resolved;\n }\n if (resolved.type === \"submenu\") {\n return { ...resolved, type: \"menu\", key: resolved.id };\n }\n const { checked, ...item } = resolved;\n return { ...item, type: \"button\", key: item.id, pressed: checked };\n }\n\n return collapseSeparators(\n entries.map(resolveEntry).filter((entry) => entry !== null),\n isSpacer,\n );\n}\n","import { collapseSeparators } from \"../menu/resolveMenu\";\nimport type { ResolvedMenuEntry } from \"../menu/types\";\nimport type { ResolvedToolbarItem } from \"./types\";\n\n/** What `fitToolbarItems` fits: a toolbar's entries, by width, into its space. */\nexport interface ToolbarFitInput {\n /** Each entry's width, in order — `0` for a spacer, whose width is only the space left over. */\n readonly widths: readonly number[];\n /** The width the entries share. */\n readonly available: number;\n /** The width of the \"More\" button the entries that do not fit go into. */\n readonly moreWidth: number;\n /** Whether each entry, in order, stays however little room there is. */\n readonly pinned: readonly boolean[];\n}\n\n/**\n * How many of a toolbar's entries fit, from the start: the first `count`\n * stay in the toolbar, with every pinned entry after them, and the rest go\n * into a \"More\" menu.\n *\n * Pinned entries take their room first, wherever they are. Room for \"More\"\n * is kept only when something does not fit — when everything does, the\n * result is every entry and no \"More\" is drawn. Entries are taken in order\n * and the first that does not fit ends the count, so the toolbar keeps its\n * order rather than filling gaps with later, narrower entries; one with no\n * width, a spacer, fits wherever the entries before it did.\n */\nexport function fitToolbarItems({\n widths,\n available,\n moreWidth,\n pinned,\n}: ToolbarFitInput): number {\n const total = widths.reduce((sum, width) => sum + width, 0);\n if (total <= available) {\n return widths.length;\n }\n let used =\n moreWidth +\n widths.reduce((sum, width, index) => sum + (pinned[index] ? width : 0), 0);\n for (const [index, width] of widths.entries()) {\n if (!pinned[index]) {\n used += width;\n if (used > available) {\n return index;\n }\n }\n }\n return widths.length;\n}\n\n/**\n * Whether a toolbar entry stays in the toolbar however narrow it gets: the\n * search box and custom entries, which have no menu item to become.\n */\nexport function isPinnedToolbarItem(\n item: Pick<ResolvedToolbarItem, \"type\">,\n): boolean {\n return item.type === \"search\" || item.type === \"custom\";\n}\n\n/** A toolbar split at the count `fitToolbarItems` gave — see `splitToolbarItems`. */\nexport interface ToolbarSplit {\n /** What stays in the toolbar. */\n readonly shown: readonly ResolvedToolbarItem[];\n /** The \"More\" menu's entries, empty when everything fits. */\n readonly overflow: readonly ResolvedMenuEntry[];\n}\n\n/** An entry that did not fit, as the \"More\" menu lists it; `null` for a spacer. */\nfunction asMenuEntry(item: ResolvedToolbarItem): ResolvedMenuEntry | null {\n switch (item.type) {\n case \"button\":\n return {\n type: \"item\",\n id: item.id,\n label: item.label,\n icon: item.icon,\n shortcut: item.shortcut,\n disabled: item.disabled,\n checked: item.pressed,\n run: item.run,\n };\n case \"menu\":\n return {\n type: \"submenu\",\n id: item.id,\n label: item.label,\n icon: item.icon,\n items: item.items,\n };\n case \"separator\":\n return item;\n default:\n return null;\n }\n}\n\n/**\n * `items` split at the first `fit`: those before it, and every pinned item,\n * stay in the toolbar; the rest become the \"More\" menu's entries — a button\n * an item, checked where it was pressed, and a dropdown a submenu. Neither\n * side keeps a separator at its ends, doubled, or beside a spacer.\n */\nexport function splitToolbarItems(\n items: readonly ResolvedToolbarItem[],\n fit: number,\n): ToolbarSplit {\n const fits = (item: ResolvedToolbarItem, index: number) =>\n index < fit || isPinnedToolbarItem(item);\n return {\n shown: collapseSeparators(\n items.filter(fits),\n (item) => item.type === \"spacer\",\n ),\n overflow: collapseSeparators(\n items\n .filter((item, index) => !fits(item, index))\n .map(asMenuEntry)\n .filter((entry) => entry !== null),\n ),\n };\n}\n","import type { FilterState } from \"../types\";\nimport { filterQueryFor, setColumnFilter } from \"../util/filtering\";\n\n/**\n * What a search box shows for `filter`: the global text entry's query — the\n * one naming no column — without the `%` anchors that make it a \"contains\"\n * match, or `\"\"` when there is none. A `%` the user typed inside the text\n * stays: only the first and last characters are anchors.\n */\nexport function searchTextOf<Row>(filter: FilterState<Row>): string {\n const query = filterQueryFor(filter) ?? \"\";\n const start = query.startsWith(\"%\") ? 1 : 0;\n const end = query.endsWith(\"%\") ? -1 : undefined;\n return query.slice(start, end);\n}\n\n/**\n * `filter` with its global text entry set to search for `text` anywhere in\n * any column — the query `%text%` — or removed for an empty `text`. Every\n * entry naming a column stays as it was. `filter` itself, unchanged, when\n * it already searches for `text`.\n *\n * `text` is written as typed, spaces and all: a search box reads its text\n * back from the filter, and trimming here would take a space away from\n * under the caret as the user types it.\n */\nexport function setSearchText<Row>(\n filter: FilterState<Row>,\n text: string,\n): FilterState<Row> {\n return setColumnFilter(filter, undefined, text === \"\" ? \"\" : `%${text}%`);\n}\n","/**\n * The header's row index. One coordinate space covers the header and the body\n * so that arrowing up out of the first row reaches the header without a case\n * of its own, and every other move is plain arithmetic.\n */\nexport const HEADER_ROW = -1;\n\n/** The cell the grid's single tab stop sits on. */\nexport interface GridFocus {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\n/** The modifier keys held with a navigation key press. */\nexport interface NavigationModifiers {\n readonly ctrlKey: boolean;\n readonly metaKey: boolean;\n readonly altKey: boolean;\n readonly shiftKey: boolean;\n}\n\n/**\n * Holds a coordinate inside the grid, so that a focus surviving a column\n * removal or a shorter page never leaves the grid with no tab stop at all —\n * which is a grid a keyboard cannot reach.\n */\nexport function clampFocus(\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n): GridFocus {\n return {\n rowIndex: Math.min(Math.max(focus.rowIndex, HEADER_ROW), rowCount - 1),\n columnIndex: Math.min(\n Math.max(focus.columnIndex, 0),\n Math.max(columnCount - 1, 0),\n ),\n };\n}\n\n/** Never treats any row as unreachable — the default when a caller has no skippable rows at all. */\nfunction noRowsSkippable(): boolean {\n return false;\n}\n\n/**\n * `rowIndex` moved forward one row at a time in `direction` (`1` or `-1`)\n * until it lands on a row `isSkippableRow` says is reachable, or would run\n * off the grid's own bounds (`HEADER_ROW` to `rowCount - 1`) trying — in\n * which case it returns `fallback` (the position before this move started)\n * instead of an out-of-range index.\n *\n * Deliberately not \"step one past the bound\" the way an ordinary move here\n * left unclamped would: `clampFocus` downstream holds any out-of-range\n * `rowIndex` at the nearest in-range one, and if that nearest row happens\n * to be the very one that was skippable (the grid's actual last row is a\n * group's own summary row, say), clamping back onto it would silently\n * defeat the skip. Staying at `fallback` is what a \"there is nowhere valid\n * to move to\" press should do instead — the same way `ArrowLeft` at column\n * 0 already leaves `rowIndex`/`columnIndex` exactly where they were,\n * `clampFocus` is left with nothing to correct either way, and a caller\n * that still wants to detect \"did this move go anywhere\" can compare the\n * result to `focus` itself.\n */\nfunction skipSkippableRows(\n rowIndex: number,\n direction: 1 | -1,\n rowCount: number,\n isSkippableRow: (rowIndex: number) => boolean,\n fallback: number,\n): number {\n let next = rowIndex;\n // The header (HEADER_ROW) and anything already out of the body's own\n // [0, rowCount) range are never skippable — an ordinary PageUp/ArrowUp\n // overshoot past the header, in particular, has nothing to skip past, so\n // this function has nothing to do; `clampFocus` downstream still handles\n // holding it in bounds as it always has.\n while (next >= 0 && next < rowCount && isSkippableRow(next)) {\n const stepped = next + direction;\n // Landing on the header itself (moving up from row 0) is always valid —\n // only a step that would leave the header *and* the body's own range\n // behind (moving down past the last row) has nowhere left to go.\n if (stepped < HEADER_ROW || stepped >= rowCount) {\n return fallback;\n }\n next = stepped;\n }\n return next;\n}\n\n/**\n * The focus a navigation key press moves to, or `null` when the key isn't\n * this grid's to handle — left for the browser or another handler.\n *\n * `pageSize` is a pre-measured row count rather than a callback: this\n * function takes plain data only, so a caller measures the viewport once and\n * hands over the number.\n *\n * `isSkippableRow` names rows the vertical moves (`ArrowUp`/`ArrowDown`/\n * `PageUp`/`PageDown`/`Ctrl+End`) never land a tab stop on — a group's own\n * summary row (`groupAggregateDisplay: \"row\"`), which still occupies a real\n * row slot for `rowCount`/`aria-rowindex` purposes but is presentational,\n * not a stop of its own. Left/right and plain `Home`/`End` stay row-scoped\n * and so never consult it. Defaults to skipping nothing, so every existing\n * caller (and every horizontal move) is unaffected.\n */\nexport function nextFocusForKey(\n key: string,\n modifiers: NavigationModifiers,\n focus: GridFocus,\n rowCount: number,\n columnCount: number,\n pageSize: number,\n isSkippableRow: (rowIndex: number) => boolean = noRowsSkippable,\n): GridFocus | null {\n // Alt on an arrow resizes and Ctrl on one reorders; the header claims both\n // before this runs, and elsewhere they belong to the browser.\n if (modifiers.altKey) {\n return null;\n }\n\n const { rowIndex, columnIndex } = focus;\n\n switch (key) {\n case \"ArrowLeft\":\n if (modifiers.ctrlKey) return null;\n return { rowIndex, columnIndex: columnIndex - 1 };\n case \"ArrowRight\":\n if (modifiers.ctrlKey) return null;\n return { rowIndex, columnIndex: columnIndex + 1 };\n case \"ArrowUp\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex - 1,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n case \"ArrowDown\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex + 1,\n 1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n // Ctrl takes Home and End to the grid's ends rather than the row's, which\n // is the one place Ctrl is navigation rather than reorder.\n case \"Home\":\n return modifiers.ctrlKey\n ? { rowIndex: HEADER_ROW, columnIndex: 0 }\n : { rowIndex, columnIndex: 0 };\n case \"End\":\n return modifiers.ctrlKey\n ? {\n rowIndex: skipSkippableRows(\n rowCount - 1,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex: columnCount - 1,\n }\n : { rowIndex, columnIndex: columnCount - 1 };\n case \"PageUp\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex - pageSize,\n -1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n case \"PageDown\":\n return {\n rowIndex: skipSkippableRows(\n rowIndex + pageSize,\n 1,\n rowCount,\n isSkippableRow,\n rowIndex,\n ),\n columnIndex,\n };\n default:\n return null;\n }\n}\n","export type PaginationWindowEntry = number | \"ellipsis\";\n\n/**\n * Which page numbers a numbered pager should show for `currentPage` of\n * `pageCount`, collapsing any gap wider than one page into a single\n * `\"ellipsis\"` entry — the boundary + sibling windowing MUI's\n * `usePagination` and antd's `Pagination` both use. Always includes the\n * first/last `boundaryCount` pages and `currentPage`'s `siblingCount`\n * neighbors on each side; a gap of exactly one page is filled in rather than\n * collapsed, since an ellipsis standing in for a single page saves no space.\n */\nexport function paginationWindow(\n currentPage: number,\n pageCount: number,\n options?: {\n boundaryCount?: number | undefined;\n siblingCount?: number | undefined;\n },\n): readonly PaginationWindowEntry[] {\n if (pageCount <= 0) {\n return [];\n }\n\n const boundaryCount = Math.max(0, options?.boundaryCount ?? 1);\n const siblingCount = Math.max(0, options?.siblingCount ?? 1);\n const current = Math.min(Math.max(currentPage, 1), pageCount);\n\n const pages = new Set<number>();\n for (let page = 1; page <= Math.min(boundaryCount, pageCount); page++) {\n pages.add(page);\n }\n for (\n let page = Math.max(pageCount - boundaryCount + 1, 1);\n page <= pageCount;\n page++\n ) {\n pages.add(page);\n }\n for (\n let page = Math.max(current - siblingCount, 1);\n page <= Math.min(current + siblingCount, pageCount);\n page++\n ) {\n pages.add(page);\n }\n\n const sorted = Array.from(pages).sort((a, b) => a - b);\n const entries: PaginationWindowEntry[] = [];\n let previous: number | undefined;\n for (const page of sorted) {\n if (previous !== undefined) {\n if (page - previous === 2) {\n entries.push(previous + 1);\n } else if (page - previous > 2) {\n entries.push(\"ellipsis\");\n }\n }\n entries.push(page);\n previous = page;\n }\n\n return entries;\n}\n","import type { ColumnVisibilityState, DataColumn } from \"../types\";\nimport type { SelectAllState } from \"./filterEditor\";\nimport { resolveColumnHeaderText } from \"./grid\";\nimport { isColumnVisible } from \"./visibility\";\n\n/** What a column chooser is drawn from: every column, the visibility, and the search typed. */\nexport interface ColumnChooserInput<Row> {\n /** Every column in its current order, hidden ones included — a view's `dataColumns`. */\n readonly columns: readonly DataColumn<Row, unknown>[];\n readonly visibility: ColumnVisibilityState;\n /** Narrows the list to the columns whose header text contains it, ignoring case. */\n readonly search?: string | undefined;\n}\n\n/** One column's checkbox in a column chooser. */\nexport interface ColumnChooserEntry {\n readonly columnId: string;\n /** The column's header text — what the search matches, and the checkbox's label. */\n readonly label: string;\n /** Whether the column is shown — whether its checkbox is checked. */\n readonly visible: boolean;\n /**\n * Whether the checkbox cannot be unchecked: the column is shown and is\n * either not `hideable` or the last column shown. A hidden column can\n * always be shown, `hideable` or not.\n */\n readonly disabled: boolean;\n}\n\n/** What toggling a chooser's \"Show all\" checkbox does: shows these columns, or hides them. */\nexport interface ColumnChooserToggle {\n readonly visible: boolean;\n readonly columnIds: readonly string[];\n}\n\nexport interface ColumnChooserModel {\n /** The columns the search matches, in column order. */\n readonly entries: readonly ColumnChooserEntry[];\n /**\n * The \"Show all\" checkbox's state over the entries whose columns are\n * `hideable` — the ones it acts on. A column the user cannot hide is\n * always on, so counting it would leave \"Show all\" stuck at mixed.\n */\n readonly selectAll: SelectAllState;\n /** What toggling \"Show all\" does, or `null` when it can do nothing — a disabled checkbox. */\n readonly toggleAll: ColumnChooserToggle | null;\n}\n\n/** A column as the chooser reads it. */\ninterface ChooserColumn<Row> {\n readonly column: DataColumn<Row, unknown>;\n readonly label: string;\n readonly visible: boolean;\n}\n\nfunction isHideable<Row>(column: DataColumn<Row, unknown>): boolean {\n return column.column.hideable !== false;\n}\n\nfunction matchesSearch(label: string, search: string): boolean {\n return label.toLowerCase().includes(search.toLowerCase());\n}\n\nfunction selectAllStateOf(states: readonly boolean[]): SelectAllState {\n if (states.length > 0 && states.every(Boolean)) {\n return \"checked\";\n }\n return states.some(Boolean) ? \"mixed\" : \"unchecked\";\n}\n\n/**\n * A column chooser's list for a search, and what its \"Show all\" checkbox\n * says and does — the same tri-state over what the search shows that a\n * filter editor's select-all is (`selectAllState`).\n *\n * \"Show all\" shows every hidden column the search shows once any is hidden,\n * and hides those it shows once none is. It never touches a column that is\n * not `hideable`, and never hides the last column shown: when that is all\n * that would be left, the first of them in column order stays, since a grid\n * with no column shown has no header to bring one back from.\n */\nexport function resolveColumnChooser<Row>({\n columns,\n visibility,\n search = \"\",\n}: ColumnChooserInput<Row>): ColumnChooserModel {\n const all = columns.map((column): ChooserColumn<Row> => ({\n column,\n label: resolveColumnHeaderText(column.column),\n visible: isColumnVisible(column.column, visibility),\n }));\n const shownCount = all.filter(({ visible }) => visible).length;\n const matched = all.filter(({ label }) => matchesSearch(label, search));\n\n const entries = matched.map(\n ({ column, label, visible }): ColumnChooserEntry => ({\n columnId: column.id,\n label,\n visible,\n disabled: visible && (!isHideable(column) || shownCount === 1),\n }),\n );\n\n const covered = matched.filter(({ column }) => isHideable(column));\n const selectAll = selectAllStateOf(covered.map(({ visible }) => visible));\n return {\n entries,\n selectAll,\n toggleAll: toggleAllOf(covered, selectAll, shownCount),\n };\n}\n\nfunction toggleAllOf<Row>(\n covered: readonly ChooserColumn<Row>[],\n selectAll: SelectAllState,\n shownCount: number,\n): ColumnChooserToggle | null {\n const show = selectAll !== \"checked\";\n const changing = covered\n .filter(({ visible }) => visible !== show)\n .map(({ column }) => column.id);\n // Hiding every column shown would leave none: the first of them stays.\n const columnIds =\n !show && changing.length === shownCount ? changing.slice(1) : changing;\n return columnIds.length === 0 ? null : { visible: show, columnIds };\n}\n","import type { SortDirection } from \"./types\";\n\n/**\n * Every string a grid shows or announces of its own — the pager, the group-by\n * bar, the loading row, the text of a boolean or missing value, the labels of\n * its built-in commands, the names of its menus, toolbar and column chooser,\n * and the live-region\n * announcements — so a grid can\n * speak a language other than English. A message that names something takes\n * a function, so a translation can put the name where its own grammar wants\n * it.\n *\n * Text the data supplies (cells, headers, labels) is not here: it is already\n * the app's to choose. Nor is formatting — dates and numbers follow\n * `locale`.\n */\nexport interface GridMessages {\n /** The pager's accessible name. */\n pagerLabel: string;\n previousPage: string;\n nextPage: string;\n /** The page-size control's label. */\n pageSizeLabel: string;\n /** A numbered pager button's accessible name. */\n pageButtonLabel: (page: number) => string;\n /**\n * The compact pager's status, and what a page change announces. `page`\n * counts from one, and is `0` while there are no pages.\n */\n pageStatus: (page: number, pageCount: number) => string;\n /** The row shown while `infiniteScroll` loads more. */\n loadingMore: string;\n /** A boolean cell's text. */\n booleanTrue: string;\n booleanFalse: string;\n /** What a group header names a group of missing values. */\n blankGroupValue: string;\n /** The group-by bar's accessible name. */\n groupByBarLabel: string;\n /** Shown in an empty group-by bar a header can be dragged into. */\n groupByBarPlaceholder: string;\n /** A group-by chip's accessible name. `level` counts from one. */\n groupByChipLabel: (\n columnName: string,\n level: number,\n levelCount: number,\n ) => string;\n /** A group-by chip's remove button's accessible name. */\n removeGroupBy: (columnName: string) => string;\n /** Announced when a resize ends, `width` in whole pixels. */\n columnResized: (columnName: string, width: number) => string;\n /** Announced when a column is moved. `position` counts from one. */\n columnMoved: (\n columnName: string,\n position: number,\n columnCount: number,\n ) => string;\n /** Announced when a column is sorted. `key` is its place in the sort, from one. */\n columnSorted: (\n columnName: string,\n direction: SortDirection,\n key: number,\n keyCount: number,\n ) => string;\n /** Announced when a column leaves the sort. */\n sortCleared: (columnName: string) => string;\n /** Announced when a column is grouped by. `level` counts from one. */\n groupedBy: (columnName: string, level: number, levelCount: number) => string;\n /** Announced when a column leaves the grouping. */\n groupingRemoved: (columnName: string) => string;\n groupExpanded: string;\n groupCollapsed: string;\n allGroupsExpanded: string;\n allGroupsCollapsed: string;\n /** Announced when one change selects or deselects more than one row or column. */\n selectedCount: (count: number, target: \"rows\" | \"columns\") => string;\n /** Announced when a cell is selected. `rowNumber` counts from one. */\n cellSelected: (columnName: string, rowNumber: number) => string;\n /** Announced when one column is hidden. */\n columnHidden: (columnName: string) => string;\n /** Announced when one column is shown. */\n columnShown: (columnName: string) => string;\n /** Announced when one change hides more than one column. */\n columnsHidden: (count: number) => string;\n /** Announced when one change shows more than one column. */\n columnsShown: (count: number) => string;\n /**\n * Announced when one action autofits more than one column, as\n * `column.autoFitAll` does, in place of each column's `columnResized`.\n */\n columnsAutoFitted: (count: number) => string;\n /** A column header's context menu's accessible name. */\n headerMenuLabel: (columnName: string) => string;\n /** A data cell's context menu's accessible name — a menu for its row. */\n cellMenuLabel: string;\n /** A group header row's context menu's accessible name. */\n groupMenuLabel: string;\n /** The accessible name of the menu in the body's empty space. */\n bodyMenuLabel: string;\n /** The built-in `sort.ascending` command's label. */\n sortAscending: string;\n sortDescending: string;\n /** `sort.clear`: takes one column out of the sort. */\n clearSort: string;\n /** `sort.clearAll` */\n clearAllSorting: string;\n /** `group.add`, naming the column it groups by. */\n groupByColumn: (columnName: string) => string;\n /** `group.clearAll`. `group.remove` reads `removeGroupBy`, as the group-by chip's button does. */\n ungroupAll: string;\n expandAllGroups: string;\n collapseAllGroups: string;\n /** `column.hide` */\n hideColumn: string;\n /** `column.autoFit`: sizes the column to its content. */\n autoFitColumn: string;\n autoFitAllColumns: string;\n /** `selection.selectAllRows` */\n selectAllRows: string;\n /** `selection.clear` */\n clearSelection: string;\n /** `filter.clearAll`, which clears the search too. */\n clearFilters: string;\n /** `column.choose`, which opens the column chooser. */\n chooseColumns: string;\n /** The toolbar's accessible name, unless its `label` gives one. */\n toolbarLabel: string;\n /** The toolbar's search box's accessible name. */\n searchLabel: string;\n /** Shown in the toolbar's empty search box. */\n searchPlaceholder: string;\n /** The toolbar's \"More\" button, holding the items that do not fit. */\n moreToolbarItems: string;\n /** Announced when a search settles: how many rows it found. */\n searchResults: (count: number) => string;\n /** The column chooser's accessible name. */\n columnChooserLabel: string;\n /** The column chooser's search box's accessible name. */\n columnChooserSearchLabel: string;\n /** The column chooser's checkbox showing or hiding every column its search lists. */\n showAllColumns: string;\n /** Shown in the column chooser when its search matches no column. */\n noMatchingColumns: string;\n}\n\n/** \"3 columns hidden\", \"1 column shown\", \"2 columns autofitted\". */\nfunction columnCount(\n count: number,\n change: \"hidden\" | \"shown\" | \"autofitted\",\n): string {\n return count === 1\n ? `1 column ${change}`\n : `${String(count)} columns ${change}`;\n}\n\n/** \"3 rows found\", \"1 row found\", \"No rows found\". */\nfunction searchResults(count: number): string {\n if (count === 0) {\n return \"No rows found\";\n }\n return count === 1 ? \"1 row found\" : `${String(count)} rows found`;\n}\n\n/** \"3 rows selected\", \"1 column selected\", \"No rows selected\". */\nfunction selectedCount(count: number, target: \"rows\" | \"columns\"): string {\n const noun = target === \"rows\" ? \"row\" : \"column\";\n if (count === 0) {\n return `No ${noun}s selected`;\n }\n return count === 1\n ? `1 ${noun} selected`\n : `${String(count)} ${noun}s selected`;\n}\n\n/** The grid's own English, which `messages` replaces key by key. */\nexport const defaultMessages: GridMessages = {\n pagerLabel: \"Pagination\",\n previousPage: \"Previous\",\n nextPage: \"Next\",\n pageSizeLabel: \"Rows per page\",\n pageButtonLabel: (page) => `Page ${String(page)}`,\n pageStatus: (page, pageCount) =>\n `Page ${String(page)} of ${String(pageCount)}`,\n loadingMore: \"Loading more…\",\n booleanTrue: \"true\",\n booleanFalse: \"false\",\n blankGroupValue: \"(blank)\",\n groupByBarLabel: \"Grouped by\",\n groupByBarPlaceholder: \"Drag a column here to group by it\",\n groupByChipLabel: (columnName, level, levelCount) =>\n levelCount > 1\n ? `${columnName}, level ${String(level)} of ${String(levelCount)}`\n : columnName,\n removeGroupBy: (columnName) => `Stop grouping by ${columnName}`,\n columnResized: (columnName, width) =>\n `${columnName}, ${String(width)} pixels wide`,\n columnMoved: (columnName, position, columnCount) =>\n `${columnName}, column ${String(position)} of ${String(columnCount)}`,\n columnSorted: (columnName, direction, key, keyCount) => {\n const sorted = `${columnName} sorted ${direction === \"asc\" ? \"ascending\" : \"descending\"}`;\n return keyCount > 1\n ? `${sorted}, key ${String(key)} of ${String(keyCount)}`\n : sorted;\n },\n sortCleared: (columnName) => `${columnName}, sort cleared`,\n groupedBy: (columnName, level, levelCount) =>\n levelCount > 1\n ? `Grouped by ${columnName}, level ${String(level)} of ${String(levelCount)}`\n : `Grouped by ${columnName}`,\n groupingRemoved: (columnName) => `${columnName}, grouping removed`,\n groupExpanded: \"Group expanded\",\n groupCollapsed: \"Group collapsed\",\n allGroupsExpanded: \"All groups expanded\",\n allGroupsCollapsed: \"All groups collapsed\",\n selectedCount,\n cellSelected: (columnName, rowNumber) =>\n `${columnName}, row ${String(rowNumber)}, selected`,\n columnHidden: (columnName) => `${columnName}, column hidden`,\n columnShown: (columnName) => `${columnName}, column shown`,\n columnsHidden: (count) => columnCount(count, \"hidden\"),\n columnsShown: (count) => columnCount(count, \"shown\"),\n columnsAutoFitted: (count) => columnCount(count, \"autofitted\"),\n headerMenuLabel: (columnName) => `${columnName} column menu`,\n cellMenuLabel: \"Row menu\",\n groupMenuLabel: \"Group menu\",\n bodyMenuLabel: \"Grid menu\",\n sortAscending: \"Sort ascending\",\n sortDescending: \"Sort descending\",\n clearSort: \"Clear sort\",\n clearAllSorting: \"Clear all sorting\",\n groupByColumn: (columnName) => `Group by ${columnName}`,\n ungroupAll: \"Ungroup all\",\n expandAllGroups: \"Expand all groups\",\n collapseAllGroups: \"Collapse all groups\",\n hideColumn: \"Hide column\",\n autoFitColumn: \"Autofit column\",\n autoFitAllColumns: \"Autofit all columns\",\n selectAllRows: \"Select all rows\",\n clearSelection: \"Clear selection\",\n clearFilters: \"Clear filters\",\n chooseColumns: \"Choose columns\",\n toolbarLabel: \"Grid toolbar\",\n searchLabel: \"Search\",\n searchPlaceholder: \"Search…\",\n moreToolbarItems: \"More\",\n searchResults,\n columnChooserLabel: \"Columns\",\n columnChooserSearchLabel: \"Search columns\",\n showAllColumns: \"Show all\",\n noMatchingColumns: \"No matching columns\",\n};\n\n/**\n * `messages` over the defaults — every key the grid needs, whichever the\n * caller gave. The defaults themselves, same object, when it gave none, so a\n * renderer memoising on the result does not see a change that is not one.\n */\nexport function resolveMessages(\n messages: Partial<GridMessages> | undefined,\n): GridMessages {\n return messages === undefined\n ? defaultMessages\n : { ...defaultMessages, ...messages };\n}\n","import type { GridMessages } from \"../messages\";\nimport type { AggregateSpec, ColumnDefinition, ColumnType } from \"../types\";\n\n/** The locale(s) values are formatted for — `undefined` is the runtime's own. */\nexport type FormatLocale = string | readonly string[] | undefined;\n\ntype FormatOptions = Intl.NumberFormatOptions | Intl.DateTimeFormatOptions;\n\n/**\n * The fields `Date.prototype.toLocaleString` and its date-/time-only\n * siblings print, so a column given a `locale` but no `format` reads as\n * those would in that locale. `Intl.DateTimeFormat` with no fields at all\n * prints the date alone, which suits `\"date\"` but would drop the time from a\n * date-and-time column.\n */\nconst DATE_FIELDS: Intl.DateTimeFormatOptions = {\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n};\nconst TIME_FIELDS: Intl.DateTimeFormatOptions = {\n hour: \"numeric\",\n minute: \"numeric\",\n second: \"numeric\",\n};\nconst DATE_TIME_FIELDS: Intl.DateTimeFormatOptions = {\n ...DATE_FIELDS,\n ...TIME_FIELDS,\n};\n\n/** Without a `format.currency` there is no symbol to show, only the digits a price has. */\nconst CURRENCY_DIGITS: Intl.NumberFormatOptions = {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n};\n\n/** Stands in for an absent `format` as a `WeakMap` key. */\nconst NO_FORMAT: FormatOptions = {};\n\n/**\n * Formatters already built, keyed first by the column's `format` object and\n * then by type and locale. Building an `Intl` formatter costs far more than\n * using one, and a grid formats every visible cell on every render, so each\n * distinct (type, locale, format) gets one formatter for the life of the\n * page. Weakly keyed on `format` so that a column definition thrown away\n * takes its formatters with it.\n */\nconst formatters = new WeakMap<\n FormatOptions,\n Map<string, Intl.NumberFormat | Intl.DateTimeFormat>\n>();\n\nfunction cached<Formatter extends Intl.NumberFormat | Intl.DateTimeFormat>(\n format: FormatOptions | undefined,\n key: string,\n create: () => Formatter,\n): Formatter {\n const owner = format ?? NO_FORMAT;\n let byKey = formatters.get(owner);\n if (byKey === undefined) {\n byKey = new Map();\n formatters.set(owner, byKey);\n }\n const existing = byKey.get(key);\n if (existing !== undefined) {\n // Each key is only ever filled by the `create` of the same kind.\n return existing as Formatter;\n }\n const formatter = create();\n byKey.set(key, formatter);\n return formatter;\n}\n\nfunction localeKey(locale: FormatLocale): string {\n return typeof locale === \"string\" ? locale : (locale?.join(\",\") ?? \"\");\n}\n\nfunction isNumericType(type: ColumnType | undefined): boolean {\n return (\n type === \"number\" ||\n type === \"decimal\" ||\n type === \"currency\" ||\n type === \"percent\"\n );\n}\n\n/**\n * The options a numeric `type` starts from, with the column's own `format`\n * laid over them — so `{ maximumFractionDigits: 0 }` on a currency column\n * keeps the currency style and changes only the digits.\n */\nfunction numberOptions(\n type: ColumnType | undefined,\n format: Intl.NumberFormatOptions | undefined,\n): Intl.NumberFormatOptions {\n switch (type) {\n case \"currency\":\n return format?.currency === undefined\n ? { ...CURRENCY_DIGITS, ...format }\n : { style: \"currency\", ...format };\n case \"percent\":\n // Intl's own reading: `0.25` is a quarter, shown as \"25%\".\n return { style: \"percent\", ...format };\n default:\n return format ?? {};\n }\n}\n\n/**\n * The fields a date `type` prints. A column's own `format` replaces them\n * rather than merging in: `dateStyle`/`timeStyle` refuse to be combined with\n * individual fields, and a format naming only a month means only a month.\n */\nfunction dateOptions(\n type: ColumnType | undefined,\n format: Intl.DateTimeFormatOptions | undefined,\n): Intl.DateTimeFormatOptions {\n if (format !== undefined) {\n return format;\n }\n if (type === \"date\") return DATE_FIELDS;\n if (type === \"time\") return TIME_FIELDS;\n return DATE_TIME_FIELDS;\n}\n\nfunction formatNumber(\n value: number | bigint,\n type: ColumnType | undefined,\n format: FormatOptions | undefined,\n locale: FormatLocale,\n): string {\n const formatter = cached(\n format,\n `number|${type ?? \"\"}|${localeKey(locale)}`,\n () =>\n new Intl.NumberFormat(\n locale,\n numberOptions(type, format as Intl.NumberFormatOptions | undefined),\n ),\n );\n return formatter.format(value);\n}\n\nfunction formatDate(\n value: Date,\n type: ColumnType | undefined,\n format: FormatOptions | undefined,\n locale: FormatLocale,\n): string {\n // `Intl.DateTimeFormat` throws on an invalid date rather than printing one.\n if (Number.isNaN(value.getTime())) {\n return String(value);\n }\n const formatter = cached(\n format,\n `date|${type ?? \"\"}|${localeKey(locale)}`,\n () =>\n new Intl.DateTimeFormat(\n locale,\n dateOptions(type, format as Intl.DateTimeFormatOptions | undefined),\n ),\n );\n return formatter.format(value);\n}\n\n/**\n * Anything without a reading of its own. A plain object or an array is\n * written out as JSON, since `String` would make every one of them\n * `\"[object Object]\"`. One JSON cannot write — a cycle, a `bigint` inside\n * — is left at that `\"[object Object]\"` after all. A function is named\n * rather than printed, since `String` would print its source.\n */\nfunction formatOther(value: unknown): string {\n if (typeof value === \"function\") {\n return \"(function)\";\n }\n if (typeof value === \"object\" && value !== null) {\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n }\n return String(value);\n}\n\n/**\n * The text a value reads as in `column` — what a cell shows when the column\n * has no `cellTemplate`, and what an export or a print writes, so the two\n * cannot disagree.\n *\n * A `valueFormatter` decides outright. `null`/`undefined` read `\"\"`, a\n * boolean `\"true\"`/`\"false\"` — or `messages.booleanTrue`/`booleanFalse`\n * when given, for a grid speaking another language — a string as it is, a\n * plain object or array as JSON.\n *\n * Dates and numbers are formatted through `Intl` only once asked to — the\n * column has a `format`, or a `locale` is given. Until then they print as a\n * grid always printed them, so adopting this changes nothing on screen: a\n * `Date` through `toLocaleString()`, a number as-is (`1234.5`, never\n * `1,234.5`). Once asked:\n *\n * - A `Date` → `Intl.DateTimeFormat`: the date alone under `\"date\"`, the time\n * alone under `\"time\"`, both otherwise.\n * - A number under a numeric `type` → `Intl.NumberFormat`: `\"currency\"` with\n * a currency symbol once `format.currency` names one (two fraction digits\n * until then), `\"percent\"` reading `0.25` as 25 %. Under any other type it\n * is still printed as-is, the way a number id should be.\n *\n * `format` and `locale` go to the `Intl` constructor unchanged, so any\n * option it accepts is honoured.\n */\nexport function formatCellValue<Row>(\n value: unknown,\n column: ColumnDefinition<Row, unknown>,\n locale?: FormatLocale,\n row?: Row,\n messages?: Pick<GridMessages, \"booleanTrue\" | \"booleanFalse\">,\n): string {\n if (column.valueFormatter !== undefined) {\n return column.valueFormatter(value, row);\n }\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"boolean\" && messages !== undefined) {\n return value ? messages.booleanTrue : messages.booleanFalse;\n }\n const { type, format } = column;\n const formatted = format !== undefined || locale !== undefined;\n if (value instanceof Date) {\n return formatted\n ? formatDate(value, type, format, locale)\n : value.toLocaleString();\n }\n if (\n formatted &&\n (typeof value === \"number\" || typeof value === \"bigint\") &&\n isNumericType(type)\n ) {\n return formatNumber(value, type, format, locale);\n }\n if (typeof value === \"string\") {\n return value;\n }\n return formatOther(value);\n}\n\n/**\n * Whose rules an aggregate result formats by: the column's, unless the\n * result is plainly not one of the column's values. A `count` or\n * `countDistinct` is a number of rows — a count of a currency column is 12,\n * not $12.00 — and a number reduced from a column whose `type` is not\n * numeric (the sum of a column left untyped) is still a number to read as\n * one, unless the column's own `valueFormatter` claims it.\n */\nfunction aggregateFormatColumn<Row>(\n value: unknown,\n spec: AggregateSpec<Row>,\n column: ColumnDefinition<Row, unknown> | undefined,\n): ColumnDefinition<Row, unknown> {\n const plain: ColumnDefinition<Row, unknown> = {\n field: spec.columnId,\n type: \"number\",\n };\n if (\n column === undefined ||\n spec.fn === \"count\" ||\n spec.fn === \"countDistinct\"\n ) {\n return plain;\n }\n const numeric = typeof value === \"number\" || typeof value === \"bigint\";\n return column.valueFormatter === undefined &&\n numeric &&\n !isNumericType(column.type)\n ? plain\n : column;\n}\n\n/**\n * The text an aggregate result reads as — a footer cell, a group's subtotal\n * — through `formatCellValue`, so once a `format` or `locale` asks for it a\n * `sum` of a currency column reads as currency and a `max` of a date column\n * as a date. `column` is `undefined` for a spec naming a column the grid\n * does not have, which then formats by its value alone.\n *\n * Until then a numeric result reads through `toLocaleString()`, with digit\n * grouping, where a cell prints its number as-is: that is how a grid has\n * always shown its totals, and a sum easily runs into the thousands.\n */\nexport function formatAggregateValue<Row>(\n value: unknown,\n spec: AggregateSpec<Row>,\n column: ColumnDefinition<Row, unknown> | undefined,\n locale?: FormatLocale,\n): string {\n const target = aggregateFormatColumn(value, spec, column);\n if (\n typeof value === \"number\" &&\n target.valueFormatter === undefined &&\n target.format === undefined &&\n locale === undefined\n ) {\n return value.toLocaleString();\n }\n return formatCellValue(value, target, locale);\n}\n","import type { GridMessages } from \"../messages\";\nimport { resolveMessages } from \"../messages\";\nimport type {\n ColumnType,\n DataColumn,\n FilterEntry,\n FilterScalar,\n FilterState,\n OperatorFilterEntry,\n} from \"../types\";\nimport { filterValueKey, isEmptyCell, isScalarList } from \"./filterOperators\";\nimport { compileFilter } from \"./filtering\";\nimport type { FormatLocale } from \"./format\";\nimport { formatCellValue } from \"./format\";\nimport { accessDotted } from \"./grid\";\nimport { compareValues } from \"./sorting\";\n\n/**\n * What one column's filter looks like to an editor — which of its forms can\n * show it, or that none can.\n *\n * - `\"none\"`: no entry touches the column.\n * - `\"values\"`: a checklist — one `in` entry, optionally OR-grouped with an\n * `isEmpty` on the same column (`includeBlanks`).\n * - `\"conditions\"`: one or two operator entries on the column (any but\n * `in`), at the top level (ANDed) or alone in one group with its\n * combinator.\n * - `\"custom\"`: anything else that touches the column — a text query, a\n * predicate, a group spanning several columns. An editor shows it as\n * such, and applying an editor's draft replaces it.\n */\nexport type ColumnFilterShape<Row> =\n | { readonly kind: \"none\" }\n | {\n readonly kind: \"values\";\n readonly values: readonly FilterScalar[];\n readonly includeBlanks: boolean;\n }\n | {\n readonly kind: \"conditions\";\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n readonly combinator: \"and\" | \"or\";\n }\n | { readonly kind: \"custom\" };\n\n/** One distinct value a column holds, as a checklist offers it. */\nexport interface ColumnValueOption {\n readonly value: Exclude<FilterScalar, null>;\n /** The value as the column prints it — what a search matches against. */\n readonly label: string;\n /** How many rows hold it, among the rows the other columns' filters keep. */\n readonly count: number;\n}\n\n/** What `columnValueOptions` narrows its list by. */\nexport interface ColumnValueQuery {\n /** Keeps the values whose label contains this, ignoring case. */\n readonly search?: string;\n /** Keeps at most this many values, first in sorted order. */\n readonly limit?: number;\n /** The locale labels are formatted for — the grid's own `locale`. */\n readonly locale?: FormatLocale;\n /**\n * The grid's own `messages`, over the defaults: a boolean is labelled\n * `booleanTrue`/`booleanFalse`, as its cells print it.\n */\n readonly messages?: Partial<GridMessages>;\n}\n\nexport interface ColumnValueOptions {\n /** The distinct values, sorted as the column sorts, searched and cut to `limit`. */\n readonly options: readonly ColumnValueOption[];\n /** How many values matched the search, before `limit` cut them. */\n readonly total: number;\n /** Whether `limit` left values out. */\n readonly truncated: boolean;\n /** How many of the same rows hold a blank — `null`, `undefined` or `\"\"`. */\n readonly blanks: number;\n /**\n * The column's `type`, which tells values apart the way an `in` filter\n * does — on a date column, a date string and the `Date` it names are one\n * value. `initialFilterEditorDraft` carries it into the draft.\n */\n readonly columnType?: ColumnType | undefined;\n}\n\n/**\n * A checklist or condition editor's working copy of one column's filter,\n * changed by `filterEditorReducer` and turned into a filter by\n * `draftToFilter` only when the user applies it — so cancelling is just\n * dropping the draft.\n */\nexport interface FilterEditorDraft<Row> {\n /** Which half of the draft `draftToFilter` applies: the last one changed. */\n readonly mode: \"values\" | \"conditions\";\n /** Every value the editor offers, from `columnValueOptions`. */\n readonly options: readonly ColumnValueOption[];\n /** How many rows hold a blank; the blanks entry only matters when some do. */\n readonly blanks: number;\n readonly search: string;\n /** The checked values, keyed as an `in` filter on the column keys them. */\n readonly checked: ReadonlyMap<string, FilterScalar>;\n readonly includeBlanks: boolean;\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n readonly combinator: \"and\" | \"or\";\n /** The column's `type`, from `ColumnValueOptions` — what values are keyed by. */\n readonly columnType?: ColumnType | undefined;\n}\n\nexport type FilterEditorAction<Row> =\n | { readonly type: \"search\"; readonly search: string }\n | { readonly type: \"toggleValue\"; readonly value: FilterScalar }\n /** Checks every value the search shows, or unchecks them once all are. */\n | { readonly type: \"toggleAll\" }\n | { readonly type: \"setIncludeBlanks\"; readonly includeBlanks: boolean }\n | {\n readonly type: \"setConditions\";\n readonly conditions: readonly OperatorFilterEntry<Row>[];\n /** Keeps the draft's own when omitted. */\n readonly combinator?: \"and\" | \"or\";\n }\n /** Back to \"no filter\": every value checked, no conditions, no search. */\n | { readonly type: \"clear\" };\n\n/** A select-all checkbox's state over the values the search shows. */\nexport type SelectAllState = \"checked\" | \"unchecked\" | \"mixed\";\n\n/**\n * Whether `entry` is about `columnId`: names it, or is a group with an entry\n * anywhere inside that does. An entry across every column is about none.\n */\nfunction touchesColumn<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): boolean {\n return \"combinator\" in entry\n ? entry.entries.some((nested) => touchesColumn(nested, columnId))\n : entry.columnId === columnId;\n}\n\nfunction isOperatorOn<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): entry is OperatorFilterEntry<Row> {\n return \"operator\" in entry && entry.columnId === columnId;\n}\n\n/** An operator entry on `columnId` a condition editor can show: any but `in`. */\nfunction isConditionOn<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): entry is OperatorFilterEntry<Row> {\n return isOperatorOn(entry, columnId) && entry.operator !== \"in\";\n}\n\n/** `entry` as a checklist, when it is the `in` (+ `isEmpty`) one stores. */\nfunction valuesShape<Row>(\n entry: FilterEntry<Row>,\n columnId: string,\n): ColumnFilterShape<Row> | undefined {\n const values = (candidate: FilterEntry<Row> | undefined) =>\n candidate !== undefined &&\n isOperatorOn(candidate, columnId) &&\n candidate.operator === \"in\" &&\n isScalarList(candidate.value)\n ? candidate.value\n : undefined;\n const blanks = (candidate: FilterEntry<Row> | undefined) =>\n candidate !== undefined &&\n isOperatorOn(candidate, columnId) &&\n candidate.operator === \"isEmpty\";\n\n const alone = values(entry);\n if (alone !== undefined) {\n return { kind: \"values\", values: alone, includeBlanks: false };\n }\n if (\n !(\"combinator\" in entry) ||\n entry.combinator !== \"or\" ||\n entry.entries.length !== 2\n ) {\n return undefined;\n }\n const [first, second] = entry.entries;\n const listed = blanks(first) ? values(second) : values(first);\n return listed !== undefined && (blanks(first) || blanks(second))\n ? { kind: \"values\", values: listed, includeBlanks: true }\n : undefined;\n}\n\n/** `touching` as one or two conditions, when that is all it is. */\nfunction conditionsShape<Row>(\n touching: FilterState<Row>,\n columnId: string,\n): ColumnFilterShape<Row> | undefined {\n const [only] = touching;\n const grouped =\n touching.length === 1 && only !== undefined && \"combinator\" in only;\n const entries = grouped ? only.entries : touching;\n const combinator = grouped ? only.combinator : \"and\";\n if (entries.length === 0 || entries.length > 2) {\n return undefined;\n }\n const conditions = entries.filter((entry) => isConditionOn(entry, columnId));\n return conditions.length === entries.length\n ? { kind: \"conditions\", conditions, combinator }\n : undefined;\n}\n\n/**\n * How `filter` filters `columnId`, as one of the forms an editor can show —\n * see `ColumnFilterShape`. Entries about other columns don't count, nor do\n * entries across every column (a global search).\n */\nexport function describeColumnFilter<Row>(\n filter: FilterState<Row>,\n columnId: string,\n): ColumnFilterShape<Row> {\n const touching = filter.filter((entry) => touchesColumn(entry, columnId));\n const [only] = touching;\n if (only === undefined) {\n return { kind: \"none\" };\n }\n return (\n (touching.length === 1 ? valuesShape(only, columnId) : undefined) ??\n conditionsShape(touching, columnId) ?? { kind: \"custom\" }\n );\n}\n\n/**\n * A value a checklist can offer: an `in` entry can hold it. An object or an\n * array in a cell can't be, so it isn't offered.\n */\nfunction isOfferable(value: unknown): value is Exclude<FilterScalar, null> {\n return (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value instanceof Date\n );\n}\n\nfunction matchesSearch(label: string, search: string): boolean {\n return label.toLowerCase().includes(search.toLowerCase());\n}\n\ninterface Bucket<Row> {\n readonly value: Exclude<FilterScalar, null>;\n /** The first row holding it, for a `valueFormatter` that reads the row. */\n readonly row: Row;\n count: number;\n}\n\n/**\n * The distinct values `columnId` holds, for a checklist editor: each with\n * its label and how many rows hold it.\n *\n * Counted over the rows every *other* column's filter keeps — every entry\n * except those `describeColumnFilter` would count for this column — so a\n * column's list cascades from the other filters without its own pick\n * hiding the values the user unchecked. Values are told apart as an `in`\n * filter tells them apart — as grouping does, except that a date column's\n * date strings are the dates they name — ordered as the column sorts, and\n * labelled as its cells print, a boolean in `query.messages`' words; blanks\n * are counted apart, in `blanks`.\n *\n * Costs one pass over `rows` (tens of milliseconds at 100k rows), so compute\n * it when an editor opens rather than on every render, and hand the whole\n * list to `initialFilterEditorDraft`, whose search needs no recount.\n */\nexport function columnValueOptions<Row>(\n rows: readonly Row[],\n dataColumns: readonly DataColumn<Row, unknown>[],\n filter: FilterState<Row>,\n columnId: string,\n query: ColumnValueQuery = {},\n): ColumnValueOptions {\n const column = dataColumns.find((entry) => entry.id === columnId)?.column;\n if (column === undefined) {\n return { options: [], total: 0, truncated: false, blanks: 0 };\n }\n const keep = compileFilter(\n filter.filter((entry) => !touchesColumn(entry, columnId)),\n dataColumns,\n );\n\n const buckets = new Map<string, Bucket<Row>>();\n let blanks = 0;\n for (const row of rows) {\n if (keep !== undefined && !keep(row)) {\n continue;\n }\n const value = accessDotted(row, column.field);\n if (isEmptyCell(value)) {\n blanks++;\n } else if (isOfferable(value)) {\n const key = filterValueKey(value, column.type);\n const bucket = buckets.get(key);\n if (bucket === undefined) {\n buckets.set(key, { value, row, count: 1 });\n } else {\n bucket.count++;\n }\n }\n }\n\n const { search = \"\", limit, locale } = query;\n const messages = resolveMessages(query.messages);\n const options = [...buckets.values()]\n .sort((a, b) => compareValues(a.value, b.value, column.type))\n .map(({ value, row, count }) => ({\n value,\n label: formatCellValue(value, column, locale, row, messages),\n count,\n }))\n .filter((option) => matchesSearch(option.label, search));\n const shown = limit === undefined ? options : options.slice(0, limit);\n return {\n options: shown,\n total: options.length,\n truncated: shown.length < options.length,\n blanks,\n columnType: column.type,\n };\n}\n\n/** The key `draft.checked` holds `value` under. */\nfunction keyOf<Row>(\n draft: Pick<FilterEditorDraft<Row>, \"columnType\">,\n value: FilterScalar,\n): string {\n return filterValueKey(value, draft.columnType);\n}\n\nfunction everyOption<Row>(\n draft: Pick<FilterEditorDraft<Row>, \"columnType\" | \"options\">,\n): ReadonlyMap<string, FilterScalar> {\n return new Map(\n draft.options.map((option) => [keyOf(draft, option.value), option.value]),\n );\n}\n\n/**\n * A draft showing `shape` over `values` — what an editor opens with. A\n * column with no filter, or one only a custom editor could show, opens with\n * every value checked; a checklist with its own values checked, kept even\n * when the other filters now hide them; conditions as they are.\n */\nexport function initialFilterEditorDraft<Row>(\n shape: ColumnFilterShape<Row>,\n values: ColumnValueOptions,\n): FilterEditorDraft<Row> {\n const draft: FilterEditorDraft<Row> = {\n mode: \"values\",\n options: values.options,\n blanks: values.blanks,\n search: \"\",\n checked: everyOption(values),\n includeBlanks: values.blanks > 0,\n conditions: [],\n combinator: \"and\",\n columnType: values.columnType,\n };\n switch (shape.kind) {\n case \"values\":\n return {\n ...draft,\n checked: new Map(\n shape.values\n .filter((value) => !isEmptyCell(value))\n .map((value) => [keyOf(draft, value), value]),\n ),\n includeBlanks: shape.includeBlanks,\n };\n case \"conditions\":\n return {\n ...draft,\n mode: \"conditions\",\n conditions: shape.conditions,\n combinator: shape.combinator,\n };\n case \"none\":\n case \"custom\":\n return draft;\n }\n}\n\n/** The options the draft's search shows — those a select-all acts on. */\nexport function visibleFilterOptions<Row>(\n draft: FilterEditorDraft<Row>,\n): readonly ColumnValueOption[] {\n return draft.search === \"\"\n ? draft.options\n : draft.options.filter((option) =>\n matchesSearch(option.label, draft.search),\n );\n}\n\n/** Blanks count among what select-all covers only while nothing is searched. */\nfunction selectAllCoversBlanks<Row>(draft: FilterEditorDraft<Row>): boolean {\n return draft.search === \"\" && draft.blanks > 0;\n}\n\n/**\n * The select-all checkbox's state: whether every value the search shows is\n * checked, none is, or some are — blanks included while nothing is\n * searched.\n */\nexport function selectAllState<Row>(\n draft: FilterEditorDraft<Row>,\n): SelectAllState {\n const states = visibleFilterOptions(draft).map((option) =>\n draft.checked.has(keyOf(draft, option.value)),\n );\n if (selectAllCoversBlanks(draft)) {\n states.push(draft.includeBlanks);\n }\n if (states.length > 0 && states.every(Boolean)) {\n return \"checked\";\n }\n return states.some(Boolean) ? \"mixed\" : \"unchecked\";\n}\n\nfunction toggleAll<Row>(draft: FilterEditorDraft<Row>): FilterEditorDraft<Row> {\n const check = selectAllState(draft) !== \"checked\";\n const checked = new Map(draft.checked);\n for (const option of visibleFilterOptions(draft)) {\n const key = keyOf(draft, option.value);\n if (check) {\n checked.set(key, option.value);\n } else {\n checked.delete(key);\n }\n }\n return {\n ...draft,\n mode: \"values\",\n checked,\n includeBlanks: selectAllCoversBlanks(draft) ? check : draft.includeBlanks,\n };\n}\n\n/**\n * The next draft after `action` — a plain reducer, so a renderer can hold\n * the draft in whatever state it has (`useReducer`, a signal, a store).\n * Changing a value or the blanks switches the draft to its checklist;\n * setting conditions switches it to them.\n */\nexport function filterEditorReducer<Row>(\n draft: FilterEditorDraft<Row>,\n action: FilterEditorAction<Row>,\n): FilterEditorDraft<Row> {\n switch (action.type) {\n case \"search\":\n return { ...draft, search: action.search };\n case \"toggleValue\": {\n const key = keyOf(draft, action.value);\n const checked = new Map(draft.checked);\n if (checked.has(key)) {\n checked.delete(key);\n } else {\n checked.set(key, action.value);\n }\n return { ...draft, mode: \"values\", checked };\n }\n case \"toggleAll\":\n return toggleAll(draft);\n case \"setIncludeBlanks\":\n return { ...draft, mode: \"values\", includeBlanks: action.includeBlanks };\n case \"setConditions\":\n return {\n ...draft,\n mode: \"conditions\",\n conditions: action.conditions,\n combinator: action.combinator ?? draft.combinator,\n };\n case \"clear\":\n return {\n ...draft,\n search: \"\",\n checked: everyOption(draft),\n includeBlanks: draft.blanks > 0,\n conditions: [],\n };\n }\n}\n\n/**\n * Whether the checklist keeps every row: every offered value checked, and\n * the blanks too when there are any.\n */\nfunction checksEverything<Row>(draft: FilterEditorDraft<Row>): boolean {\n return (\n draft.options.every((option) =>\n draft.checked.has(keyOf(draft, option.value)),\n ) &&\n (draft.includeBlanks || draft.blanks === 0)\n );\n}\n\n/** The entries `draft` stands for on `columnId` — none for \"no filter\". */\nfunction draftEntries<Row>(\n draft: FilterEditorDraft<Row>,\n columnId: string,\n): FilterState<Row> {\n if (draft.mode === \"conditions\") {\n const conditions = draft.conditions.map((condition) => ({\n ...condition,\n columnId,\n }));\n return conditions.length > 1\n ? [{ combinator: draft.combinator, entries: conditions }]\n : conditions;\n }\n if (checksEverything(draft)) {\n return [];\n }\n const picked: OperatorFilterEntry<Row> = {\n columnId,\n operator: \"in\",\n value: [...draft.checked.values()],\n };\n return draft.includeBlanks\n ? [\n {\n combinator: \"or\",\n entries: [picked, { columnId, operator: \"isEmpty\" }],\n },\n ]\n : [picked];\n}\n\n/**\n * `current` with `columnId`'s filter replaced by what `draft` holds — what\n * applying an editor sets. Every entry about the column goes (custom ones\n * included); the draft's entries take the place of the first, so the rest\n * keep their order.\n *\n * A checklist with everything checked is no filter at all, and a partial\n * pick is one `in` entry, OR-grouped with an `isEmpty` when blanks are\n * kept. One condition is stored as itself, two as a group with the\n * draft's combinator. Returns `current` itself when nothing changes.\n */\nexport function draftToFilter<Row>(\n draft: FilterEditorDraft<Row>,\n columnId: string,\n current: FilterState<Row>,\n): FilterState<Row> {\n const replacement = draftEntries(draft, columnId);\n const first = current.findIndex((entry) => touchesColumn(entry, columnId));\n if (first === -1) {\n return replacement.length === 0 ? current : [...current, ...replacement];\n }\n const kept = current.filter((entry) => !touchesColumn(entry, columnId));\n return [...kept.slice(0, first), ...replacement, ...kept.slice(first)];\n}\n","/**\n * One entry per row: its measured height once known, `undefined` until then.\n * A row never yet rendered (or rendered but not yet observed) falls back to\n * `visibleRange`'s own `estimatedHeight` argument.\n */\nexport type RowHeights = readonly (number | undefined)[];\n\nexport interface VisibleRange {\n readonly startIndex: number;\n readonly endIndex: number; // inclusive\n /** Total height of every row before `startIndex` — the leading spacer's height. */\n readonly offsetBefore: number;\n /** Total height of every row after `endIndex` — the trailing spacer's height. */\n readonly offsetAfter: number;\n}\n\n/**\n * Which rows of a dynamic-height, virtualized list fall within\n * `[scrollTop, scrollTop + viewportHeight)`, padded by `overscan` rows on\n * each side and clamped to the array's own bounds.\n *\n * Walks a cumulative-offset prefix sum built from `heights` (measured height\n * where known, `estimatedHeight` otherwise) rather than assuming a uniform\n * row height — this codebase's rows are not uniform (`.is-wrapped` cells,\n * group header/summary rows), so a fixed-height virtualizer would either\n * break wrapping or force it out of scope.\n *\n * `O(n)` in `heights.length`. Deliberately not a Fenwick tree or a\n * binary-searchable prefix-sum structure — that optimization belongs in the\n * mutable height cache that already owns mutability (`createRowVirtualizer`\n * in `@gridkitjs/dom`), not in this pure function's contract, and is not\n * worth taking on until a profiled scenario actually shows it matters at\n * realistic row counts.\n */\nexport function visibleRange(\n heights: RowHeights,\n estimatedHeight: number,\n scrollTop: number,\n viewportHeight: number,\n overscan: number,\n): VisibleRange {\n const rowCount = heights.length;\n if (rowCount === 0) {\n return { startIndex: 0, endIndex: -1, offsetBefore: 0, offsetAfter: 0 };\n }\n\n function heightAt(index: number): number {\n return heights[index] ?? estimatedHeight;\n }\n\n const viewportBottom = scrollTop + viewportHeight;\n\n // The first row whose bottom edge crosses `scrollTop` — everything before\n // it is fully scrolled past. `top` tracks that row's own top edge (the\n // cumulative height of every row before it) as the walk advances. Stops at\n // the last row rather than walking off the end when `scrollTop` reaches or\n // exceeds the total height.\n let start = 0;\n let top = 0;\n while (start < rowCount - 1 && top + heightAt(start) <= scrollTop) {\n top += heightAt(start);\n start += 1;\n }\n const startTop = top;\n\n // From `start`, the last row whose top edge is still above `viewportBottom`\n // — the first row no longer even partially visible ends the walk one row\n // earlier than it, or the array itself runs out first. `bottom` tracks the\n // current row's own bottom edge.\n let end = start;\n let bottom = startTop + heightAt(start);\n while (end < rowCount - 1 && bottom < viewportBottom) {\n end += 1;\n bottom += heightAt(end);\n }\n\n const overscanStart = Math.max(0, start - overscan);\n const overscanEnd = Math.min(rowCount - 1, end + overscan);\n\n let offsetBefore = 0;\n for (let index = 0; index < overscanStart; index++) {\n offsetBefore += heightAt(index);\n }\n let offsetAfter = 0;\n for (let index = overscanEnd + 1; index < rowCount; index++) {\n offsetAfter += heightAt(index);\n }\n\n return {\n startIndex: overscanStart,\n endIndex: overscanEnd,\n offsetBefore,\n offsetAfter,\n };\n}\n"],"mappings":";AAOA,SAAS,SAAS,OAAkD;AAClE,SACE,OAAO,UAAU,YACjB,UAAU,QACV,CAAC,MAAM,QAAQ,KAAK,KACpB,EAAE,iBAAiB;AAEvB;AAEA,SAAS,QAAQ,OAA4B;AAC3C,MAAI,iBAAiB,KAAM,QAAO;AAClC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO;AACT;AAMO,SAAS,iBAAiB,MAAmC;AAClE,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,aAAa,OAAiC;AACrD,SAAO,iBAAiB,QAAQ,KAAK,CAAC;AACxC;AAeO,SAAS,sBACd,MACwC;AACxC,QAAM,UAAyC,CAAC;AAChD,QAAM,OAAO,oBAAI,IAAY;AAE7B,WAAS,IAAI,OAAe,OAAsB;AAChD,QAAI,KAAK,IAAI,KAAK,GAAG;AACnB;AAAA,IACF;AACA,SAAK,IAAI,KAAK;AACd,YAAQ,KAAK;AAAA,MACX;AAAA,MACA,MAAM,QAAQ,KAAK;AAAA,MACnB,WAAW,aAAa,KAAK;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,SAAS,GAAG,GAAG;AAClB;AAAA,IACF;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,UAAI,CAAC,SAAS,KAAK,GAAG;AACpB,YAAI,KAAK,KAAK;AACd;AAAA,MACF;AACA,iBAAW,CAAC,WAAW,WAAW,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC5D,YAAI,CAAC,SAAS,WAAW,GAAG;AAC1B,cAAI,GAAG,GAAG,IAAI,SAAS,IAAI,WAAW;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,YACd,QACQ;AACR,SAAO,OAAO,MAAM,OAAO;AAC7B;AAYO,SAAS,aACd,KACA,OACA,UACQ;AACR,SAAO,WAAW,KAAK,KAAK,KAAK,OAAO,KAAK;AAC/C;AAGA,SAAS,eAAe,OAAuB;AAC7C,SAAO,MAAM,MAAM,GAAG,EAAE,KAAK,GAAG;AAClC;AAOO,SAAS,mBACd,QACe;AACf,QAAM,EAAE,eAAe,IAAI;AAC3B,MAAI,mBAAmB,QAAW;AAChC,WAAO,OAAO,UAAU,eAAe,OAAO,KAAK;AAAA,EACrD;AAIA,SAAO,OAAO,mBAAmB,aAC5B,eAA8B,IAC/B;AACN;AASO,SAAS,wBACd,QACQ;AACR,MAAI,OAAO,WAAW,QAAW;AAC/B,WAAO,OAAO;AAAA,EAChB;AACA,QAAM,QAAQ,mBAAmB,MAAM;AACvC,SAAO,OAAO,UAAU,WAAW,QAAQ,eAAe,OAAO,KAAK;AACxE;AAiBO,SAAS,kBACd,cACQ;AACR,SAAO;AAAA,IACL,aAAa,cAAc,yCAAyC;AAAA;AAAA;AAAA;AAAA,IAIpE,aAAa,YAAY,2CAA2C;AAAA,IACpE,aAAa,WAAW,gBAAgB;AAAA;AAAA;AAAA,IAGxC,aAAa,YAAY,kBAAkB;AAAA;AAAA,IAE3C,aAAa,gBAAgB,OAAO,cAAc;AAAA,EACpD,EACG,OAAO,OAAO,EACd,KAAK,GAAG;AACb;AASO,SAAS,aAAa,KAAc,MAAuB;AAChE,SAAO,KACJ,MAAM,GAAG,EACT,OAAO,CAAC,OAAO,QAAS,SAAS,KAAK,IAAI,MAAM,GAAG,IAAI,QAAY,GAAG;AAC3E;;;AC5MA,SAAS,QAAQ,OAAyB;AACxC,SAAO,UAAU,QAAQ,UAAU;AACrC;AAGA,SAAS,OAAO,OAAwB;AACtC,SAAO,iBAAiB,OACpB,MAAM,QAAQ,IACd,IAAI,KAAK,OAAO,KAAK,CAAC,EAAE,QAAQ;AACtC;AAYO,SAAS,cACd,GACA,GACA,MACQ;AACR,MAAI,QAAQ,CAAC,GAAG;AACd,WAAO,QAAQ,CAAC,IAAI,IAAI;AAAA,EAC1B;AACA,MAAI,QAAQ,CAAC,GAAG;AACd,WAAO;AAAA,EACT;AAEA,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,OAAO,CAAC,IAAI,OAAO,CAAC;AAAA,IAC7B,KAAK;AACH,aAAO,OAAO,QAAQ,CAAC,CAAC,IAAI,OAAO,QAAQ,CAAC,CAAC;AAAA,IAC/C,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,OAAO,CAAC,IAAI,OAAO,CAAC;AAAA,IAC7B;AACE,aAAO,OAAO,CAAC,EAAE,cAAc,OAAO,CAAC,CAAC;AAAA,EAC5C;AACF;AAGO,SAAS,iBACd,MACA,UACsB;AACtB,SAAO,KAAK,KAAK,CAAC,UAAU,MAAM,aAAa,QAAQ,GAAG,aAAa;AACzE;AAGO,SAAS,gBACd,MACA,UACe;AACf,QAAM,QAAQ,KAAK,UAAU,CAAC,UAAU,MAAM,aAAa,QAAQ;AACnE,SAAO,UAAU,KAAK,OAAO,QAAQ;AACvC;AAeO,SAAS,iBACd,MACA,UACA,SACiB;AACjB,QAAM,QAAQ,KAAK,UAAU,CAAC,UAAU,MAAM,aAAa,QAAQ;AACnE,QAAM,cAAc,KAAK,WAAW,KAAK,UAAU;AAEnD,MAAI,CAAC,QAAQ,SAAS,CAAC,aAAa;AAClC,WAAO,CAAC,EAAE,UAAU,WAAW,MAAM,CAAC;AAAA,EACxC;AAEA,QAAM,UAAU,UAAU,KAAK,SAAY,KAAK,KAAK,GAAG;AACxD,QAAM,OACJ,YAAY,SAAY,QAAQ,YAAY,QAAQ,SAAS;AAE/D,MAAI,SAAS,MAAM;AACjB,WAAO,KAAK,OAAO,CAAC,UAAU,MAAM,aAAa,QAAQ;AAAA,EAC3D;AACA,MAAI,UAAU,IAAI;AAChB,WAAO,CAAC,GAAG,MAAM,EAAE,UAAU,WAAW,KAAK,CAAC;AAAA,EAChD;AACA,SAAO,KAAK;AAAA,IAAI,CAAC,OAAO,MACtB,MAAM,QAAQ,EAAE,UAAU,WAAW,KAAK,IAAI;AAAA,EAChD;AACF;AAmBO,SAAS,SACd,MACA,MACA,SAC6B;AAC7B,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;AACrE,QAAM,SAAS,KAAK,OAAO,CAAC,UAAU,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC9D,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM;AACtC,eAAW,EAAE,UAAU,UAAU,KAAK,QAAQ;AAC5C,YAAM,SAAS,KAAK,IAAI,QAAQ;AAChC,UAAI,WAAW,QAAW;AACxB;AAAA,MACF;AACA,YAAM,OAAO,aAAa,EAAE,KAAK,OAAO,KAAK;AAC7C,YAAM,QAAQ,aAAa,EAAE,KAAK,OAAO,KAAK;AAC9C,YAAM,YAAY,QAAQ,IAAI;AAC9B,YAAM,aAAa,QAAQ,KAAK;AAChC,UAAI,aAAa,YAAY;AAC3B,YAAI,aAAa,YAAY;AAC3B;AAAA,QACF;AACA,eAAO,YAAY,IAAI;AAAA,MACzB;AAEA,YAAM,SAAS,cAAc,MAAM,OAAO,OAAO,IAAI;AACrD,UAAI,WAAW,GAAG;AAChB,eAAO,cAAc,QAAQ,SAAS,CAAC;AAAA,MACzC;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,OAAO;AAAA,IAAI,CAAC,KAAK,UACtB,IAAI,aAAa,QAAQ,MAAM,EAAE,GAAG,KAAK,UAAU,MAAM;AAAA,EAC3D;AACF;;;ACzJO,SAAS,WAAW,MAAkC;AAC3D,SAAO,KAAK,UAAU,IAAI;AAC5B;AAiBO,SAAS,UAAU,OAAwB;AAChD,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO;AAAA,EACT;AACA,MAAI,iBAAiB,MAAM;AACzB,WAAO,UAAU,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,EAC1C;AACA,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC;AAAA,IAC3C,KAAK;AACH,aAAO;AAAA,IACT;AAEE,aAAO,YAAY,KAAK,UAAU,KAAK,CAAC;AAAA,EAC5C;AACF;AAQA,SAAS,iBACP,MACA,QACA,WAC4B;AAC5B,QAAM,UAAU,oBAAI,IAA6B;AACjD,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,aAAa,IAAI,KAAK,OAAO,KAAK;AAChD,UAAM,MAAM,UAAU,KAAK;AAC3B,UAAM,SAAS,QAAQ,IAAI,GAAG;AAC9B,QAAI,WAAW,QAAW;AACxB,cAAQ,IAAI,KAAK,EAAE,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC;AAAA,IACzC,OAAO;AACL,aAAO,KAAK,KAAK,GAAG;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,SAAS,CAAC,GAAG,QAAQ,OAAO,CAAC;AACnC,SAAO,KAAK,CAAC,GAAG,MAAM;AACpB,UAAM,SAAS,cAAc,EAAE,OAAO,EAAE,OAAO,OAAO,IAAI;AAC1D,WAAO,cAAc,QAAQ,SAAS,CAAC;AAAA,EACzC,CAAC;AACD,SAAO;AACT;AAUA,SAAS,WACP,MACA,QACA,YACA,WACA,MACA,KACM;AACN,QAAM,QAAQ,OAAO,CAAC;AACtB,MAAI,UAAU,QAAW;AACvB,QAAI,KAAK,GAAG,IAAI;AAChB;AAAA,EACF;AAIA,QAAM,SAAS,KAAK,IAAI,MAAM,QAAQ;AACtC,MAAI,WAAW,QAAW;AACxB,QAAI,KAAK,GAAG,IAAI;AAChB;AAAA,EACF;AAEA,QAAM,OAAO,OAAO,MAAM,CAAC;AAC3B,QAAM,SAAS,iBAAiB,MAAM,QAAQ,MAAM,aAAa,KAAK;AAEtE,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,CAAC,GAAG,YAAY,MAAM,KAAK;AACxC,UAAM,UAAU,WAAW,IAAI;AAC/B,UAAM,WAAW,CAAC,UAAU,SAAS,OAAO;AAC5C,UAAM,SAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,OAAO,WAAW;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb;AAAA,MACA;AAAA,MACA,OAAO,MAAM,KAAK;AAAA;AAAA;AAAA;AAAA,MAIlB,UAAU;AAAA,MACV,cAAc;AAAA;AAAA;AAAA,MAGd,YAAY,oBAAI,IAAI;AAAA,IACtB;AACA,QAAI,KAAK,MAAM;AACf,QAAI,UAAU;AACZ,iBAAW,MAAM,MAAM,MAAM,MAAM,WAAW,MAAM,GAAG;AAAA,IACzD;AAAA,EACF;AACF;AAuBO,SAAS,UACd,MACA,SACA,WACA,SAC4B;AAC5B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;AACrE,QAAM,SAAS,QAAQ,OAAO,CAAC,UAAU,KAAK,IAAI,MAAM,QAAQ,CAAC;AACjE,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,MAAyB,CAAC;AAChC,aAAW,MAAM,QAAQ,CAAC,GAAG,WAAW,MAAM,GAAG;AAEjD,SAAO,IAAI,IAAI,CAAC,OAAO,UAAU;AAC/B,QAAI,UAAU,OAAO;AACnB,aAAO,MAAM,aAAa,SAAS,MAAM,iBAAiB,QACtD,QACA,EAAE,GAAG,OAAO,UAAU,OAAO,cAAc,MAAM;AAAA,IACvD;AACA,WAAO,MAAM,aAAa,QAAQ,QAAQ,EAAE,GAAG,OAAO,UAAU,MAAM;AAAA,EACxE,CAAC;AACH;AAMO,SAAS,qBACd,WACA,SACqB;AACrB,SAAO,UAAU,SAAS,OAAO,IAC7B,UAAU,OAAO,CAAC,OAAO,OAAO,OAAO,IACvC,CAAC,GAAG,WAAW,OAAO;AAC5B;AAGO,SAAS,gBACd,WACqB;AACrB,SAAO,UAAU,WAAW,IAAI,YAAY,CAAC;AAC/C;AAaO,SAAS,kBACd,MACqB;AACrB,SAAO,KACJ;AAAA,IACC,CAAC,UACC,UAAU,SAAS,MAAM,SAAS;AAAA,EACtC,EACC,IAAI,CAAC,UAAU,MAAM,OAAO;AACjC;AAoBO,SAAS,kBACd,SACA,UACA,gBACc;AACd,MAAI,aAAa,gBAAgB;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,QAAQ,OAAO,CAAC,UAAU,MAAM,aAAa,QAAQ;AACrE,QAAM,QAAQ,QAAQ,KAAK,CAAC,UAAU,MAAM,aAAa,QAAQ,KAAK;AAAA,IACpE;AAAA,EACF;AACA,QAAM,SACJ,mBAAmB,OACf,QAAQ,SACR,QAAQ,UAAU,CAAC,UAAU,MAAM,aAAa,cAAc;AACpE,MAAI,WAAW,IAAI;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,CAAC,GAAG,OAAO;AACxB,OAAK,OAAO,QAAQ,GAAG,KAAK;AAC5B,SAAO,KAAK,WAAW,QAAQ,UAC7B,KAAK,MAAM,CAAC,OAAO,UAAU,UAAU,QAAQ,KAAK,CAAC,IACnD,UACA;AACN;AASO,SAAS,aACd,SACA,UACA,gBACS;AACT,SAAO,kBAAkB,SAAS,UAAU,cAAc,MAAM;AAClE;;;AC9SO,SAAS,YACd,SAC2B;AAC3B,MAAI;AACJ,SAAO,IAAI,SAAS;AAClB,UAAM,WAAW;AACjB,QACE,aAAa,UACb,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,GAAG,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,GAC/D;AACA,aAAO,SAAS;AAAA,IAClB;AACA,UAAM,SAAS,QAAQ,GAAG,IAAI;AAC9B,WAAO,EAAE,MAAM,OAAO;AACtB,WAAO;AAAA,EACT;AACF;;;ACPO,SAAS,iBACd,SACA,OACwC;AACxC,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,WAAW,CAAC,YAAY,MAAM,GAAG,MAAM,CAAC,CAAC;AAC3E,QAAM,SAAS,MACZ,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC,EACxB,OAAO,CAAC,WAAW,WAAW,MAAS;AAC1C,QAAM,QAAQ,IAAI,IAAI,OAAO,IAAI,CAAC,WAAW,YAAY,MAAM,CAAC,CAAC;AAEjE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG,QAAQ,OAAO,CAAC,WAAW,CAAC,MAAM,IAAI,YAAY,MAAM,CAAC,CAAC;AAAA,EAC/D;AACF;AASO,SAAS,mBACd,SACA,OACkC;AAClC,SAAO,iBAAiB,SAAS,KAAK,EAAE,IAAI,CAAC,YAAY;AAAA,IACvD,IAAI,YAAY,MAAM;AAAA,IACtB;AAAA,EACF,EAAE;AACJ;AASO,SAAS,iBACd,YACA,SACA,UACkB;AAClB,MAAI,YAAY,YAAY,CAAC,WAAW,SAAS,OAAO,GAAG;AACzD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,WAAW,OAAO,CAAC,OAAO,OAAO,OAAO;AAGxD,QAAM,SAAS,aAAa,OAAO,QAAQ,SAAS,QAAQ,QAAQ,QAAQ;AAC5E,MAAI,WAAW,IAAI;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,CAAC,GAAG,OAAO;AACxB,OAAK,OAAO,QAAQ,GAAG,OAAO;AAC9B,SAAO,KAAK,MAAM,CAAC,IAAI,UAAU,OAAO,WAAW,KAAK,CAAC,IACrD,aACA;AACN;AASO,SAAS,YACd,YACA,SACA,UACS;AACT,SAAO,iBAAiB,YAAY,SAAS,QAAQ,MAAM;AAC7D;AASO,SAAS,kBACd,YACA,UACA,MACe;AACf,MAAI,SAAS,UAAU;AACrB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,WAAW,QAAQ,QAAQ;AACzC,SAAO,UAAU,KAAK,OAAQ,WAAW,QAAQ,CAAC,KAAK;AACzD;AAWO,SAAS,0BACd,YACA,UACA,WAC2B;AAC3B,QAAM,QAAQ,WAAW,QAAQ,QAAQ;AACzC,MAAI,UAAU,IAAI;AAChB,WAAO;AAAA,EACT;AAMA,QAAM,cAAc,cAAc,KAAK,QAAQ,IAAI,QAAQ;AAC3D,MAAI,cAAc,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,SAAO,WAAW,WAAW,KAAK;AACpC;;;ACzGA,SAAS,QAAa,MAAmD;AACvE,QAAM,QAAgB,CAAC;AACvB,MAAI,QAAQ;AACZ,MAAI,gBAAgB;AACpB,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,UAAM,QAAQ,KAAK,KAAK;AACxB,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AACA,UAAM,mBACJ,UAAU,SAAS,MAAM,SAAS,WAAW,MAAM,UAAU;AAC/D,UAAM,aAAa,UAAU,UAAU,oBAAoB,CAAC;AAC5D,QAAI,YAAY;AACd,YAAM,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;AAChC,cAAQ;AACR,sBAAgB;AAAA,IAClB,WAAW,UAAU,OAAO;AAC1B,sBAAgB;AAAA,IAClB;AAAA,EACF;AACA,MAAI,QAAQ,KAAK,QAAQ;AACvB,UAAM,KAAK,EAAE,OAAO,KAAK,KAAK,OAAO,CAAC;AAAA,EACxC;AACA,SAAO;AACT;AAaO,SAAS,aACd,MACA,YACoB;AACpB,QAAM,WAAW,KAAK,IAAI,GAAG,WAAW,QAAQ;AAChD,QAAM,QAAQ,QAAQ,IAAI;AAC1B,QAAM,YAAY,KAAK,KAAK,MAAM,SAAS,QAAQ;AAEnD,MAAI,cAAc,GAAG;AACnB,WAAO,EAAE,MAAM,CAAC,GAAG,WAAW,GAAG,WAAW,EAAE;AAAA,EAChD;AAEA,QAAM,YAAY,KAAK,IAAI,KAAK,IAAI,WAAW,WAAW,CAAC,GAAG,YAAY,CAAC;AAC3E,QAAM,YAAY,MAAM,YAAY,QAAQ;AAC5C,QAAM,WACJ,MAAM,KAAK,IAAI,YAAY,WAAW,UAAU,MAAM,MAAM,IAAI,CAAC;AACnE,MAAI,cAAc,UAAa,aAAa,QAAW;AACrD,WAAO,EAAE,MAAM,CAAC,GAAG,WAAW,UAAU;AAAA,EAC1C;AAEA,QAAM,OAAO,KAAK,MAAM,UAAU,OAAO,SAAS,GAAG;AACrD,QAAM,aAAa,KAAK;AAAA,IAAI,CAAC,OAAO,UAClC,MAAM,aAAa,QAAQ,QAAQ,EAAE,GAAG,OAAO,UAAU,MAAM;AAAA,EACjE;AAEA,SAAO,EAAE,MAAM,YAAY,WAAW,UAAU;AAClD;;;AC7FO,SAAS,YAAY,SAAuB;AACjD,UAAQ,MAAM,YAAY,OAAO,EAAE;AACrC;;;ACIA,IAAM,eAAyB,MAAM;AAErC,SAAS,OAAO,MAAyC;AACvD,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAGO,SAAS,WAAW,MAAuC;AAChE,SAAO,OAAO,IAAI,MAAM;AAC1B;AAOO,SAAS,YAAY,OAAyB;AACnD,SAAO,UAAU,QAAQ,UAAU,UAAa,UAAU;AAC5D;AAOO,SAAS,OAAO,OAAkC;AACvD,QAAM,OACJ,iBAAiB,OACb,QACA,OAAO,UAAU,WACf,IAAI,KAAK,KAAK,IACd;AACR,SAAO,SAAS,UAAa,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,SAAY;AAC1E;AAOA,SAAS,WAAW,OAAgB,MAA0B;AAC5D,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO,UAAU,YAAY,CAAC,OAAO,MAAM,KAAK,IACnD,QACA;AAAA,IACN,KAAK;AACH,aAAO,OAAO,UAAU,YAAY,QAAQ;AAAA,IAC9C,KAAK;AACH,aAAO,OAAO,KAAK;AAAA,IACrB,KAAK;AACH,aAAO,OAAO,KAAK,EAAE,YAAY;AAAA,EACrC;AACF;AAGA,SAAS,gBAAgB,SAAkB,MAA0B;AACnE,MAAI,SAAS,QAAQ;AACnB,WAAO,WAAW,SAAS,IAAI,MAAM;AAAA,EACvC;AACA,SACE,OAAO,YAAY,YACnB,OAAO,YAAY,YACnB,OAAO,YAAY;AAEvB;AAOA,SAAS,kBACP,SACA,MACwB;AACxB,QAAM,OAAO,OAAO,IAAI;AACxB,MAAI,CAAC,gBAAgB,SAAS,IAAI,GAAG;AACnC,WAAO;AAAA,EACT;AACA,QAAM,SAAS,WAAW,SAAS,IAAI;AACvC,SAAO,CAAC,UAAU;AAChB,QAAI,YAAY,KAAK,GAAG;AACtB,aAAO;AAAA,IACT;AACA,UAAM,OAAO,WAAW,OAAO,IAAI;AACnC,WAAO,SAAS,SAAY,SAAY,cAAc,MAAM,QAAQ,IAAI;AAAA,EAC1E;AACF;AAGO,SAAS,aACd,SAC8B;AAC9B,SAAO,MAAM,QAAQ,OAAO;AAC9B;AAEA,SAAS,gBACP,UACA,SACA,MACU;AACV,QAAM,UAAU,kBAAkB,SAAS,IAAI;AAC/C,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,QACJ,CAAC,UACD,CAAC,UAAU;AACT,UAAM,SAAS,QAAQ,KAAK;AAC5B,WAAO,WAAW,UAAa,MAAM,MAAM;AAAA,EAC7C;AACF,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,MAAM,CAAC,WAAW,WAAW,CAAC;AAAA,IACvC,KAAK,MAAM;AACT,YAAM,SAAS,MAAM,CAAC,WAAW,WAAW,CAAC;AAC7C,aAAO,CAAC,UAAU,CAAC,OAAO,KAAK;AAAA,IACjC;AAAA,IACA,KAAK;AACH,aAAO,MAAM,CAAC,WAAW,SAAS,CAAC;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,CAAC,WAAW,UAAU,CAAC;AAAA,IACtC,KAAK;AACH,aAAO,MAAM,CAAC,WAAW,SAAS,CAAC;AAAA,IACrC,KAAK;AACH,aAAO,MAAM,CAAC,WAAW,UAAU,CAAC;AAAA,EACxC;AACF;AAEA,SAAS,eACP,SACA,MACU;AACV,MAAI,CAAC,aAAa,OAAO,KAAK,QAAQ,WAAW,GAAG;AAClD,WAAO;AAAA,EACT;AACA,QAAM,CAAC,KAAK,IAAI,IAAI;AACpB,QAAM,UAAU,kBAAkB,KAAK,IAAI;AAC3C,QAAM,WAAW,kBAAkB,MAAM,IAAI;AAC7C,MAAI,YAAY,UAAa,aAAa,QAAW;AACnD,WAAO;AAAA,EACT;AACA,SAAO,CAAC,UAAU;AAChB,UAAM,WAAW,QAAQ,KAAK;AAC9B,UAAM,YAAY,SAAS,KAAK;AAChC,WACE,aAAa,UACb,cAAc,UACd,YAAY,KACZ,aAAa;AAAA,EAEjB;AACF;AAQO,SAAS,eACd,OACA,MACQ;AACR,SAAO,UAAU,WAAW,IAAI,IAAK,OAAO,KAAK,KAAK,QAAS,KAAK;AACtE;AAEA,SAAS,UAAU,SAAkB,MAAwC;AAC3E,MAAI,CAAC,aAAa,OAAO,GAAG;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,OAAO,IAAI;AAAA,IACf,QACG,OAAO,CAAC,WAAW,CAAC,YAAY,MAAM,CAAC,EACvC,IAAI,CAAC,WAAW,eAAe,QAAQ,IAAI,CAAC;AAAA,EACjD;AACA,SAAO,CAAC,UACN,CAAC,YAAY,KAAK,KAAK,KAAK,IAAI,eAAe,OAAO,IAAI,CAAC;AAC/D;AAEA,SAAS,YACP,UACA,SACU;AACV,MAAI,CAAC,gBAAgB,SAAS,MAAM,GAAG;AACrC,WAAO;AAAA,EACT;AACA,QAAM,OAAO,OAAO,OAAO,EAAE,YAAY;AACzC,QAAM,OAAO,CAAC,UAAmB,OAAO,KAAK,EAAE,YAAY;AAC3D,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,CAAC,UAAU,CAAC,YAAY,KAAK,KAAK,KAAK,KAAK,EAAE,SAAS,IAAI;AAAA,IACpE,KAAK;AACH,aAAO,CAAC,UAAU,YAAY,KAAK,KAAK,CAAC,KAAK,KAAK,EAAE,SAAS,IAAI;AAAA,IACpE,KAAK;AACH,aAAO,CAAC,UAAU,CAAC,YAAY,KAAK,KAAK,KAAK,KAAK,EAAE,WAAW,IAAI;AAAA,IACtE,KAAK;AACH,aAAO,CAAC,UAAU,CAAC,YAAY,KAAK,KAAK,KAAK,KAAK,EAAE,SAAS,IAAI;AAAA,EACtE;AACF;AAQO,SAAS,qBACd,OACA,MACU;AACV,QAAM,EAAE,UAAU,MAAM,IAAI;AAC5B,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,CAAC,SAAS,CAAC,YAAY,IAAI;AAAA,IACpC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,YAAY,UAAU,KAAK;AAAA,IACpC,KAAK;AACH,aAAO,eAAe,OAAO,IAAI;AAAA,IACnC,KAAK;AACH,aAAO,UAAU,OAAO,IAAI;AAAA,IAC9B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,gBAAgB,UAAU,OAAO,IAAI;AAAA,EAChD;AACF;;;ACrPA,SAAS,gBAAgB,QAA8C;AACrE,SAAO,kBAAkB,OAAO,OAAO,YAAY,IAAI;AACzD;AAEA,SAAS,iBAAiB,SAAqC;AAC7D,SAAO,aAAa,OAAO,IACvB,QAAQ,IAAI,eAAe,IAC3B,gBAAgB,OAAO;AAC7B;AAMA,SAAS,eACP,OACwC;AACxC,MAAI,gBAAgB,OAAO;AACzB,UAAM,UAAU,gBAAgB,MAAM,OAAO;AAG7C,WAAO,QAAQ,WAAW,KAAK,MAAM,QAAQ,SAAS,IAClD,SACA,EAAE,YAAY,MAAM,YAAY,QAAQ;AAAA,EAC9C;AACA,MAAI,eAAe,OAAO;AACxB;AAAA,MACE,MAAM,aAAa,SACf,6GACA,iCAAiC,MAAM,QAAQ;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AACA,MAAI,cAAc,OAAO;AACvB,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,WAAO,UAAU,SACb,OACA,EAAE,GAAG,MAAM,OAAO,iBAAiB,KAAK,EAAE;AAAA,EAChD;AACA,MAAI,WAAW,OAAO;AACpB,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,OAAO,iBAAiB,OAAO,MAAM,YAAY,IAAI;AAAA,IACvD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBACP,QAC4B;AAC5B,SAAO,OACJ,IAAI,CAAC,UAAU,eAAe,KAAK,CAAC,EACpC,OAAO,CAAC,UAAU,UAAU,MAAS;AAC1C;AAUO,SAAS,mBACd,OAC0B;AAC1B,SAAO,EAAE,GAAG,OAAO,QAAQ,gBAAgB,MAAM,MAAM,EAAE;AAC3D;AAGA,SAAS,aACP,QACA,MACc;AACd,SAAO,WAAW,IAAI,KAAK,OAAO,WAAW,WACxC,OAAO,MAAM,KAAK,SACnB;AACN;AAEA,SAAS,cACP,SACA,MACS;AACT,SAAO,aAAa,OAAO,IACvB,QAAQ,IAAI,CAAC,WAAW,aAAa,QAAQ,IAAI,CAAC,IAClD,aAAa,SAAS,IAAI;AAChC;AAEA,SAAS,YACP,OACA,QACkB;AAClB,MAAI,gBAAgB,OAAO;AACzB,WAAO;AAAA,MACL,YAAY,MAAM;AAAA,MAClB,SAAS,cAAc,MAAM,SAAS,MAAM;AAAA,IAC9C;AAAA,EACF;AACA,MAAI,cAAc,OAAO;AACvB,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,WAAO,UAAU,SACb,OACA,EAAE,GAAG,MAAM,OAAO,cAAc,OAAO,OAAO,MAAM,QAAQ,CAAC,EAAE;AAAA,EACrE;AACA,MAAI,WAAW,OAAO;AACpB,UAAM,EAAE,OAAO,GAAG,KAAK,IAAI;AAC3B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,OAAO,OAAO,UAAU,WAAW,IAAI,KAAK,KAAK,IAAI;AAAA,IACvD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cACP,QACA,QACkB;AAClB,SAAO,OAAO,IAAI,CAAC,UAAU,YAAY,OAAO,MAAM,CAAC;AACzD;AAUO,SAAS,aACd,QACA,SACkB;AAClB,QAAM,QAAQ,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC;AAC3E,SAAO,cAAc,QAAQ,CAAC,aAAa,MAAM,IAAI,QAAQ,CAAC;AAChE;;;AChJO,IAAM,uBAA2C;AAAA,EACtD,OAAO;AAAA,EACP,UAAU;AAAA,EACV,UAAU,OAAO;AACnB;AAGO,IAAM,gBAAgB;AAE7B,SAAS,aACP,UACoB;AACpB,SAAO,EAAE,GAAG,sBAAsB,GAAG,SAAS;AAChD;AAMO,SAAS,yBACd,QACA,UACmB;AACnB,QAAM,WAAW,aAAa,QAAQ;AACtC,SAAO;AAAA,IACL,UAAU,OAAO,YAAY,SAAS;AAAA,IACtC,UAAU,OAAO,YAAY,SAAS;AAAA,EACxC;AACF;AAGO,SAAS,iBACd,OACA,aACQ;AACR,SAAO,KAAK,IAAI,KAAK,IAAI,OAAO,YAAY,QAAQ,GAAG,YAAY,QAAQ;AAC7E;AAWO,SAAS,oBACd,SACA,QACA,SACsC;AACtC,QAAM,WAAW,aAAa,SAAS,KAAK;AAE5C,SAAO,QAAQ,IAAI,CAAC,WAAW;AAC7B,UAAM,KAAK,YAAY,MAAM;AAC7B,UAAM,SAAS,OAAO,EAAE;AAExB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO,WAAW;AAAA,MAClB,OAAO;AAAA,QACL,UAAU,OAAO,SAAS,SAAS;AAAA,QACnC,yBAAyB,QAAQ,QAAQ;AAAA,MAC3C;AAAA,MACA,OAAO,mBAAmB,MAAM;AAAA,MAChC,WAAW,OAAO,aAAa,SAAS,aAAa;AAAA,MACrD,aAAa,OAAO,eAAe,SAAS,eAAe;AAAA,MAC3D,kBACE,OAAO,oBAAoB,SAAS,oBAAoB;AAAA,MAC1D,WAAW,OAAO,aAAa,iBAAiB,OAAO,QAAQ,QAAQ;AAAA,IACzE;AAAA,EACF,CAAC;AACH;AAEO,SAAS,iBACd,UACQ;AACR,SAAO,SAAS,OAAO,CAAC,OAAO,UAAU,QAAQ,MAAM,OAAO,CAAC;AACjE;AASO,SAAS,kBACd,QACA,YACA,eACA,UACqB;AACrB,SAAO;AAAA,IACL,UAAU,YAAY,MAAM;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,aAAa,yBAAyB,QAAQ,QAAQ;AAAA,EACxD;AACF;AAMO,SAAS,kBACd,SACA,UACQ;AACR,SAAO;AAAA,IACL,QAAQ,cAAc,WAAW,QAAQ;AAAA,IACzC,QAAQ;AAAA,EACV;AACF;AAcA,SAAS,aACP,OACA,MACS;AACT,SAAO,KAAK,QAAQ,KAAK,QAAQ,SAAS,KAAK,QAAQ,SAAS,KAAK;AACvE;AAQA,SAAS,aACP,SACA,WACM;AACN,aAAS;AACP,UAAM,UAAU,QAAQ;AAAA,MACtB,CAAC,SAAS,KAAK,cAAc,CAAC,aAAa,KAAK,OAAO,IAAI;AAAA,IAC7D;AACA,UAAM,OAAO,UAAU,QAAQ,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC,CAAC;AAC/D,QAAI,QAAQ,KAAK,QAAQ,WAAW,GAAG;AACrC;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ,OAAO,CAAC,OAAO,SAAS,QAAQ,KAAK,OAAO,CAAC;AAClE,QAAI,UAAU;AAEd,eAAW,QAAQ,SAAS;AAC1B,YAAM,QACJ,SAAS,IAAI,OAAO,QAAQ,SAAU,OAAO,KAAK,QAAS;AAC7D,YAAM,OAAO,KAAK,SAAS,KAAK,QAAQ,KAAK,QAAQ,QAAQ,CAAC;AAE9D,UAAI,aAAa,MAAM,IAAI,GAAG;AAC5B,aAAK,QAAQ,KAAK;AAClB,kBAAU;AAAA,MACZ,OAAO;AACL,aAAK,QAAQ;AAAA,MACf;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AAAA,EACF;AACF;AAcO,SAAS,kBACd,UACA,gBACA,UACsC;AACtC,QAAM,SAAS,KAAK,MAAM,cAAc;AACxC,QAAM,QAAQ,iBAAiB,QAAQ;AACvC,MAAI,SAAS,WAAW,KAAK,UAAU,QAAQ;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,QAAQ;AACxB,QAAM,UAAoC,SAAS,IAAI,CAAC,UAAU;AAChE,UAAM,cAAc,yBAAyB,MAAM,QAAQ,QAAQ;AACnE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,MAAM;AAAA,MACb,OAAO,UAAU,YAAY,WAAW,YAAY;AAAA,MACpD,YAAY,CAAC,MAAM;AAAA,IACrB;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS;AAGZ,UAAM,QAAQ,QAAQ;AAAA,MACpB,CAAC,KAAK,SAAS,OAAO,KAAK,aAAa,KAAK,QAAQ,KAAK;AAAA,MAC1D;AAAA,IACF;AACA,QAAI,QAAQ,QAAQ;AAClB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,eAAa,SAAS,CAAC,QAAS,UAAU,SAAS,MAAM,MAAM,MAAO;AAMtE,QAAM,UAAU,QAAQ;AAAA,IAAI,CAAC,SAC3B,UAAU,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK;AAAA,EACzD;AACA,MAAI,YAAY,SAAS,QAAQ,OAAO,CAACA,QAAO,UAAUA,SAAQ,OAAO,CAAC;AAE1E,SAAO,QAAQ,IAAI,CAAC,MAAM,UAAU;AAClC,QAAI,QAAQ,QAAQ,KAAK,KAAK,KAAK;AAInC,UAAM,UAAU,UAAU,QAAQ,KAAK,QAAQ,QAAQ,KAAK;AAE5D,QAAI,cAAc,KAAK,KAAK,cAAc,SAAS;AACjD,eAAS,UAAU,IAAI;AACvB,mBAAa,UAAU,KAAK;AAAA,IAC9B;AAEA,WAAO,EAAE,GAAG,KAAK,OAAO,MAAM;AAAA,EAChC,CAAC;AACH;AAQO,SAAS,oBACd,eACA,aACA,UAAU,GACF;AACR,SAAO,iBAAiB,KAAK,KAAK,gBAAgB,OAAO,GAAG,WAAW;AACzE;AAUO,SAAS,iBACd,SACA,MACA,UACmB;AACnB,QAAM,OAAO,OAAO;AAAA,IAClB,OAAO,QAAQ,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,OAAO,QAAQ;AAAA,EAC1D;AACA,MAAI,YAAY,MAAM;AACpB,SAAK,QAAQ,IAAI,KAAK,QAAQ;AAAA,EAChC;AACA,SAAO;AACT;;;AC1RA,SAASC,SAAQ,OAAyB;AACxC,SAAO,UAAU,QAAQ,UAAU;AACrC;AAGA,SAAS,SAAS,OAAwB;AACxC,SAAO,OAAO,KAAK;AACrB;AAQA,SAAS,YAAY,OAAwB;AAC3C,MAAIA,SAAQ,KAAK,GAAG;AAClB,WAAO;AAAA,EACT;AACA,MAAI,iBAAiB,MAAM;AACzB,WAAO,UAAU,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,EAC1C;AACA,UAAQ,OAAO,OAAO;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,KAAK,OAAO,KAAK,IAAI,OAAO,KAAK,CAAC;AAAA,IAC3C,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,YAAY,KAAK,UAAU,KAAK,CAAC;AAAA,EAC5C;AACF;AAkBA,SAAS,cACP,MACA,IACA,QACS;AACT,MAAI,OAAO,SAAS;AAClB,WAAO,KAAK;AAAA,EACd;AAEA,QAAM,QAAQ,QAAQ,OAAO;AAC7B,QAAM,SACJ,UAAU,SAAY,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,aAAa,KAAK,KAAK,CAAC;AAEvE,UAAQ,IAAI;AAAA,IACV,KAAK,OAAO;AACV,UAAI,QAAQ;AACZ,iBAAW,SAAS,QAAQ;AAC1B,YAAIA,SAAQ,KAAK,EAAG;AACpB,iBAAS,SAAS,KAAK;AAAA,MACzB;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,OAAO;AACV,YAAM,UAAU,OAAO,OAAO,CAAC,UAAU,CAACA,SAAQ,KAAK,CAAC;AACxD,UAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,YAAM,QAAQ,QAAQ;AAAA,QACpB,CAAC,KAAa,UAAU,MAAM,SAAS,KAAK;AAAA,QAC5C;AAAA,MACF;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,IACA,KAAK;AAAA,IACL,KAAK,OAAO;AACV,YAAM,OAAO,QAAQ,OAAO;AAC5B,UAAI;AACJ,iBAAW,SAAS,QAAQ;AAC1B,YAAIA,SAAQ,KAAK,EAAG;AACpB,YAAI,WAAW,QAAW;AACxB,mBAAS;AACT;AAAA,QACF;AACA,cAAM,aAAa,cAAc,OAAO,QAAQ,IAAI;AACpD,YAAI,OAAO,QAAQ,aAAa,IAAI,aAAa,GAAG;AAClD,mBAAS;AAAA,QACX;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,iBAAiB;AACpB,YAAM,OAAO,oBAAI,IAAY;AAC7B,iBAAW,SAAS,QAAQ;AAC1B,YAAIA,SAAQ,KAAK,EAAG;AACpB,aAAK,IAAI,YAAY,KAAK,CAAC;AAAA,MAC7B;AACA,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACF;AAGA,SAAS,MAAW,MAAkC;AACpD,SAAO,KAAK,MAAM,KAAK;AACzB;AAiBO,SAAS,kBACd,MACA,OACA,SACkB;AAClB,QAAM,UAAU,oBAAI,IAAqB;AACzC,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAC9D,aAAW,QAAQ,OAAO;AACxB,UAAM,QACJ,OAAO,KAAK,OAAO,aACf,KAAK,GAAG,IAAI,IACZ,cAAc,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,QAAQ,CAAC;AAC1D,YAAQ,IAAI,MAAM,IAAI,GAAG,KAAK;AAAA,EAChC;AACA,SAAO;AACT;AAgBA,SAAS,kBACP,UACA,MACA,SACA,MACO;AACP,QAAM,OAAO,KAAK,IAAI,CAAC,UAAU,UAAU,KAAK,CAAC;AACjD,SAAO,SACJ;AAAA,IAAO,CAAC,QACP,KAAK,MAAM,CAAC,KAAK,UAAU;AACzB,YAAM,WAAW,QAAQ,KAAK,GAAG;AACjC,YAAM,SAAS,aAAa,SAAY,SAAY,KAAK,IAAI,QAAQ;AACrE,UAAI,WAAW,OAAW,QAAO;AACjC,aAAO,UAAU,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC,MAAM;AAAA,IAC5D,CAAC;AAAA,EACH,EACC,IAAI,CAAC,QAAQ,IAAI,GAAG;AACzB;AAyCA,SAAS,qBACP,aACA,OACA,YACA,UACA,SACA,MACA,OACA,SACA,SACA,KACQ;AACR,MAAI,QAAQ;AACZ,SAAO,QAAQ,YAAY,QAAQ;AACjC,UAAM,QAAQ,YAAY,KAAK;AAC/B,QAAI,UAAU,QAAW;AACvB;AACA;AAAA,IACF;AACA,QACE,eAAe,QACf,UAAU,SACV,MAAM,SAAS,WACf,MAAM,SAAS,YACf;AAGA;AAAA,IACF;AACA;AACA,QAAI,EAAE,UAAU,UAAU,MAAM,SAAS,SAAS;AAChD,UAAI,KAAK,KAAK;AACd;AAAA,IACF;AAEA,UAAM,SAAS,kBAAkB,UAAU,MAAM,MAAM,SAAS,IAAI;AACpE,UAAM,aAAa,kBAAkB,QAAQ,OAAO,OAAO;AAC3D,UAAM,iBAAmC,EAAE,GAAG,OAAO,WAAW;AAChE,QAAI,KAAK,cAAc;AAEvB,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,YAAY,OAAO;AACrB,YAAM,UAAmC;AAAA,QACvC,MAAM;AAAA,QACN,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,QACb,UAAU;AAAA,QACV,cAAc;AAAA,QACd;AAAA,MACF;AACA,UAAI,KAAK,OAAO;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,oBACd,aACA,UACA,SACA,OACA,SACA,UAAiC,UACL;AAC5B,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;AACrE,QAAM,MAAyB,CAAC;AAChC;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,IAAI,IAAI,CAAC,OAAO,aAAa;AAClC,QAAI,UAAU,OAAO;AACnB,aAAO,MAAM,aAAa,YAAY,MAAM,iBAAiB,WACzD,QACA,EAAE,GAAG,OAAO,UAAU,UAAU,cAAc,SAAS;AAAA,IAC7D;AACA,WAAO,MAAM,aAAa,WACtB,QACA,EAAE,GAAG,OAAO,UAAU,SAAS;AAAA,EACrC,CAAC;AACH;;;ACnUA,SAAS,mBAAmB,OAA8B;AACxD,QAAM,QAAQ,MAAM,WAAW,GAAG;AAClC,QAAM,MAAM,MAAM,SAAS,GAAG;AAC9B,MAAI,OAAO;AACX,MAAI,OAAO;AACT,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,MAAI,KAAK;AACP,WAAO,KAAK,MAAM,GAAG,EAAE;AAAA,EACzB;AACA,SAAO,KAAK,YAAY;AAExB,MAAI,SAAS,KAAK;AAChB,WAAO,EAAE,MAAM,YAAY,KAAK;AAAA,EAClC;AACA,MAAI,OAAO;AACT,WAAO,EAAE,MAAM,YAAY,KAAK;AAAA,EAClC;AACA,MAAI,KAAK;AACP,WAAO,EAAE,MAAM,cAAc,KAAK;AAAA,EACpC;AACA,SAAO,EAAE,MAAM,SAAS,KAAK;AAC/B;AAEA,SAAS,aAAa,OAAyB;AAC7C,SAAO,UAAU,QAAQ,UAAU;AACrC;AAMA,SAAS,mBAAmB,OAA4C;AACtE,QAAM,EAAE,MAAM,KAAK,IAAI,mBAAmB,KAAK;AAC/C,SAAO,CAAC,UAAmB;AACzB,UAAM,aAAa,aAAa,KAAK,IAAI,KAAK,OAAO,KAAK,GAAG,YAAY;AACzE,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,eAAO,cAAc;AAAA,MACvB,KAAK;AACH,eAAO,UAAU,SAAS,IAAI;AAAA,MAChC,KAAK;AACH,eAAO,UAAU,WAAW,IAAI;AAAA,MAClC,KAAK;AACH,eAAO,UAAU,SAAS,IAAI;AAAA,IAClC;AAAA,EACF;AACF;AAOA,SAAS,kBACP,OACA,QACA,MACS;AACT,MAAI,OAAO,WAAW,UAAU;AAC9B,QACE,SAAS,YACT,SAAS,aACT,SAAS,cACT,SAAS,WACT;AACA,aAAO;AAAA,IACT;AACA,WAAO,OAAO,UAAU,YAAY,UAAU;AAAA,EAChD;AACA,MAAI,OAAO,WAAW,WAAW;AAC/B,QAAI,SAAS,WAAW;AACtB,aAAO;AAAA,IACT;AACA,WAAO,OAAO,UAAU,aAAa,UAAU;AAAA,EACjD;AACA,MAAI,SAAS,UAAU,SAAS,cAAc,SAAS,QAAQ;AAC7D,WAAO;AAAA,EACT;AACA,SAAO,iBAAiB,QAAQ,MAAM,QAAQ,MAAM,OAAO,QAAQ;AACrE;AAkBA,SAAS,cACP,OACA,MACS;AACT,MAAI,gBAAgB,OAAO;AACzB,WAAO;AAAA,EACT;AACA,SAAO,MAAM,aAAa,UAAa,KAAK,IAAI,MAAM,QAAQ;AAChE;AAMA,SAAS,mBACP,OACA,MACA,SACuB;AACvB,MAAI,gBAAgB,OAAO;AACzB,UAAM,QAAQ,MAAM,QACjB,OAAO,CAAC,WAAW,cAAc,QAAQ,IAAI,CAAC,EAC9C,IAAI,CAAC,WAAW,mBAAmB,QAAQ,MAAM,OAAO,CAAC;AAC5D,WAAO,MAAM,eAAe,QACxB,CAAC,QAAQ,MAAM,MAAM,CAACC,UAASA,MAAK,GAAG,CAAC,IACxC,CAAC,QAAQ,MAAM,KAAK,CAACA,UAASA,MAAK,GAAG,CAAC;AAAA,EAC7C;AAEA,MAAI,eAAe,OAAO;AACxB,UAAM,EAAE,UAAAC,WAAU,UAAU,IAAI;AAChC,UAAM,SAASA,cAAa,SAAY,SAAY,KAAK,IAAIA,SAAQ;AACrE,WAAO,CAAC,QACN;AAAA,MACE,WAAW,SAAY,SAAY,aAAa,KAAK,OAAO,KAAK;AAAA,MACjE;AAAA,IACF;AAAA,EACJ;AAGA,MAAI,cAAc,OAAO;AACvB,UAAM,SAAS,KAAK,IAAI,MAAM,QAAQ;AACtC,QAAI,WAAW,QAAW;AACxB,aAAO,MAAM;AAAA,IACf;AACA,UAAMD,QAAO,qBAAqB,OAAO,OAAO,IAAI;AACpD,WAAO,CAAC,QAAQA,MAAK,aAAa,KAAK,OAAO,KAAK,CAAC;AAAA,EACtD;AAEA,MAAI,WAAW,OAAO;AACpB,UAAM,EAAE,UAAAC,WAAU,MAAM,IAAI;AAC5B,QAAIA,cAAa,QAAW;AAC1B,YAAM,SAAS,KAAK,IAAIA,SAAQ;AAChC,UAAI,WAAW,QAAW;AACxB,eAAO,MAAM;AAAA,MACf;AACA,aAAO,CAAC,QACN,kBAAkB,aAAa,KAAK,OAAO,KAAK,GAAG,OAAO,OAAO,IAAI;AAAA,IACzE;AACA,WAAO,CAAC,QACN,QAAQ;AAAA,MAAK,CAACC,WACZ;AAAA,QACE,aAAa,KAAKA,OAAM,OAAO,KAAK;AAAA,QACpC;AAAA,QACAA,OAAM,OAAO;AAAA,MACf;AAAA,IACF;AAAA,EACJ;AAEA,QAAM,EAAE,UAAU,MAAM,IAAI;AAC5B,QAAM,OAAO,mBAAmB,KAAK;AACrC,MAAI,aAAa,QAAW;AAC1B,UAAM,SAAS,KAAK,IAAI,QAAQ;AAChC,QAAI,WAAW,QAAW;AACxB,aAAO,MAAM;AAAA,IACf;AACA,WAAO,CAAC,QAAQ,KAAK,aAAa,KAAK,OAAO,KAAK,CAAC;AAAA,EACtD;AACA,SAAO,CAAC,QACN,QAAQ,KAAK,CAACA,WAAU,KAAK,aAAa,KAAKA,OAAM,OAAO,KAAK,CAAC,CAAC;AACvE;AAQO,SAAS,cACd,QACA,SACqC;AACrC,QAAM,OAAO,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC;AACrE,QAAM,WAAW,OACd,OAAO,CAAC,UAAU,cAAc,OAAO,IAAI,CAAC,EAC5C,IAAI,CAAC,UAAU,mBAAmB,OAAO,MAAM,OAAO,CAAC;AAC1D,SAAO,SAAS,WAAW,IACvB,SACA,CAAC,QAAQ,SAAS,MAAM,CAAC,SAAS,KAAK,GAAG,CAAC;AACjD;AAYO,SAAS,aAAa,OAAgB,OAAwB;AACnE,SAAO,mBAAmB,KAAK,EAAE,KAAK;AACxC;AASO,SAAS,eACd,QACA,UACe;AACf,QAAM,QAAQ,OAAO;AAAA,IACnB,CAAC,cACC,WAAW,aAAa,UAAU,aAAa;AAAA,EACnD;AACA,SAAO,OAAO,SAAS;AACzB;AAaO,SAAS,gBACd,QACA,UACA,OACkB;AAClB,QAAM,QAAQ,OAAO;AAAA,IACnB,CAAC,UAAU,EAAE,gBAAgB,UAAU,MAAM,aAAa;AAAA,EAC5D;AAEA,MAAI,UAAU,IAAI;AAChB,WAAO,UAAU,KAAK,SAAS,OAAO,OAAO,CAAC,QAAQ,MAAM,MAAM,KAAK;AAAA,EACzE;AAEA,QAAM,OACJ,aAAa,SAAY,EAAE,MAAM,IAAI,EAAE,UAAU,MAAM;AAEzD,MAAI,UAAU,IAAI;AAChB,WAAO,CAAC,GAAG,QAAQ,IAAI;AAAA,EACzB;AACA,QAAM,WAAW,OAAO,KAAK;AAC7B,MACE,aAAa,UACb,WAAW,YACX,SAAS,UAAU,OACnB;AACA,WAAO;AAAA,EACT;AACA,SAAO,OAAO,IAAI,CAAC,OAAO,MAAO,MAAM,QAAQ,OAAO,KAAM;AAC9D;AAGO,SAAS,gBACd,QACkB;AAClB,SAAO,OAAO,WAAW,IAAI,SAAS,CAAC;AACzC;AAmBO,SAAS,WACd,MACA,QACA,SAC6B;AAC7B,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,cAAc,QAAQ,OAAO;AAC1C,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,KAAK,OAAO,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC;AAEnD,SAAO,SAAS;AAAA,IAAI,CAAC,KAAK,UACxB,IAAI,aAAa,QAAQ,MAAM,EAAE,GAAG,KAAK,UAAU,MAAM;AAAA,EAC3D;AACF;;;ACxTO,SAAS,iBACd,MACA,QACA,MACA,SAC6B;AAC7B,SAAO,SAAS,WAAW,MAAM,QAAQ,OAAO,GAAG,MAAM,OAAO;AAClE;AAUO,SAAS,YACd,UACA,KAC6B;AAC7B,SAAO,IAAI,IAAI,CAAC,OAAO,SAAS,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,QAAQ,QAAQ,MAAS;AAC5E;AAMO,SAAS,eACd,SACA,KACsC;AACtC,SAAO,IACJ,IAAI,CAAC,OAAO;AACX,UAAM,cAAc,QAAQ,UAAU,CAAC,UAAU,MAAM,OAAO,EAAE;AAChE,UAAM,SAAS,QAAQ,WAAW;AAClC,WAAO,WAAW,SACd,SACA,EAAE,UAAU,IAAI,QAAQ,YAAY;AAAA,EAC1C,CAAC,EACA,OAAO,CAAC,WAAW,WAAW,MAAS;AAC5C;AAOO,SAAS,YACd,UACA,SACA,MACgC;AAChC,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,SAAS,IAAI,KAAK,KAAK;AACrC,QAAM,cAAc,QAAQ;AAAA,IAC1B,CAAC,cAAc,UAAU,OAAO,KAAK;AAAA,EACvC;AACA,QAAM,SAAS,QAAQ,WAAW;AAClC,MAAI,UAAU,UAAa,WAAW,QAAW;AAC/C,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK;AAAA,IACf,KAAK,MAAM;AAAA,IACX;AAAA,IACA,UAAU,MAAM;AAAA,IAChB;AAAA,IACA,OAAO,aAAa,MAAM,KAAK,OAAO,OAAO,KAAK;AAAA,EACpD;AACF;;;ACtFO,SAAS,gBACd,QACA,YACS;AACT,SAAO,WAAW,YAAY,MAAM,CAAC,KAAK,OAAO,WAAW;AAC9D;AAOO,SAAS,sBACd,SACA,YACkC;AAClC,QAAM,UAAU,QAAQ;AAAA,IAAO,CAAC,UAC9B,gBAAgB,MAAM,QAAQ,UAAU;AAAA,EAC1C;AACA,SAAO,QAAQ,WAAW,QAAQ,SAAS,UAAU;AACvD;AASO,SAAS,oBACd,SACA,YACA,WACA,SACuB;AACvB,QAAM,YAAY,IAAI,IAAI,SAAS;AACnC,QAAM,UAAU,QAAQ;AAAA,IACtB,CAAC,UACC,UAAU,IAAI,MAAM,EAAE,KACtB,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAAA,EAClD;AACA,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG,OAAO,YAAY,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC;AAAA,EACnE;AACF;;;AChCA,IAAM,gBAAuC,CAAC;AAY9C,SAAS,aACP,MACA,UAC6B;AAC7B,SAAO,KAAK,IAAI,CAAC,KAAK,cAAc;AAAA,IAClC,OAAO,aAAa,KAAK,UAAU,QAAQ;AAAA,IAC3C;AAAA,IACA;AAAA,IACA,cAAc;AAAA,EAChB,EAAE;AACJ;AAaA,SAAS,YACP,gBACA,QACA,OACA,WACA,aACA,kBACA,YACA,eACsC;AACtC,QAAM,SAAS;AAAA,IACb,eAAe,IAAI,CAAC,UAAU,MAAM,MAAM;AAAA,IAC1C;AAAA,IACA,EAAE,OAAO,WAAW,aAAa,iBAAiB;AAAA,EACpD;AACA,SAAO,eAAe,SAAS,kBAAkB,OAC7C,kBAAkB,QAAQ,eAAe,KAAK,IAC9C;AACN;AAQA,SAAS,gBACP,MACA,YACA,aACkB;AAClB,SAAO;AAAA,IACL,KAAK,IAAI,CAAC,UAAU,MAAM,GAAG;AAAA,IAC7B;AAAA,IACA;AAAA,EACF;AACF;AASA,SAAS,SACP,aACA,WACA,YACoB;AACpB,SAAO,YACH,aAAa,aAAa,UAAU,IACpC,EAAE,MAAM,aAAa,WAAW,GAAG,WAAW,EAAE;AACtD;AAaA,SAAS,iBACP,UACA,MACA,UAC6B;AAC7B,SAAO,WACH,SAAS,OAAO,CAAC,UAAqC,EAAE,UAAU,MAAM,IACxE;AACN;AAgBO,SAAS,yBAES;AACvB,QAAM,WAAW,YAAY,YAAiB;AAC9C,QAAM,eAAe,YAAY,kBAA6B;AAC9D,QAAM,cAAc,YAAY,qBAAgC;AAChE,QAAM,OAAO,YAAY,WAAsB;AAC/C,QAAM,gBAAgB,YAAY,gBAAqB;AACvD,QAAM,QAAQ,YAAY,SAAc;AACxC,QAAM,YAAY,YAAY,mBAAwB;AACtD,QAAM,QAAQ,YAAY,eAAoB;AAC9C,QAAM,OAAO,YAAY,QAAa;AACtC,QAAM,SAAS,YAAY,gBAAqB;AAChD,QAAM,WAAW;AAAA,IACf,CACE,aACA,SACA,MACA,aACA,UACA,iBACA,WACA,WACA,gBACyB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC,EAAE,MAAM,MAAM,UAAU,SAAS,aAAa,OAAO,QAAQ,MAAM;AACzE,UAAM,YAAY,QAAQ,aAAa;AACvC,UAAM,aACJ,QAAQ,cAAe;AAEzB,UAAM,cAAc,aAAa,aAAa,MAAM,WAAW;AAI/D,UAAM,UAAU;AAAA,MACd,YAAY,aAAa,MAAM,gBAAgB;AAAA,MAC/C,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ,cAAc;AAAA,MACtB,QAAQ,iBAAiB;AAAA,IAC3B;AAEA,UAAM,OAAO;AAAA,MACX,SAAS,MAAM,QAAQ;AAAA,MACvB,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AAIA,UAAM,cAAc;AAAA,MAClB,MAAM,MAAM,MAAM,SAAS,MAAM,gBAAgB,WAAW;AAAA,MAC5D;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,QAAQ,yBAAyB;AAAA,IACnC;AACA,UAAM;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF,IAAI,KAAK,aAAa,WAAW,MAAM,UAAU;AAEjD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,UAAU,MAAM,MAAM,QAAQ,SAAS,KAAK,SAAS;AAAA,MAC5D;AAAA,MACA;AAAA,MACA,MAAM,MAAM,YAAY,WAAW;AAAA,IACrC;AAAA,EACF;AACF;AAaO,SAAS,gBACd,OACqB;AACrB,SAAO,uBAAkC,EAAE,KAAK;AAClD;;;AC9OO,SAAS,qBACd,UACA,MACoB;AACpB,QAAM,SAAS,KAAK,IAAI,SAAS,QAAQ,KAAK,MAAM;AACpD,WAAS,QAAQ,GAAG,QAAQ,QAAQ,SAAS;AAC3C,UAAM,SAAS,SAAS,KAAK;AAC7B,UAAM,QAAQ,KAAK,KAAK;AACxB,QACE,QAAQ,aAAa,OAAO,YAC5B,QAAQ,cAAc,OAAO,WAC7B;AACA,cAAQ,SAAS,SAAS;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,UACd,UACA,MACoB;AACpB,QAAM,SAAS,KAAK,IAAI,SAAS,QAAQ,KAAK,MAAM;AACpD,WAAS,QAAQ,GAAG,QAAQ,QAAQ,SAAS;AAC3C,QAAI,SAAS,KAAK,MAAM,KAAK,KAAK,GAAG;AACnC,aAAO,KAAK,KAAK,KAAK,SAAS,KAAK;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,YACd,UACA,MACmB;AACnB,QAAM,OAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC;AACrE,SAAO,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,QAAQ,SAAS,GAAG,MAAM,KAAK,GAAG,CAAC;AAC9D;AAGO,SAAS,UACd,UACA,MACS;AACT,SACE,SAAS,WAAW,KAAK,UACzB,SAAS,MAAM,CAAC,MAAM,UAAU,SAAS,KAAK,KAAK,CAAC;AAExD;AAEO,SAAS,eACd,UACA,MACS;AACT,SACE,SAAS,cAAc,KAAK,aAAa,SAAS,aAAa,KAAK;AAExE;AAEA,SAAS,UAAU,UAAmB,MAAwB;AAC5D,SAAO,oBAAoB,QAAQ,gBAAgB,OAC/C,SAAS,QAAQ,MAAM,KAAK,QAAQ,IACpC,aAAa;AACnB;AAGA,SAAS,YACP,UACA,MACS;AACT,MAAI,aAAa,QAAQ,KAAK,aAAa,IAAI,GAAG;AAChD,WACE,aAAa,QAAQ,KACrB,aAAa,IAAI,KACjB,SAAS,WAAW,KAAK,UACzB,SAAS,MAAM,CAAC,QAAQ,UAAU,UAAU,QAAQ,KAAK,KAAK,CAAC,CAAC;AAAA,EAEpE;AACA,SAAO,UAAU,UAAU,IAAI;AACjC;AAEA,SAAS,UACP,UACA,MACS;AACT,MAAI,gBAAgB,YAAY,gBAAgB,MAAM;AACpD,WACE,gBAAgB,YAChB,gBAAgB,QAChB,SAAS,eAAe,KAAK,cAC7B,WAAW,SAAS,SAAS,KAAK,OAAO;AAAA,EAE7C;AACA,MAAI,SAAS,aAAa,KAAK,UAAU;AACvC,WAAO;AAAA,EACT;AACA,MAAI,eAAe,YAAY,eAAe,MAAM;AAClD,WACE,eAAe,YACf,eAAe,QACf,SAAS,cAAc,KAAK;AAAA,EAEhC;AAEA,MAAI,cAAc,YAAY,cAAc,MAAM;AAChD,WACE,cAAc,YACd,cAAc,QACd,SAAS,aAAa,KAAK,YAC3B,YAAY,SAAS,OAAO,KAAK,KAAK;AAAA,EAE1C;AACA,MAAI,WAAW,YAAY,WAAW,MAAM;AAC1C,WACE,WAAW,YACX,WAAW,QACX,UAAU,SAAS,OAAO,KAAK,KAAK;AAAA,EAExC;AACA,SAAO,SAAS,UAAU,KAAK;AACjC;AAQO,SAAS,WACd,UACA,MACS;AACT,SACE,SAAS,WAAW,KAAK,UACzB,SAAS,MAAM,CAAC,OAAO,UAAU;AAC/B,UAAM,QAAQ,KAAK,KAAK;AACxB,WAAO,UAAU,UAAa,UAAU,OAAO,KAAK;AAAA,EACtD,CAAC;AAEL;;;AChKA,IAAM,YAA2B,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;AAS1D,SAAS,cAAc,GAAmB,GAA4B;AACpE,SAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,UAAU,OAAO,EAAE,KAAK,CAAC;AACxE;AAYO,SAAS,gBACd,WACA,IACA,MACgB;AAChB,MAAI,SAAS,OAAO;AAClB,WAAO;AAAA,EACT;AACA,MAAI,UAAU,SAAS,EAAE,GAAG;AAC1B,WAAO,UAAU,OAAO,CAAC,eAAe,eAAe,EAAE;AAAA,EAC3D;AACA,SAAO,SAAS,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,WAAW,EAAE;AACrD;AASO,SAAS,WACd,WACA,IACA,MACgB;AAChB,MAAI,SAAS,OAAO;AAClB,WAAO;AAAA,EACT;AACA,SAAO,UAAU,WAAW,KAAK,UAAU,CAAC,MAAM,KAAK,YAAY,CAAC,EAAE;AACxE;AAWO,SAAS,YACd,WACA,YACA,UACA,SACA,MACgB;AAChB,MAAI,SAAS,YAAY;AACvB,WAAO,WAAW,WAAW,SAAS,IAAI;AAAA,EAC5C;AAEA,QAAM,SAAS,WAAW,QAAQ,QAAQ;AAC1C,QAAM,QAAQ,WAAW,QAAQ,OAAO;AACxC,MAAI,WAAW,MAAM,UAAU,IAAI;AACjC,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,WAAW;AAAA,IACtB,KAAK,IAAI,QAAQ,KAAK;AAAA,IACtB,KAAK,IAAI,QAAQ,KAAK,IAAI;AAAA,EAC5B;AACA,SAAO,cAAc,WAAW,IAAI,IAAI,YAAY;AACtD;AAMO,SAAS,UACd,WACA,YACA,MACgB;AAChB,MAAI,SAAS,YAAY;AACvB,WAAO;AAAA,EACT;AACA,SAAO,cAAc,WAAW,UAAU,IAAI,YAAY;AAC5D;AAEO,SAAS,eAAe,WAA2C;AACxE,SAAO,UAAU,WAAW,IAAI,YAAY,CAAC;AAC/C;AASO,SAAS,cACd,UACA,MACe;AACf,MAAI,aAAa,MAAM;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,IAAI,IAAI,QAAQ;AAC/B,QAAM,QAAQ,IAAI,IAAI,IAAI;AAC1B,SAAO;AAAA,IACL,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;AAAA,IAC1C,SAAS,SAAS,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;AAAA,EACjD;AACF;AAEO,SAAS,WACd,GACA,GACS;AACT,MAAI,MAAM,QAAQ,MAAM,MAAM;AAC5B,WAAO,MAAM;AAAA,EACf;AACA,SAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE;AACjD;AAMO,SAAS,WACd,WACA,MACA,MACoB;AACpB,MAAI,SAAS,SAAS,WAAW,WAAW,IAAI,GAAG;AACjD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAMO,SAAS,oBACd,WACA,MACA,MACoB;AACpB,MAAI,SAAS,OAAO;AAClB,WAAO;AAAA,EACT;AACA,SAAO,WAAW,WAAW,IAAI,IAAI,OAAO;AAC9C;AASO,SAAS,SACd,OAKA,SACc;AACd,MAAI,MAAM,UAAU;AAClB,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,WAAW,MAAM,SAAS;AAClC,WAAO;AAAA,EACT;AACA,SAAO,SAAS,kBAAkB,OAAO,WAAW;AACtD;AAOO,SAAS,qBACd,WACA,YACA,UACA,IACA,QACA,MACgB;AAChB,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,gBAAgB,WAAW,IAAI,IAAI;AAAA;AAAA;AAAA,IAG5C,KAAK;AACH,aAAO,YAAY,WAAW,YAAY,YAAY,IAAI,IAAI,IAAI;AAAA,IACpE;AACE,aAAO,WAAW,WAAW,IAAI,IAAI;AAAA,EACzC;AACF;;;ACpNO,SAAS,mBACd,UACA,MACA,UACA,WACe;AACf,QAAM,OAAO,cAAc,UAAU,IAAI;AACzC,QAAM,QAAQ,YAAY,UAAU,KAAK,KAAK;AAC9C,QAAM,UAAU,YAAY,UAAU,KAAK,OAAO;AAElD,aAAW,OAAO,OAAO;AACvB,cAAU,cAAc,EAAE,KAAK,WAAW,KAAK,CAAC;AAAA,EAClD;AACA,MAAI,MAAM,SAAS,GAAG;AACpB,cAAU,eAAe,EAAE,MAAM,OAAO,WAAW,KAAK,CAAC;AAAA,EAC3D;AACA,aAAW,OAAO,SAAS;AACzB,cAAU,gBAAgB,EAAE,KAAK,WAAW,KAAK,CAAC;AAAA,EACpD;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,cAAU,iBAAiB,EAAE,MAAM,SAAS,WAAW,KAAK,CAAC;AAAA,EAC/D;AACA,YAAU,uBAAuB;AAAA,IAC/B;AAAA,IACA;AAAA,IACA,UAAU,YAAY,UAAU,IAAI;AAAA,IACpC,WAAW;AAAA,EACb,CAAC;AACD,SAAO;AACT;AAGO,SAAS,sBACd,UACA,MACA,SACA,WACe;AACf,QAAM,OAAO,cAAc,UAAU,IAAI;AACzC,QAAM,QAAQ,eAAe,SAAS,KAAK,KAAK;AAChD,QAAM,UAAU,eAAe,SAAS,KAAK,OAAO;AAEpD,aAAW,UAAU,OAAO;AAC1B,cAAU,iBAAiB,EAAE,QAAQ,WAAW,KAAK,CAAC;AAAA,EACxD;AACA,MAAI,MAAM,SAAS,GAAG;AACpB,cAAU,kBAAkB,EAAE,SAAS,OAAO,WAAW,KAAK,CAAC;AAAA,EACjE;AACA,aAAW,UAAU,SAAS;AAC5B,cAAU,mBAAmB,EAAE,QAAQ,WAAW,KAAK,CAAC;AAAA,EAC1D;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,cAAU,oBAAoB,EAAE,SAAS,SAAS,WAAW,KAAK,CAAC;AAAA,EACrE;AACA,YAAU,0BAA0B;AAAA,IAClC;AAAA,IACA;AAAA,IACA,UAAU,eAAe,SAAS,IAAI;AAAA,IACtC,WAAW;AAAA,EACb,CAAC;AACD,SAAO;AACT;AAOO,SAAS,oBACd,UACA,MACA,UACA,SACA,WACM;AACN,QAAM,WAAW,YAAY,UAAU,SAAS,IAAI;AACpD,QAAM,aAAa,YAAY,UAAU,SAAS,QAAQ;AAE1D,MAAI,eAAe,MAAM;AACvB,cAAU,iBAAiB,EAAE,MAAM,YAAY,WAAW,KAAK,CAAC;AAAA,EAClE;AACA,MAAI,aAAa,MAAM;AACrB,cAAU,eAAe,EAAE,MAAM,UAAU,WAAW,KAAK,CAAC;AAAA,EAC9D;AACA,YAAU,wBAAwB;AAAA,IAChC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AACH;;;ACvDA,SAAS,UACP,MACuC;AACvC,SAAO,IAAI,IAAI,KAAK,IAAI,CAAC,UAAU,CAAC,MAAM,OAAO,KAAK,CAAC,CAAC;AAC1D;AAGA,SAAS,SAAS,KAA2C;AAC3D,SAAO,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC;AACzB;AAWO,SAAS,uBACd,MAC6B;AAM7B,MAAI,YAA2B;AAC/B,MAAI,eAA8B;AAClC,QAAM,WAAW,YAAY,SAAc;AAE3C,WAAS,QAAQ;AACf,UAAM,aAAa,KAAK,WAAW,EAAE;AACrC,WAAO;AAAA,MACL,MAAM,YAAY,QAAQ;AAAA,MAC1B,SAAS,YAAY,WAAW;AAAA,MAChC,OAAO,YAAY,SAAS;AAAA,IAC9B;AAAA,EACF;AAEA,WAAS,SAA4B;AACnC,WAAO,KAAK,QAAQ,EAAE,gBAAgB,IAAI,CAAC,UAAU,MAAM,KAAK;AAAA,EAClE;AAEA,WAAS,YAA+B;AACtC,WAAO,KAAK,QAAQ,EAAE,QAAQ,IAAI,CAAC,UAAU,MAAM,EAAE;AAAA,EACvD;AAEA,WAAS,WAAW,MAA4B;AAC9C,UAAM,WAAW,KAAK,SAAS,EAAE;AACjC,SAAK,OAAO,gBAAgB,MAAM,MAAM;AACtC,YAAM,UAAU,KAAK,WAAW;AAChC,YAAM,OAAO;AAAA,QACX;AAAA,QACA;AAAA,QACA,SAAS,KAAK,QAAQ,EAAE,eAAe;AAAA,QACvC;AAAA,MACF;AACA,cAAQ,kBAAkB,EAAE,QAAQ,QAAQ,GAAG,MAAM,WAAW,KAAK,CAAC;AAAA,IACxE,CAAC;AAAA,EACH;AAEA,WAAS,cAAc,MAA4B;AACjD,UAAM,WAAW,KAAK,SAAS,EAAE;AACjC,SAAK,OAAO,mBAAmB,MAAM,MAAM;AACzC,YAAM,UAAU,KAAK,WAAW;AAChC,YAAM,OAAO;AAAA,QACX;AAAA,QACA;AAAA,QACA,KAAK,QAAQ,EAAE;AAAA,QACf;AAAA,MACF;AACA,cAAQ,kBAAkB;AAAA,QACxB,QAAQ;AAAA,QACR,GAAG;AAAA,QACH,WAAW;AAAA,MACb,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAEA,WAAS,WAAW,MAAgC;AAClD,UAAM,WAAW,KAAK,SAAS,EAAE;AACjC,SAAK,OAAO,iBAAiB,MAAM,MAAM;AACvC,YAAM,OAAO,KAAK,QAAQ;AAC1B;AAAA,QACE;AAAA,QACA;AAAA,QACA,SAAS,KAAK,eAAe;AAAA,QAC7B,KAAK;AAAA,QACL,KAAK,WAAW;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,gBAAgB,WAAW;AACzB,UAAI,CAAC,UAAU,KAAK,SAAS,EAAE,cAAc,SAAS,GAAG;AACvD,mBAAW,SAAS;AAAA,MACtB;AAAA,IACF;AAAA,IACA,WAAW,KAAK,SAAS,WAAW;AAClC,YAAM,OAAO,MAAM,EAAE;AACrB,YAAM,UAAU,KAAK,SAAS,EAAE;AAChC,UAAI,SAAS,SAAS,IAAI,WAAW,GAAG;AACtC;AAAA,MACF;AACA,YAAM,OACJ,WAAW,WACP,IAAI;AAAA,QACF,CAAC,WAAW,OAAO,gBAAgB,WAAW,IAAI,IAAI;AAAA,QACtD;AAAA,MACF,IACA,SAAS,WACP,IAAI,MAAM,EAAE,IACZ,SAAS,GAAG;AACpB,kBAAY,IAAI,GAAG,EAAE,KAAK;AAC1B,UAAI,CAAC,UAAU,SAAS,IAAI,GAAG;AAC7B,mBAAW,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,IACA,UAAU,OAAO,QAAQ;AACvB,YAAM,OAAO;AAAA,QACX,KAAK,SAAS,EAAE;AAAA,QAChB,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,EAAE;AAAA,MACV;AACA,UAAI,WAAW,SAAS;AACtB,oBAAY;AAAA,MACd;AACA,iBAAW,IAAI;AAAA,IACjB;AAAA,IACA,gBAAgB;AACd;AAAA,QACE,UAAU,KAAK,SAAS,EAAE,cAAc,OAAO,GAAG,MAAM,EAAE,IAAI;AAAA,MAChE;AAAA,IACF;AAAA,IACA,iBAAiB;AACf,iBAAW,eAAe,KAAK,SAAS,EAAE,YAAY,CAAC;AACvD,oBAAc,eAAe,KAAK,SAAS,EAAE,eAAe,CAAC;AAC7D,iBAAW,IAAI;AAAA,IACjB;AAAA,IAEA,mBAAmB,WAAW;AAC5B,UAAI,CAAC,UAAU,KAAK,SAAS,EAAE,iBAAiB,SAAS,GAAG;AAC1D,sBAAc,SAAS;AAAA,MACzB;AAAA,IACF;AAAA,IACA,aAAa,UAAU,QAAQ;AAC7B,YAAM,OAAO;AAAA,QACX,KAAK,SAAS,EAAE;AAAA,QAChB,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,EAAE;AAAA,MACV;AACA,UAAI,WAAW,SAAS;AACtB,uBAAe;AAAA,MACjB;AACA,oBAAc,IAAI;AAAA,IACpB;AAAA,IAEA,iBAAiB,WAAW;AAC1B,UAAI,CAAC,WAAW,KAAK,SAAS,EAAE,eAAe,SAAS,GAAG;AACzD,mBAAW,SAAS;AAAA,MACtB;AAAA,IACF;AAAA,IACA,WAAW,MAAM,QAAQ;AACvB,YAAM,UAAU,KAAK,SAAS,EAAE;AAChC,YAAM,OAAO,MAAM,EAAE;AACrB;AAAA,QACE,WAAW,WACP,oBAAoB,SAAS,MAAM,IAAI,IACvC,WAAW,SAAS,MAAM,IAAI;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF;;;ACjMA,IAAM,oBAAoB;AAM1B,IAAM,UAA4B,CAAC;AACnC,IAAM,aAA+B,CAAC;AAItC,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,iBACJ;AAAA,EACE,cAAc;AAAA,EACd,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,eAAe;AACjB;AAgBF,SAAS,cAAmB,SAA0C;AACpE,SAAO;AAAA,IACL,cAAc,QAAQ,uBAAuB,CAAC;AAAA,IAC9C,aAAa,QAAQ,sBAAsB,CAAC;AAAA,IAC5C,kBAAkB,QAAQ,2BAA2B,CAAC;AAAA,IACtD,YAAY,QAAQ,qBAAqB,CAAC;AAAA,IAC1C,QAAQ,QAAQ,iBAAiB,CAAC;AAAA,IAClC,SAAS,QAAQ,kBAAkB,CAAC;AAAA,IACpC,gBAAgB,QAAQ,yBAAyB,CAAC;AAAA,IAClD,YAAY,QAAQ,qBAAqB;AAAA,MACvC,WAAW;AAAA,MACX,UAAU;AAAA,IACZ;AAAA,IACA,cAAc,QAAQ,uBAAuB,CAAC;AAAA,IAC9C,iBAAiB,QAAQ,0BAA0B,CAAC;AAAA,IACpD,eAAe,QAAQ,wBAAwB;AAAA,EACjD;AACF;AAMA,SAAS,eACP,SACA,MACwC;AACxC,MAAI,YAAY,UAAa,QAAQ,SAAS,GAAG;AAC/C,WAAO;AAAA,EACT;AACA,MAAI,SAAS,UAAa,KAAK,SAAS,GAAG;AACzC,WAAO,sBAAiC,IAAI;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,SAAS,eAAoB,OAA0C;AACrE,SAAO;AAAA,IACL,QAAQ,MAAM;AAAA,IACd,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM;AAAA,EACjB;AACF;AAOO,SAAS,qBACd,SAC2B;AAC3B,MAAI,UAAU;AACd,QAAM,MAAM,cAAc,OAAO;AACjC,QAAM,cAAc,uBAAkC;AACtD,QAAMC,kBAAiB,YAAY,cAAyB;AAC5D,QAAM,YAAY,oBAAI,IAAgB;AAEtC,QAAM,oBAAoB,oBAAI,IAAc;AAK5C,MAAI;AAEJ,MAAI,QAAQ,cAAc;AAC1B,MAAI,eAAe,eAAe,KAAK;AACvC,kBAAgB;AAEhB,WAAS,gBACP,KAC+B;AAC/B,UAAM,aAAmC;AACzC,WAAO,WAAW,GAAG;AAAA,EACvB;AAEA,WAAS,aAAa,KAAwB;AAC5C,WAAO,gBAAgB,GAAG,MAAM;AAAA,EAClC;AAEA,WAAS,aAAiC,KAA2B;AACnE,UAAM,aAAa,gBAAgB,GAAG;AACtC,WAAO,eAAe,SAAY,IAAI,GAAG,IAAI;AAAA,EAC/C;AAEA,WAAS,gBAAgC;AACvC,WAAO;AAAA,MACL,cAAc,aAAa,cAAc;AAAA,MACzC,aAAa,aAAa,aAAa;AAAA,MACvC,kBAAkB,aAAa,kBAAkB;AAAA,MACjD,YAAY,aAAa,YAAY;AAAA,MACrC,QAAQ,aAAa,QAAQ;AAAA,MAC7B,SAAS,aAAa,SAAS;AAAA,MAC/B,gBAAgB,aAAa,gBAAgB;AAAA,MAC7C,YAAY,aAAa,YAAY;AAAA,MACrC,cAAc,aAAa,cAAc;AAAA,MACzC,iBAAiB,aAAa,iBAAiB;AAAA,MAC/C,eAAe,aAAa,eAAe;AAAA,IAC7C;AAAA,EACF;AAOA,WAAS,kBAAwB;AAC/B,eAAW,OAAO,YAAY;AAC5B,YAAM,aAAa,eAAe,GAAG;AACrC,UACE,kBAAkB,IAAI,GAAG,KACzB,CAAC,aAAa,GAAG,KACjB,QAAQ,UAAU,MAAM,QACxB;AACA;AAAA,MACF;AACA,wBAAkB,IAAI,GAAG;AACzB;AAAA,QACE,KAAK,GAAG,YAAY,UAAU,4BAAuB,GAAG,0BAA0B,UAAU;AAAA,MAC9F;AAAA,IACF;AAAA,EACF;AAaA,WAAS,UAAgB;AACvB,QAAI,OAAO,cAAc;AACzB,QACE,KAAK,WAAW,aAAa,UAC7B,KAAK,eAAe,aAAa,cACjC,KAAK,YAAY,aAAa,SAC9B;AACA,qBAAe,eAAe,IAAI;AAClC,UAAI,CAAC,aAAa,YAAY,KAAK,IAAI,WAAW,cAAc,GAAG;AACjE,YAAI,aAAa,EAAE,GAAG,IAAI,YAAY,WAAW,EAAE;AACnD,eAAO,EAAE,GAAG,MAAM,YAAY,IAAI,WAAW;AAAA,MAC/C;AAAA,IACF;AACA,YAAQ,WAAW,MAAM,CAAC,QAAQ,KAAK,GAAG,MAAM,MAAM,GAAG,CAAC,IAAI,QAAQ;AAAA,EACxE;AAEA,WAAS,SAAe;AACtB,eAAW,YAAY,CAAC,GAAG,SAAS,GAAG;AACrC,eAAS;AAAA,IACX;AAAA,EACF;AAOA,WAAS,OACP,KACA,MACA,QACM;AACN,QAAI,SAAS,MAAM,GAAG,GAAG;AACvB;AAAA,IACF;AACA,QAAI,CAAC,aAAa,GAAG,GAAG;AACtB,UAAI,GAAG,IAAI;AAAA,IACb;AACA,QAAI,gBAAgB,QAAW;AAC7B,kBAAY,KAAK,MAAM;AACvB;AAAA,IACF;AACA,YAAQ;AACR,WAAO;AACP,WAAO;AAAA,EACT;AAEA,WAAS,UAA+B;AACtC,WAAO,YAAY;AAAA,MACjB,MAAM,QAAQ,cAAc;AAAA,MAC5B,UAAU,QAAQ;AAAA,MAClB,SAASA,gBAAe,QAAQ,SAAS,QAAQ,UAAU;AAAA,MAC3D;AAAA,MACA,SAAS;AAAA,QACP,WAAW,QAAQ;AAAA,QACnB,YAAY,QAAQ;AAAA,QACpB,uBAAuB,QAAQ;AAAA,QAC/B,oBAAoB,QAAQ;AAAA,QAC5B,kBAAkB,QAAQ;AAAA,QAC1B,oBAAoB,QAAQ;AAAA,QAC5B,yBAAyB,QAAQ;AAAA,QACjC,YAAY,QAAQ;AAAA,QACpB,eAAe,QAAQ;AAAA,MACzB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,mBACP,MACA,UACA,OACA,OACM;AACN,WAAO,gBAAgB,MAAM,MAAM;AACjC,cAAQ,iBAAiB,EAAE,UAAU,OAAO,QAAQ,MAAM,MAAM,CAAC;AAAA,IACnE,CAAC;AAAA,EACH;AAMA,WAAS,aAAa,UAA0B;AAC9C,UAAM,QAAQ,QAAQ,EAAE,YAAY;AAAA,MAClC,CAAC,cAAc,UAAU,OAAO;AAAA,IAClC;AACA,UAAM,CAAC,QAAQ,IACb,UAAU,SACN,CAAC,IACD;AAAA,MACE,CAAC,MAAM,MAAM;AAAA,MACb,CAAC;AAAA,MACD;AAAA,QACE,OAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AACN,WAAO,UAAU,SAAS;AAAA,EAC5B;AAOA,WAAS,uBAAuB,MAAmC;AACjE,UAAM,WAAW,MAAM;AACvB,WAAO,oBAAoB,MAAM,MAAM;AACrC,YAAM,UAAU,IAAI,IAAI,YAAY,UAAU,IAAI,CAAC;AACnD,YAAM,QAAQ,QAAQ,EACnB,YAAY,IAAI,CAAC,UAAU,MAAM,EAAE,EACnC,OAAO,CAAC,OAAO,QAAQ,OAAO,EAAE,CAAC;AACpC,cAAQ,2BAA2B;AAAA,QACjC,WAAW,CAAC,GAAG,OAAO,GAAG,OAAO;AAAA,QAChC,YAAY;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAEA,WAAS,uBACP,WACA,SACM;AACN;AAAA,MACE;AAAA,QACE,QAAQ,EAAE;AAAA,QACV,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,WAAS,cAAc,MAAoB,UAAwB;AACjE,WAAO,WAAW,MAAM,MAAM;AAC5B,cAAQ,kBAAkB,EAAE,UAAU,SAAS,KAAK,CAAC;AAAA,IACvD,CAAC;AAAA,EACH;AAEA,WAAS,qBACP,MACA,SACM;AACN,WAAO,kBAAkB,MAAM,MAAM;AACnC,cAAQ,yBAAyB,EAAE,SAAS,WAAW,KAAK,CAAC;AAAA,IAC/D,CAAC;AAAA,EACH;AAQA,WAAS,iBAAiB,MAA6B;AACrD,QAAI,eAAe,MAAM,YAAY,IAAI,GAAG;AAC1C;AAAA,IACF;AACA,WAAO,cAAc,MAAM,MAAM;AAC/B,cAAQ,qBAAqB;AAAA,QAC3B,YAAY;AAAA,QACZ,WAAW,aAAa,QAAQ,EAAE,aAAa,IAAI,EAAE;AAAA,MACvD,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAOA,WAAS,SAAS,WAAyB;AACzC,UAAM,UAAU,MAAM;AACtB,UAAM,UAAU,aAAa,QAAQ,EAAE,aAAa;AAAA,MAClD,GAAG;AAAA,MACH;AAAA,IACF,CAAC,EAAE;AACH,qBAAiB,EAAE,GAAG,SAAS,WAAW,QAAQ,CAAC;AAAA,EACrD;AAGA,WAAS,iBAAyB;AAChC,WAAO,aAAa,QAAQ,EAAE,aAAa,MAAM,UAAU,EAAE;AAAA,EAC/D;AAEA,QAAM,YAAY,uBAAkC;AAAA,IAClD,UAAU,MAAM;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,aAAwC;AAAA,IAC5C,GAAG;AAAA,IACH,YAAY,MAAM;AAAA,IAClB,WAAW,MAAM;AACf,gBAAU;AACV,sBAAgB;AAChB,cAAQ;AAAA,IACV;AAAA,IACA,UAAU,MAAM;AAAA,IAChB;AAAA,IACA,aAAa,OAAO;AAClB,YAAM,UAA0B,CAAC;AACjC,oBAAc;AACd,UAAI;AACF,sBAAc,KAAK;AAAA,MACrB,UAAE;AACA,sBAAc;AAAA,MAChB;AACA,UAAI,MAAM,eAAe,QAAW;AAGlC,uBAAe,eAAe,cAAc,CAAC;AAAA,MAC/C;AACA,cAAQ;AACR,iBAAW,UAAU,SAAS;AAC5B,eAAO;AAAA,MACT;AACA,UAAI,QAAQ,SAAS,GAAG;AACtB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,UAAU,UAAU;AAClB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,gBAAgB,QAAQ;AACtB,YAAM,CAAC,QAAQ,IAAI,YAAY,MAAM,cAAc,MAAM;AACzD,UAAI,aAAa,QAAW;AAC1B;AAAA,UACE;AAAA,UACA;AAAA,UACA,OAAO,QAAQ,KAAK,aAAa,QAAQ;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,aAAa,UAAU,OAAO,OAAO;AACnC;AAAA,QACE,EAAE,GAAG,MAAM,cAAc,CAAC,QAAQ,GAAG,MAAM;AAAA,QAC3C;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACA,mBAAmB,UAAU,aAAa,YAAY;AACpD;AAAA,QACE,iBAAiB,MAAM,cAAc,aAAa,QAAQ;AAAA,QAC1D;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IAEA,eAAe,OAAO;AACpB,YAAM,WAAW,UAAU,MAAM,aAAa,KAAK;AACnD,UAAI,aAAa,QAAW;AAC1B;AAAA,MACF;AACA,aAAO,eAAe,OAAO,MAAM;AACjC,gBAAQ,sBAAsB,EAAE,UAAU,MAAM,CAAC;AAAA,MACnD,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,WAAW,UAAU,UAAU;AAC7B,YAAM,aAAa,QAAQ,EAAE,YAAY,IAAI,CAAC,UAAU,MAAM,EAAE;AAChE,YAAM,OAAO,iBAAiB,YAAY,UAAU,QAAQ;AAC5D,UAAI,SAAS,YAAY;AACvB;AAAA,MACF;AACA,aAAO,eAAe,MAAM,MAAM;AAChC,gBAAQ,sBAAsB,EAAE,UAAU,OAAO,KAAK,CAAC;AAAA,MACzD,CAAC;AAAA,IACH;AAAA,IAEA,oBAAoB,YAAY;AAC9B,UAAI,YAAY,MAAM,kBAAkB,UAAU,EAAE,SAAS,GAAG;AAC9D,+BAAuB,UAAU;AAAA,MACnC;AAAA,IACF;AAAA,IACA,YAAY,WAAW;AACrB,6BAAuB,WAAW,IAAI;AAAA,IACxC;AAAA,IACA,YAAY,WAAW;AACrB,6BAAuB,WAAW,KAAK;AAAA,IACzC;AAAA,IAEA,UAAU,QAAQ;AAChB,UAAI,WAAW,MAAM,QAAQ,MAAM,GAAG;AACpC;AAAA,MACF;AACA,aAAO,UAAU,QAAQ,MAAM;AAC7B,gBAAQ,iBAAiB,EAAE,OAAO,CAAC;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,IAEA,cAAc,MAAM;AAClB,YAAM,WAAW,qBAAqB,MAAM,YAAY,IAAI;AAC5D,UAAI,aAAa,QAAW;AAC1B;AAAA,MACF;AACA,aAAO,cAAc,MAAM,MAAM;AAC/B,gBAAQ,qBAAqB,EAAE,UAAU,KAAK,CAAC;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,IACA,iBAAiB,UAAU,EAAE,QAAQ,MAAM,IAAI,CAAC,GAAG;AACjD,YAAM,OAAO,iBAAkB,MAAM,YAAY,UAAU,EAAE,MAAM,CAAC;AACpE,aAAO,cAAc,MAAM,MAAM;AAC/B,gBAAQ,qBAAqB,EAAE,UAAU,MAAM,KAAK,CAAC;AAAA,MACvD,CAAC;AAAA,IACH;AAAA,IACA,gBAAgB,UAAU;AACxB,YAAM,OAAO,MAAM,WAAW;AAAA,QAC5B,CAAC,UAAU,MAAM,aAAa;AAAA,MAChC;AACA,UAAI,KAAK,WAAW,MAAM,WAAW,QAAQ;AAC3C;AAAA,MACF;AACA,aAAO,cAAc,MAAM,MAAM;AAC/B,gBAAQ,qBAAqB,EAAE,UAAU,MAAM,KAAK,CAAC;AAAA,MACvD,CAAC;AAAA,IACH;AAAA,IAEA,WAAW,SAAS;AAClB,YAAM,WAAW,qBAAqB,MAAM,SAAS,OAAO;AAC5D,UAAI,aAAa,QAAW;AAC1B,sBAAc,SAAS,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,IACA,cAAc,UAAU;AACtB,YAAM,UAAU,MAAM,QAAQ;AAAA,QAC5B,CAAC,UAAU,MAAM,aAAa;AAAA,MAChC;AACA;AAAA,QACE,UACI,MAAM,QAAQ,OAAO,CAAC,UAAU,MAAM,aAAa,QAAQ,IAC3D,CAAC,GAAG,MAAM,SAAS,EAAE,SAAS,CAAC;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAAA,IACA,YAAY,UAAU,gBAAgB;AACpC;AAAA,QACE,kBAAkB,MAAM,SAAS,UAAU,cAAc;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,kBAAkB,WAAW;AAC3B,UAAI,CAAC,UAAU,MAAM,gBAAgB,SAAS,GAAG;AAC/C,6BAAqB,WAAW,IAAI;AAAA,MACtC;AAAA,IACF;AAAA,IACA,qBAAqB,SAAS;AAC5B;AAAA,QACE,qBAAsB,MAAM,gBAAgB,OAAO;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,IACA,kBAAkB;AAChB,2BAAqB,gBAAe,MAAM,cAAc,GAAG,IAAI;AAAA,IACjE;AAAA,IACA,oBAAoB;AAClB,2BAAqB,kBAAgB,QAAQ,EAAE,WAAW,GAAG,IAAI;AAAA,IACnE;AAAA,IAEA,eAAe;AAAA,IACf;AAAA,IACA,WAAW;AACT,eAAS,eAAe,IAAI,CAAC;AAAA,IAC/B;AAAA,IACA,eAAe;AACb,eAAS,eAAe,IAAI,CAAC;AAAA,IAC/B;AAAA,IACA,YAAY,UAAU;AACpB,YAAM,QAAQ,EAAE,WAAW,GAAG,SAAS;AACvC,uBAAiB;AAAA,QACf,GAAG;AAAA,QACH,WAAW,aAAa,QAAQ,EAAE,aAAa,KAAK,EAAE;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,WAAS,cACP,OACM;AACN,QAAI,MAAM,iBAAiB,QAAW;AACpC,iBAAW,gBAAgB,MAAM,YAAY;AAAA,IAC/C;AACA,QAAI,MAAM,gBAAgB,QAAW;AACnC,iBAAW,eAAe,MAAM,WAAW;AAAA,IAC7C;AACA,QAAI,MAAM,qBAAqB,QAAW;AACxC,iBAAW,oBAAoB,MAAM,gBAAgB;AAAA,IACvD;AACA,QAAI,MAAM,eAAe,QAAW;AAClC,iBAAW,cAAc,MAAM,UAAU;AAAA,IAC3C;AACA,QAAI,MAAM,WAAW,QAAW;AAC9B,iBAAW,UAAU,aAAa,MAAM,QAAQ,QAAQ,EAAE,WAAW,CAAC;AAAA,IACxE;AACA,QAAI,MAAM,YAAY,QAAW;AAC/B,iBAAW,WAAW,MAAM,OAAO;AAAA,IACrC;AACA,QAAI,MAAM,mBAAmB,QAAW;AACtC,iBAAW,kBAAkB,MAAM,cAAc;AAAA,IACnD;AACA,QAAI,MAAM,eAAe,QAAW;AAClC,iBAAW,cAAc,MAAM,UAAU;AAAA,IAC3C;AACA,QAAI,MAAM,iBAAiB,QAAW;AACpC,iBAAW,gBAAgB,MAAM,YAAY;AAAA,IAC/C;AACA,QAAI,MAAM,oBAAoB,QAAW;AACvC,iBAAW,mBAAmB,MAAM,eAAe;AAAA,IACrD;AACA,QAAI,MAAM,kBAAkB,QAAW;AACrC,iBAAW,iBAAiB,MAAM,aAAa;AAAA,IACjD;AAAA,EACF;AAEA,SAAO;AACT;;;AC3nBA,SAAS,eACP,MACA,WAC6B;AAC7B,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,CAAC;AAAA,EACV;AACA,QAAM,WAAW,IAAI,IAAI,SAAS;AAClC,SAAO,KAAK,OAAO,CAAC,UAAU,SAAS,IAAI,MAAM,KAAK,CAAC;AACzD;AAWO,SAAS,qBAAgC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgE;AAC9D,QAAM,QAAQ,WAAW,SAAS;AAClC,QAAM,OAAO,WAAW,QAAQ;AAChC,MAAI;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,WAAW,WAAW;AAAA,IAC/B;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA,KACE,OAAO,SAAS,SACX,KAAK,KAAK,KAAK,CAAC,UAAU,MAAM,UAAU,OAAO,KAAK,KAAK,OAC5D;AAAA,IACN,QACE,cAAc,SACT,KAAK,YAAY,KAAK,CAAC,UAAU,MAAM,OAAO,OAAO,QAAQ,KAC9D,OACA;AAAA,IACN,cAAc,MACX,iBAAiB,eAAe,KAAK,MAAM,MAAM,YAAY;AAAA,EAClE;AACF;;;AC5BA,SAAS,KAAU,SAAuB,OAAiC;AACzE,SAAO,MAAM,SAAS,QAAQ,OAAO,IAAI;AAC3C;AAGA,SAAS,SACP,SACA,OACoB;AACpB,SAAO,KAAK,SAAS,KAAK,IAAI,QAAQ,SAAS;AACjD;AAEA,SAAS,YAAiB,SAAuB,UAA2B;AAC1E,SAAO,QAAQ,MAAM,QAAQ,KAAK,CAAC,UAAU,MAAM,aAAa,QAAQ;AAC1E;AAEA,SAAS,eAAoB,SAA2C;AACtE,QAAM,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC;AAC3C,SAAO,WAAW,SACf,OAAO,OAAO,YAAY,QAAQ,QAAQ,mBAAmB,SAC5D,SACA;AACN;AAGA,SAAS,gBAAqB,SAA2C;AACvE,QAAM,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC;AAC3C,SAAO,WAAW,SACf,OAAO,OAAO,aAAa,QAAQ,QAAQ,oBAAoB,UAChE,CAAC,YAAY,SAAS,OAAO,EAAE,IAC7B,SACA;AACN;AAEA,SAAS,cAAmB,SAA2C;AACrE,QAAM,SAAS,SAAS,SAAS,CAAC,UAAU,OAAO,CAAC;AACpD,SAAO,WAAW,QAAQ,YAAY,SAAS,OAAO,EAAE,IAAI,SAAS;AACvE;AAEA,SAAS,eAAoB,SAA2C;AACtE,QAAM,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC;AAC3C,SAAO,WAAW,QAAQ,OAAO,OAAO,aAAa,QAAQ,SAAS;AACxE;AAOA,SAAS,gBAAqB,SAA2C;AACvE,QAAM,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC;AAC3C,MAAI,WAAW,MAAM;AACnB,WAAO;AAAA,EACT;AACA,SACE,QAAQ,KAAK,QAAQ;AAAA,IACnB,CAAC,UAAU,MAAM,OAAO,OAAO,MAAM,MAAM;AAAA,EAC7C,KAAK;AAET;AAEA,SAAS,mBAAwB,SAA0C;AACzE,SAAO,QAAQ,KAAK,QACjB,OAAO,CAAC,UAAU,MAAM,SAAS,EACjC,IAAI,CAAC,UAAU,MAAM,EAAE;AAC5B;AAEA,SAAS,qBACP,YACS;AACT,SAAO,CAAC,YAAY,MAAM,YAAY,SAAS,YAAY,KAAK,EAAE;AAAA,IAChE,CAAC,SAAS,SAAS,UAAa,SAAS;AAAA,EAC3C;AACF;AAGA,SAAS,WAAgB,SAA+B;AACtD,SAAO,QAAQ,WAAW,OACtB,KACA,wBAAwB,QAAQ,OAAO,MAAM;AACnD;AAmBA,SAAS,cAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6C;AAC3C,WAAS,KACP,WACA;AACA,WAAO,CAAC,YAA0B;AAChC,YAAM,SAAS,KAAK,OAAO;AAC3B,aAAO,WAAW,QAAQ,UAAU,QAAQ,OAAO;AAAA,IACrD;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,CAAC,YAAY,KAAK,OAAO,MAAM;AAAA,IAC1C,WAAW,cAAc,SAAY,SAAY,KAAK,SAAS;AAAA,IAC/D,WAAW,cAAc,SAAY,SAAY,KAAK,SAAS;AAAA,IAC/D,SAAS,CAAC,YAAY;AACpB,YAAM,SAAS,KAAK,OAAO;AAC3B,UAAI,WAAW,MAAM;AACnB,gBAAQ,QAAQ,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,YAAiB,WAA4C;AACpE,SAAO,cAAc;AAAA,IACnB,IAAI,cAAc,QAAQ,mBAAmB;AAAA,IAC7C,OAAO,CAAC,EAAE,SAAS,MACjB,cAAc,QAAQ,SAAS,gBAAgB,SAAS;AAAA,IAC1D,MAAM,cAAc,QAAQ,kBAAkB;AAAA,IAC9C,MAAM;AAAA,IACN,WAAW,CAAC,QAAQ,EAAE,MAAM,MAC1B,iBAAiB,MAAM,YAAY,OAAO,EAAE,MAAM;AAAA,IACpD,SAAS,CAAC,QAAQ,EAAE,QAAQ,MAAM;AAChC,cAAQ,cAAc,CAAC,EAAE,UAAU,OAAO,IAAI,UAAU,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF,CAAC;AACH;AAWO,SAAS,kBAAoD;AAClE,SAAO;AAAA,IACL,YAAY,KAAK;AAAA,IACjB,YAAY,MAAM;AAAA;AAAA;AAAA,IAGlB,cAAc;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,MAAM;AAAA,MACN,WAAW,CAAC,QAAQ,EAAE,MAAM,MAC1B,iBAAiB,MAAM,YAAY,OAAO,EAAE,MAAM;AAAA,MACpD,SAAS,CAAC,QAAQ,EAAE,QAAQ,MAAM;AAChC,gBAAQ,gBAAgB,OAAO,EAAE;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,IACD;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YAAY,KAAK,SAAS,CAAC,QAAQ,WAAW,QAAQ,CAAC;AAAA,MACnE,WAAW,CAAC,EAAE,MAAM,MAAM,MAAM,WAAW,SAAS;AAAA,MACpD,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,cAAc,CAAC,CAAC;AAAA,MAC1B;AAAA,IACF;AAAA,IACA,cAAc;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO,CAAC,YAAY,QAAQ,SAAS,cAAc,WAAW,OAAO,CAAC;AAAA,MACtE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,CAAC,QAAQ,EAAE,QAAQ,MAAM;AAChC,gBAAQ,cAAc,OAAO,EAAE;AAAA,MACjC;AAAA,IACF,CAAC;AAAA;AAAA;AAAA,IAGD,cAAc;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO,CAAC,YAAY,QAAQ,SAAS,cAAc,WAAW,OAAO,CAAC;AAAA,MACtE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,CAAC,QAAQ,EAAE,QAAQ,MAAM;AAChC,gBAAQ,cAAc,OAAO,EAAE;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,IACD;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YACV,KAAK,SAAS,CAAC,QAAQ,SAAS,CAAC,KAAK,QAAQ,MAAM,QAAQ,SAAS;AAAA,MACvE,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,WAAW,CAAC,CAAC;AAAA,MACvB;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YACV,KAAK,SAAS,CAAC,QAAQ,WAAW,SAAS,MAAM,CAAC,KAClD,QAAQ,MAAM,QAAQ,SAAS;AAAA,MACjC,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,gBAAgB;AAAA,MAC1B;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YACV,KAAK,SAAS,CAAC,QAAQ,WAAW,SAAS,MAAM,CAAC,KAClD,QAAQ,MAAM,QAAQ,SAAS;AAAA,MACjC,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,kBAAkB;AAAA,MAC5B;AAAA,IACF;AAAA,IACA,cAAc;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,MAAM;AAAA,MACN,MAAM;AAAA;AAAA;AAAA,MAGN,WAAW,CAAC,QAAQ,EAAE,KAAK,MACzB,KAAK,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO,OAAO,EAAE;AAAA,MACrD,SAAS,CAAC,QAAQ,EAAE,QAAQ,MAAM;AAChC,gBAAQ,YAAY,CAAC,OAAO,EAAE,CAAC;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,IACD,cAAc;AAAA,MACZ,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,CAAC,QAAQ,EAAE,KAAK,MAAM;AAC7B,aAAK,eAAe,CAAC,OAAO,EAAE,CAAC;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,IACD;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,MAAM;AAAA,MACN,WAAW,CAAC,YACV,KAAK,SAAS,CAAC,QAAQ,WAAW,QAAQ,CAAC,KAC3C,mBAAmB,OAAO,EAAE,SAAS;AAAA,MACvC,SAAS,CAAC,YAAY;AACpB,gBAAQ,KAAK,eAAe,mBAAmB,OAAO,CAAC;AAAA,MACzD;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YAAY,KAAK,SAAS,CAAC,QAAQ,WAAW,QAAQ,CAAC;AAAA,MACnE,SAAS,CAAC,EAAE,MAAM,OAAO,MAAM;AAC7B,aAAK,UAAU,iBAAiB,MAAM;AAAA,MACxC;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YACV,KAAK,SAAS,CAAC,QAAQ,MAAM,CAAC,KAC9B,QAAQ,QAAQ,YAAY,SAAS;AAAA,MACvC,WAAW,CAAC,EAAE,KAAK,MAAM,KAAK,gBAAgB,SAAS;AAAA,MACvD,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,cAAc;AAAA,MACxB;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YACV,KAAK,SAAS,CAAC,QAAQ,QAAQ,QAAQ,CAAC,KACxC,qBAAqB,QAAQ,QAAQ,UAAU;AAAA,MACjD,WAAW,CAAC,EAAE,MAAM,MAClB,MAAM,aAAa,SAAS,KAC5B,MAAM,gBAAgB,SAAS,KAC/B,MAAM,kBAAkB;AAAA,MAC1B,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,eAAe;AAAA,MACzB;AAAA,IACF;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,CAAC,EAAE,SAAS,MAAM,SAAS;AAAA,MAClC,WAAW,CAAC,YAAY,KAAK,SAAS,CAAC,QAAQ,WAAW,QAAQ,CAAC;AAAA,MACnE,WAAW,CAAC,EAAE,MAAM,MAAM,MAAM,OAAO,SAAS;AAAA,MAChD,SAAS,CAAC,EAAE,QAAQ,MAAM;AACxB,gBAAQ,UAAU,CAAC,CAAC;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;;;AC5VO,SAAS,iBACd,SACA,SACS;AACT,SAAO,QAAQ,YAAY,OAAO,KAAK;AACzC;AAGO,SAAS,iBACd,SACA,SACS;AACT,SAAO,QAAQ,YAAY,OAAO,KAAK;AACzC;AAWO,SAAS,gBACd,UACuC;AACvC,QAAM,WAAW,IAAI;AAAA,IACnB,gBAAqB,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC;AAAA,EAC/D;AACA,aAAW,WAAW,YAAY,CAAC,GAAG;AACpC,QAAI,QAAQ,OAAO,aAAa;AAC9B;AAAA,QACE;AAAA,MACF;AACA;AAAA,IACF;AACA,aAAS,IAAI,QAAQ,IAAI,OAAO;AAAA,EAClC;AACA,SAAO;AACT;AAQO,SAAS,WACd,SACA,SACS;AACT,MACE,CAAC,iBAAiB,SAAS,OAAO,KAClC,CAAC,iBAAiB,SAAS,OAAO,GAClC;AACA,WAAO;AAAA,EACT;AACA,UAAQ,QAAQ,OAAO;AACvB,SAAO;AACT;;;ACrCA,IAAM,qBAAqB,oBAAI,QAA6B;AAE5D,SAAS,gBAAgB,UAAkB,IAAkB;AAC3D,MAAI,WAAW,mBAAmB,IAAI,QAAQ;AAC9C,MAAI,aAAa,QAAW;AAC1B,eAAW,oBAAI,IAAI;AACnB,uBAAmB,IAAI,UAAU,QAAQ;AAAA,EAC3C;AACA,MAAI,SAAS,IAAI,EAAE,GAAG;AACpB;AAAA,EACF;AACA,WAAS,IAAI,EAAE;AACf;AAAA,IACE,+BAA+B,EAAE;AAAA,EACnC;AACF;AAGA,SAAS,SACP,OACA,SACO;AAGP,SAAO,OAAO,UAAU,aACnB,MAAsD,OAAO,IAC9D;AACN;AAEA,SAAS,YACP,SACA,SACyB;AACzB,MAAI,CAAC,iBAAiB,SAAS,OAAO,GAAG;AACvC,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,QAAQ;AAAA,IACZ,OAAO,SAAS,QAAQ,OAAO,OAAO;AAAA,IACtC,MAAM,QAAQ;AAAA,IACd,UAAU,QAAQ;AAAA,IAClB,UAAU,CAAC,iBAAiB,SAAS,OAAO;AAAA,IAC5C,SAAS,QAAQ,YAAY,OAAO;AAAA,IACpC,KAAK,MAAM,WAAW,SAAS,OAAO;AAAA,EACxC;AACF;AAEA,SAAS,WACP,OACA,SACyB;AACzB,MAAI,SAAS,MAAM,UAAU,OAAO,OAAO,GAAG;AAC5C,WAAO;AAAA,EACT;AACA,QAAM,WAAW,SAAS,MAAM,YAAY,OAAO,OAAO;AAC1D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,MAAM;AAAA,IACV,OAAO,SAAS,MAAM,OAAO,OAAO;AAAA,IACpC,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM;AAAA,IAChB;AAAA,IACA,SACE,MAAM,YAAY,SACd,SACA,SAAS,MAAM,SAAS,OAAO;AAAA,IACrC,KAAK,MAAM;AACT,UAAI,UAAU;AACZ,eAAO;AAAA,MACT;AACA,YAAM,SAAS,OAAO;AACtB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAQO,SAAS,mBACd,SACA,SAAoC,MAAM,OACxB;AAClB,QAAM,YAAqB,CAAC;AAC5B,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAW,UAAU,GAAG,EAAE;AAChC,QAAI,MAAM,SAAS,aAAa;AAC9B,UAAI,OAAO,KAAK,KAAK,UAAU,SAAS,aAAa;AACnD,kBAAU,IAAI;AAAA,MAChB;AACA,gBAAU,KAAK,KAAK;AAAA,IACtB,WACE,aAAa,UACb,SAAS,SAAS,eAClB,CAAC,OAAO,QAAQ,GAChB;AACA,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AACA,MAAI,UAAU,GAAG,EAAE,GAAG,SAAS,aAAa;AAC1C,cAAU,IAAI;AAAA,EAChB;AACA,SAAO;AACT;AAQO,SAAS,iBACd,OACA,OACA,SAC0B;AAC1B,QAAM,EAAE,UAAU,QAAQ,IAAI;AAC9B,MAAI,UAAU,aAAa;AACzB,WAAO,EAAE,MAAM,aAAa,KAAK,aAAa,OAAO,KAAK,CAAC,GAAG;AAAA,EAChE;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,SAAS,IAAI,KAAK;AAClC,QAAI,YAAY,QAAW;AACzB,sBAAgB,UAAU,KAAK;AAC/B,aAAO;AAAA,IACT;AACA,WAAO,YAAY,SAAS,OAAO;AAAA,EACrC;AACA,SAAO,MAAM,SAAS,SAClB,WAAW,OAAO,OAAO,IACzB,eAAe,OAAO,OAAO;AACnC;AAEA,SAAS,eACP,OACA,SAC4B;AAC5B,QAAM,QAAQ,YAAY,MAAM,OAAO,OAAO;AAC9C,SAAO,MAAM,WAAW,IACpB,OACA;AAAA,IACE,MAAM;AAAA,IACN,IAAI,MAAM;AAAA,IACV,OAAO,SAAS,MAAM,OAAO,QAAQ,OAAO;AAAA,IAC5C,MAAM,MAAM;AAAA,IACZ;AAAA,EACF;AACN;AAmBO,SAAS,YACd,SACA,SAC8B;AAC9B,SAAO;AAAA,IACL,QACG,IAAI,CAAC,OAAO,UAAU,iBAAiB,OAAO,OAAO,OAAO,CAAC,EAC7D,OAAO,CAAC,UAAU,UAAU,IAAI;AAAA,EACrC;AACF;;;ACtIO,IAAM,qBAIT;AAAA,EACF,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO,CAAC,mBAAmB,qBAAqB,aAAa,cAAc;AAAA,EAC3E,MAAM,CAAC;AACT;AAQO,SAAS,eACd,aACA,MACS;AACT,MAAI,gBAAgB,UAAa,gBAAgB,OAAO;AACtD,WAAO;AAAA,EACT;AACA,QAAM,WACH,gBAAgB,OAAO,SAAY,YAAY,IAAI,MACpD,mBAAmB,IAAI;AACzB,SAAO,OAAO,YAAY,cAAc,QAAQ,SAAS;AAC3D;AAGA,SAAS,WACP,OACA,SAC2B;AAC3B,MAAI,UAAU,QAAW;AACvB,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO,OAAO,UAAU,aAAc,MAAM,OAAO,KAAK,CAAC,IAAK;AAChE;AAUO,SAAS,mBACd,aACA,SAC2B;AAC3B,MAAI,gBAAgB,UAAa,gBAAgB,OAAO;AACtD,WAAO,CAAC;AAAA,EACV;AACA,QAAM,UACJ,gBAAgB,OAAO,CAAC,IAAI;AAC9B,QAAM,EAAE,OAAO,IAAI;AACnB,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,WAAW,QAAQ,QAAQ;AAAA,QAChC;AAAA,QACA,UAAU,mBAAmB;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH,KAAK;AACH,aAAO,WAAW,QAAQ,MAAM;AAAA,QAC9B;AAAA,QACA,UAAU,mBAAmB;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH,KAAK;AACH,aAAO,WAAW,QAAQ,OAAO;AAAA,QAC/B;AAAA,QACA,UAAU,mBAAmB;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH,KAAK;AACH,aAAO,WAAW,QAAQ,MAAM;AAAA,QAC9B;AAAA,QACA,UAAU,mBAAmB;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACH;AACE,aAAO,CAAC;AAAA,EACZ;AACF;;;AC7KA,SAAS,WAAW,OAAe,MAAc,MAAwB;AACvE,QAAM,UAAU,QAAQ,KAAK,OAAO;AACpC,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,UAAU,OAAO,IAAI;AAAA,IAC9B,KAAK;AACH,aAAO,UAAU,OAAO,IAAI,QAAQ;AAAA,EACxC;AACF;AAYO,SAAS,cACd,SACA,MACA,MACQ;AACR,QAAM,QAAQ,QAAQ;AACtB,QAAM,OAAO,SAAS,UAAU,SAAS,UAAU,IAAI;AACvD,QAAM,QAAQ,WAAW,OAAO,MAAM,IAAI;AAC1C,WAAS,SAAS,GAAG,SAAS,OAAO,UAAU;AAC7C,UAAM,UAAW,QAAQ,OAAO,UAAU,QAAS,SAAS;AAC5D,QAAI,QAAQ,KAAK,GAAG,SAAS,aAAa;AACxC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,eACd,QACA,MACA,OACQ;AACR,QAAM,QAAQ,MAAM,YAAY;AAChC,QAAM,iBAAiB,MAAM,YAAY,CAAC;AAC1C,MAAI,mBAAmB,QAAW;AAChC,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,OAAO,cAAc,cAAc;AACjD,QAAM,WAAW,MAAM,WAAW,OAAO,EAAE,MAAM;AACjD,QAAM,SAAS,WAAW,QAAQ;AAClC,QAAM,QAAQ,WAAW,OAAO,IAAI,KAAK,IAAI,MAAM,CAAC;AACpD,WAAS,SAAS,GAAG,SAAS,OAAO,QAAQ,UAAU;AACrD,UAAM,SAAS,QAAQ,UAAU,OAAO;AACxC,QAAI,OAAO,KAAK,GAAG,YAAY,EAAE,WAAW,MAAM,MAAM,MAAM;AAC5D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;AChEO,IAAM,iBAEP,CAAC,UAAU,UAAU,mBAAmB,eAAe;AAQtD,SAAS,eACd,SAC8B;AAC9B,MAAI,YAAY,UAAa,YAAY,OAAO;AAC9C,WAAO,CAAC;AAAA,EACV;AACA,UAAQ,YAAY,OAAO,SAAY,QAAQ,UAAU;AAC3D;;;ACZA,SAAS,SAAS,OAAqC;AACrD,SAAO,MAAM,SAAS;AACxB;AAmBO,SAAS,eACd,SACA,SACgC;AAChC,QAAM,EAAE,UAAU,WAAW,IAAI;AAEjC,WAAS,aACP,OACA,OAC4B;AAC5B,QAAI,UAAU,UAAU;AACtB,aAAO,EAAE,MAAM,UAAU,KAAK,SAAS;AAAA,IACzC;AACA,QAAI,UAAU,UAAU;AACtB,aAAO,EAAE,MAAM,UAAU,KAAK,UAAU,OAAO,KAAK,CAAC,GAAG;AAAA,IAC1D;AACA,QAAI,OAAO,UAAU,YAAY,MAAM,SAAS,UAAU;AACxD,aAAO,EAAE,MAAM,UAAU,IAAI,MAAM,IAAI,KAAK,MAAM,GAAG;AAAA,IACvD;AACA,QAAI,UAAU,aAAa;AACzB,aAAO,EAAE,MAAM,aAAa,KAAK,aAAa,OAAO,KAAK,CAAC,GAAG;AAAA,IAChE;AACA,UAAM,WAAW,iBAAiB,OAAO,OAAO;AAAA,MAC9C;AAAA,MACA,SAAS,WAAW;AAAA,QAClB,MAAM;AAAA,QACN,QAAQ,OAAO,UAAU,WAAW,QAAQ,MAAM;AAAA,MACpD,CAAC;AAAA,IACH,CAAC;AACD,QAAI,aAAa,QAAQ,SAAS,SAAS,aAAa;AACtD,aAAO;AAAA,IACT;AACA,QAAI,SAAS,SAAS,WAAW;AAC/B,aAAO,EAAE,GAAG,UAAU,MAAM,QAAQ,KAAK,SAAS,GAAG;AAAA,IACvD;AACA,UAAM,EAAE,SAAS,GAAG,KAAK,IAAI;AAC7B,WAAO,EAAE,GAAG,MAAM,MAAM,UAAU,KAAK,KAAK,IAAI,SAAS,QAAQ;AAAA,EACnE;AAEA,SAAO;AAAA,IACL,QAAQ,IAAI,YAAY,EAAE,OAAO,CAAC,UAAU,UAAU,IAAI;AAAA,IAC1D;AAAA,EACF;AACF;;;ACxDO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,OAAO,CAAC;AAC1D,MAAI,SAAS,WAAW;AACtB,WAAO,OAAO;AAAA,EAChB;AACA,MAAI,OACF,YACA,OAAO,OAAO,CAAC,KAAK,OAAO,UAAU,OAAO,OAAO,KAAK,IAAI,QAAQ,IAAI,CAAC;AAC3E,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,GAAG;AAC7C,QAAI,CAAC,OAAO,KAAK,GAAG;AAClB,cAAQ;AACR,UAAI,OAAO,WAAW;AACpB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAMO,SAAS,oBACd,MACS;AACT,SAAO,KAAK,SAAS,YAAY,KAAK,SAAS;AACjD;AAWA,SAAS,YAAY,MAAqD;AACxE,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,KAAK;AAAA,QACT,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf,SAAS,KAAK;AAAA,QACd,KAAK,KAAK;AAAA,MACZ;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,KAAK;AAAA,QACT,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,MACd;AAAA,IACF,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAQO,SAAS,kBACd,OACA,KACc;AACd,QAAM,OAAO,CAAC,MAA2B,UACvC,QAAQ,OAAO,oBAAoB,IAAI;AACzC,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM,OAAO,IAAI;AAAA,MACjB,CAAC,SAAS,KAAK,SAAS;AAAA,IAC1B;AAAA,IACA,UAAU;AAAA,MACR,MACG,OAAO,CAAC,MAAM,UAAU,CAAC,KAAK,MAAM,KAAK,CAAC,EAC1C,IAAI,WAAW,EACf,OAAO,CAAC,UAAU,UAAU,IAAI;AAAA,IACrC;AAAA,EACF;AACF;;;AClHO,SAAS,aAAkB,QAAkC;AAClE,QAAM,QAAQ,eAAe,MAAM,KAAK;AACxC,QAAM,QAAQ,MAAM,WAAW,GAAG,IAAI,IAAI;AAC1C,QAAM,MAAM,MAAM,SAAS,GAAG,IAAI,KAAK;AACvC,SAAO,MAAM,MAAM,OAAO,GAAG;AAC/B;AAYO,SAAS,cACd,QACA,MACkB;AAClB,SAAO,gBAAgB,QAAQ,QAAW,SAAS,KAAK,KAAK,IAAI,IAAI,GAAG;AAC1E;;;AC1BO,IAAM,aAAa;AAqBnB,SAAS,WACd,OACA,UACAC,cACW;AACX,SAAO;AAAA,IACL,UAAU,KAAK,IAAI,KAAK,IAAI,MAAM,UAAU,UAAU,GAAG,WAAW,CAAC;AAAA,IACrE,aAAa,KAAK;AAAA,MAChB,KAAK,IAAI,MAAM,aAAa,CAAC;AAAA,MAC7B,KAAK,IAAIA,eAAc,GAAG,CAAC;AAAA,IAC7B;AAAA,EACF;AACF;AAGA,SAAS,kBAA2B;AAClC,SAAO;AACT;AAqBA,SAAS,kBACP,UACA,WACA,UACA,gBACA,UACQ;AACR,MAAI,OAAO;AAMX,SAAO,QAAQ,KAAK,OAAO,YAAY,eAAe,IAAI,GAAG;AAC3D,UAAM,UAAU,OAAO;AAIvB,QAAI,UAAU,cAAc,WAAW,UAAU;AAC/C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAkBO,SAAS,gBACd,KACA,WACA,OACA,UACAA,cACA,UACA,iBAAgD,iBAC9B;AAGlB,MAAI,UAAU,QAAQ;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,UAAU,YAAY,IAAI;AAElC,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,UAAI,UAAU,QAAS,QAAO;AAC9B,aAAO,EAAE,UAAU,aAAa,cAAc,EAAE;AAAA,IAClD,KAAK;AACH,UAAI,UAAU,QAAS,QAAO;AAC9B,aAAO,EAAE,UAAU,aAAa,cAAc,EAAE;AAAA,IAClD,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA;AAAA;AAAA,IAGF,KAAK;AACH,aAAO,UAAU,UACb,EAAE,UAAU,YAAY,aAAa,EAAE,IACvC,EAAE,UAAU,aAAa,EAAE;AAAA,IACjC,KAAK;AACH,aAAO,UAAU,UACb;AAAA,QACE,UAAU;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,aAAaA,eAAc;AAAA,MAC7B,IACA,EAAE,UAAU,aAAaA,eAAc,EAAE;AAAA,IAC/C,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,UACR,WAAW;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACE,aAAO;AAAA,EACX;AACF;;;ACzLO,SAAS,iBACd,aACA,WACA,SAIkC;AAClC,MAAI,aAAa,GAAG;AAClB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,gBAAgB,KAAK,IAAI,GAAG,SAAS,iBAAiB,CAAC;AAC7D,QAAM,eAAe,KAAK,IAAI,GAAG,SAAS,gBAAgB,CAAC;AAC3D,QAAM,UAAU,KAAK,IAAI,KAAK,IAAI,aAAa,CAAC,GAAG,SAAS;AAE5D,QAAM,QAAQ,oBAAI,IAAY;AAC9B,WAAS,OAAO,GAAG,QAAQ,KAAK,IAAI,eAAe,SAAS,GAAG,QAAQ;AACrE,UAAM,IAAI,IAAI;AAAA,EAChB;AACA,WACM,OAAO,KAAK,IAAI,YAAY,gBAAgB,GAAG,CAAC,GACpD,QAAQ,WACR,QACA;AACA,UAAM,IAAI,IAAI;AAAA,EAChB;AACA,WACM,OAAO,KAAK,IAAI,UAAU,cAAc,CAAC,GAC7C,QAAQ,KAAK,IAAI,UAAU,cAAc,SAAS,GAClD,QACA;AACA,UAAM,IAAI,IAAI;AAAA,EAChB;AAEA,QAAM,SAAS,MAAM,KAAK,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACrD,QAAM,UAAmC,CAAC;AAC1C,MAAI;AACJ,aAAW,QAAQ,QAAQ;AACzB,QAAI,aAAa,QAAW;AAC1B,UAAI,OAAO,aAAa,GAAG;AACzB,gBAAQ,KAAK,WAAW,CAAC;AAAA,MAC3B,WAAW,OAAO,WAAW,GAAG;AAC9B,gBAAQ,KAAK,UAAU;AAAA,MACzB;AAAA,IACF;AACA,YAAQ,KAAK,IAAI;AACjB,eAAW;AAAA,EACb;AAEA,SAAO;AACT;;;ACPA,SAAS,WAAgB,QAA2C;AAClE,SAAO,OAAO,OAAO,aAAa;AACpC;AAEA,SAAS,cAAc,OAAe,QAAyB;AAC7D,SAAO,MAAM,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC;AAC1D;AAEA,SAAS,iBAAiB,QAA4C;AACpE,MAAI,OAAO,SAAS,KAAK,OAAO,MAAM,OAAO,GAAG;AAC9C,WAAO;AAAA,EACT;AACA,SAAO,OAAO,KAAK,OAAO,IAAI,UAAU;AAC1C;AAaO,SAAS,qBAA0B;AAAA,EACxC;AAAA,EACA;AAAA,EACA,SAAS;AACX,GAAgD;AAC9C,QAAM,MAAM,QAAQ,IAAI,CAAC,YAAgC;AAAA,IACvD;AAAA,IACA,OAAO,wBAAwB,OAAO,MAAM;AAAA,IAC5C,SAAS,gBAAgB,OAAO,QAAQ,UAAU;AAAA,EACpD,EAAE;AACF,QAAM,aAAa,IAAI,OAAO,CAAC,EAAE,QAAQ,MAAM,OAAO,EAAE;AACxD,QAAM,UAAU,IAAI,OAAO,CAAC,EAAE,MAAM,MAAM,cAAc,OAAO,MAAM,CAAC;AAEtE,QAAM,UAAU,QAAQ;AAAA,IACtB,CAAC,EAAE,QAAQ,OAAO,QAAQ,OAA2B;AAAA,MACnD,UAAU,OAAO;AAAA,MACjB;AAAA,MACA;AAAA,MACA,UAAU,YAAY,CAAC,WAAW,MAAM,KAAK,eAAe;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,OAAO,CAAC,EAAE,OAAO,MAAM,WAAW,MAAM,CAAC;AACjE,QAAMC,aAAY,iBAAiB,QAAQ,IAAI,CAAC,EAAE,QAAQ,MAAM,OAAO,CAAC;AACxE,SAAO;AAAA,IACL;AAAA,IACA,WAAAA;AAAA,IACA,WAAW,YAAY,SAASA,YAAW,UAAU;AAAA,EACvD;AACF;AAEA,SAAS,YACP,SACAA,YACA,YAC4B;AAC5B,QAAM,OAAOA,eAAc;AAC3B,QAAM,WAAW,QACd,OAAO,CAAC,EAAE,QAAQ,MAAM,YAAY,IAAI,EACxC,IAAI,CAAC,EAAE,OAAO,MAAM,OAAO,EAAE;AAEhC,QAAM,YACJ,CAAC,QAAQ,SAAS,WAAW,aAAa,SAAS,MAAM,CAAC,IAAI;AAChE,SAAO,UAAU,WAAW,IAAI,OAAO,EAAE,SAAS,MAAM,UAAU;AACpE;;;ACqBA,SAAS,YACP,OACA,QACQ;AACR,SAAO,UAAU,IACb,YAAY,MAAM,KAClB,GAAG,OAAO,KAAK,CAAC,YAAY,MAAM;AACxC;AAGA,SAAS,cAAc,OAAuB;AAC5C,MAAI,UAAU,GAAG;AACf,WAAO;AAAA,EACT;AACA,SAAO,UAAU,IAAI,gBAAgB,GAAG,OAAO,KAAK,CAAC;AACvD;AAGA,SAAS,cAAc,OAAe,QAAoC;AACxE,QAAM,OAAO,WAAW,SAAS,QAAQ;AACzC,MAAI,UAAU,GAAG;AACf,WAAO,MAAM,IAAI;AAAA,EACnB;AACA,SAAO,UAAU,IACb,KAAK,IAAI,cACT,GAAG,OAAO,KAAK,CAAC,IAAI,IAAI;AAC9B;AAGO,IAAM,kBAAgC;AAAA,EAC3C,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,UAAU;AAAA,EACV,eAAe;AAAA,EACf,iBAAiB,CAAC,SAAS,QAAQ,OAAO,IAAI,CAAC;AAAA,EAC/C,YAAY,CAAC,MAAM,cACjB,QAAQ,OAAO,IAAI,CAAC,OAAO,OAAO,SAAS,CAAC;AAAA,EAC9C,aAAa;AAAA,EACb,aAAa;AAAA,EACb,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,kBAAkB,CAACC,aAAY,OAAO,eACpC,aAAa,IACT,GAAGA,WAAU,WAAW,OAAO,KAAK,CAAC,OAAO,OAAO,UAAU,CAAC,KAC9DA;AAAA,EACN,eAAe,CAACA,gBAAe,oBAAoBA,WAAU;AAAA,EAC7D,eAAe,CAACA,aAAY,UAC1B,GAAGA,WAAU,KAAK,OAAO,KAAK,CAAC;AAAA,EACjC,aAAa,CAACA,aAAY,UAAUC,iBAClC,GAAGD,WAAU,YAAY,OAAO,QAAQ,CAAC,OAAO,OAAOC,YAAW,CAAC;AAAA,EACrE,cAAc,CAACD,aAAY,WAAW,KAAK,aAAa;AACtD,UAAM,SAAS,GAAGA,WAAU,WAAW,cAAc,QAAQ,cAAc,YAAY;AACvF,WAAO,WAAW,IACd,GAAG,MAAM,SAAS,OAAO,GAAG,CAAC,OAAO,OAAO,QAAQ,CAAC,KACpD;AAAA,EACN;AAAA,EACA,aAAa,CAACA,gBAAe,GAAGA,WAAU;AAAA,EAC1C,WAAW,CAACA,aAAY,OAAO,eAC7B,aAAa,IACT,cAAcA,WAAU,WAAW,OAAO,KAAK,CAAC,OAAO,OAAO,UAAU,CAAC,KACzE,cAAcA,WAAU;AAAA,EAC9B,iBAAiB,CAACA,gBAAe,GAAGA,WAAU;AAAA,EAC9C,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB;AAAA,EACA,cAAc,CAACA,aAAY,cACzB,GAAGA,WAAU,SAAS,OAAO,SAAS,CAAC;AAAA,EACzC,cAAc,CAACA,gBAAe,GAAGA,WAAU;AAAA,EAC3C,aAAa,CAACA,gBAAe,GAAGA,WAAU;AAAA,EAC1C,eAAe,CAAC,UAAU,YAAY,OAAO,QAAQ;AAAA,EACrD,cAAc,CAAC,UAAU,YAAY,OAAO,OAAO;AAAA,EACnD,mBAAmB,CAAC,UAAU,YAAY,OAAO,YAAY;AAAA,EAC7D,iBAAiB,CAACA,gBAAe,GAAGA,WAAU;AAAA,EAC9C,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,eAAe,CAACA,gBAAe,YAAYA,WAAU;AAAA,EACrD,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,cAAc;AAAA,EACd,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB;AAAA,EACA,oBAAoB;AAAA,EACpB,0BAA0B;AAAA,EAC1B,gBAAgB;AAAA,EAChB,mBAAmB;AACrB;AAOO,SAAS,gBACd,UACc;AACd,SAAO,aAAa,SAChB,kBACA,EAAE,GAAG,iBAAiB,GAAG,SAAS;AACxC;;;ACxPA,IAAM,cAA0C;AAAA,EAC9C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AACP;AACA,IAAM,cAA0C;AAAA,EAC9C,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AACV;AACA,IAAM,mBAA+C;AAAA,EACnD,GAAG;AAAA,EACH,GAAG;AACL;AAGA,IAAM,kBAA4C;AAAA,EAChD,uBAAuB;AAAA,EACvB,uBAAuB;AACzB;AAGA,IAAM,YAA2B,CAAC;AAUlC,IAAM,aAAa,oBAAI,QAGrB;AAEF,SAAS,OACP,QACA,KACA,QACW;AACX,QAAM,QAAQ,UAAU;AACxB,MAAI,QAAQ,WAAW,IAAI,KAAK;AAChC,MAAI,UAAU,QAAW;AACvB,YAAQ,oBAAI,IAAI;AAChB,eAAW,IAAI,OAAO,KAAK;AAAA,EAC7B;AACA,QAAM,WAAW,MAAM,IAAI,GAAG;AAC9B,MAAI,aAAa,QAAW;AAE1B,WAAO;AAAA,EACT;AACA,QAAM,YAAY,OAAO;AACzB,QAAM,IAAI,KAAK,SAAS;AACxB,SAAO;AACT;AAEA,SAAS,UAAU,QAA8B;AAC/C,SAAO,OAAO,WAAW,WAAW,SAAU,QAAQ,KAAK,GAAG,KAAK;AACrE;AAEA,SAAS,cAAc,MAAuC;AAC5D,SACE,SAAS,YACT,SAAS,aACT,SAAS,cACT,SAAS;AAEb;AAOA,SAAS,cACP,MACA,QAC0B;AAC1B,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,QAAQ,aAAa,SACxB,EAAE,GAAG,iBAAiB,GAAG,OAAO,IAChC,EAAE,OAAO,YAAY,GAAG,OAAO;AAAA,IACrC,KAAK;AAEH,aAAO,EAAE,OAAO,WAAW,GAAG,OAAO;AAAA,IACvC;AACE,aAAO,UAAU,CAAC;AAAA,EACtB;AACF;AAOA,SAAS,YACP,MACA,QAC4B;AAC5B,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,OAAQ,QAAO;AAC5B,MAAI,SAAS,OAAQ,QAAO;AAC5B,SAAO;AACT;AAEA,SAAS,aACP,OACA,MACA,QACA,QACQ;AACR,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,UAAU,QAAQ,EAAE,IAAI,UAAU,MAAM,CAAC;AAAA,IACzC,MACE,IAAI,KAAK;AAAA,MACP;AAAA,MACA,cAAc,MAAM,MAA8C;AAAA,IACpE;AAAA,EACJ;AACA,SAAO,UAAU,OAAO,KAAK;AAC/B;AAEA,SAAS,WACP,OACA,MACA,QACA,QACQ;AAER,MAAI,OAAO,MAAM,MAAM,QAAQ,CAAC,GAAG;AACjC,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,QAAQ,QAAQ,EAAE,IAAI,UAAU,MAAM,CAAC;AAAA,IACvC,MACE,IAAI,KAAK;AAAA,MACP;AAAA,MACA,YAAY,MAAM,MAAgD;AAAA,IACpE;AAAA,EACJ;AACA,SAAO,UAAU,OAAO,KAAK;AAC/B;AASA,SAAS,YAAY,OAAwB;AAC3C,MAAI,OAAO,UAAU,YAAY;AAC/B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,QAAI;AACF,aAAO,KAAK,UAAU,KAAK;AAAA,IAC7B,QAAQ;AACN,aAAO,OAAO,UAAU,SAAS,KAAK,KAAK;AAAA,IAC7C;AAAA,EACF;AACA,SAAO,OAAO,KAAK;AACrB;AA4BO,SAAS,gBACd,OACA,QACA,QACA,KACA,UACQ;AACR,MAAI,OAAO,mBAAmB,QAAW;AACvC,WAAO,OAAO,eAAe,OAAO,GAAG;AAAA,EACzC;AACA,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,aAAa,aAAa,QAAW;AACxD,WAAO,QAAQ,SAAS,cAAc,SAAS;AAAA,EACjD;AACA,QAAM,EAAE,MAAM,OAAO,IAAI;AACzB,QAAM,YAAY,WAAW,UAAa,WAAW;AACrD,MAAI,iBAAiB,MAAM;AACzB,WAAO,YACH,WAAW,OAAO,MAAM,QAAQ,MAAM,IACtC,MAAM,eAAe;AAAA,EAC3B;AACA,MACE,cACC,OAAO,UAAU,YAAY,OAAO,UAAU,aAC/C,cAAc,IAAI,GAClB;AACA,WAAO,aAAa,OAAO,MAAM,QAAQ,MAAM;AAAA,EACjD;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,YAAY,KAAK;AAC1B;AAUA,SAAS,sBACP,OACA,MACA,QACgC;AAChC,QAAM,QAAwC;AAAA,IAC5C,OAAO,KAAK;AAAA,IACZ,MAAM;AAAA,EACR;AACA,MACE,WAAW,UACX,KAAK,OAAO,WACZ,KAAK,OAAO,iBACZ;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,OAAO,UAAU,YAAY,OAAO,UAAU;AAC9D,SAAO,OAAO,mBAAmB,UAC/B,WACA,CAAC,cAAc,OAAO,IAAI,IACxB,QACA;AACN;AAaO,SAAS,qBACd,OACA,MACA,QACA,QACQ;AACR,QAAM,SAAS,sBAAsB,OAAO,MAAM,MAAM;AACxD,MACE,OAAO,UAAU,YACjB,OAAO,mBAAmB,UAC1B,OAAO,WAAW,UAClB,WAAW,QACX;AACA,WAAO,MAAM,eAAe;AAAA,EAC9B;AACA,SAAO,gBAAgB,OAAO,QAAQ,MAAM;AAC9C;;;AChLA,SAAS,cACP,OACA,UACS;AACT,SAAO,gBAAgB,QACnB,MAAM,QAAQ,KAAK,CAAC,WAAW,cAAc,QAAQ,QAAQ,CAAC,IAC9D,MAAM,aAAa;AACzB;AAEA,SAAS,aACP,OACA,UACmC;AACnC,SAAO,cAAc,SAAS,MAAM,aAAa;AACnD;AAGA,SAAS,cACP,OACA,UACmC;AACnC,SAAO,aAAa,OAAO,QAAQ,KAAK,MAAM,aAAa;AAC7D;AAGA,SAAS,YACP,OACA,UACoC;AACpC,QAAM,SAAS,CAAC,cACd,cAAc,UACd,aAAa,WAAW,QAAQ,KAChC,UAAU,aAAa,QACvB,aAAa,UAAU,KAAK,IACxB,UAAU,QACV;AACN,QAAM,SAAS,CAAC,cACd,cAAc,UACd,aAAa,WAAW,QAAQ,KAChC,UAAU,aAAa;AAEzB,QAAM,QAAQ,OAAO,KAAK;AAC1B,MAAI,UAAU,QAAW;AACvB,WAAO,EAAE,MAAM,UAAU,QAAQ,OAAO,eAAe,MAAM;AAAA,EAC/D;AACA,MACE,EAAE,gBAAgB,UAClB,MAAM,eAAe,QACrB,MAAM,QAAQ,WAAW,GACzB;AACA,WAAO;AAAA,EACT;AACA,QAAM,CAAC,OAAO,MAAM,IAAI,MAAM;AAC9B,QAAM,SAAS,OAAO,KAAK,IAAI,OAAO,MAAM,IAAI,OAAO,KAAK;AAC5D,SAAO,WAAW,WAAc,OAAO,KAAK,KAAK,OAAO,MAAM,KAC1D,EAAE,MAAM,UAAU,QAAQ,QAAQ,eAAe,KAAK,IACtD;AACN;AAGA,SAAS,gBACP,UACA,UACoC;AACpC,QAAM,CAAC,IAAI,IAAI;AACf,QAAM,UACJ,SAAS,WAAW,KAAK,SAAS,UAAa,gBAAgB;AACjE,QAAM,UAAU,UAAU,KAAK,UAAU;AACzC,QAAM,aAAa,UAAU,KAAK,aAAa;AAC/C,MAAI,QAAQ,WAAW,KAAK,QAAQ,SAAS,GAAG;AAC9C,WAAO;AAAA,EACT;AACA,QAAM,aAAa,QAAQ,OAAO,CAAC,UAAU,cAAc,OAAO,QAAQ,CAAC;AAC3E,SAAO,WAAW,WAAW,QAAQ,SACjC,EAAE,MAAM,cAAc,YAAY,WAAW,IAC7C;AACN;AAOO,SAAS,qBACd,QACA,UACwB;AACxB,QAAM,WAAW,OAAO,OAAO,CAAC,UAAU,cAAc,OAAO,QAAQ,CAAC;AACxE,QAAM,CAAC,IAAI,IAAI;AACf,MAAI,SAAS,QAAW;AACtB,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACA,UACG,SAAS,WAAW,IAAI,YAAY,MAAM,QAAQ,IAAI,WACvD,gBAAgB,UAAU,QAAQ,KAAK,EAAE,MAAM,SAAS;AAE5D;AAMA,SAAS,YAAY,OAAsD;AACzE,SACE,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,aACjB,iBAAiB;AAErB;AAEA,SAASE,eAAc,OAAe,QAAyB;AAC7D,SAAO,MAAM,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC;AAC1D;AA0BO,SAAS,mBACd,MACA,aACA,QACA,UACA,QAA0B,CAAC,GACP;AACpB,QAAM,SAAS,YAAY,KAAK,CAAC,UAAU,MAAM,OAAO,QAAQ,GAAG;AACnE,MAAI,WAAW,QAAW;AACxB,WAAO,EAAE,SAAS,CAAC,GAAG,OAAO,GAAG,WAAW,OAAO,QAAQ,EAAE;AAAA,EAC9D;AACA,QAAM,OAAO;AAAA,IACX,OAAO,OAAO,CAAC,UAAU,CAAC,cAAc,OAAO,QAAQ,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,QAAM,UAAU,oBAAI,IAAyB;AAC7C,MAAI,SAAS;AACb,aAAW,OAAO,MAAM;AACtB,QAAI,SAAS,UAAa,CAAC,KAAK,GAAG,GAAG;AACpC;AAAA,IACF;AACA,UAAM,QAAQ,aAAa,KAAK,OAAO,KAAK;AAC5C,QAAI,YAAY,KAAK,GAAG;AACtB;AAAA,IACF,WAAW,YAAY,KAAK,GAAG;AAC7B,YAAM,MAAM,eAAe,OAAO,OAAO,IAAI;AAC7C,YAAM,SAAS,QAAQ,IAAI,GAAG;AAC9B,UAAI,WAAW,QAAW;AACxB,gBAAQ,IAAI,KAAK,EAAE,OAAO,KAAK,OAAO,EAAE,CAAC;AAAA,MAC3C,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,IAAI,OAAO,OAAO,IAAI;AACvC,QAAM,WAAW,gBAAgB,MAAM,QAAQ;AAC/C,QAAM,UAAU,CAAC,GAAG,QAAQ,OAAO,CAAC,EACjC,KAAK,CAAC,GAAG,MAAM,cAAc,EAAE,OAAO,EAAE,OAAO,OAAO,IAAI,CAAC,EAC3D,IAAI,CAAC,EAAE,OAAO,KAAK,MAAM,OAAO;AAAA,IAC/B;AAAA,IACA,OAAO,gBAAgB,OAAO,QAAQ,QAAQ,KAAK,QAAQ;AAAA,IAC3D;AAAA,EACF,EAAE,EACD,OAAO,CAAC,WAAWA,eAAc,OAAO,OAAO,MAAM,CAAC;AACzD,QAAM,QAAQ,UAAU,SAAY,UAAU,QAAQ,MAAM,GAAG,KAAK;AACpE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO,QAAQ;AAAA,IACf,WAAW,MAAM,SAAS,QAAQ;AAAA,IAClC;AAAA,IACA,YAAY,OAAO;AAAA,EACrB;AACF;AAGA,SAASC,OACP,OACA,OACQ;AACR,SAAO,eAAe,OAAO,MAAM,UAAU;AAC/C;AAEA,SAAS,YACP,OACmC;AACnC,SAAO,IAAI;AAAA,IACT,MAAM,QAAQ,IAAI,CAAC,WAAW,CAACA,OAAM,OAAO,OAAO,KAAK,GAAG,OAAO,KAAK,CAAC;AAAA,EAC1E;AACF;AAQO,SAAS,yBACd,OACA,QACwB;AACxB,QAAM,QAAgC;AAAA,IACpC,MAAM;AAAA,IACN,SAAS,OAAO;AAAA,IAChB,QAAQ,OAAO;AAAA,IACf,QAAQ;AAAA,IACR,SAAS,YAAY,MAAM;AAAA,IAC3B,eAAe,OAAO,SAAS;AAAA,IAC/B,YAAY,CAAC;AAAA,IACb,YAAY;AAAA,IACZ,YAAY,OAAO;AAAA,EACrB;AACA,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,SAAS,IAAI;AAAA,UACX,MAAM,OACH,OAAO,CAAC,UAAU,CAAC,YAAY,KAAK,CAAC,EACrC,IAAI,CAAC,UAAU,CAACA,OAAM,OAAO,KAAK,GAAG,KAAK,CAAC;AAAA,QAChD;AAAA,QACA,eAAe,MAAM;AAAA,MACvB;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,YAAY,MAAM;AAAA,QAClB,YAAY,MAAM;AAAA,MACpB;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAGO,SAAS,qBACd,OAC8B;AAC9B,SAAO,MAAM,WAAW,KACpB,MAAM,UACN,MAAM,QAAQ;AAAA,IAAO,CAAC,WACpBD,eAAc,OAAO,OAAO,MAAM,MAAM;AAAA,EAC1C;AACN;AAGA,SAAS,sBAA2B,OAAwC;AAC1E,SAAO,MAAM,WAAW,MAAM,MAAM,SAAS;AAC/C;AAOO,SAAS,eACd,OACgB;AAChB,QAAM,SAAS,qBAAqB,KAAK,EAAE;AAAA,IAAI,CAAC,WAC9C,MAAM,QAAQ,IAAIC,OAAM,OAAO,OAAO,KAAK,CAAC;AAAA,EAC9C;AACA,MAAI,sBAAsB,KAAK,GAAG;AAChC,WAAO,KAAK,MAAM,aAAa;AAAA,EACjC;AACA,MAAI,OAAO,SAAS,KAAK,OAAO,MAAM,OAAO,GAAG;AAC9C,WAAO;AAAA,EACT;AACA,SAAO,OAAO,KAAK,OAAO,IAAI,UAAU;AAC1C;AAEA,SAAS,UAAe,OAAuD;AAC7E,QAAM,QAAQ,eAAe,KAAK,MAAM;AACxC,QAAM,UAAU,IAAI,IAAI,MAAM,OAAO;AACrC,aAAW,UAAU,qBAAqB,KAAK,GAAG;AAChD,UAAM,MAAMA,OAAM,OAAO,OAAO,KAAK;AACrC,QAAI,OAAO;AACT,cAAQ,IAAI,KAAK,OAAO,KAAK;AAAA,IAC/B,OAAO;AACL,cAAQ,OAAO,GAAG;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,IACN;AAAA,IACA,eAAe,sBAAsB,KAAK,IAAI,QAAQ,MAAM;AAAA,EAC9D;AACF;AAQO,SAAS,oBACd,OACA,QACwB;AACxB,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,QAAQ,OAAO,OAAO;AAAA,IAC3C,KAAK,eAAe;AAClB,YAAM,MAAMA,OAAM,OAAO,OAAO,KAAK;AACrC,YAAM,UAAU,IAAI,IAAI,MAAM,OAAO;AACrC,UAAI,QAAQ,IAAI,GAAG,GAAG;AACpB,gBAAQ,OAAO,GAAG;AAAA,MACpB,OAAO;AACL,gBAAQ,IAAI,KAAK,OAAO,KAAK;AAAA,MAC/B;AACA,aAAO,EAAE,GAAG,OAAO,MAAM,UAAU,QAAQ;AAAA,IAC7C;AAAA,IACA,KAAK;AACH,aAAO,UAAU,KAAK;AAAA,IACxB,KAAK;AACH,aAAO,EAAE,GAAG,OAAO,MAAM,UAAU,eAAe,OAAO,cAAc;AAAA,IACzE,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,MAAM;AAAA,QACN,YAAY,OAAO;AAAA,QACnB,YAAY,OAAO,cAAc,MAAM;AAAA,MACzC;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,SAAS,YAAY,KAAK;AAAA,QAC1B,eAAe,MAAM,SAAS;AAAA,QAC9B,YAAY,CAAC;AAAA,MACf;AAAA,EACJ;AACF;AAMA,SAAS,iBAAsB,OAAwC;AACrE,SACE,MAAM,QAAQ;AAAA,IAAM,CAAC,WACnB,MAAM,QAAQ,IAAIA,OAAM,OAAO,OAAO,KAAK,CAAC;AAAA,EAC9C,MACC,MAAM,iBAAiB,MAAM,WAAW;AAE7C;AAGA,SAAS,aACP,OACA,UACkB;AAClB,MAAI,MAAM,SAAS,cAAc;AAC/B,UAAM,aAAa,MAAM,WAAW,IAAI,CAAC,eAAe;AAAA,MACtD,GAAG;AAAA,MACH;AAAA,IACF,EAAE;AACF,WAAO,WAAW,SAAS,IACvB,CAAC,EAAE,YAAY,MAAM,YAAY,SAAS,WAAW,CAAC,IACtD;AAAA,EACN;AACA,MAAI,iBAAiB,KAAK,GAAG;AAC3B,WAAO,CAAC;AAAA,EACV;AACA,QAAM,SAAmC;AAAA,IACvC;AAAA,IACA,UAAU;AAAA,IACV,OAAO,CAAC,GAAG,MAAM,QAAQ,OAAO,CAAC;AAAA,EACnC;AACA,SAAO,MAAM,gBACT;AAAA,IACE;AAAA,MACE,YAAY;AAAA,MACZ,SAAS,CAAC,QAAQ,EAAE,UAAU,UAAU,UAAU,CAAC;AAAA,IACrD;AAAA,EACF,IACA,CAAC,MAAM;AACb;AAaO,SAAS,cACd,OACA,UACA,SACkB;AAClB,QAAM,cAAc,aAAa,OAAO,QAAQ;AAChD,QAAM,QAAQ,QAAQ,UAAU,CAAC,UAAU,cAAc,OAAO,QAAQ,CAAC;AACzE,MAAI,UAAU,IAAI;AAChB,WAAO,YAAY,WAAW,IAAI,UAAU,CAAC,GAAG,SAAS,GAAG,WAAW;AAAA,EACzE;AACA,QAAM,OAAO,QAAQ,OAAO,CAAC,UAAU,CAAC,cAAc,OAAO,QAAQ,CAAC;AACtE,SAAO,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK,GAAG,GAAG,aAAa,GAAG,KAAK,MAAM,KAAK,CAAC;AACvE;;;ACzgBO,SAAS,aACd,SACA,iBACA,WACA,gBACA,UACc;AACd,QAAM,WAAW,QAAQ;AACzB,MAAI,aAAa,GAAG;AAClB,WAAO,EAAE,YAAY,GAAG,UAAU,IAAI,cAAc,GAAG,aAAa,EAAE;AAAA,EACxE;AAEA,WAAS,SAAS,OAAuB;AACvC,WAAO,QAAQ,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,iBAAiB,YAAY;AAOnC,MAAI,QAAQ;AACZ,MAAI,MAAM;AACV,SAAO,QAAQ,WAAW,KAAK,MAAM,SAAS,KAAK,KAAK,WAAW;AACjE,WAAO,SAAS,KAAK;AACrB,aAAS;AAAA,EACX;AACA,QAAM,WAAW;AAMjB,MAAI,MAAM;AACV,MAAI,SAAS,WAAW,SAAS,KAAK;AACtC,SAAO,MAAM,WAAW,KAAK,SAAS,gBAAgB;AACpD,WAAO;AACP,cAAU,SAAS,GAAG;AAAA,EACxB;AAEA,QAAM,gBAAgB,KAAK,IAAI,GAAG,QAAQ,QAAQ;AAClD,QAAM,cAAc,KAAK,IAAI,WAAW,GAAG,MAAM,QAAQ;AAEzD,MAAI,eAAe;AACnB,WAAS,QAAQ,GAAG,QAAQ,eAAe,SAAS;AAClD,oBAAgB,SAAS,KAAK;AAAA,EAChC;AACA,MAAI,cAAc;AAClB,WAAS,QAAQ,cAAc,GAAG,QAAQ,UAAU,SAAS;AAC3D,mBAAe,SAAS,KAAK;AAAA,EAC/B;AAEA,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;","names":["total","isEmpty","test","columnId","entry","resolveColumns","columnCount","selectAll","columnName","columnCount","matchesSearch","keyOf"]}
|