@calliopelabs/ui 0.16.0 → 0.18.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.
Files changed (71) hide show
  1. package/README.md +94 -1
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +2 -0
  4. package/dist/primitives/Menubar.d.ts +21 -0
  5. package/dist/primitives/Menubar.js +43 -0
  6. package/dist/provider/messages.d.ts +148 -0
  7. package/dist/provider/messages.js +178 -0
  8. package/dist/shell/RailPanel.js +1 -1
  9. package/dist/workbench/ActivityBar.d.ts +37 -0
  10. package/dist/workbench/ActivityBar.js +57 -0
  11. package/dist/workbench/BottomPanel.d.ts +30 -0
  12. package/dist/workbench/BottomPanel.js +20 -0
  13. package/dist/workbench/CodeEditor.d.ts +48 -0
  14. package/dist/workbench/CodeEditor.js +153 -0
  15. package/dist/workbench/CommandPalette.d.ts +49 -0
  16. package/dist/workbench/CommandPalette.js +114 -0
  17. package/dist/workbench/DataChart.d.ts +45 -0
  18. package/dist/workbench/DataChart.js +146 -0
  19. package/dist/workbench/DataGrid.d.ts +89 -0
  20. package/dist/workbench/DataGrid.js +590 -0
  21. package/dist/workbench/DataProfile.d.ts +17 -0
  22. package/dist/workbench/DataProfile.js +51 -0
  23. package/dist/workbench/EditorTabs.d.ts +62 -0
  24. package/dist/workbench/EditorTabs.js +115 -0
  25. package/dist/workbench/GridCell.d.ts +19 -0
  26. package/dist/workbench/GridCell.js +50 -0
  27. package/dist/workbench/GridDetails.d.ts +31 -0
  28. package/dist/workbench/GridDetails.js +78 -0
  29. package/dist/workbench/MenuBar.d.ts +49 -0
  30. package/dist/workbench/MenuBar.js +25 -0
  31. package/dist/workbench/PaneGroup.d.ts +50 -0
  32. package/dist/workbench/PaneGroup.js +146 -0
  33. package/dist/workbench/PendingChangesBar.d.ts +20 -0
  34. package/dist/workbench/PendingChangesBar.js +19 -0
  35. package/dist/workbench/Shortcuts.d.ts +50 -0
  36. package/dist/workbench/Shortcuts.js +109 -0
  37. package/dist/workbench/SqlEditor.d.ts +21 -0
  38. package/dist/workbench/SqlEditor.js +79 -0
  39. package/dist/workbench/StatusBar.d.ts +28 -0
  40. package/dist/workbench/StatusBar.js +26 -0
  41. package/dist/workbench/TruncationBanner.d.ts +11 -0
  42. package/dist/workbench/TruncationBanner.js +12 -0
  43. package/dist/workbench/WorkbenchShell.d.ts +36 -0
  44. package/dist/workbench/WorkbenchShell.js +20 -0
  45. package/dist/workbench/download.d.ts +11 -0
  46. package/dist/workbench/download.js +28 -0
  47. package/dist/workbench/editor-theme.d.ts +42 -0
  48. package/dist/workbench/editor-theme.js +113 -0
  49. package/dist/workbench/grid-format.d.ts +59 -0
  50. package/dist/workbench/grid-format.js +169 -0
  51. package/dist/workbench/grid-model.d.ts +75 -0
  52. package/dist/workbench/grid-model.js +259 -0
  53. package/dist/workbench/grid-selection.d.ts +69 -0
  54. package/dist/workbench/grid-selection.js +183 -0
  55. package/dist/workbench/grid-stats.d.ts +58 -0
  56. package/dist/workbench/grid-stats.js +185 -0
  57. package/dist/workbench/index.d.ts +28 -0
  58. package/dist/workbench/index.js +31 -0
  59. package/dist/workbench/keys.d.ts +23 -0
  60. package/dist/workbench/keys.js +105 -0
  61. package/dist/workbench/palette.d.ts +17 -0
  62. package/dist/workbench/palette.js +45 -0
  63. package/dist/workbench/pending.d.ts +92 -0
  64. package/dist/workbench/pending.js +207 -0
  65. package/dist/workbench/sql-completion.d.ts +107 -0
  66. package/dist/workbench/sql-completion.js +475 -0
  67. package/dist/workflow/WorkflowRuntimeControls.d.ts +21 -0
  68. package/dist/workflow/WorkflowRuntimeControls.js +54 -0
  69. package/dist/workflow/runtime-controls.d.ts +29 -0
  70. package/dist/workflow/runtime-controls.js +10 -0
  71. package/package.json +13 -2
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The code editor's colours, from the library's tokens: the ground, the
3
+ * text, the accent for the cursor and selection, and the chart series for
4
+ * syntax (a categorical palette that already holds contrast on every
5
+ * ground). Pure apart from `cssColorToHex`, which needs a canvas.
6
+ */
7
+ /** Monaco's theme shape, kept structural so this module needs no Monaco types. */
8
+ export interface EditorThemeData {
9
+ base: "vs" | "vs-dark";
10
+ inherit: boolean;
11
+ rules: {
12
+ token: string;
13
+ foreground?: string;
14
+ fontStyle?: string;
15
+ }[];
16
+ colors: Record<string, string>;
17
+ }
18
+ /** The tokens the theme reads, as `#rrggbb`. */
19
+ export interface EditorPalette {
20
+ background: string;
21
+ foreground: string;
22
+ muted: string;
23
+ border: string;
24
+ popover: string;
25
+ accent: string;
26
+ primary: string;
27
+ ring: string;
28
+ danger: string;
29
+ chart: [string, string, string, string, string];
30
+ }
31
+ /**
32
+ * Any CSS colour (oklch, hex, a named colour) as `#rrggbb`, by painting one
33
+ * pixel. Null where there is no canvas (a server, jsdom) or the value does
34
+ * not parse.
35
+ */
36
+ export declare function cssColorToHex(value: string): string | null;
37
+ /** The palette under `element`, or null when a token cannot be read. */
38
+ export declare function readEditorPalette(element: Element, toHex?: (value: string) => string | null): EditorPalette | null;
39
+ /** Relative luminance of `#rrggbb`, 0 to 1. */
40
+ export declare function luminance(hex: string): number;
41
+ /** Monaco theme data for a palette. Dark or light follows the ground. */
42
+ export declare function editorTheme(p: EditorPalette): EditorThemeData;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The code editor's colours, from the library's tokens: the ground, the
3
+ * text, the accent for the cursor and selection, and the chart series for
4
+ * syntax (a categorical palette that already holds contrast on every
5
+ * ground). Pure apart from `cssColorToHex`, which needs a canvas.
6
+ */
7
+ const TOKEN_NAMES = {
8
+ background: "--background",
9
+ foreground: "--foreground",
10
+ muted: "--muted-foreground",
11
+ border: "--border",
12
+ popover: "--popover",
13
+ accent: "--accent",
14
+ primary: "--primary",
15
+ ring: "--ring",
16
+ danger: "--danger",
17
+ };
18
+ /**
19
+ * Any CSS colour (oklch, hex, a named colour) as `#rrggbb`, by painting one
20
+ * pixel. Null where there is no canvas (a server, jsdom) or the value does
21
+ * not parse.
22
+ */
23
+ export function cssColorToHex(value) {
24
+ if (typeof document === "undefined" || !value.trim())
25
+ return null;
26
+ try {
27
+ const canvas = document.createElement("canvas");
28
+ canvas.width = canvas.height = 1;
29
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
30
+ if (!ctx)
31
+ return null;
32
+ ctx.clearRect(0, 0, 1, 1);
33
+ ctx.fillStyle = "#000000";
34
+ ctx.fillStyle = value.trim();
35
+ ctx.fillRect(0, 0, 1, 1);
36
+ const [r = 0, g = 0, b = 0, a = 0] = ctx.getImageData(0, 0, 1, 1).data;
37
+ if (a === 0)
38
+ return null;
39
+ return `#${[r, g, b].map((n) => n.toString(16).padStart(2, "0")).join("")}`;
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ /** The palette under `element`, or null when a token cannot be read. */
46
+ export function readEditorPalette(element, toHex = cssColorToHex) {
47
+ const style = getComputedStyle(element);
48
+ const read = (name) => toHex(style.getPropertyValue(name));
49
+ const out = {};
50
+ for (const [key, name] of Object.entries(TOKEN_NAMES)) {
51
+ const hex = read(name);
52
+ if (!hex)
53
+ return null;
54
+ out[key] = hex;
55
+ }
56
+ const chart = [1, 2, 3, 4, 5].map((n) => read(`--chart-${n}`) ?? out.foreground);
57
+ return { ...out, chart: chart };
58
+ }
59
+ /** Relative luminance of `#rrggbb`, 0 to 1. */
60
+ export function luminance(hex) {
61
+ const channel = (i) => {
62
+ const c = parseInt(hex.slice(i, i + 2), 16) / 255;
63
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
64
+ };
65
+ return 0.2126 * channel(1) + 0.7152 * channel(3) + 0.0722 * channel(5);
66
+ }
67
+ const bare = (hex) => hex.slice(1);
68
+ /** Monaco theme data for a palette. Dark or light follows the ground. */
69
+ export function editorTheme(p) {
70
+ const dark = luminance(p.background) < 0.4;
71
+ const [keyword, string, number, fn, type] = p.chart;
72
+ return {
73
+ base: dark ? "vs-dark" : "vs",
74
+ inherit: true,
75
+ rules: [
76
+ { token: "", foreground: bare(p.foreground) },
77
+ { token: "keyword", foreground: bare(keyword) },
78
+ { token: "operator", foreground: bare(keyword) },
79
+ { token: "string", foreground: bare(string) },
80
+ { token: "number", foreground: bare(number) },
81
+ { token: "predefined", foreground: bare(fn) },
82
+ { token: "type", foreground: bare(type) },
83
+ { token: "comment", foreground: bare(p.muted), fontStyle: "italic" },
84
+ { token: "delimiter", foreground: bare(p.muted) },
85
+ { token: "invalid", foreground: bare(p.danger) },
86
+ ],
87
+ colors: {
88
+ "editor.background": p.background,
89
+ "editor.foreground": p.foreground,
90
+ "editorLineNumber.foreground": p.muted,
91
+ "editorLineNumber.activeForeground": p.foreground,
92
+ "editorCursor.foreground": p.primary,
93
+ "editor.selectionBackground": `${p.primary}40`,
94
+ "editor.inactiveSelectionBackground": `${p.primary}26`,
95
+ "editor.lineHighlightBackground": `${p.foreground}0a`,
96
+ "editor.lineHighlightBorder": `${p.foreground}00`,
97
+ "editorIndentGuide.background1": p.border,
98
+ "editorWhitespace.foreground": p.border,
99
+ "editorWidget.background": p.popover,
100
+ "editorWidget.border": p.border,
101
+ "editorSuggestWidget.background": p.popover,
102
+ "editorSuggestWidget.border": p.border,
103
+ "editorSuggestWidget.foreground": p.foreground,
104
+ "editorSuggestWidget.selectedBackground": p.accent,
105
+ "editorHoverWidget.background": p.popover,
106
+ "editorHoverWidget.border": p.border,
107
+ "editorError.foreground": p.danger,
108
+ focusBorder: p.ring,
109
+ "scrollbarSlider.background": `${p.muted}33`,
110
+ "scrollbarSlider.hoverBackground": `${p.muted}55`,
111
+ },
112
+ };
113
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Every way the grid turns cells into text, shared by the clipboard and the
3
+ * export menu so a "Copy as CSV" and an exported .csv cannot quote
4
+ * differently. Pure: the grid hands the text to the clipboard or a Blob.
5
+ */
6
+ import { type GridRow } from "./grid-model.js";
7
+ import { type SelectionState } from "./grid-selection.js";
8
+ /** A rectangle of cells with its column names. */
9
+ export interface CellMatrix {
10
+ headers: string[];
11
+ rows: unknown[][];
12
+ }
13
+ /** Tab-separated, as a spreadsheet pastes it; tabs and newlines inside a cell become spaces. */
14
+ export declare function toTSV(matrix: CellMatrix, withHeaders?: boolean): string;
15
+ /** RFC 4180 CSV; NULL is an empty field. */
16
+ export declare function toCSV(matrix: CellMatrix, withHeaders?: boolean): string;
17
+ /** Rows as objects keyed by column; NULL stays null. */
18
+ export declare function toObjects(matrix: CellMatrix): Record<string, unknown>[];
19
+ export declare function toJSON(matrix: CellMatrix): string;
20
+ export declare function toJSONL(matrix: CellMatrix): string;
21
+ /** A Markdown table; pipes are escaped and newlines flattened. */
22
+ export declare function toMarkdown(matrix: CellMatrix): string;
23
+ /** A SQL literal for a cell. Binary is its base64 text; a non-finite number is NULL. */
24
+ export declare function sqlLiteral(value: unknown): string;
25
+ /** A quoted identifier; a qualified name ("public.users") keeps its parts. */
26
+ export declare function quoteIdentifier(name: string): string;
27
+ /**
28
+ * One INSERT per row. `table_name` stands in when the result has no table,
29
+ * deliberately obvious so nobody runs it unedited.
30
+ */
31
+ export declare function toInsert(matrix: CellMatrix, tableName?: string): string;
32
+ /** Rows as a matrix over `columns`. */
33
+ export declare function rowsMatrix(columns: readonly string[], rows: readonly GridRow[]): CellMatrix;
34
+ /**
35
+ * The selection as a matrix: the bounding box of everything selected, with
36
+ * unselected cells inside it as NULL (a clipboard payload is rectangular).
37
+ * `getValue` takes view coordinates.
38
+ */
39
+ export declare function selectionMatrix(state: SelectionState, columns: readonly string[], getValue: (row: number, col: number) => unknown): CellMatrix;
40
+ /** The text formats the grid copies as. "tsv-headers" is Copy with headers. */
41
+ export type CopyFormat = "tsv" | "tsv-headers" | "csv" | "json" | "insert" | "markdown";
42
+ export declare function formatMatrix(format: CopyFormat, matrix: CellMatrix, options?: {
43
+ tableName?: string;
44
+ }): string;
45
+ /** The file formats the library writes itself. Anything heavier (xlsx) is the host's. */
46
+ export type ExportFormat = "csv" | "tsv" | "json" | "jsonl" | "sql" | "markdown";
47
+ export declare const EXPORT_FORMATS: readonly ExportFormat[];
48
+ /** An export, ready to save: text, a name and a type. `exportBlob` makes the Blob. */
49
+ export interface ExportFile {
50
+ format: ExportFormat;
51
+ filename: string;
52
+ mimeType: string;
53
+ text: string;
54
+ }
55
+ export declare function exportMatrix(format: ExportFormat, matrix: CellMatrix, options?: {
56
+ tableName?: string;
57
+ baseName?: string;
58
+ }): ExportFile;
59
+ export declare function exportBlob(file: ExportFile): Blob;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Every way the grid turns cells into text, shared by the clipboard and the
3
+ * export menu so a "Copy as CSV" and an exported .csv cannot quote
4
+ * differently. Pure: the grid hands the text to the clipboard or a Blob.
5
+ */
6
+ import { asBinary, cellText } from "./grid-model.js";
7
+ import { isSelected, selectionBounds } from "./grid-selection.js";
8
+ function tsvField(value) {
9
+ return cellText(value).replace(/\t/g, " ").replace(/\r?\n/g, " ");
10
+ }
11
+ /** Tab-separated, as a spreadsheet pastes it; tabs and newlines inside a cell become spaces. */
12
+ export function toTSV(matrix, withHeaders = false) {
13
+ const lines = matrix.rows.map((row) => row.map(tsvField).join("\t"));
14
+ if (withHeaders)
15
+ lines.unshift(matrix.headers.map(tsvField).join("\t"));
16
+ return lines.join("\n");
17
+ }
18
+ function csvField(value) {
19
+ const text = cellText(value);
20
+ if (/[",\r\n]/.test(text))
21
+ return `"${text.replace(/"/g, '""')}"`;
22
+ return text;
23
+ }
24
+ /** RFC 4180 CSV; NULL is an empty field. */
25
+ export function toCSV(matrix, withHeaders = true) {
26
+ const lines = matrix.rows.map((row) => row.map(csvField).join(","));
27
+ if (withHeaders)
28
+ lines.unshift(matrix.headers.map(csvField).join(","));
29
+ return lines.join("\n");
30
+ }
31
+ /** Rows as objects keyed by column; NULL stays null. */
32
+ export function toObjects(matrix) {
33
+ return matrix.rows.map((row) => {
34
+ const out = {};
35
+ matrix.headers.forEach((header, i) => {
36
+ out[header] = row[i] === undefined ? null : row[i];
37
+ });
38
+ return out;
39
+ });
40
+ }
41
+ export function toJSON(matrix) {
42
+ return JSON.stringify(toObjects(matrix), null, 2);
43
+ }
44
+ export function toJSONL(matrix) {
45
+ return toObjects(matrix)
46
+ .map((row) => JSON.stringify(row))
47
+ .join("\n");
48
+ }
49
+ /** A Markdown table; pipes are escaped and newlines flattened. */
50
+ export function toMarkdown(matrix) {
51
+ const cell = (v) => cellText(v).replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
52
+ const header = `| ${matrix.headers.map(cell).join(" | ")} |`;
53
+ const rule = `| ${matrix.headers.map(() => "---").join(" | ")} |`;
54
+ const body = matrix.rows.map((row) => `| ${row.map(cell).join(" | ")} |`);
55
+ return [header, rule, ...body].join("\n");
56
+ }
57
+ /** A SQL literal for a cell. Binary is its base64 text; a non-finite number is NULL. */
58
+ export function sqlLiteral(value) {
59
+ if (value === null || value === undefined)
60
+ return "NULL";
61
+ if (typeof value === "number")
62
+ return Number.isFinite(value) ? String(value) : "NULL";
63
+ if (typeof value === "boolean")
64
+ return value ? "TRUE" : "FALSE";
65
+ const binary = asBinary(value);
66
+ if (binary)
67
+ return `'${binary.base64}'`;
68
+ const text = typeof value === "object" ? JSON.stringify(value) : String(value);
69
+ return `'${text.replace(/'/g, "''")}'`;
70
+ }
71
+ /** A quoted identifier; a qualified name ("public.users") keeps its parts. */
72
+ export function quoteIdentifier(name) {
73
+ return name
74
+ .split(".")
75
+ .map((part) => `"${part.replace(/"/g, '""')}"`)
76
+ .join(".");
77
+ }
78
+ /**
79
+ * One INSERT per row. `table_name` stands in when the result has no table,
80
+ * deliberately obvious so nobody runs it unedited.
81
+ */
82
+ export function toInsert(matrix, tableName = "table_name") {
83
+ if (matrix.rows.length === 0)
84
+ return "";
85
+ const table = quoteIdentifier(tableName);
86
+ const cols = matrix.headers.map(quoteIdentifier).join(", ");
87
+ return matrix.rows
88
+ .map((row) => {
89
+ const values = matrix.headers.map((_, i) => sqlLiteral(row[i])).join(", ");
90
+ return `INSERT INTO ${table} (${cols}) VALUES (${values});`;
91
+ })
92
+ .join("\n");
93
+ }
94
+ /** Rows as a matrix over `columns`. */
95
+ export function rowsMatrix(columns, rows) {
96
+ return { headers: [...columns], rows: rows.map((row) => columns.map((c) => row[c])) };
97
+ }
98
+ /**
99
+ * The selection as a matrix: the bounding box of everything selected, with
100
+ * unselected cells inside it as NULL (a clipboard payload is rectangular).
101
+ * `getValue` takes view coordinates.
102
+ */
103
+ export function selectionMatrix(state, columns, getValue) {
104
+ const bounds = selectionBounds(state);
105
+ if (!bounds)
106
+ return { headers: [], rows: [] };
107
+ const headers = [];
108
+ for (let c = bounds.minCol; c <= bounds.maxCol; c++)
109
+ headers.push(columns[c] ?? `col_${c}`);
110
+ const rows = [];
111
+ for (let r = bounds.minRow; r <= bounds.maxRow; r++) {
112
+ const row = [];
113
+ for (let c = bounds.minCol; c <= bounds.maxCol; c++) {
114
+ row.push(isSelected(state, r, c) ? getValue(r, c) : null);
115
+ }
116
+ rows.push(row);
117
+ }
118
+ return { headers, rows };
119
+ }
120
+ export function formatMatrix(format, matrix, options = {}) {
121
+ switch (format) {
122
+ case "tsv":
123
+ return toTSV(matrix);
124
+ case "tsv-headers":
125
+ return toTSV(matrix, true);
126
+ case "csv":
127
+ return toCSV(matrix);
128
+ case "json":
129
+ return toJSON(matrix);
130
+ case "insert":
131
+ return toInsert(matrix, options.tableName);
132
+ case "markdown":
133
+ return toMarkdown(matrix);
134
+ }
135
+ }
136
+ export const EXPORT_FORMATS = [
137
+ "csv",
138
+ "tsv",
139
+ "json",
140
+ "jsonl",
141
+ "sql",
142
+ "markdown",
143
+ ];
144
+ const FILE = {
145
+ csv: { extension: "csv", mimeType: "text/csv" },
146
+ tsv: { extension: "tsv", mimeType: "text/tab-separated-values" },
147
+ json: { extension: "json", mimeType: "application/json" },
148
+ jsonl: { extension: "jsonl", mimeType: "application/x-ndjson" },
149
+ sql: { extension: "sql", mimeType: "application/sql" },
150
+ markdown: { extension: "md", mimeType: "text/markdown" },
151
+ };
152
+ export function exportMatrix(format, matrix, options = {}) {
153
+ const text = format === "csv"
154
+ ? toCSV(matrix)
155
+ : format === "tsv"
156
+ ? toTSV(matrix, true)
157
+ : format === "json"
158
+ ? toJSON(matrix)
159
+ : format === "jsonl"
160
+ ? toJSONL(matrix)
161
+ : format === "sql"
162
+ ? toInsert(matrix, options.tableName)
163
+ : toMarkdown(matrix);
164
+ const { extension, mimeType } = FILE[format];
165
+ return { format, filename: `${options.baseName ?? "export"}.${extension}`, mimeType, text };
166
+ }
167
+ export function exportBlob(file) {
168
+ return new Blob([file.text], { type: file.mimeType });
169
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The data grid's model, as pure data: what a column is, how a value reads as
3
+ * text, how rows sort (NULLs last) and filter. No React, no DOM, so a Server
4
+ * Component or a worker can import it. Extracted from Loadr's grid (shared
5
+ * with Chat Studio).
6
+ */
7
+ /** A row of a result: column name to value. */
8
+ export type GridRow = Readonly<Record<string, unknown>>;
9
+ /**
10
+ * What a column is, in the grid's own vocabulary. `normalizeColumnType`
11
+ * takes any driver's spelling ("timestamptz", "Nullable(Int64)",
12
+ * "datetime64[ns, UTC]") and lands on one of these.
13
+ */
14
+ export type ColumnType = "integer" | "number" | "text" | "boolean" | "datetime" | "date" | "time" | "json" | "binary" | "uuid" | "other";
15
+ export declare const COLUMN_TYPES: readonly ColumnType[];
16
+ /** A column as the host describes it. Only `name` is required. */
17
+ export interface GridColumn {
18
+ name: string;
19
+ /** Any spelling: a normalized type or the driver's ("int4", "varchar(255)"). Sniffed from the rows when absent. */
20
+ type?: string;
21
+ /** The driver's spelling, shown in the header's title and the row detail. */
22
+ dataType?: string;
23
+ nullable?: boolean;
24
+ /** Primary key columns identify a row for an update or a delete. */
25
+ primaryKey?: boolean;
26
+ foreignKey?: boolean;
27
+ /** "schema.table.column" for a foreign key. */
28
+ references?: string;
29
+ }
30
+ /** Everything the grid knows about one column, resolved. */
31
+ export interface GridColumnMeta {
32
+ name: string;
33
+ type: ColumnType;
34
+ dataType?: string;
35
+ nullable?: boolean;
36
+ primaryKey: boolean;
37
+ foreignKey: boolean;
38
+ references?: string;
39
+ }
40
+ /** Types whose values are right-aligned and get numeric stats. */
41
+ export declare function isNumericType(type: ColumnType): boolean;
42
+ /** Any spelling of a column type onto the vocabulary; unknown spellings are "other". */
43
+ export declare function normalizeColumnType(raw: string | null | undefined): ColumnType;
44
+ /** A guess at a column's type from its values, for a result that declares none. */
45
+ export declare function sniffColumnType(values: readonly unknown[]): ColumnType;
46
+ /** Columns as the host gave them (names or descriptions), resolved; undeclared types are sniffed. */
47
+ export declare function buildColumnMeta(columns: readonly (string | GridColumn)[], rows?: readonly GridRow[]): GridColumnMeta[];
48
+ /** A fingerprint of a result's shape: a grid keyed on it starts clean for different columns. */
49
+ export declare function columnSignature(columns: readonly (string | GridColumn)[]): string;
50
+ /** The envelope Loadr's API wraps bytes in. */
51
+ export interface BinaryCell {
52
+ __binary__: true;
53
+ base64: string;
54
+ size: number;
55
+ truncated?: boolean;
56
+ }
57
+ export declare function asBinary(value: unknown): BinaryCell | null;
58
+ /**
59
+ * How a value reads in a text format. NULL is an empty field, not the word,
60
+ * so a pasted column lands in a spreadsheet empty.
61
+ */
62
+ export declare function cellText(value: unknown): string;
63
+ export type SortDirection = "asc" | "desc";
64
+ export interface GridSort {
65
+ column: string;
66
+ direction: SortDirection;
67
+ }
68
+ /** Compares two cells in a direction; NULLs sort last in both. */
69
+ export declare function compareCells(a: unknown, b: unknown, direction?: SortDirection): number;
70
+ /**
71
+ * The source indexes of the rows in view, in view order: those with a cell
72
+ * in `columns` containing `filter` (case-insensitive), sorted by `sort`
73
+ * (stable, NULLs last).
74
+ */
75
+ export declare function viewRowIndexes(rows: readonly GridRow[], columns: readonly string[], filter: string, sort: GridSort | null): number[];