@gridkitjs/core 0.1.0 → 0.2.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 +63 -1
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,11 @@ interface ColumnDefinition<Row, Node = string> {
|
|
|
88
88
|
maxWidth?: number;
|
|
89
89
|
/** Whether this column can be resized, overriding the grid-level default. */
|
|
90
90
|
resizable?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Whether this column can be dragged to a new position, overriding the
|
|
93
|
+
* grid-level default. A column that cannot move can still be moved past.
|
|
94
|
+
*/
|
|
95
|
+
reorderable?: boolean;
|
|
91
96
|
}
|
|
92
97
|
/**
|
|
93
98
|
* Widths the user has changed, keyed by column id. Holding only what changed —
|
|
@@ -114,6 +119,8 @@ interface ColumnResolveOptions {
|
|
|
114
119
|
sizes?: Partial<ColumnSizeDefaults> | undefined;
|
|
115
120
|
/** Whether columns are resizable, unless a column says otherwise. */
|
|
116
121
|
resizable?: boolean | undefined;
|
|
122
|
+
/** Whether columns are reorderable, unless a column says otherwise. */
|
|
123
|
+
reorderable?: boolean | undefined;
|
|
117
124
|
}
|
|
118
125
|
/**
|
|
119
126
|
* A column paired with everything it takes to render it. Each field is a
|
|
@@ -138,6 +145,8 @@ interface ResolvedColumn<Row, Node = string> {
|
|
|
138
145
|
label: Node | string;
|
|
139
146
|
/** Whether this column can be resized, after the grid-level default. */
|
|
140
147
|
resizable: boolean;
|
|
148
|
+
/** Whether this column can be dragged, after the grid-level default. */
|
|
149
|
+
reorderable: boolean;
|
|
141
150
|
/** How this column's cells align, after falling back to its type. */
|
|
142
151
|
alignment: ColumnAlignment;
|
|
143
152
|
}
|
|
@@ -161,6 +170,25 @@ interface ColumnResizeEvent {
|
|
|
161
170
|
readonly sizing: ColumnSizingState;
|
|
162
171
|
readonly phase: "move" | "end";
|
|
163
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Column ids in the order they render. It need not list every column: one
|
|
175
|
+
* absent from it keeps its position among the definitions and follows those
|
|
176
|
+
* that are listed.
|
|
177
|
+
*/
|
|
178
|
+
type ColumnOrderState = readonly string[];
|
|
179
|
+
/**
|
|
180
|
+
* Which side of a column a drop lands on, normalised away by
|
|
181
|
+
* `resolveDropBefore` so it reaches no state.
|
|
182
|
+
*/
|
|
183
|
+
type DropSide = "before" | "after";
|
|
184
|
+
/**
|
|
185
|
+
* Reports a user reorder. Unlike a resize there is no `"move"` phase — the
|
|
186
|
+
* order does not change until the drop.
|
|
187
|
+
*/
|
|
188
|
+
interface ColumnOrderEvent {
|
|
189
|
+
readonly columnId: string;
|
|
190
|
+
readonly order: ColumnOrderState;
|
|
191
|
+
}
|
|
164
192
|
|
|
165
193
|
/**
|
|
166
194
|
* How a column of `type` aligns by default. Numeric types align right so that
|
|
@@ -198,6 +226,40 @@ declare function resolveColumnLabel<Row, Node>(column: ColumnDefinition<Row, Nod
|
|
|
198
226
|
*/
|
|
199
227
|
declare function accessDotted(obj: unknown, path: string): unknown;
|
|
200
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Puts `columns` in the order `order` gives. Ids it lists come first, in that
|
|
231
|
+
* order; columns it omits keep their position among the definitions and
|
|
232
|
+
* follow. Ids naming no column are ignored.
|
|
233
|
+
*
|
|
234
|
+
* Tolerating both gaps is what lets a stored order outlive the column list it
|
|
235
|
+
* was made against.
|
|
236
|
+
*/
|
|
237
|
+
declare function applyColumnOrder<Row, Node>(columns: readonly ColumnDefinition<Row, Node>[], order: ColumnOrderState): readonly ColumnDefinition<Row, Node>[];
|
|
238
|
+
/**
|
|
239
|
+
* The order with `movedId` lifted out and put back in front of `beforeId`, or
|
|
240
|
+
* at the end when that is `null`.
|
|
241
|
+
*
|
|
242
|
+
* Returns `orderedIds` itself when the move changes nothing, so callers can
|
|
243
|
+
* treat an unchanged reference as "no move happened".
|
|
244
|
+
*/
|
|
245
|
+
declare function moveColumnBefore(orderedIds: ColumnOrderState, movedId: string, beforeId: string | null): ColumnOrderState;
|
|
246
|
+
/**
|
|
247
|
+
* Whether moving `movedId` in front of `beforeId` would rearrange anything, so
|
|
248
|
+
* that a drop indicator promises exactly the moves that happen.
|
|
249
|
+
*
|
|
250
|
+
* Defined against `moveColumnBefore` rather than restating its conditions, so
|
|
251
|
+
* the two cannot disagree about what a no-op is.
|
|
252
|
+
*/
|
|
253
|
+
declare function movesColumn(orderedIds: ColumnOrderState, movedId: string, beforeId: string | null): boolean;
|
|
254
|
+
/**
|
|
255
|
+
* The id a drop on `side` of `targetId` lands in front of, which is `null`
|
|
256
|
+
* past the last column.
|
|
257
|
+
*
|
|
258
|
+
* "After C" and "before D" name the same gap, so collapsing both to one id
|
|
259
|
+
* keeps a drop target a single nullable string.
|
|
260
|
+
*/
|
|
261
|
+
declare function resolveDropBefore(orderedIds: ColumnOrderState, targetId: string, side: DropSide): string | null;
|
|
262
|
+
|
|
201
263
|
/**
|
|
202
264
|
* Applied to any column that does not size itself. The minimum is a width a
|
|
203
265
|
* header stays legible at rather than a measured value — a column dragged
|
|
@@ -254,4 +316,4 @@ declare function fitColumnsToWidth<Row, Node>(resolved: readonly ResolvedColumn<
|
|
|
254
316
|
*/
|
|
255
317
|
declare function sizeColumnToContent(measuredWidth: number, constraints: ColumnConstraints, padding?: number): number;
|
|
256
318
|
|
|
257
|
-
export { type CellTemplateContext, type ColumnAlignment, type ColumnConstraints, type ColumnDefinition, type ColumnResizeEvent, type ColumnResizeSession, type ColumnResolveOptions, type ColumnSizeDefaults, type ColumnSizingState, type ColumnType, DEFAULT_COLUMN_SIZES, type FieldPath, KEYBOARD_STEP, type ResolvedColumn, accessDotted, alignmentForType, applyColumnResize, beginColumnResize, clampColumnWidth, defineColumnsFromRows, fitColumnsToWidth, getColumnId, resolveColumnConstraints, resolveColumnLabel, resolveColumnWidths, sizeColumnToContent, totalColumnWidth };
|
|
319
|
+
export { type CellTemplateContext, type ColumnAlignment, type ColumnConstraints, type ColumnDefinition, type ColumnOrderEvent, type ColumnOrderState, type ColumnResizeEvent, type ColumnResizeSession, type ColumnResolveOptions, type ColumnSizeDefaults, type ColumnSizingState, type ColumnType, DEFAULT_COLUMN_SIZES, type DropSide, type FieldPath, KEYBOARD_STEP, type ResolvedColumn, accessDotted, alignmentForType, applyColumnOrder, applyColumnResize, beginColumnResize, clampColumnWidth, defineColumnsFromRows, fitColumnsToWidth, getColumnId, moveColumnBefore, movesColumn, resolveColumnConstraints, resolveColumnLabel, resolveColumnWidths, resolveDropBefore, sizeColumnToContent, totalColumnWidth };
|
package/dist/index.js
CHANGED
|
@@ -71,6 +71,43 @@ function accessDotted(obj, path) {
|
|
|
71
71
|
return path.split(".").reduce((value, key) => isNested(value) ? value[key] : void 0, obj);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
// src/util/ordering.ts
|
|
75
|
+
function applyColumnOrder(columns, order) {
|
|
76
|
+
if (order.length === 0) {
|
|
77
|
+
return columns;
|
|
78
|
+
}
|
|
79
|
+
const byId = new Map(columns.map((column) => [getColumnId(column), column]));
|
|
80
|
+
const listed = order.map((id) => byId.get(id)).filter((column) => column !== void 0);
|
|
81
|
+
const taken = new Set(listed.map((column) => getColumnId(column)));
|
|
82
|
+
return [
|
|
83
|
+
...listed,
|
|
84
|
+
...columns.filter((column) => !taken.has(getColumnId(column)))
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
function moveColumnBefore(orderedIds, movedId, beforeId) {
|
|
88
|
+
if (movedId === beforeId || !orderedIds.includes(movedId)) {
|
|
89
|
+
return orderedIds;
|
|
90
|
+
}
|
|
91
|
+
const without = orderedIds.filter((id) => id !== movedId);
|
|
92
|
+
const target = beforeId === null ? without.length : without.indexOf(beforeId);
|
|
93
|
+
if (target === -1) {
|
|
94
|
+
return orderedIds;
|
|
95
|
+
}
|
|
96
|
+
const next = [...without];
|
|
97
|
+
next.splice(target, 0, movedId);
|
|
98
|
+
return next.every((id, index) => id === orderedIds[index]) ? orderedIds : next;
|
|
99
|
+
}
|
|
100
|
+
function movesColumn(orderedIds, movedId, beforeId) {
|
|
101
|
+
return moveColumnBefore(orderedIds, movedId, beforeId) !== orderedIds;
|
|
102
|
+
}
|
|
103
|
+
function resolveDropBefore(orderedIds, targetId, side) {
|
|
104
|
+
if (side === "before") {
|
|
105
|
+
return targetId;
|
|
106
|
+
}
|
|
107
|
+
const index = orderedIds.indexOf(targetId);
|
|
108
|
+
return index === -1 ? null : orderedIds[index + 1] ?? null;
|
|
109
|
+
}
|
|
110
|
+
|
|
74
111
|
// src/util/sizing.ts
|
|
75
112
|
var DEFAULT_COLUMN_SIZES = {
|
|
76
113
|
width: 150,
|
|
@@ -106,6 +143,7 @@ function resolveColumnWidths(columns, sizing, options) {
|
|
|
106
143
|
),
|
|
107
144
|
label: resolveColumnLabel(column),
|
|
108
145
|
resizable: column.resizable ?? options?.resizable ?? false,
|
|
146
|
+
reorderable: column.reorderable ?? options?.reorderable ?? false,
|
|
109
147
|
alignment: column.alignment ?? alignmentForType(column.type ?? "string")
|
|
110
148
|
};
|
|
111
149
|
});
|
|
@@ -180,15 +218,19 @@ export {
|
|
|
180
218
|
KEYBOARD_STEP,
|
|
181
219
|
accessDotted,
|
|
182
220
|
alignmentForType,
|
|
221
|
+
applyColumnOrder,
|
|
183
222
|
applyColumnResize,
|
|
184
223
|
beginColumnResize,
|
|
185
224
|
clampColumnWidth,
|
|
186
225
|
defineColumnsFromRows,
|
|
187
226
|
fitColumnsToWidth,
|
|
188
227
|
getColumnId,
|
|
228
|
+
moveColumnBefore,
|
|
229
|
+
movesColumn,
|
|
189
230
|
resolveColumnConstraints,
|
|
190
231
|
resolveColumnLabel,
|
|
191
232
|
resolveColumnWidths,
|
|
233
|
+
resolveDropBefore,
|
|
192
234
|
sizeColumnToContent,
|
|
193
235
|
totalColumnWidth
|
|
194
236
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/util/grid.ts","../src/util/sizing.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 * 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/**\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 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 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\n/**\n * Grows columns proportionally until they fill `availableWidth`.\n *\n * Growth only: columns that already meet or exceed the width are returned\n * untouched, so a container too narrow for them scrolls rather than crushing\n * them. Columns the user has sized are left at that width and the rest share\n * what is left, so dragging one column does not rubber-band it back.\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 if (resolved.length === 0 || totalColumnWidth(resolved) >= target) {\n return resolved;\n }\n\n const entries = resolved.map((entry) => ({\n entry,\n width: entry.width,\n maxWidth: resolveColumnConstraints(entry.column, defaults).maxWidth,\n growable: !entry.sized,\n }));\n const sum = () => entries.reduce((total, item) => total + item.width, 0);\n\n // Clamping a column at its maximum frees surplus the others have to absorb,\n // so a pass that clamped anything is followed by another.\n for (;;) {\n const growing = entries.filter(\n (item) => item.growable && item.width < item.maxWidth,\n );\n const surplus = target - sum();\n if (surplus <= 0 || growing.length === 0) {\n break;\n }\n\n const base = growing.reduce((total, item) => total + item.width, 0);\n let clamped = false;\n\n for (const item of growing) {\n const share =\n base === 0 ? surplus / growing.length : (surplus * item.width) / base;\n\n if (item.width + share >= item.maxWidth) {\n item.width = item.maxWidth;\n clamped = true;\n } else {\n item.width += share;\n }\n }\n\n if (!clamped) {\n break;\n }\n }\n\n // Fractional widths would leave the table a sub-pixel short of its container\n // and show a scrollbar that never goes away, so floor every column and hand\n // the lost pixels back out one at a time.\n let remainder = target - entries.reduce((t, i) => t + Math.floor(i.width), 0);\n\n return entries.map((item) => {\n let width = Math.floor(item.width);\n if (remainder > 0 && item.growable && width < item.maxWidth) {\n width += 1;\n remainder -= 1;\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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/util/grid.ts","../src/util/ordering.ts","../src/util/sizing.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 * 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/**\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 { 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","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 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\n/**\n * Grows columns proportionally until they fill `availableWidth`.\n *\n * Growth only: columns that already meet or exceed the width are returned\n * untouched, so a container too narrow for them scrolls rather than crushing\n * them. Columns the user has sized are left at that width and the rest share\n * what is left, so dragging one column does not rubber-band it back.\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 if (resolved.length === 0 || totalColumnWidth(resolved) >= target) {\n return resolved;\n }\n\n const entries = resolved.map((entry) => ({\n entry,\n width: entry.width,\n maxWidth: resolveColumnConstraints(entry.column, defaults).maxWidth,\n growable: !entry.sized,\n }));\n const sum = () => entries.reduce((total, item) => total + item.width, 0);\n\n // Clamping a column at its maximum frees surplus the others have to absorb,\n // so a pass that clamped anything is followed by another.\n for (;;) {\n const growing = entries.filter(\n (item) => item.growable && item.width < item.maxWidth,\n );\n const surplus = target - sum();\n if (surplus <= 0 || growing.length === 0) {\n break;\n }\n\n const base = growing.reduce((total, item) => total + item.width, 0);\n let clamped = false;\n\n for (const item of growing) {\n const share =\n base === 0 ? surplus / growing.length : (surplus * item.width) / base;\n\n if (item.width + share >= item.maxWidth) {\n item.width = item.maxWidth;\n clamped = true;\n } else {\n item.width += share;\n }\n }\n\n if (!clamped) {\n break;\n }\n }\n\n // Fractional widths would leave the table a sub-pixel short of its container\n // and show a scrollbar that never goes away, so floor every column and hand\n // the lost pixels back out one at a time.\n let remainder = target - entries.reduce((t, i) => t + Math.floor(i.width), 0);\n\n return entries.map((item) => {\n let width = Math.floor(item.width);\n if (remainder > 0 && item.growable && width < item.maxWidth) {\n width += 1;\n remainder -= 1;\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"],"mappings":"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","names":[]}
|