@updog/data-editor 0.1.59 → 0.1.60
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 +3 -3
- package/index.css +1 -1
- package/index.d.ts +110 -11
- package/index.js +2747 -2201
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -376,6 +376,7 @@ declare var export_default = {
|
|
|
376
376
|
redo: "Redo",
|
|
377
377
|
},
|
|
378
378
|
validation: {
|
|
379
|
+
alreadyExists: "Already exists in your database",
|
|
379
380
|
endDateBeforeStart: "End date must be after start date",
|
|
380
381
|
invalidDate: "Invalid date",
|
|
381
382
|
invalidEmail: "Invalid email address",
|
|
@@ -650,6 +651,38 @@ type BuiltInValidator = {
|
|
|
650
651
|
} | {
|
|
651
652
|
type: "numeric";
|
|
652
653
|
message?: string;
|
|
654
|
+
} | {
|
|
655
|
+
type: "unique";
|
|
656
|
+
message?: string;
|
|
657
|
+
fn?: UniqueRemoteFn;
|
|
658
|
+
};
|
|
659
|
+
/** One cell in an asyncFunction batch. Row is passed by reference. */
|
|
660
|
+
type AsyncValidatorCell = {
|
|
661
|
+
/** Value of the validated column for this cell. */
|
|
662
|
+
value: unknown;
|
|
663
|
+
/** The full row — for row-dependent checks. */
|
|
664
|
+
row: DataEditorRow;
|
|
665
|
+
};
|
|
666
|
+
/**
|
|
667
|
+
* Remote existence check for `{ type: "unique" }`. Called once per sweep
|
|
668
|
+
* with all distinct candidate values; report the subset that already exists —
|
|
669
|
+
* return it and/or stream it via onChunk (results are unioned). `signal`
|
|
670
|
+
* fires only when results can no longer be used. Client-mode only.
|
|
671
|
+
*/
|
|
672
|
+
type UniqueRemoteFn = (values: unknown[], onChunk: (existing: unknown[]) => void, signal: AbortSignal) => Promise<unknown[] | void>;
|
|
673
|
+
type AsyncFunctionValidator = {
|
|
674
|
+
type: "asyncFunction";
|
|
675
|
+
/**
|
|
676
|
+
* Called once per column per operation with every affected cell. Report
|
|
677
|
+
* failures by `index` into `cells`: return an array aligned with the input
|
|
678
|
+
* (null = valid) and/or stream sparse failures via onChunk (unioned, any
|
|
679
|
+
* order). `signal` fires only when results can no longer be used.
|
|
680
|
+
* Client-mode only. For uniqueness use `unique.fn`, not this.
|
|
681
|
+
*/
|
|
682
|
+
fn: (cells: AsyncValidatorCell[], onChunk: (failures: {
|
|
683
|
+
index: number;
|
|
684
|
+
error: ValidationError;
|
|
685
|
+
}[]) => void, signal: AbortSignal) => Promise<(ValidationError | null)[] | void>;
|
|
653
686
|
};
|
|
654
687
|
/**
|
|
655
688
|
* Server-mode-only escape hatch: an expression evaluated by the Go binary
|
|
@@ -676,7 +709,13 @@ type FunctionValidator = {
|
|
|
676
709
|
* Named `ValidatorRule` (not `Validator`) so it doesn't clash with the
|
|
677
710
|
* runtime `Validator` class in `core/Validator.ts`.
|
|
678
711
|
*/
|
|
679
|
-
type ValidatorRule = BuiltInValidator | ExpressionValidator | FunctionValidator;
|
|
712
|
+
type ValidatorRule = BuiltInValidator | ExpressionValidator | FunctionValidator | AsyncFunctionValidator;
|
|
713
|
+
/**
|
|
714
|
+
* Async-check state of a cell, orthogonal to errors/misplaced: "pending"
|
|
715
|
+
* while a verdict is awaited, "unverified" when the check failed or timed
|
|
716
|
+
* out. Idle cells carry no entry.
|
|
717
|
+
*/
|
|
718
|
+
type CellAsyncState = "pending" | "unverified";
|
|
680
719
|
|
|
681
720
|
/**
|
|
682
721
|
* Severity level for a validation message.
|
|
@@ -808,7 +847,7 @@ type ColumnLockMode = "all" | "default";
|
|
|
808
847
|
* ```ts
|
|
809
848
|
* const columns: DataEditorColumn[] = [
|
|
810
849
|
* { id: "name", title: "Full Name", size: 200, validators: [{ type: "required", message: "Name is required" }] },
|
|
811
|
-
* { id: "email", title: "Email", size: 250, validators: [{ type: "required", message: "Email is required" }, { type: "email", message: "Invalid email" }
|
|
850
|
+
* { id: "email", title: "Email", size: 250, validators: [{ type: "required", message: "Email is required" }, { type: "email", message: "Invalid email" }, { type: "unique" }] },
|
|
812
851
|
* { id: "role", title: "Role", editor: { type: "select", options: ["Admin", "Editor", "Viewer"] } },
|
|
813
852
|
* { id: "salary", title: "Salary", validators: [{ type: "numeric", message: "Must be a number" }], formatter: (v) => v ? `$${v}` : "" },
|
|
814
853
|
* ];
|
|
@@ -821,19 +860,13 @@ type DataEditorColumn = {
|
|
|
821
860
|
title: string;
|
|
822
861
|
/**
|
|
823
862
|
* One or more validators run on every edit. Accepts:
|
|
824
|
-
* - Built-in object literals: `{ type: "required" | "email" | "regex" | "range" | "oneOf" | "date" | "numeric", ... }`.
|
|
863
|
+
* - Built-in object literals: `{ type: "required" | "email" | "regex" | "range" | "oneOf" | "date" | "numeric" | "unique", ... }`.
|
|
825
864
|
* - `{ type: "expression", expr }` — server-mode only. Warned in client mode.
|
|
826
865
|
* - `{ type: "function", fn }` — client-mode only. Dropped+warned in server mode.
|
|
827
866
|
*
|
|
828
867
|
* See `_specs/VALIDATIONS.md` §4.5 for the per-mode support matrix.
|
|
829
868
|
*/
|
|
830
869
|
validators?: ValidatorRule[];
|
|
831
|
-
/**
|
|
832
|
-
* When `true`, the editor flags duplicate values in this column as errors.
|
|
833
|
-
* The error message is localized via the `translations` prop
|
|
834
|
-
* (`dataEditor.validation.valueMustBeUnique`).
|
|
835
|
-
*/
|
|
836
|
-
unique?: boolean;
|
|
837
870
|
/**
|
|
838
871
|
* Column IDs to revalidate when this column changes. Use for cross-field
|
|
839
872
|
* rules like "end date must be after start date".
|
|
@@ -1470,6 +1503,21 @@ declare class ErrorHandler {
|
|
|
1470
1503
|
handleError(error: UpdogError): void;
|
|
1471
1504
|
}
|
|
1472
1505
|
|
|
1506
|
+
type UniqueConfig = {
|
|
1507
|
+
message?: string;
|
|
1508
|
+
fn?: UniqueRemoteFn;
|
|
1509
|
+
};
|
|
1510
|
+
/**
|
|
1511
|
+
* Core-internal column shape produced by normalizeUniqueColumns. Uniqueness
|
|
1512
|
+
* lives in `uniqueConfig` and asyncFunction rules in `asyncConfig` — the
|
|
1513
|
+
* single internal sources of truth — never as entries in `validators`.
|
|
1514
|
+
* Never exported from the package entry.
|
|
1515
|
+
*/
|
|
1516
|
+
type NormalizedColumn = DataEditorColumn & {
|
|
1517
|
+
uniqueConfig?: UniqueConfig;
|
|
1518
|
+
asyncConfig?: AsyncFunctionValidator[];
|
|
1519
|
+
};
|
|
1520
|
+
|
|
1473
1521
|
type FormulaCellContext = {
|
|
1474
1522
|
value: unknown;
|
|
1475
1523
|
field: string;
|
|
@@ -2023,6 +2071,7 @@ interface SnapshotStateReader {
|
|
|
2023
2071
|
hasColumnScoping(): boolean;
|
|
2024
2072
|
getSortState(): SortState;
|
|
2025
2073
|
getShowOnlyDeletedRows(): boolean;
|
|
2074
|
+
getPendingValidationCount(): number;
|
|
2026
2075
|
/** Server-provided aggregate counts. Present only in server mode. */
|
|
2027
2076
|
getServerEditedCount?(): number;
|
|
2028
2077
|
getServerNewCount?(): number;
|
|
@@ -2095,10 +2144,15 @@ type ValidationDelta = {
|
|
|
2095
2144
|
errorDelta: number;
|
|
2096
2145
|
rowErrorChanged: boolean;
|
|
2097
2146
|
rowMisplacedChanged: boolean;
|
|
2147
|
+
pendingDelta: number;
|
|
2098
2148
|
};
|
|
2099
2149
|
type IValidationStore = {
|
|
2100
2150
|
setCellValidation(rowId: TRowId, field: string, result: ValidationResult): ValidationDelta;
|
|
2101
2151
|
getCellValidation(rowId: TRowId, field: string): ValidationResult;
|
|
2152
|
+
setCellAsyncState(rowId: TRowId, field: string, state: CellAsyncState | null): ValidationDelta;
|
|
2153
|
+
getCellAsyncState(rowId: TRowId, field: string): CellAsyncState | null;
|
|
2154
|
+
getPendingCount(): number;
|
|
2155
|
+
getRowsWithPending(): ReadonlySet<TRowId>;
|
|
2102
2156
|
clearRowValidations(rowId: TRowId): void;
|
|
2103
2157
|
hasRowErrors(rowId: TRowId): boolean;
|
|
2104
2158
|
getRowsWithErrors(): ReadonlySet<TRowId>;
|
|
@@ -2114,6 +2168,40 @@ type IValidationStore = {
|
|
|
2114
2168
|
clear(): void;
|
|
2115
2169
|
};
|
|
2116
2170
|
|
|
2171
|
+
/**
|
|
2172
|
+
* AsyncValidationScheduler — facade over the async annotation channel.
|
|
2173
|
+
*
|
|
2174
|
+
* Owns: per-cell version stamps (the ONLY staleness arbiter), pending /
|
|
2175
|
+
* unverified transitions, edit debounce (SweepQueue), inactivity timeout,
|
|
2176
|
+
* once-per-sweep error reporting, and throttled notify. Checks
|
|
2177
|
+
* (UniqueRemoteCheck / FunctionCheck) own only the client protocol.
|
|
2178
|
+
*
|
|
2179
|
+
* No cancellation — last write wins. Sweeps are never aborted by other
|
|
2180
|
+
* sweeps; every dispatched sweep runs to completion. Each enqueue stamps its
|
|
2181
|
+
* cells with a fresh token; a sweep may touch a cell (state transitions,
|
|
2182
|
+
* asyncFunction error writes) only while its recorded token is current.
|
|
2183
|
+
* Unique error writes go through the live index instead (same last-state-
|
|
2184
|
+
* wins property). The AbortSignal handed to the client fn fires only on
|
|
2185
|
+
* sweep timeout and destroy — a courtesy, never a correctness mechanism.
|
|
2186
|
+
*/
|
|
2187
|
+
|
|
2188
|
+
type AsyncCellRequest = {
|
|
2189
|
+
rowId: TRowId;
|
|
2190
|
+
field: string;
|
|
2191
|
+
value: unknown;
|
|
2192
|
+
};
|
|
2193
|
+
type EnqueueOptions = {
|
|
2194
|
+
bulk?: boolean;
|
|
2195
|
+
};
|
|
2196
|
+
/** What Validator sees — one method, never the class (ValidatorDataAccess idiom). */
|
|
2197
|
+
type AsyncValidationPort = {
|
|
2198
|
+
enqueue(requests: AsyncCellRequest[], opts?: EnqueueOptions): void;
|
|
2199
|
+
};
|
|
2200
|
+
type IAsyncValidationScheduler = AsyncValidationPort & {
|
|
2201
|
+
flush(): void;
|
|
2202
|
+
destroy(): void;
|
|
2203
|
+
};
|
|
2204
|
+
|
|
2117
2205
|
type IValidator<TRow extends DataEditorRow = DataEditorRow> = {
|
|
2118
2206
|
validateRow(rowId: TRowId): void;
|
|
2119
2207
|
validateRows(rows: TRow[], rowIds: TRowId[]): void;
|
|
@@ -2123,6 +2211,7 @@ type IValidator<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2123
2211
|
validateColumn(field: string, oldValues: ReadonlyMap<TRowId, unknown>): void;
|
|
2124
2212
|
revalidateColumnChunked(field: string, oldValues: ReadonlyMap<TRowId, unknown>, newValues: ReadonlyMap<TRowId, unknown>, processor: ChunkedProcessor<TRowId>, onComplete: () => void): void;
|
|
2125
2213
|
removeRow(rowId: TRowId): void;
|
|
2214
|
+
setAsyncPort(port: AsyncValidationPort): void;
|
|
2126
2215
|
destroy(): void;
|
|
2127
2216
|
};
|
|
2128
2217
|
|
|
@@ -2271,6 +2360,7 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
2271
2360
|
private dirtyTracker;
|
|
2272
2361
|
private filterEngine;
|
|
2273
2362
|
private validationStore;
|
|
2363
|
+
private asyncScheduler;
|
|
2274
2364
|
private snapshotManager;
|
|
2275
2365
|
private history;
|
|
2276
2366
|
private validator;
|
|
@@ -2343,8 +2433,8 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
2343
2433
|
private withAddedOptions;
|
|
2344
2434
|
private rebuildEffectiveColumns;
|
|
2345
2435
|
setSchemaColumns(columns: DataEditorColumn[]): void;
|
|
2346
|
-
getDynamicColumns():
|
|
2347
|
-
getEffectiveColumns: () =>
|
|
2436
|
+
getDynamicColumns(): NormalizedColumn[];
|
|
2437
|
+
getEffectiveColumns: () => NormalizedColumn[];
|
|
2348
2438
|
setDynamicColumns(fn: (prev: DataEditorColumn[]) => DataEditorColumn[]): void;
|
|
2349
2439
|
addDynamicColumns(columns: DataEditorColumn[]): void;
|
|
2350
2440
|
addColumnOptions(columnId: string, values: string[]): void;
|
|
@@ -2511,6 +2601,9 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
2511
2601
|
syncWorkerFlags(): void;
|
|
2512
2602
|
setCellValidation(rowId: TRowId, field: string, result: ValidationResult): void;
|
|
2513
2603
|
getCellValidation(rowId: TRowId, field: string): ValidationResult;
|
|
2604
|
+
setAsyncScheduler(scheduler: IAsyncValidationScheduler): void;
|
|
2605
|
+
setCellAsyncState(rowId: TRowId, field: string, state: CellAsyncState | null): void;
|
|
2606
|
+
getCellAsyncState(rowId: TRowId, field: string): CellAsyncState | null;
|
|
2514
2607
|
/** Strips "misplaced" from one cell, keeping any error-level entries. */
|
|
2515
2608
|
private clearCellMisplaced;
|
|
2516
2609
|
/**
|
|
@@ -2547,6 +2640,8 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
|
|
|
2547
2640
|
getOriginalCellValue(rowId: TRowId, field: string): unknown | undefined;
|
|
2548
2641
|
isCellDirty(rowId: TRowId, field: string): boolean;
|
|
2549
2642
|
hasRowErrors(rowId: TRowId): boolean;
|
|
2643
|
+
/** O(1) row gate for the grid's pending-stripe pass. */
|
|
2644
|
+
hasRowPending(rowId: TRowId): boolean;
|
|
2550
2645
|
hasEmptyCells(rowId: TRowId): boolean;
|
|
2551
2646
|
hasRowMisplaced(rowId: TRowId): boolean;
|
|
2552
2647
|
getRowsWithMisplaced(): ReadonlySet<TRowId>;
|
|
@@ -2836,6 +2931,10 @@ type DataStoreSnapshot = {
|
|
|
2836
2931
|
filteredEmptyRowCount: number;
|
|
2837
2932
|
/** Visible non-deleted rows with a cell flagged as misplaced after ragged-row realignment. */
|
|
2838
2933
|
misplacedRowCount: number;
|
|
2934
|
+
/** Cells currently awaiting an async validation verdict. */
|
|
2935
|
+
pendingValidationCount: number;
|
|
2936
|
+
/** True while any async check is queued or in flight — drives submit gating. */
|
|
2937
|
+
isAsyncValidating: boolean;
|
|
2839
2938
|
isLoading: boolean;
|
|
2840
2939
|
isFiltering: boolean;
|
|
2841
2940
|
/** Unified phase state machine. Controls what actions are allowed. */
|