@updog/data-editor-wc 0.1.17 → 0.1.19

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/LICENSE CHANGED
@@ -232,8 +232,10 @@ Sections 5, 8, 11, 12, and 14 survive termination of this License.
232
232
  --------------------------------------------------------------------------------
233
233
 
234
234
  This License shall be governed by and construed in accordance with the laws of
235
- the United Arab Emirates. Any disputes arising under this License shall be
236
- subject to the exclusive jurisdiction of the courts of the United Arab Emirates.
235
+ the Dubai International Financial Centre (DIFC), as applied by the DIFC Courts.
236
+ Any dispute arising out of or in connection with this License, including any
237
+ question regarding its existence, validity, or termination, shall be subject to
238
+ the exclusive jurisdiction of the courts of the DIFC.
237
239
 
238
240
  --------------------------------------------------------------------------------
239
241
  15. EXPORT COMPLIANCE
package/README.md CHANGED
@@ -45,7 +45,6 @@ How you wire the element into a framework (Angular's `CUSTOM_ELEMENTS_SCHEMA`, V
45
45
  <script type="module">
46
46
  import "@updog/data-editor-wc";
47
47
  import "@updog/data-editor-wc/styles.css";
48
- import { required, email } from "@updog/data-editor-wc";
49
48
 
50
49
  const editor = document.getElementById("editor");
51
50
 
@@ -53,9 +52,26 @@ How you wire the element into a framework (Angular's `CUSTOM_ELEMENTS_SCHEMA`, V
53
52
  apiKey: "your-license-key",
54
53
  primaryKey: "id",
55
54
  columns: [
56
- { id: "name", title: "Full Name", size: 200, validate: required("Name is required") },
57
- { id: "email", title: "Email", size: 250, validate: [required("Email is required"), email("Invalid email")] },
58
- { id: "role", title: "Role", editor: { type: "select", options: ["Admin", "Editor", "Viewer"] } },
55
+ {
56
+ id: "name",
57
+ title: "Full Name",
58
+ size: 200,
59
+ validators: [{ type: "required", message: "Name is required" }],
60
+ },
61
+ {
62
+ id: "email",
63
+ title: "Email",
64
+ size: 250,
65
+ validators: [
66
+ { type: "required", message: "Email is required" },
67
+ { type: "email", message: "Invalid email" },
68
+ ],
69
+ },
70
+ {
71
+ id: "role",
72
+ title: "Role",
73
+ editor: { type: "select", options: ["Admin", "Editor", "Viewer"] },
74
+ },
59
75
  ],
60
76
  loadData: async (onChunk) => {
61
77
  const res = await fetch("/api/employees");
@@ -190,16 +206,17 @@ editor.addEventListener("close", () => editor.hide());
190
206
  ## Column Configuration
191
207
 
192
208
  ```js
193
- import { required, email } from "@updog/data-editor-wc";
194
-
195
209
  editor.columns = [
196
210
  {
197
211
  id: "email",
198
212
  title: "Email",
199
213
  size: 260,
200
214
 
201
- // One validator, or an array. Each returns `{ level: "error", message }` or null.
202
- validate: [required("Email is required"), email("Enter a valid email")],
215
+ // Declarative validators. See "Built-in Validators" for the full list.
216
+ validators: [
217
+ { type: "required", message: "Email is required" },
218
+ { type: "email", message: "Enter a valid email" },
219
+ ],
203
220
 
204
221
  // Flag duplicates in this column as errors.
205
222
  unique: true,
@@ -231,36 +248,42 @@ editor.columns = [
231
248
 
232
249
  ## Built-in Validators
233
250
 
234
- Validators are factory functions call each one with the error message you want displayed.
251
+ Validators are declarative objects passed in the `validators` array on each column. The SDK ships a TS interpreter for the client; Updog Scale ships a matching Go interpreter for server mode. Both runtimes are pinned to the same fixture set, so a column definition produces identical pass/fail results regardless of where it runs.
235
252
 
236
- ```js
237
- import {
238
- required,
239
- numeric,
240
- email,
241
- date,
242
- oneOf,
243
- endDateAfterStart,
244
- } from "@updog/data-editor-wc";
253
+ | `type` | Fields | Behavior |
254
+ |---|---|---|
255
+ | `"required"` | `message?` | Value must be non-empty. |
256
+ | `"email"` | `message?` | Value must look like an email address. |
257
+ | `"numeric"` | `message?` | Value must parse as a number. Commas are stripped before parsing. |
258
+ | `"regex"` | `pattern`, `flags?`, `message?` | Value must match the regular expression. Empty values are skipped. |
259
+ | `"range"` | `min?`, `max?`, `message?` | Value must be numerically within `[min, max]`. Either bound is optional. |
260
+ | `"oneOf"` | `values: string[]`, `message?` | Value must be one of the listed strings. |
261
+ | `"date"` | `format?: "YYYY-MM-DD" \| "DD/MM/YYYY"`, `message?` | Value must parse as a date in the given format. When `format` is omitted, either format is accepted. |
245
262
 
263
+ ```js
246
264
  editor.columns = [
247
- { id: "name", title: "Name", validate: required("Required") },
248
- { id: "email", title: "Email", validate: [required("Required"), email("Invalid email")] },
249
- { id: "salary", title: "Salary", validate: numeric("Must be a number") },
250
- { id: "status", title: "Status", validate: oneOf(["active", "inactive"], "Invalid status") },
265
+ { id: "name", title: "Name", validators: [{ type: "required", message: "Required" }] },
266
+ {
267
+ id: "email",
268
+ title: "Email",
269
+ validators: [
270
+ { type: "required", message: "Required" },
271
+ { type: "email", message: "Invalid email" },
272
+ ],
273
+ },
274
+ { id: "salary", title: "Salary", validators: [{ type: "numeric", message: "Must be a number" }] },
275
+ {
276
+ id: "status",
277
+ title: "Status",
278
+ validators: [{ type: "oneOf", values: ["active", "inactive"], message: "Invalid status" }],
279
+ },
251
280
  {
252
281
  id: "startDate",
253
282
  title: "Start",
254
- validate: date("Use YYYY-MM-DD or DD/MM/YYYY"),
283
+ validators: [{ type: "date", format: "YYYY-MM-DD", message: "Use YYYY-MM-DD" }],
255
284
  editor: { type: "date" },
256
285
  dependentFields: ["endDate"],
257
286
  },
258
- {
259
- id: "endDate",
260
- title: "End",
261
- validate: [date("Invalid date"), endDateAfterStart("startDate", "End must be on or after start")],
262
- editor: { type: "date" },
263
- },
264
287
  ];
265
288
  ```
266
289
 
@@ -268,16 +291,32 @@ A `ValidationError` with `level: "error"` flags the cell in the grid but does **
268
291
 
269
292
  ### Custom validators
270
293
 
271
- A validator is `(value, row) => ValidationError | null`. The only `level` is `"error"`.
294
+ For cross-field checks or anything not covered by the built-ins, wrap a `(value, row) => ValidationError | null` function in `{ type: "function", fn }`. Function validators are client-mode only — they're dropped (with a one-time warning) when the SDK serializes the schema for server mode. Use `dependentFields` on the column to trigger re-validation when another column changes.
272
295
 
273
296
  ```js
274
- const mustContainAt = (value) => {
275
- if (!value) return null;
276
- if (!String(value).includes("@")) return { level: "error", message: "Must contain @" };
297
+ const endAfterStart = (value, row) => {
298
+ if (!value || !row.startDate) return null;
299
+ if (String(value) < String(row.startDate)) {
300
+ return { level: "error", message: "End must be on or after start" };
301
+ }
277
302
  return null;
278
303
  };
304
+
305
+ editor.columns = [
306
+ {
307
+ id: "endDate",
308
+ title: "End",
309
+ editor: { type: "date" },
310
+ validators: [
311
+ { type: "date", message: "Invalid date" },
312
+ { type: "function", fn: endAfterStart },
313
+ ],
314
+ },
315
+ ];
279
316
  ```
280
317
 
318
+ The only `level` is `"error"`. Return `null` to indicate the value is valid.
319
+
281
320
  ## Data Loading
282
321
 
283
322
  `loadData` is called once when the editor opens. Call `onChunk` one or more times to stream rows. The grid renders each chunk without blocking.
package/index.d.ts CHANGED
@@ -1427,18 +1427,20 @@ type UpdogEditorProps = Omit<Props, "onClose" | "className"> & {
1427
1427
  /** Close the editor modal. Same as setting `editor.open = false`. */
1428
1428
  hide(): void;
1429
1429
  };
1430
+ /**
1431
+ * The `<updog-editor>` custom element. A full-screen modal spreadsheet editor.
1432
+ *
1433
+ * Supports CSV/XLSX import, cell validation, undo/redo, find & replace, and exporting.
1434
+ * Works in any framework (Angular, Vue, vanilla JS) — no React needed.
1435
+ *
1436
+ * @see {@link UpdogEditorProps} for all available properties.
1437
+ */
1438
+ interface UpdogEditorElement extends HTMLElement, UpdogEditorProps {
1439
+ }
1430
1440
  declare global {
1431
- /**
1432
- * The `<updog-editor>` custom element. A full-screen modal spreadsheet editor.
1433
- *
1434
- * Supports CSV/XLSX import, cell validation, undo/redo, find & replace, and exporting.
1435
- * Works in any framework (Angular, Vue, vanilla JS) — no React needed.
1436
- *
1437
- * @see {@link UpdogEditorProps} for all available properties.
1438
- */
1439
- interface UpdogEditorElement extends HTMLElement, UpdogEditorProps {
1440
- }
1441
1441
  interface HTMLElementTagNameMap {
1442
1442
  "updog-editor": UpdogEditorElement;
1443
1443
  }
1444
1444
  }
1445
+
1446
+ export type { UpdogEditorElement, UpdogEditorProps };
package/index.js CHANGED
@@ -39027,17 +39027,27 @@ var dN = ({ source: e }) => {
39027
39027
  })]
39028
39028
  })
