@updog/data-editor-wc 0.1.14 → 0.1.16

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 (4) hide show
  1. package/README.md +6 -12
  2. package/index.d.ts +9 -20
  3. package/index.js +55 -43
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -61,14 +61,13 @@ How you wire the element into a framework (Angular's `CUSTOM_ELEMENTS_SCHEMA`, V
61
61
  const res = await fetch("/api/employees");
62
62
  onChunk(await res.json());
63
63
  },
64
- onComplete: async (result, actions) => {
64
+ onComplete: async (result) => {
65
65
  for (const source of result.sources) {
66
66
  const inserts = source.rows.filter((r) => r.isNew && !r.isDeleted && r.isValid);
67
67
  const updates = source.rows.filter((r) => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
68
68
  const deletes = source.rows.filter((r) => r.isDeleted && !r.isNew);
69
69
  await persist(source.sourceId, { inserts, updates, deletes });
70
70
  }
71
- actions.reset();
72
71
  editor.hide();
73
72
  },
74
73
  });
@@ -109,7 +108,7 @@ Everything else — objects, functions, arrays — must be set as a JS property
109
108
  const editor = document.querySelector("updog-editor");
110
109
  editor.columns = [...];
111
110
  editor.loadData = async (onChunk) => { ... };
112
- editor.onComplete = (result, actions) => { ... };
111
+ editor.onComplete = async (result) => { ... };
113
112
  ```
114
113
 
115
114
  ### `configure(props)`
@@ -122,7 +121,7 @@ editor.configure({
122
121
  primaryKey: "id",
123
122
  columns: [...],
124
123
  loadData: async (onChunk) => onChunk(await fetchRows()),
125
- onComplete: (result, actions) => { save(result); actions.reset(); },
124
+ onComplete: async (result) => { await save(result); },
126
125
  });
127
126
  ```
128
127
 
@@ -146,7 +145,7 @@ In inline mode, `show()` / `hide()` and the `open` attribute don't apply. The `c
146
145
  | `mode` | `"modal"` \| `"inline"` | No | `"modal"` | Rendering mode. |
147
146
  | `open` | `boolean` | Modal only | — | Controlled modal visibility. Equivalent to `show()` / `hide()`. |
148
147
  | `loadData` | `(onChunk) => Promise<void>` | No | — | Async data loader. Stream rows in chunks, optionally tagged by source. |
