@updog/data-editor 0.1.4 → 0.1.6
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/README.md +281 -107
- package/assets/chatTransform.worker-xnO1PFUC.js +1 -0
- package/index.d.ts +412 -145
- package/index.js +2402 -2325
- package/package.json +1 -1
- package/assets/chatTransform.worker-BuuMWuTX.js +0 -1
package/index.d.ts
CHANGED
|
@@ -818,11 +818,40 @@ declare class ServerEditBuilder<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
818
818
|
private viewContext;
|
|
819
819
|
}
|
|
820
820
|
|
|
821
|
+
/**
|
|
822
|
+
* Categories of internal errors surfaced through the `onError` callback.
|
|
823
|
+
*
|
|
824
|
+
* - `PARSE_ERROR` — file parsing failed (corrupt CSV, invalid XLSX, etc.).
|
|
825
|
+
* - `RENDER_ERROR` — component render failed (caught by error boundary).
|
|
826
|
+
* - `TRANSFORM_ERROR` — data transformation failed (column transform, value mapping).
|
|
827
|
+
* - `VALIDATION_ERROR` — validation execution failed (validator threw instead of returning).
|
|
828
|
+
* - `WORKER_ERROR` — Web Worker failed (filter worker, chat transform worker).
|
|
829
|
+
* - `COMMAND_ERROR` — undo/redo command failed.
|
|
830
|
+
* - `OPERATION_ERROR` — general operation failed (bulk mutations, imports).
|
|
831
|
+
*/
|
|
821
832
|
type UpdogErrorCode = "PARSE_ERROR" | "RENDER_ERROR" | "TRANSFORM_ERROR" | "VALIDATION_ERROR" | "WORKER_ERROR" | "COMMAND_ERROR" | "OPERATION_ERROR";
|
|
833
|
+
/**
|
|
834
|
+
* An internal error caught by the SDK and passed to `onError`. The SDK
|
|
835
|
+
* recovers gracefully where possible — `onError` is for your logging and
|
|
836
|
+
* monitoring (Sentry, Datadog, etc.).
|
|
837
|
+
*
|
|
838
|
+
* @example
|
|
839
|
+
* ```ts
|
|
840
|
+
* onError={(error) => {
|
|
841
|
+
* Sentry.captureException(error.originalError ?? error, {
|
|
842
|
+
* tags: { code: error.code, source: error.source },
|
|
843
|
+
* });
|
|
844
|
+
* }}
|
|
845
|
+
* ```
|
|
846
|
+
*/
|
|
822
847
|
type UpdogError = {
|
|
848
|
+
/** The error category. */
|
|
823
849
|
code: UpdogErrorCode;
|
|
850
|
+
/** Human-readable description. */
|
|
824
851
|
message: string;
|
|
852
|
+
/** Module or subsystem that raised the error. */
|
|
825
853
|
source: string;
|
|
854
|
+
/** The underlying thrown value, when available. */
|
|
826
855
|
originalError?: unknown;
|
|
827
856
|
};
|
|
828
857
|
|
|
@@ -1350,6 +1379,189 @@ type PasteSpec = {
|
|
|
1350
1379
|
isCut: boolean;
|
|
1351
1380
|
};
|
|
1352
1381
|
|
|
1382
|
+
/**
|
|
1383
|
+
* Base row shape. Each key is a column ID, each value is the cell data.
|
|
1384
|
+
* Extend this with your own type via the `<DataEditor<TRow>>` generic for
|
|
1385
|
+
* type-safe column access. When the generic is omitted, rows are typed as
|
|
1386
|
+
* `Record<string, unknown>`.
|
|
1387
|
+
*
|
|
1388
|
+
* @example
|
|
1389
|
+
* ```ts
|
|
1390
|
+
* type Employee = { id: string; name: string; email: string };
|
|
1391
|
+
* <DataEditor<Employee> columns={...} primaryKey="id" />
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
type DataEditorRow = Record<string, unknown>;
|
|
1395
|
+
/** Sort direction. */
|
|
1396
|
+
type SortDirection = "asc" | "desc";
|
|
1397
|
+
/** Current sort state. `null` means no active sort. */
|
|
1398
|
+
type SortState = {
|
|
1399
|
+
columnId: string;
|
|
1400
|
+
direction: SortDirection;
|
|
1401
|
+
} | null;
|
|
1402
|
+
type Filters = {
|
|
1403
|
+
search: string;
|
|
1404
|
+
matchCase: boolean;
|
|
1405
|
+
matchEntireCell: boolean;
|
|
1406
|
+
errorMessageFilters: string[];
|
|
1407
|
+
showOnlyNewRows: boolean;
|
|
1408
|
+
showOnlyEditedRows: boolean;
|
|
1409
|
+
showOnlyEmptyCells: boolean;
|
|
1410
|
+
/** When true, show only rows flagged for deletion (bin mode). All other filters are bypassed. */
|
|
1411
|
+
showOnlyDeletedRows: boolean;
|
|
1412
|
+
filterColumns: string[] | null;
|
|
1413
|
+
/** Per-column value filters. Key = column ID, value = allowed display-formatted strings. */
|
|
1414
|
+
columnValueFilters: Record<string, string[]>;
|
|
1415
|
+
/** Per-column numeric range filters. Key = column ID. */
|
|
1416
|
+
columnRangeFilters: Record<string, {
|
|
1417
|
+
min?: number;
|
|
1418
|
+
max?: number;
|
|
1419
|
+
}>;
|
|
1420
|
+
/** Per-column date range filters. Key = column ID, values are ISO date strings (YYYY-MM-DD). */
|
|
1421
|
+
columnDateRangeFilters: Record<string, {
|
|
1422
|
+
min?: string;
|
|
1423
|
+
max?: string;
|
|
1424
|
+
}>;
|
|
1425
|
+
};
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* A single operation the LLM wants to apply to rows in the current filtered view.
|
|
1429
|
+
*
|
|
1430
|
+
* - `edit` — `fn` is `(r, ctx) => void`. Mutates `r` in place. Changed fields
|
|
1431
|
+
* become column deltas. Rows with no changes are no-ops.
|
|
1432
|
+
* - `delete` — `fn` is `(r, ctx) => boolean`. Truthy means "flag this row for
|
|
1433
|
+
* deletion". Soft delete via `DeleteRowCommand`.
|
|
1434
|
+
*/
|
|
1435
|
+
type ChatOp = {
|
|
1436
|
+
action: "edit";
|
|
1437
|
+
fn: string;
|
|
1438
|
+
} | {
|
|
1439
|
+
action: "delete";
|
|
1440
|
+
fn: string;
|
|
1441
|
+
};
|
|
1442
|
+
/**
|
|
1443
|
+
* A single chunk in the stream returned from `DataEditorChat.onMessage`.
|
|
1444
|
+
*
|
|
1445
|
+
* - `status` — progress message shown while processing (e.g. "Analyzing 500 rows...").
|
|
1446
|
+
* - `message` — chat reply shown to the user.
|
|
1447
|
+
* - `rows` — updated rows to apply to the grid. Matched by `primaryKey`.
|
|
1448
|
+
* - `ops` — array of per-row operations (edits and/or deletes) to apply in order.
|
|
1449
|
+
*/
|
|
1450
|
+
type ChatResponseChunk<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1451
|
+
type: "status";
|
|
1452
|
+
content: string;
|
|
1453
|
+
} | {
|
|
1454
|
+
type: "message";
|
|
1455
|
+
content: string;
|
|
1456
|
+
} | {
|
|
1457
|
+
type: "rows";
|
|
1458
|
+
content: TRow[];
|
|
1459
|
+
} | {
|
|
1460
|
+
type: "ops";
|
|
1461
|
+
content: ChatOp[];
|
|
1462
|
+
};
|
|
1463
|
+
/** Status of a row in the chat sample, relative to its origin snapshot. */
|
|
1464
|
+
type ChatRowStatus = "new" | "edited" | "original";
|
|
1465
|
+
/** A sample row handed to the chat callback, with its current status and validation errors. */
|
|
1466
|
+
type ChatRow<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1467
|
+
/** Row data keyed by column ID. */
|
|
1468
|
+
data: TRow;
|
|
1469
|
+
/** Whether the row was newly added, edited, or is unchanged. */
|
|
1470
|
+
status: ChatRowStatus;
|
|
1471
|
+
/** Validation errors keyed by column ID. */
|
|
1472
|
+
errors: Record<string, string[]>;
|
|
1473
|
+
/** The source this row belongs to. */
|
|
1474
|
+
source: string;
|
|
1475
|
+
};
|
|
1476
|
+
/** Aggregated error count across the current view, grouped by field and message. */
|
|
1477
|
+
type ChatErrorSummary = {
|
|
1478
|
+
/** Column ID where the error occurred. */
|
|
1479
|
+
field: string;
|
|
1480
|
+
/** The validation message. */
|
|
1481
|
+
message: string;
|
|
1482
|
+
/** How many rows hit this error. */
|
|
1483
|
+
count: number;
|
|
1484
|
+
/** A few example values that triggered the error. */
|
|
1485
|
+
examples: string[];
|
|
1486
|
+
};
|
|
1487
|
+
/**
|
|
1488
|
+
* Context about the current dataset, passed to `loadSuggestions` and extended
|
|
1489
|
+
* into `ChatContext` for `onMessage`.
|
|
1490
|
+
*/
|
|
1491
|
+
type ChatDataContext<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1492
|
+
/** Full column definitions. */
|
|
1493
|
+
columns: DataEditorColumn[];
|
|
1494
|
+
/** Row identifier field. */
|
|
1495
|
+
primaryKey: keyof TRow;
|
|
1496
|
+
/** Total rows in the dataset. */
|
|
1497
|
+
totalRowCount: number;
|
|
1498
|
+
/** Rows in the current filtered view. */
|
|
1499
|
+
filteredRowCount: number;
|
|
1500
|
+
/** Sample rows, with status and errors. Size controlled by `sampleSize`. */
|
|
1501
|
+
sample: ChatRow<TRow>[];
|
|
1502
|
+
/** Aggregated error counts by field and message. */
|
|
1503
|
+
errorSummary: ChatErrorSummary[];
|
|
1504
|
+
/** Access all rows. Use for full-dataset operations. */
|
|
1505
|
+
getRows: () => ChatRow<TRow>[];
|
|
1506
|
+
};
|
|
1507
|
+
/**
|
|
1508
|
+
* The full context passed to `DataEditorChat.onMessage` when the user sends
|
|
1509
|
+
* a prompt. Includes the prompt itself and all dataset context.
|
|
1510
|
+
*/
|
|
1511
|
+
type ChatContext<TRow extends DataEditorRow = DataEditorRow> = ChatDataContext<TRow> & {
|
|
1512
|
+
/** The user's chat prompt. */
|
|
1513
|
+
message: string;
|
|
1514
|
+
};
|
|
1515
|
+
/**
|
|
1516
|
+
* Bring-your-own-AI chat configuration. When provided via the `chat` prop,
|
|
1517
|
+
* the editor shows a chat panel alongside the grid. You own the AI
|
|
1518
|
+
* integration; the SDK hands you dataset context and renders the streamed
|
|
1519
|
+
* response.
|
|
1520
|
+
*
|
|
1521
|
+
* @example
|
|
1522
|
+
* ```ts
|
|
1523
|
+
* chat={{
|
|
1524
|
+
* sampleSize: 50,
|
|
1525
|
+
* onMessage: async function* (context) {
|
|
1526
|
+
* yield { type: "status", content: "Thinking..." };
|
|
1527
|
+
* const res = await fetch("/api/ai", {
|
|
1528
|
+
* method: "POST",
|
|
1529
|
+
* body: JSON.stringify({
|
|
1530
|
+
* prompt: context.message,
|
|
1531
|
+
* columns: context.columns,
|
|
1532
|
+
* sample: context.sample.map(r => r.data),
|
|
1533
|
+
* errors: context.errorSummary,
|
|
1534
|
+
* }),
|
|
1535
|
+
* }).then(r => r.json());
|
|
1536
|
+
* yield { type: "rows", content: res.updatedRows };
|
|
1537
|
+
* yield { type: "ops", content: res.ops };
|
|
1538
|
+
* yield { type: "message", content: res.reply };
|
|
1539
|
+
* },
|
|
1540
|
+
* }}
|
|
1541
|
+
* ```
|
|
1542
|
+
*/
|
|
1543
|
+
type DataEditorChat<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1544
|
+
/**
|
|
1545
|
+
* How many rows to include in the context sample. The SDK picks a
|
|
1546
|
+
* representative slice including rows with errors. When omitted, the SDK decides.
|
|
1547
|
+
*/
|
|
1548
|
+
sampleSize?: number;
|
|
1549
|
+
/** Title shown above the suggestion list when the chat is empty. */
|
|
1550
|
+
emptyTitle?: string;
|
|
1551
|
+
/** How many suggestions to request from `loadSuggestions`. */
|
|
1552
|
+
suggestionsCount?: number;
|
|
1553
|
+
/** Optional prompt generator for the empty-state suggestion chips. */
|
|
1554
|
+
loadSuggestions?: (context: ChatDataContext<TRow>) => Promise<string[]>;
|
|
1555
|
+
/**
|
|
1556
|
+
* Called when the user sends a message. Receives full dataset context.
|
|
1557
|
+
* Returns an async iterable of response chunks — the SDK streams them
|
|
1558
|
+
* into the UI.
|
|
1559
|
+
*/
|
|
1560
|
+
onMessage: (context: ChatContext<TRow>) => AsyncIterable<ChatResponseChunk<TRow>>;
|
|
1561
|
+
/** Called when the user cancels a pending request. Use to abort your API call. */
|
|
1562
|
+
onCancel?: () => void;
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1353
1565
|
type ApplyFormulaOptions = {
|
|
1354
1566
|
/**
|
|
1355
1567
|
* Column IDs to delete AFTER the formula has been applied.
|
|
@@ -1654,12 +1866,14 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
1654
1866
|
private syncFormulaToServer;
|
|
1655
1867
|
private transformWorker;
|
|
1656
1868
|
private initTransformWorker;
|
|
1657
|
-
private
|
|
1658
|
-
|
|
1869
|
+
private buildChatOpsCommand;
|
|
1870
|
+
applyChatOps(ops: ChatOp[], ctx: {
|
|
1659
1871
|
opts: Record<string, Set<string>>;
|
|
1660
|
-
}): Promise<void>;
|
|
1661
|
-
private
|
|
1662
|
-
private
|
|
1872
|
+
}, enableDeleteRow: 'all' | 'new' | false): Promise<void>;
|
|
1873
|
+
private filterDeleteIdsByPolicy;
|
|
1874
|
+
private _applyChatOpsViaWorker;
|
|
1875
|
+
private _applyChatOpsSync;
|
|
1876
|
+
private _commitChatOps;
|
|
1663
1877
|
applyChatRows(incomingRows: Record<string, unknown>[], primaryKey: string): Promise<void>;
|
|
1664
1878
|
private syncChatTransformToServer;
|
|
1665
1879
|
private get revertRowReader();
|
|
@@ -1743,94 +1957,6 @@ type ColumnDelta = {
|
|
|
1743
1957
|
newValues: Map<TRowId, unknown>;
|
|
1744
1958
|
};
|
|
1745
1959
|
|
|
1746
|
-
/**
|
|
1747
|
-
* Base row shape. Each key is a column ID, each value is the cell data.
|
|
1748
|
-
* Extend this with your own type for type-safe column access.
|
|
1749
|
-
*
|
|
1750
|
-
* @example
|
|
1751
|
-
* ```ts
|
|
1752
|
-
* type Employee = { id: string; name: string; email: string };
|
|
1753
|
-
* <DataEditor<Employee> columns={...} primaryKey="id" />
|
|
1754
|
-
* ```
|
|
1755
|
-
*/
|
|
1756
|
-
type DataEditorRow = Record<string, unknown>;
|
|
1757
|
-
type SortDirection = "asc" | "desc";
|
|
1758
|
-
type SortState = {
|
|
1759
|
-
columnId: string;
|
|
1760
|
-
direction: SortDirection;
|
|
1761
|
-
} | null;
|
|
1762
|
-
type Filters = {
|
|
1763
|
-
search: string;
|
|
1764
|
-
matchCase: boolean;
|
|
1765
|
-
matchEntireCell: boolean;
|
|
1766
|
-
errorMessageFilters: string[];
|
|
1767
|
-
showOnlyNewRows: boolean;
|
|
1768
|
-
showOnlyEditedRows: boolean;
|
|
1769
|
-
showOnlyEmptyCells: boolean;
|
|
1770
|
-
/** When true, show only rows flagged for deletion (bin mode). All other filters are bypassed. */
|
|
1771
|
-
showOnlyDeletedRows: boolean;
|
|
1772
|
-
filterColumns: string[] | null;
|
|
1773
|
-
/** Per-column value filters. Key = column ID, value = allowed display-formatted strings. */
|
|
1774
|
-
columnValueFilters: Record<string, string[]>;
|
|
1775
|
-
/** Per-column numeric range filters. Key = column ID. */
|
|
1776
|
-
columnRangeFilters: Record<string, {
|
|
1777
|
-
min?: number;
|
|
1778
|
-
max?: number;
|
|
1779
|
-
}>;
|
|
1780
|
-
/** Per-column date range filters. Key = column ID, values are ISO date strings (YYYY-MM-DD). */
|
|
1781
|
-
columnDateRangeFilters: Record<string, {
|
|
1782
|
-
min?: string;
|
|
1783
|
-
max?: string;
|
|
1784
|
-
}>;
|
|
1785
|
-
};
|
|
1786
|
-
|
|
1787
|
-
type ChatResponseChunk<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1788
|
-
type: "status";
|
|
1789
|
-
content: string;
|
|
1790
|
-
} | {
|
|
1791
|
-
type: "message";
|
|
1792
|
-
content: string;
|
|
1793
|
-
} | {
|
|
1794
|
-
type: "rows";
|
|
1795
|
-
content: TRow[];
|
|
1796
|
-
} | {
|
|
1797
|
-
type: "transform";
|
|
1798
|
-
content: string;
|
|
1799
|
-
};
|
|
1800
|
-
type ChatRowStatus = "new" | "edited" | "original";
|
|
1801
|
-
type ChatRow<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1802
|
-
data: TRow;
|
|
1803
|
-
status: ChatRowStatus;
|
|
1804
|
-
errors: Record<string, string[]>;
|
|
1805
|
-
source: string;
|
|
1806
|
-
};
|
|
1807
|
-
type ChatErrorSummary = {
|
|
1808
|
-
field: string;
|
|
1809
|
-
message: string;
|
|
1810
|
-
count: number;
|
|
1811
|
-
examples: string[];
|
|
1812
|
-
};
|
|
1813
|
-
type ChatDataContext<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1814
|
-
columns: DataEditorColumn[];
|
|
1815
|
-
primaryKey: keyof TRow;
|
|
1816
|
-
totalRowCount: number;
|
|
1817
|
-
filteredRowCount: number;
|
|
1818
|
-
sample: ChatRow<TRow>[];
|
|
1819
|
-
errorSummary: ChatErrorSummary[];
|
|
1820
|
-
getRows: () => ChatRow<TRow>[];
|
|
1821
|
-
};
|
|
1822
|
-
type ChatContext<TRow extends DataEditorRow = DataEditorRow> = ChatDataContext<TRow> & {
|
|
1823
|
-
message: string;
|
|
1824
|
-
};
|
|
1825
|
-
type DataEditorChat<TRow extends DataEditorRow = DataEditorRow> = {
|
|
1826
|
-
sampleSize?: number;
|
|
1827
|
-
emptyTitle?: string;
|
|
1828
|
-
suggestionsCount?: number;
|
|
1829
|
-
loadSuggestions?: (context: ChatDataContext<TRow>) => Promise<string[]>;
|
|
1830
|
-
onMessage: (context: ChatContext<TRow>) => AsyncIterable<ChatResponseChunk<TRow>>;
|
|
1831
|
-
onCancel?: () => void;
|
|
1832
|
-
};
|
|
1833
|
-
|
|
1834
1960
|
/** Severity level for a validation message. */
|
|
1835
1961
|
type ValidationLevel = "error";
|
|
1836
1962
|
/**
|
|
@@ -1847,8 +1973,13 @@ type ValidationResult = ValidationError[] | null;
|
|
|
1847
1973
|
* A function that validates a single cell value.
|
|
1848
1974
|
* Return a `ValidationError` to flag a problem, or `null` if the value is valid.
|
|
1849
1975
|
*
|
|
1976
|
+
* A `ValidationError` with `level: "error"` flags the cell in the grid but
|
|
1977
|
+
* does not block submission — invalid rows are delivered to `onComplete`
|
|
1978
|
+
* alongside valid ones, tagged via the `isValid` flag.
|
|
1979
|
+
*
|
|
1850
1980
|
* Built-in validator factories: `required(msg)`, `numeric(msg)`, `email(msg)`,
|
|
1851
|
-
* `date(msg)`, `endDateAfterStart(startField, msg)`.
|
|
1981
|
+
* `date(msg)`, `oneOf(values, msg)`, `endDateAfterStart(startField, msg)`.
|
|
1982
|
+
* Import them from the package root.
|
|
1852
1983
|
*
|
|
1853
1984
|
* @param value - The current cell value.
|
|
1854
1985
|
* @param row - The full row, useful for cross-field checks.
|
|
@@ -1932,41 +2063,62 @@ type ColumnLockMode = "all" | "default";
|
|
|
1932
2063
|
*
|
|
1933
2064
|
* @example
|
|
1934
2065
|
* ```ts
|
|
2066
|
+
* import { required, email, numeric } from "@updog/data-editor";
|
|
2067
|
+
*
|
|
1935
2068
|
* const columns: DataEditorColumn[] = [
|
|
1936
|
-
* { id: "name", title: "Full Name",
|
|
1937
|
-
* { id: "email", title: "Email",
|
|
1938
|
-
* { id: "role", title: "Role", editor: { type: "select", options:
|
|
1939
|
-
* { id: "salary", title: "Salary", validate: numeric, formatter: (v) => `$${v}` },
|
|
2069
|
+
* { id: "name", title: "Full Name", size: 200, validate: required("Name is required") },
|
|
2070
|
+
* { id: "email", title: "Email", size: 250, validate: [required("Email is required"), email("Invalid email")], unique: true },
|
|
2071
|
+
* { id: "role", title: "Role", editor: { type: "select", options: ["Admin", "Editor", "Viewer"] } },
|
|
2072
|
+
* { id: "salary", title: "Salary", validate: numeric("Must be a number"), formatter: (v) => v ? `$${v}` : "" },
|
|
1940
2073
|
* ];
|
|
1941
2074
|
* ```
|
|
1942
2075
|
*/
|
|
1943
2076
|
type DataEditorColumn = {
|
|
1944
2077
|
/** Unique column identifier. Must match the keys in your row data. */
|
|
1945
2078
|
id: string;
|
|
1946
|
-
/** Column header text. */
|
|
2079
|
+
/** Column header text shown to the user. */
|
|
1947
2080
|
title: string;
|
|
1948
|
-
/**
|
|
2081
|
+
/**
|
|
2082
|
+
* One or more validators run on every edit. Each receives the cell value and
|
|
2083
|
+
* the full row, and returns a `ValidationError` to flag a problem or `null`
|
|
2084
|
+
* if valid. Errors do not block submission — see `CellValidator`.
|
|
2085
|
+
*/
|
|
1949
2086
|
validate?: CellValidator | CellValidator[];
|
|
1950
|
-
/**
|
|
2087
|
+
/**
|
|
2088
|
+
* When `true`, the editor flags duplicate values in this column as errors.
|
|
2089
|
+
* The error message is localized via the `translations` prop
|
|
2090
|
+
* (`dataEditor.validation.valueMustBeUnique`).
|
|
2091
|
+
*/
|
|
1951
2092
|
unique?: boolean;
|
|
1952
|
-
/**
|
|
2093
|
+
/**
|
|
2094
|
+
* Column IDs to revalidate when this column changes. Use for cross-field
|
|
2095
|
+
* rules like "end date must be after start date".
|
|
2096
|
+
*/
|
|
1953
2097
|
dependentFields?: string[];
|
|
1954
2098
|
/** Format the display value without changing stored data. E.g. add `$` prefix. */
|
|
1955
2099
|
formatter?: (value: string) => string;
|
|
1956
|
-
/**
|
|
2100
|
+
/**
|
|
2101
|
+
* Transform a value before it enters the store. Runs when rows are uploaded
|
|
2102
|
+
* to the data editor.
|
|
2103
|
+
*/
|
|
1957
2104
|
transformer?: (value: unknown) => unknown;
|
|
1958
2105
|
/** How the cell is edited. Defaults to text input. */
|
|
1959
2106
|
editor?: CellEditor;
|
|
1960
2107
|
/** Adds a filter control for this column in the sidebar Filters panel. */
|
|
1961
2108
|
filter?: ColumnFilter;
|
|
1962
|
-
/**
|
|
2109
|
+
/**
|
|
2110
|
+
* Whether this column can be pinned to the left (right in RTL) via the
|
|
2111
|
+
* header context menu. @default true
|
|
2112
|
+
*/
|
|
1963
2113
|
pinnable?: boolean;
|
|
1964
2114
|
/** Column width in pixels. @default 150 */
|
|
1965
2115
|
size?: number;
|
|
1966
2116
|
/**
|
|
1967
|
-
* Controls whether cells in this column are locked.
|
|
1968
|
-
*
|
|
1969
|
-
* - `"
|
|
2117
|
+
* Controls whether cells in this column are locked. A column locked via
|
|
2118
|
+
* configuration cannot be unlocked from the UI.
|
|
2119
|
+
* - `true` | `"all"` — locked for every row.
|
|
2120
|
+
* - `"default"` — locked only for default-source rows; rows added manually,
|
|
2121
|
+
* duplicated, or imported remain editable.
|
|
1970
2122
|
* - `false` | `undefined` — not locked.
|
|
1971
2123
|
*/
|
|
1972
2124
|
locked?: boolean | ColumnLockMode;
|
|
@@ -2386,9 +2538,12 @@ type UndoRedoResult = {
|
|
|
2386
2538
|
success: boolean;
|
|
2387
2539
|
targetCell?: CellLocation;
|
|
2388
2540
|
};
|
|
2389
|
-
/**
|
|
2541
|
+
/**
|
|
2542
|
+
* Actions available inside the `onComplete` callback. Call `reset()` after a
|
|
2543
|
+
* successful save to clear the editor and re-fetch via `loadData`.
|
|
2544
|
+
*/
|
|
2390
2545
|
type DataEditorActions = {
|
|
2391
|
-
/** Discard all changes and reload the original data
|
|
2546
|
+
/** Discard all changes and reload the original data via `loadData`. */
|
|
2392
2547
|
reset: () => void;
|
|
2393
2548
|
};
|
|
2394
2549
|
/**
|
|
@@ -2448,14 +2603,24 @@ type DataEditorResult<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2448
2603
|
invalid: number;
|
|
2449
2604
|
};
|
|
2450
2605
|
};
|
|
2606
|
+
/**
|
|
2607
|
+
* Options used to tag a chunk passed to `loadData`'s `onChunk` callback.
|
|
2608
|
+
* Sources are auto-registered on first encounter. Chunks without options go
|
|
2609
|
+
* to "Existing Data".
|
|
2610
|
+
*/
|
|
2451
2611
|
type ChunkSourceOptions = {
|
|
2452
|
-
/** Display name for this data source. */
|
|
2612
|
+
/** Display name for this data source. Required when tagging a source. */
|
|
2453
2613
|
source: string;
|
|
2454
|
-
/** Stable identifier. Defaults to `source` value when omitted. */
|
|
2614
|
+
/** Stable identifier. Defaults to the `source` value when omitted. */
|
|
2455
2615
|
id?: string;
|
|
2456
|
-
/**
|
|
2616
|
+
/** Whether the user can delete this source from the editor. @default false */
|
|
2457
2617
|
deletable?: boolean;
|
|
2458
|
-
/**
|
|
2618
|
+
/**
|
|
2619
|
+
* Marks this source as finished loading. Shows a completion state in the
|
|
2620
|
+
* UI. When the `loadData` promise resolves, any source still loading is
|
|
2621
|
+
* automatically finalized.
|
|
2622
|
+
* @default false
|
|
2623
|
+
*/
|
|
2459
2624
|
done?: boolean;
|
|
2460
2625
|
};
|
|
2461
2626
|
type DataSourceId = string;
|
|
@@ -2509,20 +2674,34 @@ type DataStoreSnapshot = {
|
|
|
2509
2674
|
/** True when the "show deleted rows" filter is active (bin mode). */
|
|
2510
2675
|
showOnlyDeletedRows: boolean;
|
|
2511
2676
|
};
|
|
2512
|
-
/**
|
|
2677
|
+
/**
|
|
2678
|
+
* Per-column input to `onValueMatch`: the unique imported values from the
|
|
2679
|
+
* file and the allowed select options defined on the column.
|
|
2680
|
+
*/
|
|
2513
2681
|
type ValueMatchInput = {
|
|
2682
|
+
/** Distinct values seen in the imported file for this column. */
|
|
2514
2683
|
importedValues: string[];
|
|
2684
|
+
/** Allowed options from the column's `select` editor. */
|
|
2515
2685
|
options: string[];
|
|
2516
2686
|
};
|
|
2517
|
-
/**
|
|
2687
|
+
/**
|
|
2688
|
+
* Per-column result from `onValueMatch`. Outer key = column ID, inner key =
|
|
2689
|
+
* imported value, inner value = chosen option, or `null` to skip
|
|
2690
|
+
* auto-matching for that value. Unmapped values fall back to built-in fuzzy
|
|
2691
|
+
* matching.
|
|
2692
|
+
*/
|
|
2518
2693
|
type ValueMatchOutput = Record<string, Record<string, string | null>>;
|
|
2519
|
-
/** File formats supported for import and export. */
|
|
2694
|
+
/** File formats supported for import and export. Shared by `importFormats` and `exportFormats`. */
|
|
2520
2695
|
type DataEditorFormat = "csv" | "tsv" | "xlsx" | "json" | "xml";
|
|
2521
2696
|
/**
|
|
2522
2697
|
* A client-defined remote data source (e.g. Google Sheets, S3, Dropbox).
|
|
2523
2698
|
*
|
|
2524
|
-
* The SDK renders a button per source and calls `fetch()`
|
|
2525
|
-
*
|
|
2699
|
+
* The SDK renders a button per source on the upload step and calls `fetch()`
|
|
2700
|
+
* when clicked. You own all integration complexity — auth, pickers,
|
|
2701
|
+
* downloads. The SDK just processes the result.
|
|
2702
|
+
*
|
|
2703
|
+
* Return a `File` to go through the standard parse pipeline
|
|
2704
|
+
* (CSV/XLSX/JSON/XML), or return structured records to skip parsing entirely.
|
|
2526
2705
|
*
|
|
2527
2706
|
* @example
|
|
2528
2707
|
* ```ts
|
|
@@ -2546,7 +2725,10 @@ type RemoteSource = {
|
|
|
2546
2725
|
icon: string;
|
|
2547
2726
|
/** Optional tooltip text. */
|
|
2548
2727
|
description?: string;
|
|
2549
|
-
/**
|
|
2728
|
+
/**
|
|
2729
|
+
* Returns a `File` (parsed via the CSV/XLSX/JSON/XML pipeline) or structured
|
|
2730
|
+
* records (used directly, skipping parse).
|
|
2731
|
+
*/
|
|
2550
2732
|
fetch: () => Promise<File | Record<string, unknown>[]>;
|
|
2551
2733
|
};
|
|
2552
2734
|
/**
|
|
@@ -2561,8 +2743,9 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2561
2743
|
/** Column definitions. Each entry describes one column in the grid. */
|
|
2562
2744
|
columns: DataEditorColumn[];
|
|
2563
2745
|
/**
|
|
2564
|
-
* The column ID used to uniquely identify each row (e.g. `"id"` or
|
|
2565
|
-
* Used to match imported rows
|
|
2746
|
+
* The column ID used to uniquely identify each row (e.g. `"id"` or
|
|
2747
|
+
* `"employeeId"`). Used to match imported rows against existing data and to
|
|
2748
|
+
* track edits.
|
|
2566
2749
|
*/
|
|
2567
2750
|
primaryKey: keyof TRow;
|
|
2568
2751
|
/**
|
|
@@ -2616,37 +2799,78 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2616
2799
|
* ```
|
|
2617
2800
|
*/
|
|
2618
2801
|
onComplete?: (result: DataEditorResult<TRow>, actions: DataEditorActions) => void;
|
|
2619
|
-
/**
|
|
2802
|
+
/**
|
|
2803
|
+
* Controls the initial view. `"editor"` opens directly to the spreadsheet
|
|
2804
|
+
* grid. `"uploader"` opens the file import wizard first — the user uploads
|
|
2805
|
+
* a file, maps columns, fixes errors, then continues to the grid.
|
|
2806
|
+
* @default "editor"
|
|
2807
|
+
*/
|
|
2620
2808
|
variant?: DataEditorVariant;
|
|
2621
|
-
/**
|
|
2809
|
+
/**
|
|
2810
|
+
* Override any UI string. Pass a partial object — only the keys you provide
|
|
2811
|
+
* are replaced. Every key lives under `dataEditor`.
|
|
2812
|
+
*/
|
|
2622
2813
|
translations?: DataEditorTranslations;
|
|
2623
|
-
/**
|
|
2814
|
+
/**
|
|
2815
|
+
* BCP 47 locale tag (e.g. `"en"`, `"fr"`, `"ar"`). Used for plural rules
|
|
2816
|
+
* and locale-aware features.
|
|
2817
|
+
* @default "en"
|
|
2818
|
+
*/
|
|
2624
2819
|
locale?: string;
|
|
2625
2820
|
/**
|
|
2626
2821
|
* Controls row deletion via the right-click context menu.
|
|
2627
|
-
* - `false` — deletion disabled
|
|
2822
|
+
* - `false` — deletion disabled.
|
|
2628
2823
|
* - `"new"` — only manually added or imported rows can be deleted.
|
|
2629
2824
|
* - `"all"` — any row can be deleted.
|
|
2630
2825
|
* @default false
|
|
2631
2826
|
*/
|
|
2632
2827
|
enableDeleteRow?: "all" | "new" | false;
|
|
2633
|
-
/**
|
|
2828
|
+
/**
|
|
2829
|
+
* Show the "Add row" button in the data sources panel. When `false`, users
|
|
2830
|
+
* can only edit existing rows or import data — they can't manually add
|
|
2831
|
+
* blank rows.
|
|
2832
|
+
* @default true
|
|
2833
|
+
*/
|
|
2634
2834
|
enableAddRow?: boolean;
|
|
2635
|
-
/**
|
|
2835
|
+
/**
|
|
2836
|
+
* Which file formats the user can import. `undefined` allows all formats,
|
|
2837
|
+
* `[]` disables import entirely.
|
|
2838
|
+
*/
|
|
2636
2839
|
importFormats?: DataEditorFormat[];
|
|
2637
|
-
/**
|
|
2840
|
+
/**
|
|
2841
|
+
* Client-defined remote data sources rendered as buttons on the upload
|
|
2842
|
+
* step. You own the integration; the SDK renders the button and processes
|
|
2843
|
+
* the result of `fetch()`.
|
|
2844
|
+
*/
|
|
2638
2845
|
remoteSources?: RemoteSource[];
|
|
2639
|
-
/**
|
|
2846
|
+
/**
|
|
2847
|
+
* Which file formats the user can export to. `undefined` allows all
|
|
2848
|
+
* formats, `[]` disables export entirely.
|
|
2849
|
+
*/
|
|
2640
2850
|
exportFormats?: DataEditorFormat[];
|
|
2641
2851
|
/** Row height in pixels. @default 34 */
|
|
2642
2852
|
rowHeight?: number;
|
|
2643
2853
|
/** Header row height in pixels. @default 36 */
|
|
2644
2854
|
headerHeight?: number;
|
|
2645
|
-
/**
|
|
2855
|
+
/**
|
|
2856
|
+
* When `true`, hides all editing UI (submit, add row, delete, import). The
|
|
2857
|
+
* grid becomes view-only.
|
|
2858
|
+
* @default false
|
|
2859
|
+
*/
|
|
2646
2860
|
readonly?: boolean;
|
|
2647
|
-
/**
|
|
2861
|
+
/**
|
|
2862
|
+
* Enable right-to-left layout. Set to `true` for Arabic, Hebrew, and other
|
|
2863
|
+
* RTL languages. Affects grid direction, text alignment, and scrollbar
|
|
2864
|
+
* position.
|
|
2865
|
+
* @default false
|
|
2866
|
+
*/
|
|
2648
2867
|
rtl?: boolean;
|
|
2649
|
-
/**
|
|
2868
|
+
/**
|
|
2869
|
+
* Allow creating new columns for unmatched CSV headers during import. When
|
|
2870
|
+
* enabled, users can keep data from columns that don't match your schema by
|
|
2871
|
+
* creating dynamic columns on the fly.
|
|
2872
|
+
* @default true
|
|
2873
|
+
*/
|
|
2650
2874
|
enableCreateColumn?: boolean;
|
|
2651
2875
|
/** Override column matching during import. Return a map of `{ csvHeader: columnId | null }`. Unmapped or `null` entries fall back to built-in matching. */
|
|
2652
2876
|
onColumnMatch?: (headers: string[], columns: DataEditorColumn[]) => Record<string, string | null> | Promise<Record<string, string | null>>;
|
|
@@ -2667,32 +2891,68 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2667
2891
|
* ```
|
|
2668
2892
|
*/
|
|
2669
2893
|
onValueMatch?: (valuesToMatch: Record<string, ValueMatchInput>) => ValueMatchOutput | Promise<ValueMatchOutput>;
|
|
2670
|
-
/**
|
|
2894
|
+
/**
|
|
2895
|
+
* Extra synonyms for column auto-matching. Keys are column IDs, values are
|
|
2896
|
+
* alternative names the matching engine should recognize.
|
|
2897
|
+
*
|
|
2898
|
+
* @example
|
|
2899
|
+
* ```ts
|
|
2900
|
+
* synonyms={{
|
|
2901
|
+
* productSku: ["sku", "article_no", "item_code"],
|
|
2902
|
+
* firstName: ["first", "given_name", "fname"],
|
|
2903
|
+
* }}
|
|
2904
|
+
* ```
|
|
2905
|
+
*/
|
|
2671
2906
|
synonyms?: Record<string, string[]>;
|
|
2672
|
-
/**
|
|
2907
|
+
/**
|
|
2908
|
+
* Sample rows included in the "Download Example" file. When the user clicks
|
|
2909
|
+
* "Download Example" in the import wizard, the SDK generates a template
|
|
2910
|
+
* file with column headers and these rows. When omitted, a generic example
|
|
2911
|
+
* row is auto-generated from column definitions.
|
|
2912
|
+
*/
|
|
2673
2913
|
sampleData?: Record<string, unknown>[];
|
|
2674
|
-
/**
|
|
2914
|
+
/**
|
|
2915
|
+
* Bring-your-own-AI chat. When provided, a chat panel is shown alongside
|
|
2916
|
+
* the grid. You own the AI integration; the SDK hands you dataset context
|
|
2917
|
+
* and renders the streamed response.
|
|
2918
|
+
*/
|
|
2675
2919
|
chat?: DataEditorChat<TRow>;
|
|
2676
2920
|
};
|
|
2677
2921
|
/**
|
|
2678
|
-
* Controls what the editor stores in `localStorage`.
|
|
2679
|
-
*
|
|
2922
|
+
* Controls what the editor stores in `localStorage`. Set to `false` to
|
|
2923
|
+
* disable all local storage usage.
|
|
2924
|
+
*
|
|
2925
|
+
* @default { licenseGrant: true }
|
|
2680
2926
|
*/
|
|
2681
2927
|
type DataEditorLocalStorage = false | {
|
|
2682
|
-
/**
|
|
2928
|
+
/**
|
|
2929
|
+
* Cache the license validation result to skip re-validation on reload.
|
|
2930
|
+
* @default true
|
|
2931
|
+
*/
|
|
2683
2932
|
licenseGrant?: boolean;
|
|
2684
2933
|
};
|
|
2685
|
-
/**
|
|
2934
|
+
/**
|
|
2935
|
+
* Rendering mode. `"modal"` wraps the editor in a full-screen dialog
|
|
2936
|
+
* overlay. `"inline"` renders it directly in the DOM.
|
|
2937
|
+
*/
|
|
2686
2938
|
type DataEditorMode = "modal" | "inline";
|
|
2687
2939
|
/** Shared props present in both modal and inline modes. */
|
|
2688
2940
|
type DataEditorCommonProps<TRow extends DataEditorRow = DataEditorRow> = DataEditorBaseProps<TRow> & {
|
|
2689
|
-
/** Your Updog license key.
|
|
2941
|
+
/** Your Updog license key. Validated on each open. */
|
|
2690
2942
|
apiKey: string;
|
|
2691
|
-
/**
|
|
2943
|
+
/**
|
|
2944
|
+
* Controls what the editor stores in `localStorage`. Set to `false` to
|
|
2945
|
+
* disable all local storage usage.
|
|
2946
|
+
* @default { licenseGrant: true }
|
|
2947
|
+
*/
|
|
2692
2948
|
localStorage?: DataEditorLocalStorage;
|
|
2693
|
-
/** CSS class added to the wrapper element. */
|
|
2949
|
+
/** CSS class added to the wrapper element. Use for scoped styling overrides. */
|
|
2694
2950
|
className?: string;
|
|
2695
|
-
/**
|
|
2951
|
+
/**
|
|
2952
|
+
* Called when the SDK catches an internal error. The SDK recovers
|
|
2953
|
+
* gracefully where possible — use this for your logging and monitoring
|
|
2954
|
+
* (Sentry, Datadog, etc.). Client mode only.
|
|
2955
|
+
*/
|
|
2696
2956
|
onError?: (error: UpdogError) => void;
|
|
2697
2957
|
};
|
|
2698
2958
|
/**
|
|
@@ -2702,9 +2962,16 @@ type DataEditorCommonProps<TRow extends DataEditorRow = DataEditorRow> = DataEdi
|
|
|
2702
2962
|
type DataEditorModalProps<TRow extends DataEditorRow = DataEditorRow> = DataEditorCommonProps<TRow> & {
|
|
2703
2963
|
/** Rendering mode. @default "modal" */
|
|
2704
2964
|
mode?: "modal";
|
|
2705
|
-
/**
|
|
2965
|
+
/**
|
|
2966
|
+
* Controls modal visibility. This is a controlled prop — you manage the
|
|
2967
|
+
* state. Required in modal mode.
|
|
2968
|
+
*/
|
|
2706
2969
|
open: boolean;
|
|
2707
|
-
/**
|
|
2970
|
+
/**
|
|
2971
|
+
* Called when the user closes the modal (X button or Escape key). If the
|
|
2972
|
+
* user has unsaved changes, the SDK shows a confirmation dialog before
|
|
2973
|
+
* calling `onClose`. Required in modal mode.
|
|
2974
|
+
*/
|
|
2708
2975
|
onClose: () => void;
|
|
2709
2976
|
};
|
|
2710
2977
|
/**
|