@updog/data-editor 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.
- package/README.md +4 -10
- package/index.d.ts +8 -18
- package/index.js +55 -43
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,14 +62,13 @@ export function App() {
|
|
|
62
62
|
const res = await fetch("/api/employees");
|
|
63
63
|
onChunk(await res.json());
|
|
64
64
|
}}
|
|
65
|
-
onComplete={async (result
|
|
65
|
+
onComplete={async (result) => {
|
|
66
66
|
for (const source of result.sources) {
|
|
67
67
|
const inserts = source.rows.filter((r) => r.isNew && !r.isDeleted && r.isValid);
|
|
68
68
|
const updates = source.rows.filter((r) => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
|
|
69
69
|
const deletes = source.rows.filter((r) => r.isDeleted && !r.isNew);
|
|
70
70
|
await persist(source.sourceId, { inserts, updates, deletes });
|
|
71
71
|
}
|
|
72
|
-
actions.reset();
|
|
73
72
|
setOpen(false);
|
|
74
73
|
}}
|
|
75
74
|
/>
|
|
@@ -121,7 +120,7 @@ In inline mode, `open` and `onClose` don't apply.
|
|
|
121
120
|
| `open` | `boolean` | Modal only | — | Controlled modal visibility. |
|
|
122
121
|
| `onClose` | `() => void` | Modal only | — | Called when the user closes the modal (X button or Escape). |
|
|
123
122
|
| `loadData` | `(onChunk) => Promise<void>` | No | — | Async data loader. Stream rows in chunks, optionally tagged by source. |
|
|
124
|
-
| `onComplete` | `(result
|
|
123
|
+
| `onComplete` | `(result) => void \| Promise<void>` | No | — | Called on submit. See [Submission Result](#submission-result). |
|
|
125
124
|
| `variant` | `"editor"` \| `"uploader"` | No | `"editor"` | Initial view. `"uploader"` opens the import wizard first. |
|
|
126
125
|
| `translations` | `DataEditorTranslations` | No | — | Partial i18n overrides. |
|
|
127
126
|
| `locale` | `string` | No | `"en"` | BCP 47 locale tag. |
|
|
@@ -263,7 +262,7 @@ loadData={async (onChunk) => {
|
|
|
263
262
|
|
|
264
263
|
## Submission Result
|
|
265
264
|
|
|
266
|
-
`onComplete(result
|
|
265
|
+
`onComplete(result)` fires when the user submits. May return a promise.
|
|
267
266
|
|
|
268
267
|
```ts
|
|
269
268
|
type DataEditorResult<TRow> = {
|
|
@@ -280,23 +279,18 @@ type DataEditorResult<TRow> = {
|
|
|
280
279
|
}[];
|
|
281
280
|
counts: { new: number; changed: number; deleted: number; invalid: number };
|
|
282
281
|
};
|
|
283
|
-
|
|
284
|
-
type DataEditorActions = {
|
|
285
|
-
reset: () => void; // discard changes and reload via loadData
|
|
286
|
-
};
|
|
287
282
|
```
|
|
288
283
|
|
|
289
284
|
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:
|
|
290
285
|
|
|
291
286
|
```tsx
|
|
292
|
-
onComplete={async (result
|
|
287
|
+
onComplete={async (result) => {
|
|
293
288
|
for (const source of result.sources) {
|
|
294
289
|
const inserts = source.rows.filter((r) => r.isNew && !r.isDeleted && r.isValid);
|
|
295
290
|
const updates = source.rows.filter((r) => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
|
|
296
291
|
const deletes = source.rows.filter((r) => r.isDeleted && !r.isNew);
|
|
297
292
|
await persist(source.sourceId, { inserts, updates, deletes });
|
|
298
293
|
}
|
|
299
|
-
actions.reset();
|
|
300
294
|
}}
|
|
301
295
|
```
|
|
302
296
|
|
package/index.d.ts
CHANGED
|
@@ -2606,14 +2606,6 @@ type UndoRedoResult = {
|
|
|
2606
2606
|
success: boolean;
|
|
2607
2607
|
targetCell?: CellLocation;
|
|
2608
2608
|
};
|
|
2609
|
-
/**
|
|
2610
|
-
* Actions available inside the `onComplete` callback. Call `reset()` after a
|
|
2611
|
-
* successful save to clear the editor and re-fetch via `loadData`.
|
|
2612
|
-
*/
|
|
2613
|
-
type DataEditorActions = {
|
|
2614
|
-
/** Discard all changes and reload the original data via `loadData`. */
|
|
2615
|
-
reset: () => void;
|
|
2616
|
-
};
|
|
2617
2609
|
/**
|
|
2618
2610
|
* A single row in the submit result, with orthogonal flags describing its state.
|
|
2619
2611
|
*
|
|
@@ -2651,14 +2643,13 @@ type DataEditorSourceResult<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2651
2643
|
*
|
|
2652
2644
|
* @example
|
|
2653
2645
|
* ```ts
|
|
2654
|
-
* onComplete={async (result
|
|
2646
|
+
* onComplete={async (result) => {
|
|
2655
2647
|
* for (const source of result.sources) {
|
|
2656
2648
|
* const inserts = source.rows.filter(r => r.isNew && !r.isDeleted && r.isValid);
|
|
2657
2649
|
* const updates = source.rows.filter(r => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
|
|
2658
2650
|
* const deletes = source.rows.filter(r => r.isDeleted && !r.isNew);
|
|
2659
2651
|
* await persist(source.sourceId, { inserts, updates, deletes });
|
|
2660
2652
|
* }
|
|
2661
|
-
* actions.reset();
|
|
2662
2653
|
* }}
|
|
2663
2654
|
* ```
|
|
2664
2655
|
*/
|
|
@@ -2847,22 +2838,21 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2847
2838
|
loadData?: (onChunk: (rows: TRow[], options?: ChunkSourceOptions) => void) => Promise<void>;
|
|
2848
2839
|
/**
|
|
2849
2840
|
* Called when the user clicks "Submit". Receives the edited data grouped
|
|
2850
|
-
* by source.
|
|
2841
|
+
* by source. May return a promise.
|
|
2851
2842
|
*
|
|
2852
2843
|
* @example
|
|
2853
2844
|
* ```ts
|
|
2854
|
-
* onComplete={async (result
|
|
2845
|
+
* onComplete={async (result) => {
|
|
2855
2846
|
* for (const source of result.sources) {
|
|
2856
2847
|
* const inserts = source.rows.filter(r => r.isNew && !r.isDeleted && r.isValid);
|
|
2857
2848
|
* const updates = source.rows.filter(r => !r.isNew && r.isChanged && !r.isDeleted && r.isValid);
|
|
2858
2849
|
* const deletes = source.rows.filter(r => r.isDeleted && !r.isNew);
|
|
2859
2850
|
* await persist(source.sourceId, { inserts, updates, deletes });
|
|
2860
2851
|
* }
|
|
2861
|
-
* actions.reset();
|
|
2862
2852
|
* }}
|
|
2863
2853
|
* ```
|
|
2864
2854
|
*/
|
|
2865
|
-
onComplete?: (result: DataEditorResult<TRow
|
|
2855
|
+
onComplete?: (result: DataEditorResult<TRow>) => void | Promise<void>;
|
|
2866
2856
|
/**
|
|
2867
2857
|
* Controls the initial view. `"editor"` opens directly to the spreadsheet
|
|
2868
2858
|
* grid. `"uploader"` opens the file import wizard first — the user uploads
|
|
@@ -2930,7 +2920,7 @@ type DataEditorBaseProps<TRow extends DataEditorRow = DataEditorRow> = {
|
|
|
2930
2920
|
*/
|
|
2931
2921
|
rtl?: boolean;
|
|
2932
2922
|
/**
|
|
2933
|
-
* Allow creating new columns for unmatched
|
|
2923
|
+
* Allow creating new columns for unmatched headers during import. When
|
|
2934
2924
|
* enabled, users can keep data from columns that don't match your schema by
|
|
2935
2925
|
* creating dynamic columns on the fly.
|
|
2936
2926
|
* @default true
|
|
@@ -3072,7 +3062,7 @@ type DataEditorInlineProps<TRow extends DataEditorRow = DataEditorRow> = DataEdi
|
|
|
3072
3062
|
* columns={columns}
|
|
3073
3063
|
* primaryKey="id"
|
|
3074
3064
|
* loadData={async (onChunk) => onChunk(await fetchRows())}
|
|
3075
|
-
* onComplete={(result
|
|
3065
|
+
* onComplete={async (result) => { await saveChanges(result); }}
|
|
3076
3066
|
* />
|
|
3077
3067
|
*
|
|
3078
3068
|
* // Inline mode
|
|
@@ -3082,7 +3072,7 @@ type DataEditorInlineProps<TRow extends DataEditorRow = DataEditorRow> = DataEdi
|
|
|
3082
3072
|
* columns={columns}
|
|
3083
3073
|
* primaryKey="id"
|
|
3084
3074
|
* loadData={async (onChunk) => onChunk(await fetchRows())}
|
|
3085
|
-
* onComplete={(result
|
|
3075
|
+
* onComplete={async (result) => { await saveChanges(result); }}
|
|
3086
3076
|
* />
|
|
3087
3077
|
* ```
|
|
3088
3078
|
*/
|
|
@@ -3133,7 +3123,7 @@ declare function exportDataEditor<TRow extends DataEditorRow>(params: ExportPara
|
|
|
3133
3123
|
* primaryKey="id"
|
|
3134
3124
|
* server={{ url: scaleUrl }}
|
|
3135
3125
|
* loadData={async (onChunk) => onChunk(await fetchRows())}
|
|
3136
|
-
* onComplete={(result
|
|
3126
|
+
* onComplete={async (result) => { await saveChanges(result); }}
|
|
3137
3127
|
* />
|
|
3138
3128
|
* ```
|
|
3139
3129
|
*/
|
package/index.js
CHANGED
|
@@ -13017,49 +13017,53 @@ async function Lh(e) {
|
|
|
13017
13017
|
}
|
|
13018
13018
|
//#endregion
|
|
13019
13019
|
//#region src/components/DataEditor/ConfirmCompleteDialog/index.tsx
|
|
13020
|
-
var Rh = ({ open: e, onClose: t, onConfirm: n }) => {
|
|
13021
|
-
let { store:
|
|
13020
|
+
var Rh = ({ open: e, onClose: t, onConfirm: n, loading: r = !1 }) => {
|
|
13021
|
+
let { store: i } = X(), { t: a } = q(), { newRowCount: o, dirtyRowCount: s, deletedRowCount: c, errorCount: l } = Mo(i), u = s - o, d = l > 0;
|
|
13022
13022
|
return /* @__PURE__ */ w(Vi, {
|
|
13023
13023
|
open: e,
|
|
13024
|
-
onOpenChange:
|
|
13025
|
-
|
|
13024
|
+
onOpenChange: f((e) => {
|
|
13025
|
+
r || e || t();
|
|
13026
|
+
}, [r, t]),
|
|
13027
|
+
title: a("dataEditor.confirmSubmit.title"),
|
|
13026
13028
|
className: "updog__confirm-complete-dialog",
|
|
13027
13029
|
children: [/* @__PURE__ */ w(zi, {
|
|
13028
13030
|
className: "updog__confirm-complete-dialog__body",
|
|
13029
13031
|
children: [
|
|
13030
|
-
/* @__PURE__ */ C(J, { children:
|
|
13032
|
+
/* @__PURE__ */ C(J, { children: a("dataEditor.confirmSubmit.text") }),
|
|
13031
13033
|
/* @__PURE__ */ w("ul", {
|
|
13032
13034
|
className: "updog__confirm-complete-dialog__list",
|
|
13033
13035
|
children: [
|
|
13034
|
-
|
|
13036
|
+
o > 0 && /* @__PURE__ */ C(J, {
|
|
13035
13037
|
as: "li",
|
|
13036
|
-
children:
|
|
13038
|
+
children: a("dataEditor.confirmSubmit.createRows", { count: o })
|
|
13037
13039
|
}),
|
|
13038
|
-
|
|
13040
|
+
u > 0 && /* @__PURE__ */ C(J, {
|
|
13039
13041
|
as: "li",
|
|
13040
|
-
children:
|
|
13042
|
+
children: a("dataEditor.confirmSubmit.updateRows", { count: u })
|
|
13041
13043
|
}),
|
|
13042
|
-
|
|
13044
|
+
c > 0 && /* @__PURE__ */ C(J, {
|
|
13043
13045
|
as: "li",
|
|
13044
|
-
children:
|
|
13046
|
+
children: a("dataEditor.confirmSubmit.deleteRows", { count: c })
|
|
13045
13047
|
})
|
|
13046
13048
|
]
|
|
13047
13049
|
}),
|
|
13048
|
-
|
|
13050
|
+
d && /* @__PURE__ */ C(ti, {
|
|
13049
13051
|
color: "yellow",
|
|
13050
|
-
text:
|
|
13052
|
+
text: a("dataEditor.confirmSubmit.bannerTitle", { count: l })
|
|
13051
13053
|
})
|
|
13052
13054
|
]
|
|
13053
13055
|
}), /* @__PURE__ */ w(Bi, { children: [/* @__PURE__ */ C(Y, {
|
|
13054
13056
|
variant: "outlined",
|
|
13055
13057
|
color: "neutral",
|
|
13056
13058
|
onClick: t,
|
|
13057
|
-
|
|
13059
|
+
disabled: r,
|
|
13060
|
+
children: a("dataEditor.common.cancel")
|
|
13058
13061
|
}), /* @__PURE__ */ C(Y, {
|
|
13059
13062
|
onClick: n,
|
|
13060
13063
|
variant: "filled",
|
|
13061
13064
|
color: "primary",
|
|
13062
|
-
|
|
13065
|
+
loading: r,
|
|
13066
|
+
children: a("dataEditor.confirmSubmit.action")
|
|
13063
13067
|
})] })]
|
|
13064
13068
|
});
|
|
13065
13069
|
}, zh = () => {
|
|
@@ -13078,67 +13082,74 @@ var Rh = ({ open: e, onClose: t, onConfirm: n }) => {
|
|
|
13078
13082
|
})
|
|
13079
13083
|
});
|
|
13080
13084
|
}, Bh = () => {
|
|
13081
|
-
let { store: e, columns: t, onComplete: n, exportFormats: r, readonly: i, navigateToCell: a } = X(), { t: o, rtl: s } = q(), { canUndo: c, canRedo: l, undo: u, redo: d } = Vo(e, a), { dirtyRowCount: p, deletedRowCount: m, isLoading: h, sources: g, phase: _ } = Mo(e), y = p > 0 || m > 0, x = h || g.some((e) => e.isLoading), T = _ === "processing", [E, D] = b(!1), { value: O, setTrue: k, setFalse: A } = Ao(!1), j = f(() => {
|
|
13082
|
-
|
|
13085
|
+
let { store: e, columns: t, onComplete: n, exportFormats: r, readonly: i, navigateToCell: a } = X(), { t: o, rtl: s } = q(), { canUndo: c, canRedo: l, undo: u, redo: d } = Vo(e, a), { dirtyRowCount: p, deletedRowCount: m, isLoading: h, sources: g, phase: _ } = Mo(e), y = p > 0 || m > 0, x = h || g.some((e) => e.isLoading), T = _ === "processing", [E, D] = b(!1), { value: O, setTrue: k, setFalse: A } = Ao(!1), [j, M] = b(!1), N = f(async () => {
|
|
13086
|
+
if (!n) return;
|
|
13087
|
+
let t = e.getResultBySource();
|
|
13088
|
+
M(!0);
|
|
13089
|
+
try {
|
|
13090
|
+
await n(t), e.clear(), A();
|
|
13091
|
+
} catch {} finally {
|
|
13092
|
+
M(!1);
|
|
13093
|
+
}
|
|
13083
13094
|
}, [
|
|
13084
13095
|
e,
|
|
13085
13096
|
n,
|
|
13086
13097
|
A
|
|
13087
|
-
]),
|
|
13098
|
+
]), P = o("dataEditor.footer.export"), F = o("dataEditor.footer.exportAll"), I = o("dataEditor.footer.exportFiltered"), L = o("dataEditor.footer.csvFormat"), z = o("dataEditor.footer.excelFormat"), B = o("dataEditor.footer.jsonFormat"), V = o("dataEditor.footer.tsvFormat"), H = o("dataEditor.footer.xmlFormat"), ee = v(() => [
|
|
13088
13099
|
{
|
|
13089
13100
|
menuId: "csv",
|
|
13090
13101
|
format: "csv",
|
|
13091
|
-
text:
|
|
13102
|
+
text: L
|
|
13092
13103
|
},
|
|
13093
13104
|
{
|
|
13094
13105
|
menuId: "tsv",
|
|
13095
13106
|
format: "tsv",
|
|
13096
|
-
text:
|
|
13107
|
+
text: V
|
|
13097
13108
|
},
|
|
13098
13109
|
{
|
|
13099
13110
|
menuId: "excel",
|
|
13100
13111
|
format: "xlsx",
|
|
13101
|
-
text:
|
|
13112
|
+
text: z
|
|
13102
13113
|
},
|
|
13103
13114
|
{
|
|
13104
13115
|
menuId: "json",
|
|
13105
13116
|
format: "json",
|
|
13106
|
-
text:
|
|
13117
|
+
text: B
|
|
13107
13118
|
},
|
|
13108
13119
|
{
|
|
13109
13120
|
menuId: "xml",
|
|
13110
13121
|
format: "xml",
|
|
13111
|
-
text:
|
|
13122
|
+
text: H
|
|
13112
13123
|
}
|
|
13113
13124
|
], [
|
|
13114
|
-
F,
|
|
13115
|
-
z,
|
|
13116
|
-
I,
|
|
13117
13125
|
L,
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13126
|
+
V,
|
|
13127
|
+
z,
|
|
13128
|
+
B,
|
|
13129
|
+
H
|
|
13130
|
+
]), U = r.length > 0 && (!e.isServer() || e.hasServerExport), te = v(() => {
|
|
13131
|
+
let e = ee.filter((e) => r.includes(e.format));
|
|
13121
13132
|
return [{
|
|
13122
13133
|
id: "export-all",
|
|
13123
|
-
text:
|
|
13134
|
+
text: F,
|
|
13124
13135
|
options: e.map((e) => ({
|
|
13125
13136
|
id: `all-${e.menuId}`,
|
|
13126
13137
|
text: e.text
|
|
13127
13138
|
}))
|
|
13128
13139
|
}, {
|
|
13129
13140
|
id: "export-filtered",
|
|
13130
|
-
text:
|
|
13141
|
+
text: I,
|
|
13131
13142
|
options: e.map((e) => ({
|
|
13132
13143
|
id: `filtered-${e.menuId}`,
|
|
13133
13144
|
text: e.text
|
|
13134
13145
|
}))
|
|
13135
13146
|
}];
|
|
13136
13147
|
}, [
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
|
|
13148
|
+
F,
|
|
13149
|
+
I,
|
|
13150
|
+
ee,
|
|
13140
13151
|
r
|
|
13141
|
-
]),
|
|
13152
|
+
]), ne = f((n) => {
|
|
13142
13153
|
let [r, i] = n.split("-"), a = {
|
|
13143
13154
|
csv: "csv",
|
|
13144
13155
|
tsv: "tsv",
|
|
@@ -13157,7 +13168,7 @@ var Rh = ({ open: e, onClose: t, onConfirm: n }) => {
|
|
|
13157
13168
|
e,
|
|
13158
13169
|
t,
|
|
13159
13170
|
s
|
|
13160
|
-
]),
|
|
13171
|
+
]), re = o("dataEditor.footer.submit");
|
|
13161
13172
|
return /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ w("footer", {
|
|
13162
13173
|
className: "updog__data-editor-footer",
|
|
13163
13174
|
children: [/* @__PURE__ */ C(zh, {}), /* @__PURE__ */ w("div", {
|
|
@@ -13184,9 +13195,9 @@ var Rh = ({ open: e, onClose: t, onConfirm: n }) => {
|
|
|
13184
13195
|
children: /* @__PURE__ */ C(Ce, { className: "rtl-mirror" })
|
|
13185
13196
|
})
|
|
13186
13197
|
})] }),
|
|
13187
|
-
|
|
13188
|
-
options:
|
|
13189
|
-
onSelect:
|
|
13198
|
+
U && /* @__PURE__ */ C(Ma, {
|
|
13199
|
+
options: te,
|
|
13200
|
+
onSelect: ne,
|
|
13190
13201
|
placement: "top-end",
|
|
13191
13202
|
children: /* @__PURE__ */ C(Y, {
|
|
13192
13203
|
variant: "outlined",
|
|
@@ -13195,20 +13206,21 @@ var Rh = ({ open: e, onClose: t, onConfirm: n }) => {
|
|
|
13195
13206
|
disabled: x || T,
|
|
13196
13207
|
spinnerPosition: "end",
|
|
13197
13208
|
endIcon: /* @__PURE__ */ C(R, {}),
|
|
13198
|
-
children:
|
|
13209
|
+
children: P
|
|
13199
13210
|
})
|
|
13200
13211
|
}),
|
|
13201
13212
|
!i && /* @__PURE__ */ C(Y, {
|
|
13202
|
-
disabled: !y || T,
|
|
13213
|
+
disabled: !y || T || j,
|
|
13203
13214
|
onClick: k,
|
|
13204
|
-
children:
|
|
13215
|
+
children: re
|
|
13205
13216
|
})
|
|
13206
13217
|
]
|
|
13207
13218
|
})]
|
|
13208
13219
|
}), /* @__PURE__ */ C(Rh, {
|
|
13209
13220
|
open: O,
|
|
13210
13221
|
onClose: A,
|
|
13211
|
-
onConfirm:
|
|
13222
|
+
onConfirm: N,
|
|
13223
|
+
loading: j
|
|
13212
13224
|
})] });
|
|
13213
13225
|
}, Vh = ({ initialValues: e, existingNames: t, onClose: n, onSubmit: r }) => {
|
|
13214
13226
|
let { t: i } = q(), a = e.id !== void 0, o = v(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@updog/data-editor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Client-side CSV importer and spreadsheet editor SDK for React. Import CSV, Excel, JSON, TSV, and XML, match columns, validate, and edit 1M+ rows entirely in the browser.",
|
|
5
5
|
"author": "Mikhail Kutateladze <admin@updog.tech>",
|
|
6
6
|
"homepage": "https://updog.tech",
|