149
- | `onComplete` | `(result, actions) => void` | No | — | Called on submit. See [Submission Result](#submission-result). |
148
+ | `onComplete` | `(result) => void \| Promise<void>` | No | — | Called on submit. See [Submission Result](#submission-result). |
150
149
  | `variant` | `"editor"` \| `"uploader"` | No | `"editor"` | Initial view. `"uploader"` opens the import wizard first. |
151
150
  | `translations` | `DataEditorTranslations` | No | — | Partial i18n overrides. |
152
151
  | `locale` | `string` | No | `"en"` | BCP 47 locale tag. |
@@ -303,7 +302,7 @@ editor.loadData = async (onChunk) => {
303
302
 
304
303
  ## Submission Result
305
304
 
306
- `onComplete(result, actions)` fires when the user submits.
305
+ `onComplete(result)` fires when the user submits. May return a promise.
307
306
 
308
307
  ```ts
309
308
  type DataEditorResult = {
@@ -320,23 +319,18 @@ type DataEditorResult = {
320
319
  }[];
321
320
  counts: { new: number; changed: number; deleted: number; invalid: number };
322
321
  };
323
-
324
- type DataEditorActions = {
325
- reset: () => void; // discard changes and reload via loadData
326
- };
327
322
  ```
328
323
 
329
324
  Pristine backend rows (unchanged, not deleted, not new) are omitted from `sources[].rows` — they're no-ops. The flags are orthogonal: a row can be new, changed, and deleted at once. You own the routing rules:
330
325
 
331
326
  ```js
332
- editor.onComplete = async (result, actions) => {
327
+ editor.onComplete = async (result) => {
333
328
  for (const source of result.sources) {
334
329
  const inserts = source.rows.filter((r) => r.isNew && !r.isDeleted && r.isValid);
335
330
  const updates = source.rows.filter((r) => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
336
331
  const deletes = source.rows.filter((r) => r.isDeleted && !r.isNew);
337
332
  await persist(source.sourceId, { inserts, updates, deletes });
338
333
  }
339
- actions.reset();
340
334
  };
341
335
  ```
342
336
 
package/index.d.ts CHANGED
@@ -959,14 +959,6 @@ type ScaleServerConfig = {
959
959
  url: string;
960
960
  };
961
961
 
962
- /**
963
- * Actions available inside the `onComplete` callback. Call `reset()` after a
964
- * successful save to clear the editor and re-fetch via `loadData`.
965
- */
966
- type DataEditorActions = {
967
- /** Discard all changes and reload the original data via `loadData`. */
968
- reset: () => void;
969
- };
970
962
  /**
971
963
  * A single row in the submit result, with orthogonal flags describing its state.
972
964
  *
@@ -1004,14 +996,13 @@ type DataEditorSourceResult<TRow extends DataEditorRow = DataEditorRow> = {
1004
996
  *
1005
997
  * @example
1006
998
  * ```ts
1007
- * onComplete={async (result, actions) => {
999
+ * onComplete={async (result) => {
1008
1000
  * for (const source of result.sources) {
1009
1001
  * const inserts = source.rows.filter(r => r.isNew && !r.isDeleted && r.isValid);
1010
1002
  * const updates = source.rows.filter(r => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
1011
1003
  * const deletes = source.rows.filter(r => r.isDeleted && !r.isNew);
1012
1004
  * await persist(source.sourceId, { inserts, updates, deletes });
1013
1005
  * }
1014
- * actions.reset();
1015
1006
  * }}
1016
1007
  * ```
1017
1008
  */
@@ -1148,22 +1139,21 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
1148
1139
  loadData?: (onChunk: (rows: TRow[], options?: ChunkSourceOptions) => void) => Promise<void>;
1149
1140
  /**
1150
1141
  * Called when the user clicks "Submit". Receives the edited data grouped
1151
- * by source. Use `actions.reset()` to clear changes after a successful save.
1142
+ * by source. May return a promise.
1152
1143
  *
1153
1144
  * @example
1154
1145
  * ```ts
1155
- * onComplete={async (result, actions) => {
1146
+ * onComplete={async (result) => {
1156
1147
  * for (const source of result.sources) {
1157
1148
  * const inserts = source.rows.filter(r => r.isNew && !r.isDeleted && r.isValid);
1158
1149
  * const updates = source.rows.filter(r => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
1159
1150
  * const deletes = source.rows.filter(r => r.isDeleted && !r.isNew);
1160
1151
  * await persist(source.sourceId, { inserts, updates, deletes });
1161
1152
  * }
1162
- * actions.reset();
1163
1153
  * }}
1164
1154
  * ```
1165
1155
  */
1166
- onComplete?: (result: DataEditorResult<TRow>, actions: DataEditorActions) => void;
1156
+ onComplete?: (result: DataEditorResult<TRow>) => void | Promise<void>;
1167
1157
  /**
1168
1158
  * Controls the initial view. `"editor"` opens directly to the spreadsheet
1169
1159
  * grid. `"uploader"` opens the file import wizard first — the user uploads
@@ -1231,7 +1221,7 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
1231
1221
  */
1232
1222
  rtl?: boolean;
1233
1223
  /**
1234
- * Allow creating new columns for unmatched CSV headers during import. When
1224
+ * Allow creating new columns for unmatched headers during import. When
1235
1225
  * enabled, users can keep data from columns that don't match your schema by
1236
1226
  * creating dynamic columns on the fly.
1237
1227
  * @default true
@@ -1368,7 +1358,7 @@ type DataEditorInlineProps<TRow extends DataEditorRow = DataEditorRow> = DataEdi
1368
1358
  * columns={columns}
1369
1359
  * primaryKey="id"
1370
1360
  * loadData={async (onChunk) => onChunk(await fetchRows())}
1371
- * onComplete={(result, actions) => { saveChanges(result); actions.reset(); }}
1361
+ * onComplete={async (result) => { await saveChanges(result); }}
1372
1362
  * />
1373
1363
  *
1374
1364
  * // Inline mode
@@ -1378,7 +1368,7 @@ type DataEditorInlineProps<TRow extends DataEditorRow = DataEditorRow> = DataEdi
1378
1368
  * columns={columns}
1379
1369
  * primaryKey="id"
1380
1370
  * loadData={async (onChunk) => onChunk(await fetchRows())}
1381
- * onComplete={(result, actions) => { saveChanges(result); actions.reset(); }}
1371
+ * onComplete={async (result) => { await saveChanges(result); }}
1382
1372
  * />
1383
1373
  * ```
1384
1374
  */
@@ -1409,9 +1399,8 @@ type Props = DataEditorProps;
1409
1399
  * onChunk(rows);
1410
1400
  * };
1411
1401
  *
1412
- * editor.onComplete = (result, actions) => {
1413
- * console.log("Valid rows:", result.valid);
1414
- * actions.reset();
1402
+ * editor.onComplete = async (result) => {
1403
+ * await save(result);
1415
1404
  * };
1416
1405
  *
1417
1406
  * editor.addEventListener("close", () => editor.hide());
package/index.js CHANGED
@@ -25232,49 +25232,53 @@ async function Mv(e) {
25232
25232
  }
25233
25233
  //#endregion
25234
25234
  //#region src/components/DataEditor/ConfirmCompleteDialog/index.tsx
25235
- var Nv = ({ open: e, onClose: t, onConfirm: n }) => {
25236
- let { store: r } = Bd(), { t: i } = k(), { newRowCount: a, dirtyRowCount: o, deletedRowCount: s, errorCount: c } = nl(r), l = o - a, u = c > 0;
25235
+ var Nv = ({ open: e, onClose: t, onConfirm: n, loading: r = !1 }) => {
25236
+ let { store: i } = Bd(), { t: a } = k(), { newRowCount: o, dirtyRowCount: s, deletedRowCount: c, errorCount: l } = nl(i), u = s - o, d = l > 0;
25237
25237
  return /* @__PURE__ */ (0, E.jsxs)(fs, {
25238
25238
  open: e,
25239
- onOpenChange: t,
25240
- title: i("dataEditor.confirmSubmit.title"),
25239
+ onOpenChange: (0, _.useCallback)((e) => {
25240
+ r || e || t();
25241
+ }, [r, t]),
25242
+ title: a("dataEditor.confirmSubmit.title"),
25241
25243
  className: "updog__confirm-complete-dialog",
25242
25244
  children: [/* @__PURE__ */ (0, E.jsxs)(us, {
25243
25245
  className: "updog__confirm-complete-dialog__body",
25244
25246
  children: [
25245
- /* @__PURE__ */ (0, E.jsx)(W, { children: i("dataEditor.confirmSubmit.text") }),
25247
+ /* @__PURE__ */ (0, E.jsx)(W, { children: a("dataEditor.confirmSubmit.text") }),
25246
25248
  /* @__PURE__ */ (0, E.jsxs)("ul", {
25247
25249
  className: "updog__confirm-complete-dialog__list",
25248
25250
  children: [
25249
- a > 0 && /* @__PURE__ */ (0, E.jsx)(W, {
25251
+ o > 0 && /* @__PURE__ */ (0, E.jsx)(W, {
25250
25252
  as: "li",
25251
- children: i("dataEditor.confirmSubmit.createRows", { count: a })
25253
+ children: a("dataEditor.confirmSubmit.createRows", { count: o })
25252
25254
  }),
25253
- l > 0 && /* @__PURE__ */ (0, E.jsx)(W, {
25255
+ u > 0 && /* @__PURE__ */ (0, E.jsx)(W, {
25254
25256
  as: "li",
25255
- children: i("dataEditor.confirmSubmit.updateRows", { count: l })
25257
+ children: a("dataEditor.confirmSubmit.updateRows", { count: u })
25256
25258
  }),
25257
- s > 0 && /* @__PURE__ */ (0, E.jsx)(W, {
25259
+ c > 0 && /* @__PURE__ */ (0, E.jsx)(W, {
25258
25260
  as: "li",
25259
- children: i("dataEditor.confirmSubmit.deleteRows", { count: s })
25261
+ children: a("dataEditor.confirmSubmit.deleteRows", { count: c })
25260
25262
  })
25261
25263
  ]
25262
25264
  }),
25263
- u && /* @__PURE__ */ (0, E.jsx)(Ke, {
25265
+ d && /* @__PURE__ */ (0, E.jsx)(Ke, {
25264
25266
  color: "yellow",
25265
- text: i("dataEditor.confirmSubmit.bannerTitle", { count: c })
25267
+ text: a("dataEditor.confirmSubmit.bannerTitle", { count: l })
25266
25268
  })
25267
25269
  ]
25268
25270
  }), /* @__PURE__ */ (0, E.jsxs)(ds, { children: [/* @__PURE__ */ (0, E.jsx)(tt, {
25269
25271
  variant: "outlined",
25270
25272
  color: "neutral",
25271
25273
  onClick: t,
25272
- children: i("dataEditor.common.cancel")
25274
+ disabled: r,
25275
+ children: a("dataEditor.common.cancel")
25273
25276
  }), /* @__PURE__ */ (0, E.jsx)(tt, {
25274
25277
  onClick: n,
25275
25278
  variant: "filled",
25276
25279
  color: "primary",
25277
- children: i("dataEditor.confirmSubmit.action")
25280
+ loading: r,
25281
+ children: a("dataEditor.confirmSubmit.action")
25278
25282
  })] })]
25279
25283
  });
25280
25284
  }, Pv = () => {
@@ -25293,67 +25297,74 @@ var Nv = ({ open: e, onClose: t, onConfirm: n }) => {
25293
25297
  })
25294
25298
  });
25295
25299
  }, Fv = () => {
25296
- let { store: e, columns: t, onComplete: n, exportFormats: r, readonly: i, navigateToCell: a } = Bd(), { t: o, rtl: s } = k(), { canUndo: c, canRedo: l, undo: u, redo: d } = dl(e, a), { dirtyRowCount: f, deletedRowCount: p, isLoading: m, sources: h, phase: g } = nl(e), v = f > 0 || p > 0, y = m || h.some((e) => e.isLoading), b = g === "processing", [x, S] = (0, _.useState)(!1), { value: C, setTrue: w, setFalse: T } = el(!1), D = (0, _.useCallback)(() => {
25297
- n && (n(e.getResultBySource(), { reset: () => e.clear() }), T());
25300
+ let { store: e, columns: t, onComplete: n, exportFormats: r, readonly: i, navigateToCell: a } = Bd(), { t: o, rtl: s } = k(), { canUndo: c, canRedo: l, undo: u, redo: d } = dl(e, a), { dirtyRowCount: f, deletedRowCount: p, isLoading: m, sources: h, phase: g } = nl(e), v = f > 0 || p > 0, y = m || h.some((e) => e.isLoading), b = g === "processing", [x, S] = (0, _.useState)(!1), { value: C, setTrue: w, setFalse: T } = el(!1), [D, O] = (0, _.useState)(!1), A = (0, _.useCallback)(async () => {
25301
+ if (!n) return;
25302
+ let t = e.getResultBySource();
25303
+ O(!0);
25304
+ try {
25305
+ await n(t), e.clear(), T();
25306
+ } catch {} finally {
25307
+ O(!1);
25308
+ }
25298
25309
  }, [
25299
25310
  e,
25300
25311
  n,
25301
25312
  T
25302
- ]), O = o("dataEditor.footer.export"), A = o("dataEditor.footer.exportAll"), j = o("dataEditor.footer.exportFiltered"), M = o("dataEditor.footer.csvFormat"), N = o("dataEditor.footer.excelFormat"), P = o("dataEditor.footer.jsonFormat"), F = o("dataEditor.footer.tsvFormat"), I = o("dataEditor.footer.xmlFormat"), L = (0, _.useMemo)(() => [
25313
+ ]), j = o("dataEditor.footer.export"), M = o("dataEditor.footer.exportAll"), N = o("dataEditor.footer.exportFiltered"), P = o("dataEditor.footer.csvFormat"), F = o("dataEditor.footer.excelFormat"), I = o("dataEditor.footer.jsonFormat"), L = o("dataEditor.footer.tsvFormat"), R = o("dataEditor.footer.xmlFormat"), z = (0, _.useMemo)(() => [
25303
25314
  {
25304
25315
  menuId: "csv",
25305
25316
  format: "csv",
25306
- text: M
25317
+ text: P
25307
25318
  },
25308
25319
  {
25309
25320
  menuId: "tsv",
25310
25321
  format: "tsv",
25311
- text: F
25322
+ text: L
25312
25323
  },
25313
25324
  {
25314
25325
  menuId: "excel",
25315
25326
  format: "xlsx",
25316
- text: N
25327
+ text: F
25317
25328
  },
25318
25329
  {
25319
25330
  menuId: "json",
25320
25331
  format: "json",
25321
- text: P
25332
+ text: I
25322
25333
  },
25323
25334
  {
25324
25335
  menuId: "xml",
25325
25336
  format: "xml",
25326
- text: I
25337
+ text: R
25327
25338
  }
25328
25339
  ], [
25329
- M,
25330
- F,
25331
- N,
25332
25340
  P,
25333
- I
25334
- ]), R = r.length > 0 && (!e.isServer() || e.hasServerExport), z = (0, _.useMemo)(() => {
25335
- let e = L.filter((e) => r.includes(e.format));
25341
+ L,
25342
+ F,
25343
+ I,
25344
+ R
25345
+ ]), B = r.length > 0 && (!e.isServer() || e.hasServerExport), V = (0, _.useMemo)(() => {
25346
+ let e = z.filter((e) => r.includes(e.format));
25336
25347
  return [{
25337
25348
  id: "export-all",
25338
- text: A,
25349
+ text: M,
25339
25350
  options: e.map((e) => ({
25340
25351
  id: `all-${e.menuId}`,
25341
25352
  text: e.text
25342
25353
  }))
25343
25354
  }, {
25344
25355
  id: "export-filtered",
25345
- text: j,
25356
+ text: N,
25346
25357
  options: e.map((e) => ({
25347
25358
  id: `filtered-${e.menuId}`,
25348
25359
  text: e.text
25349
25360
  }))
25350
25361
  }];
25351
25362
  }, [
25352
- A,
25353
- j,
25354
- L,
25363
+ M,
25364
+ N,
25365
+ z,
25355
25366
  r
25356
- ]), B = (0, _.useCallback)((n) => {
25367
+ ]), H = (0, _.useCallback)((n) => {
25357
25368
  let [r, i] = n.split("-"), a = {
25358
25369
  csv: "csv",
25359
25370
  tsv: "tsv",
@@ -25372,7 +25383,7 @@ var Nv = ({ open: e, onClose: t, onConfirm: n }) => {
25372
25383
  e,
25373
25384
  t,
25374
25385
  s
25375
- ]), V = o("dataEditor.footer.submit");
25386
+ ]), U = o("dataEditor.footer.submit");
25376
25387
  return /* @__PURE__ */ (0, E.jsxs)(E.Fragment, { children: [/* @__PURE__ */ (0, E.jsxs)("footer", {
25377
25388
  className: "updog__data-editor-footer",
25378
25389
  children: [/* @__PURE__ */ (0, E.jsx)(Pv, {}), /* @__PURE__ */ (0, E.jsxs)("div", {
@@ -25399,9 +25410,9 @@ var Nv = ({ open: e, onClose: t, onConfirm: n }) => {
25399
25410
  children: /* @__PURE__ */ (0, E.jsx)(ke, { className: "rtl-mirror" })
25400
25411
  })
25401
25412
  })] }),
25402
- R && /* @__PURE__ */ (0, E.jsx)(rc, {
25403
- options: z,
25404
- onSelect: B,
25413
+ B && /* @__PURE__ */ (0, E.jsx)(rc, {
25414
+ options: V,
25415
+ onSelect: H,
25405
25416
  placement: "top-end",
25406
25417
  children: /* @__PURE__ */ (0, E.jsx)(tt, {
25407
25418
  variant: "outlined",
@@ -25410,20 +25421,21 @@ var Nv = ({ open: e, onClose: t, onConfirm: n }) => {
25410
25421
  disabled: y || b,
25411
25422
  spinnerPosition: "end",
25412
25423
  endIcon: /* @__PURE__ */ (0, E.jsx)(ie, {}),
25413
- children: O
25424
+ children: j
25414
25425
  })
25415
25426
  }),
25416
25427
  !i && /* @__PURE__ */ (0, E.jsx)(tt, {
25417
- disabled: !v || b,
25428
+ disabled: !v || b || D,
25418
25429
  onClick: w,
25419
- children: V
25430
+ children: U
25420
25431
  })
25421
25432
  ]
25422
25433
  })]
25423
25434
  }), /* @__PURE__ */ (0, E.jsx)(Nv, {
25424
25435
  open: C,
25425
25436
  onClose: T,
25426
- onConfirm: D
25437
+ onConfirm: A,
25438
+ loading: D
25427
25439
  })] });
25428
25440
  }, Iv = ({ initialValues: e, existingNames: t, onClose: n, onSubmit: r }) => {
25429
25441
  let { t: i } = k(), a = e.id !== void 0, o = (0, _.useMemo)(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@updog/data-editor-wc",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Client-side CSV importer and spreadsheet editor SDK as a Web Component. Drop into Vue, Angular, Svelte, or vanilla JS. Import CSV, Excel, JSON; edit 1M+ rows entirely in the browser.",
5
5
  "author": "Mikhail Kutateladze <admin@updog.tech>",
6
6
  "homepage": "https://updog.tech",