39029
39029
  }), xN = ({ filtersResetKey: e }) => {
39030
- let { store: t, scrollToGridTop: n } = Bd(), { t: r } = k(), { filteredErrorCount: i, errorMessageCounts: a } = nl(t), [o, s] = (0, _.useState)(() => new Set(t.getFilters().errorMessageFilters ?? []));
39030
+ let { store: t, scrollToGridTop: n } = Bd(), { t: r } = k(), { filteredErrorCount: i, errorMessageCounts: a } = nl(t), [o, s] = (0, _.useState)(() => new Set(t.getFilters().errorMessageFilters ?? [])), [c, l] = (0, _.useState)(!1);
39031
39031
  (0, _.useEffect)(() => {
39032
- s(new Set(t.getFilters().errorMessageFilters ?? []));
39032
+ s(new Set(t.getFilters().errorMessageFilters ?? [])), l(!1);
39033
39033
  }, [e, t]);
39034
- let c = Object.keys(a), l = c.length > 0 && c.every((e) => o.has(e)), u = c.some((e) => o.has(e)) && !l, d = (0, _.useCallback)((e) => {
39035
- s(e ? new Set(c) : /* @__PURE__ */ new Set()), n(), t.setFilters({ errorMessageFilters: e ? c : [] });
39034
+ let u = Object.keys(a), d = u.length > 0;
39035
+ (0, _.useEffect)(() => {
39036
+ !c || !d || (s(new Set(u)), t.setFilters({ errorMessageFilters: u }), l(!1));
39036
39037
  }, [
39037
39038
  c,
39039
+ d,
39040
+ u,
39041
+ t
39042
+ ]);
39043
+ let f = d && u.every((e) => o.has(e)), p = u.some((e) => o.has(e)), m = d ? f : c, h = d && p && !f, g = (0, _.useCallback)((e) => {
39044
+ l(e), d && (s(e ? new Set(u) : /* @__PURE__ */ new Set()), n(), t.setFilters({ errorMessageFilters: e ? u : [] }));
39045
+ }, [
39046
+ d,
39047
+ u,
39038
39048
  n,
39039
39049
  t
39040
- ]), f = (0, _.useCallback)((e, r) => {
39050
+ ]), v = (0, _.useCallback)((e, r) => {
39041
39051
  s((i) => {
39042
39052
  let a = new Set(i);
39043
39053
  return r ? a.add(e) : a.delete(e), t.setFilters({ errorMessageFilters: [...a] }), n(), a;
@@ -39049,9 +39059,9 @@ var dN = ({ source: e }) => {
39049
39059
  trigger: ({ toggle: e, isOpen: t }) => {
39050
39060
  let n = r(t ? "dataEditor.filters.showLess" : "dataEditor.filters.showMore");
39051
39061
  return /* @__PURE__ */ (0, E.jsx)(Tt, {
39052
- checked: l,
39053
- indeterminate: u,
39054
- onChange: d,
39062
+ checked: m,
39063
+ indeterminate: h,
39064
+ onChange: g,
39055
39065
  checkboxPosition: "start",
39056
39066
  children: /* @__PURE__ */ (0, E.jsxs)("div", {
39057
39067
  className: "updog__error-filter-section__checkbox-label",
@@ -39060,7 +39070,7 @@ var dN = ({ source: e }) => {
39060
39070
  className: "updog__error-filter-section__truncated",
39061
39071
  children: r("dataEditor.filters.rowsWithErrors")
39062
39072
  }),
39063
- c.length > 0 && /* @__PURE__ */ (0, E.jsx)(Ps, {
39073
+ u.length > 0 && /* @__PURE__ */ (0, E.jsx)(Ps, {
39064
39074
  content: n,
39065
39075
  children: /* @__PURE__ */ (0, E.jsx)(nt, {
39066
39076
  variant: "ghost",
@@ -39083,13 +39093,13 @@ var dN = ({ source: e }) => {
39083
39093
  })
39084
39094
  });
39085
39095
  },
39086
- content: c.length > 0 && /* @__PURE__ */ (0, E.jsx)("div", {
39096
+ content: u.length > 0 && /* @__PURE__ */ (0, E.jsx)("div", {
39087
39097
  className: "updog__error-filter-section__children",
39088
- children: c.map((e) => /* @__PURE__ */ (0, E.jsx)(bN, {
39098
+ children: u.map((e) => /* @__PURE__ */ (0, E.jsx)(bN, {
39089
39099
  message: e,
39090
39100
  count: a[e] ?? 0,
39091
39101
  checked: o.has(e),
39092
- onChange: f
39102
+ onChange: v
39093
39103
  }, e))
39094
39104
  })
39095
39105
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@updog/data-editor-wc",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
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",