@updog/data-editor 0.1.87 → 0.1.89

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/index.d.ts CHANGED
@@ -411,6 +411,8 @@ declare var export_default = {
411
411
  validation: {
412
412
  alreadyExists: "Already exists in your database",
413
413
  endDateBeforeStart: "End date must be after start date",
414
+ invalidCountry: "Invalid country",
415
+ invalidCurrency: "Invalid currency",
414
416
  invalidDate: "Invalid date",
415
417
  invalidEmail: "Invalid email address",
416
418
  invalidFormat: "Invalid format",
@@ -537,6 +539,8 @@ declare var export_default = {
537
539
  showAll: "Show all",
538
540
  showMatched: "Show matched",
539
541
  allMatched: "All values are matched",
542
+ corrected: "Corrected",
543
+ possibleMatch: "Possible match",
540
544
  tooManyValues: "Showing first {{shown}} of {{total}} values",
541
545
  unmatchedWarning:
542
546
  "Unmatched values won't be imported. Match this value to keep the data. You can edit values after importing.",
@@ -792,6 +796,47 @@ type MultiSelectEditorCell = {
792
796
  /** Splits a raw imported cell and joins on export. Omitted: import auto-detects, export joins with `", "`. */
793
797
  delimiter?: string;
794
798
  };
799
+ /**
800
+ * Country cell. Stores the ISO 3166-1 alpha-2 code in upper case; the screen
801
+ * shows the country name in the interface language. The list is the 249
802
+ * assigned ISO codes plus `XK` for Kosovo, which ISO does not assign.
803
+ */
804
+ type CountryEditorCell = {
805
+ type: "country";
806
+ /** Pick zero or more countries; the stored value becomes `string[]`. */
807
+ multiple?: boolean;
808
+ /**
809
+ * Let users add a value the list has not got. Defaults to **false** — the
810
+ * country list is closed until the client opens it. A created value reaches
811
+ * `onComplete` next to `DE` and `FR` with no code of its own.
812
+ */
813
+ enableCustomValue?: boolean;
814
+ /** Splits a raw imported cell and joins on export, when `multiple`. Omitted:
815
+ * import auto-detects, export joins with `", "`. */
816
+ delimiter?: string;
817
+ /**
818
+ * The codes the column takes, alpha-2, in the order the dropdown shows them
819
+ * under `currency` and before the name sort under `country`. A code the ISO
820
+ * list has not got is dropped with a warning. Omitted: the whole list.
821
+ */
822
+ only?: string[];
823
+ };
824
+ /**
825
+ * Currency cell. Stores the ISO 4217 code in upper case and shows it as is;
826
+ * the list is the 178 codes of the current ISO list. Reads codes, numeric
827
+ * codes, names in 26 languages, ISO names and symbols on the way in.
828
+ */
829
+ type CurrencyEditorCell = {
830
+ type: "currency";
831
+ /**
832
+ * Let users add a value the list has not got. Defaults to **false** — the
833
+ * currency list is closed until the client opens it. A created value reaches
834
+ * `onComplete` next to `USD` and `EUR` with no code of its own.
835
+ */
836
+ enableCustomValue?: boolean;
837
+ /** The ISO 4217 codes the column takes, in the order the dropdown shows them. */
838
+ only?: string[];
839
+ };
795
840
  /** Number input cell with locale-aware formatting. Bounds and decimal digits come from the column's `{ type: "number" }` validator. */
796
841
  type NumberEditorCell = {
797
842
  type: "number";
@@ -808,9 +853,11 @@ type NumberEditorCell = {
808
853
  * - `"time"` — plain text input for a time of day; the column is checked against `{ type: "time" }`.
809
854
  * - `"select"` — dropdown with a fixed list of options.
810
855
  * - `"multiselect"` — dropdown allowing zero or more options; stored as `string[]`.
856
+ * - `"country"` — dropdown over the ISO country list; stores the alpha-2 code, shows the name.
857
+ * - `"currency"` — dropdown over the ISO 4217 list; stores and shows the three-letter code.
811
858
  * - `"number"` — number input with locale-aware formatting.
812
859
  */
813
- type CellEditor = TextEditorCell | DateEditorCell | TimeEditorCell | SelectEditorCell | MultiSelectEditorCell | NumberEditorCell;
860
+ type CellEditor = TextEditorCell | DateEditorCell | TimeEditorCell | SelectEditorCell | MultiSelectEditorCell | CountryEditorCell | CurrencyEditorCell | NumberEditorCell;
814
861
  /** Dropdown filter shown in the sidebar Filters panel. */
815
862
  type SelectColumnFilter = {
816
863
  type: "select";
@@ -941,6 +988,16 @@ type BuiltInValidator = {
941
988
  type: "oneOf";
942
989
  values: string[];
943
990
  message?: string;
991
+ }
992
+ /** The cell holds a code from the country list. Implicit on every country column. */
993
+ | {
994
+ type: "country";
995
+ message?: string;
996
+ }
997
+ /** The cell holds a code from the currency list. Implicit on every currency column. */
998
+ | {
999
+ type: "currency";
1000
+ message?: string;
944
1001
  } | {
945
1002
  type: "number";
946
1003
  /** Inclusive lower bound. */
@@ -1206,12 +1263,30 @@ type DataEditorChat<TRow extends DataEditorRow = DataEditorRow> = {
1206
1263
  onCancel?: () => void;
1207
1264
  };
1208
1265
 
1266
+ /**
1267
+ * The parts of a column every cell type reads. Both `DataEditorColumn` and
1268
+ * `NormalizedColumn` satisfy it, so core and the UI pass the column they hold.
1269
+ */
1270
+ type TypedColumn = Pick<DataEditorColumn, "id" | "editor" | "formatter"> & {
1271
+ /** Values the person created at the screen; `options()` lists them after
1272
+ * the column's own. */
1273
+ addedOptions?: readonly string[];
1274
+ };
1275
+ type FormatContext = {
1276
+ locale: string | null;
1277
+ t: TFunction | null;
1278
+ };
1279
+ type ColumnFormat = {
1280
+ readonly typeId: string;
1281
+ readonly candidateId: string;
1282
+ };
1283
+
1209
1284
  /**
1210
1285
  * Categories of internal errors surfaced through the `onError` callback.
1211
1286
  * `license.*` codes cover license validation failures (previously a separate
1212
1287
  * `LicenseErrorCode` enum).
1213
1288
  */
1214
- type UpdogErrorCode = "PARSE_ERROR" | "RENDER_ERROR" | "TRANSFORM_ERROR" | "VALIDATION_ERROR" | "WORKER_ERROR" | "COMMAND_ERROR" | "OPERATION_ERROR" | "license.invalid" | "license.missing" | "license.domain_not_allowed" | "license.subscription_inactive" | "license.trial_expired";
1289
+ type UpdogErrorCode = "PARSE_ERROR" | "RENDER_ERROR" | "TRANSFORM_ERROR" | "VALIDATION_ERROR" | "WORKER_ERROR" | "COMMAND_ERROR" | "OPERATION_ERROR" | "HOOK_ERROR" | "license.invalid" | "license.missing" | "license.domain_not_allowed" | "license.subscription_inactive" | "license.trial_expired";
1215
1290
  /**
1216
1291
  * An internal error caught by the SDK and passed to `onError`. The SDK
1217
1292
  * recovers gracefully where possible — `onError` is for your logging and
@@ -1243,16 +1318,6 @@ declare class ErrorHandler {
1243
1318
  handleError(error: UpdogError): void;
1244
1319
  }
1245
1320
 
1246
- /**
1247
- * The parts of a column every cell type reads. Both `DataEditorColumn` and
1248
- * `NormalizedColumn` satisfy it, so core and the UI pass the column they hold.
1249
- */
1250
- type TypedColumn = Pick<DataEditorColumn, "id" | "editor" | "formatter">;
1251
- type ColumnFormat = {
1252
- readonly typeId: string;
1253
- readonly candidateId: string;
1254
- };
1255
-
1256
1321
  type FormatScope = string;
1257
1322
  type FormatField = {
1258
1323
  key: string;
@@ -1391,6 +1456,7 @@ type NormalizedColumn = Omit<DataEditorColumn, "validators"> & {
1391
1456
  numberConfig?: NumberConfig;
1392
1457
  dateConfig?: DateConfig;
1393
1458
  timeConfig?: TimeConfig;
1459
+ addedOptions?: readonly string[];
1394
1460
  };
1395
1461
  type NumberConfig = {
1396
1462
  min?: number;
@@ -1495,7 +1561,7 @@ type IFilterEngine<TRow extends DataEditorRow = DataEditorRow> = {
1495
1561
  getWordsPerRow(): number;
1496
1562
  getShowOnlyDeletedRows(): boolean;
1497
1563
  getSortState(): SortState;
1498
- setColumns(columns: DataEditorColumn[]): void;
1564
+ setColumns(columns: DataEditorColumn[], ctx?: FormatContext): void;
1499
1565
  setFilters(filters: Partial<Filters>): void;
1500
1566
  setSortState(state: SortState, sortType?: SortType, locales?: string[]): Promise<void>;
1501
1567
  updateRowText(rowId: TRowId, row: TRow): void;
@@ -1923,10 +1989,12 @@ type SelectionRect = {
1923
1989
  readonly rowIds: readonly TRowId[];
1924
1990
  };
1925
1991
 
1926
- type MultiSelectEditorConfig = {
1992
+ /** What a list column's type answers, gathered by the caller: the options,
1993
+ * the declared delimiter if any, and whether a value outside the list stays. */
1994
+ type ListCell = {
1927
1995
  options: string[];
1928
1996
  delimiter?: string;
1929
- enableCustomValue?: boolean;
1997
+ allowsCustom: boolean;
1930
1998
  };
1931
1999
 
1932
2000
  /**
@@ -1946,7 +2014,7 @@ type MultiSelectEditorConfig = {
1946
2014
 
1947
2015
  type MultiSelectTarget = {
1948
2016
  delimiter: string;
1949
- editor: MultiSelectEditorConfig;
2017
+ editor: ListCell;
1950
2018
  };
1951
2019
  type PasteSpec = {
1952
2020
  sourceColumnIds: string[];
@@ -2051,6 +2119,10 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2051
2119
  getRowId(index: number): TRowId | undefined;
2052
2120
  getLocalRowCount(): number;
2053
2121
  setValidator(validator: IValidator<TRow>): void;
2122
+ /**
2123
+ * The filter engine printed its formatters with the language it had when
2124
+ * the columns arrived, and the columns arrive before the language does.
2125
+ */
2054
2126
  setI18n(i18n: {
2055
2127
  t: TFunction;
2056
2128
  locale: string;
@@ -2170,7 +2242,7 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2170
2242
  * has already normalised through buildImportRow — never transforms twice.
2171
2243
  */
2172
2244
  appendClientRows(sourceId: DataSourceId, newRows: TRow[]): TRowId[];
2173
- private formatContext;
2245
+ getFormatContext(): FormatContext;
2174
2246
  /**
2175
2247
  * A column nothing separated is a signal to whoever integrated the SDK, so
2176
2248
  * it goes out in English through `onError` rather than to the person at the
@@ -2178,6 +2250,11 @@ declare class DataStore<TRow extends DataEditorRow = DataEditorRow> {
2178
2250
  * the dialog is out of scope (spec section 10).
2179
2251
  */
2180
2252
  private reportAmbiguity;
2253
+ /**
2254
+ * `fieldReader`, public: the value takes the column's storage shape; a
2255
+ * field outside the schema returns it untouched.
2256
+ */
2257
+ readFieldValue(field: string, value: unknown): unknown;
2181
2258
  /**
2182
2259
  * The column's reader with no verdict behind it. A formula result is one
2183
2260
  * value, so there is nothing to vote on; the reader is here to give the
@@ -2397,6 +2474,43 @@ type ColumnDelta = {
2397
2474
  newValues: Map<TRowId, unknown>;
2398
2475
  };
2399
2476
 
2477
+ /** One input row: the schema shape after reading plus the raw file row. */
2478
+ type RowImportInputRow = {
2479
+ /**
2480
+ * Keys are your schema column ids; values went through format reading,
2481
+ * value mapping, and the column's `transformer`.
2482
+ */
2483
+ row: Record<string, unknown>;
2484
+ /**
2485
+ * Keys are the file's headers, unmapped ones included; values are the
2486
+ * cell texts as they appear in the file.
2487
+ */
2488
+ raw: Record<string, string>;
2489
+ };
2490
+ type RowImportMeta = {
2491
+ /** Zero-based chunk number within the current workbook. */
2492
+ chunkIndex: number;
2493
+ /** Total number of chunks in the current workbook. */
2494
+ chunkCount: number;
2495
+ isLastChunk: boolean;
2496
+ /** The workbook being imported: source name, sheet (XLSX), file headers. */
2497
+ workbook: {
2498
+ name: string;
2499
+ sheetName?: string;
2500
+ headers: string[];
2501
+ };
2502
+ /** This workbook's column mapping: file header → schema column id. */
2503
+ mapping: Record<string, string | undefined>;
2504
+ /** The `context` prop, untouched. */
2505
+ context: unknown;
2506
+ };
2507
+ /**
2508
+ * Chunk in, chunk out. The returned array is positional: element `i` answers
2509
+ * `rows[i]`, `null` drops that row, elements past `rows.length` append new
2510
+ * rows. Returning nothing leaves the chunk as it is.
2511
+ */
2512
+ type RowImportHook = (rows: RowImportInputRow[], meta: RowImportMeta) => (Record<string, unknown> | null)[] | void | Promise<(Record<string, unknown> | null)[] | void>;
2513
+
2400
2514
  /** Numeric row identifier. V8 stores small integers (Smi) inline — no heap allocation. */
2401
2515
  type TRowId = number;
2402
2516
  type SortType = "text" | "number" | "date" | "time";
@@ -2888,6 +3002,40 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
2888
3002
  * ```
2889
3003
  */
2890
3004
  onValueMatch?: (valuesToMatch: Record<string, ValueMatchInput>) => ValueMatchOutput | Promise<ValueMatchOutput>;
3005
+ /**
3006
+ * Edit, drop, or append rows between the file and the editor. Called once
3007
+ * per chunk of 5,000 rows of each imported workbook, after every cell went
3008
+ * through format reading, value mapping, and the column's `transformer` —
3009
+ * the raw file row rides along in `raw`, unmapped headers included.
3010
+ *
3011
+ * The returned array is positional: element `i` replaces `rows[i].row`,
3012
+ * `null` drops that row, elements past `rows.length` append new rows.
3013
+ * Return nothing to leave the chunk as it is. Every field the hook changed
3014
+ * is re-read as if it came from the file — format reading, value mapping,
3015
+ * and `transformer` run again on it.
3016
+ *
3017
+ * A thrown error, a timeout of 30 seconds per chunk, or an array shorter
3018
+ * than the input counts as a failure: the chunk lands unchanged, one
3019
+ * `HOOK_ERROR` reaches `onError`, and the hook stays off for the rest of
3020
+ * that import run.
3021
+ *
3022
+ * @example
3023
+ * ```ts
3024
+ * // Split "USD 100" from the file's price column into two schema fields.
3025
+ * onRowImport={(rows) =>
3026
+ * rows.map(({ row, raw }) => {
3027
+ * const [currency, amount] = (raw["price"] ?? "").split(" ");
3028
+ * return { ...row, currency, amount };
3029
+ * })
3030
+ * }
3031
+ * ```
3032
+ */
3033
+ onRowImport?: RowImportHook;
3034
+ /**
3035
+ * Anything you want your hooks to see: `onRowImport` receives it untouched
3036
+ * as `meta.context`.
3037
+ */
3038
+ context?: unknown;
2891
3039
  /**
2892
3040
  * Extra synonyms layered on top of the built-ins, in two tables that stay
2893
3041
  * apart: `columns` scores a file header against your columns, `values`
@@ -3082,4 +3230,4 @@ declare function exportDataEditor<TRow extends DataEditorRow>(params: ExportPara
3082
3230
  declare function DataEditor<TRow extends DataEditorRow = DataEditorRow>(allProps: DataEditorProps<TRow>): react.JSX.Element;
3083
3231
 
3084
3232
  export { DataEditor, downloadExampleFile, exportDataEditor };
3085
- export type { CellValidator, ChatContext, ChatErrorSummary, ChatResponseChunk, ChatRow, ChatRowStatus, ChunkSourceOptions, CustomImportFormat, CustomImportTable, DataEditorChat, DataEditorColumn, DataEditorFormat, DataEditorInlineProps, DataEditorLocalStorage, DataEditorModalProps, DataEditorMode, DataEditorProps, DataEditorResult, DataEditorRow, DataEditorSourceResult, DataEditorTranslations, DataEditorVariant, InitialRowChange, RemoteSource, ResultRow, UpdogError, UpdogErrorCode, ValidationError, ValueMatchInput, ValueMatchOutput };
3233
+ export type { CellValidator, ChatContext, ChatErrorSummary, ChatResponseChunk, ChatRow, ChatRowStatus, ChunkSourceOptions, CustomImportFormat, CustomImportTable, DataEditorChat, DataEditorColumn, DataEditorFormat, DataEditorInlineProps, DataEditorLocalStorage, DataEditorModalProps, DataEditorMode, DataEditorProps, DataEditorResult, DataEditorRow, DataEditorSourceResult, DataEditorTranslations, DataEditorVariant, InitialRowChange, RemoteSource, ResultRow, RowImportHook, RowImportInputRow, RowImportMeta, UpdogError, UpdogErrorCode, ValidationError, ValueMatchInput, ValueMatchOutput };