Skip to content

[WIP] Add support for big-int to number column #1065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 50 additions & 10 deletions packages/core/src/cells/number-cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ const NumberOverlayEditor = React.lazy(
async () => await import("../internal/data-grid-overlay-editor/private/number-overlay-editor.js")
);

function parseToNumberOrBigInt(str: string): number | bigint | undefined {
const trimmed = str.trim();
if (trimmed === "") return undefined;

// Check if it's a plain integer string.
if (/^-?\d+$/.test(trimmed)) {
try {
const big = BigInt(trimmed);
if (big >= BigInt(Number.MIN_SAFE_INTEGER) && big <= BigInt(Number.MAX_SAFE_INTEGER)) {
return Number(big);
}
return big;
} catch {
return undefined;
}
}

// Otherwise, try to parse as a float.
const num = Number.parseFloat(trimmed);
return Number.isNaN(num) ? undefined : num;
}

export const numberCellRenderer: InternalCellRenderer<NumberCell> = {
getAccessibilityString: c => c.data?.toString() ?? "",
kind: GridCellKind.Number,
Expand Down Expand Up @@ -37,28 +59,46 @@ export const numberCellRenderer: InternalCellRenderer<NumberCell> = {
<NumberOverlayEditor
highlight={isHighlighted}
disabled={value.readonly === true}
value={value.data}
value={
typeof value.data === "bigint"
? value.data <= BigInt(Number.MAX_SAFE_INTEGER) &&
value.data >= BigInt(Number.MIN_SAFE_INTEGER)
? Number(value.data)
: undefined
: value.data
}
fixedDecimals={value.fixedDecimals}
allowNegative={value.allowNegative}
thousandSeparator={value.thousandSeparator}
decimalSeparator={value.decimalSeparator}
validatedSelection={validatedSelection}
onChange={x =>
onChange={x => {
const newNumber = parseToNumberOrBigInt(x.value);
onChange({
...value,
data: Number.isNaN(x.floatValue ?? 0) ? 0 : x.floatValue,
})
}
data: newNumber,
});
}}
/>
</React.Suspense>
);
},
onPaste: (toPaste, cell, details) => {
const newNumber =
typeof details.rawValue === "number"
? details.rawValue
: Number.parseFloat(typeof details.rawValue === "string" ? details.rawValue : toPaste);
if (Number.isNaN(newNumber) || cell.data === newNumber) return undefined;
let newNumber: number | bigint | undefined;

if (typeof details.rawValue === "number" || typeof details.rawValue === "bigint") {
newNumber = details.rawValue;
} else {
const strVal = typeof details.rawValue === "string" ? details.rawValue : toPaste;
newNumber = parseToNumberOrBigInt(strVal);
}

if (
newNumber === undefined ||
(typeof newNumber === "number" && Number.isNaN(newNumber)) ||
cell.data === newNumber
)
return undefined;
return { ...cell, data: newNumber, displayData: details.formattedString ?? cell.displayData };
},
};
16 changes: 9 additions & 7 deletions packages/core/src/data-editor/copy-paste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type StringArrayCellBuffer = {

type BasicCellBuffer = {
formatted: string;
rawValue: string | number | boolean | BooleanEmpty | BooleanIndeterminate | undefined;
rawValue: string | number | bigint | boolean | BooleanEmpty | BooleanIndeterminate | undefined;
format: "string" | "number" | "boolean" | "url";
doNotEscape?: boolean;
};
Expand All @@ -40,10 +40,10 @@ function convertCellToBuffer(cell: GridCell): CellBuffer {
cell.data === true
? "TRUE"
: cell.data === false
? "FALSE"
: cell.data === BooleanIndeterminate
? "INDETERMINATE"
: "",
? "FALSE"
: cell.data === BooleanIndeterminate
? "INDETERMINATE"
: "",
rawValue: cell.data,
format: "boolean",
};
Expand Down Expand Up @@ -85,12 +85,14 @@ function convertCellToBuffer(cell: GridCell): CellBuffer {
rawValue: cell.data,
format: "string",
};
case GridCellKind.Number:
case GridCellKind.Number: {
const v = cell.data;
return {
formatted: cell.displayData,
rawValue: cell.data,
rawValue: v,
format: "number",
};
}
case GridCellKind.Loading:
return {
formatted: "#LOADING",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/internal/data-grid/data-grid-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ export interface TextCell extends BaseGridCell {
export interface NumberCell extends BaseGridCell {
readonly kind: GridCellKind.Number;
readonly displayData: string;
readonly data: number | undefined;
readonly data: number | bigint | undefined;
readonly readonly?: boolean;
readonly fixedDecimals?: number;
readonly allowNegative?: boolean;
Expand Down
54 changes: 35 additions & 19 deletions packages/source/src/use-column-sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ function cellToSortData(c: GridCell): string {
}
}

function tryParse(val: string | number): number | string {
if (typeof val === "number") return val;
function tryParse(val: string | number | bigint): number | bigint | string {
if (typeof val === "number" || typeof val === "bigint") return val;
if (val.length > 0) {
const x = Number(val);
if (!isNaN(x)) {
Expand All @@ -37,21 +37,34 @@ function tryParse(val: string | number): number | string {
return val;
}

export function compareSmart(a: string | number, b: string | number): number {
a = tryParse(a);
b = tryParse(b);
if (typeof a === "string" && typeof b === "string") {
return a.localeCompare(b);
} else if (typeof a === "number" && typeof b === "number") {
if (a === b) return 0;
return a > b ? 1 : -1;
} else if (a == b) {
return 0;
export function compareSmart(a: string | number | bigint, b: string | number | bigint): number {
const pa = tryParse(a);
const pb = tryParse(b);

if (typeof pa === "string" && typeof pb === "string") {
return pa.localeCompare(pb);
}
return a > b ? 1 : -1;

const aIsNumeric = typeof pa === "number" || typeof pa === "bigint";
const bIsNumeric = typeof pb === "number" || typeof pb === "bigint";

if (aIsNumeric && !bIsNumeric) return -1;
if (!aIsNumeric && bIsNumeric) return 1;
if (!aIsNumeric && !bIsNumeric) return (pa as string).localeCompare(pb as string);

if (pa == pb) return 0;

// Both are numeric, potentially mixed. Convert to number for comparison.
// This may lose precision on huge BigInts, but it is the only pragmatic
// way to compare floats and bigints, and it avoids crashing.
const numA = Number(pa);
const numB = Number(pb);

if (numA === numB) return 0;
return numA > numB ? 1 : -1;
}

export function compareRaw(a: string | number, b: string | number) {
export function compareRaw(a: string | number | bigint, b: string | number | bigint) {
if (a > b) return 1;
if (a === b) return 0;
return -1;
Expand All @@ -78,11 +91,14 @@ export function useColumnSort(p: Props): Result {
return Array.isArray(sort) ? sort : [sort];
}, [sort]);

const sortCols = React.useMemo(() =>
sorts.map(s => {
const c = p.columns.findIndex(col => s.column === col || (col.id !== undefined && s.column.id === col.id));
return c === -1 ? undefined : c;
}),
const sortCols = React.useMemo(
() =>
sorts.map(s => {
const c = p.columns.findIndex(
col => s.column === col || (col.id !== undefined && s.column.id === col.id)
);
return c === -1 ? undefined : c;
}),
[sorts, p.columns]
);

Expand Down
Loading