antd-crud-table 0.7.0 → 0.8.0

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.
@@ -1,4 +1,4 @@
1
- import { t as e } from "./en_US-DGCMDOdX.js";
1
+ import { t as e } from "./en_US-DghHhwRq.js";
2
2
  import { message as t } from "antd";
3
3
  import { useCallback as n, useMemo as r, useRef as i, useState as a } from "react";
4
4
  //#region lib/core/identity.ts
@@ -138,56 +138,64 @@ var o = () => {
138
138
  updatedAt: n
139
139
  } : { updatedAt: n };
140
140
  }
141
- }, v = {
141
+ }, v = (e, t) => {
142
+ let n = t.toString();
143
+ return n === "" ? e : `${e}${e.includes("?") ? "&" : "?"}${n}`;
144
+ }, y = {
142
145
  list: "/list",
143
146
  create: "/create",
144
147
  update: "/update",
145
148
  remove: "/delete"
146
- }, y = {
149
+ }, b = {
147
150
  page: "current",
148
151
  pageSize: "pageSize",
149
152
  sortBy: "sortBy",
150
153
  sortOrder: "sortOrder"
151
- }, b = {
154
+ }, x = {
152
155
  create: "POST",
153
156
  update: "PUT",
154
157
  remove: "DELETE"
155
- }, x = class extends Error {
158
+ }, S = class extends Error {
156
159
  status;
157
160
  body;
158
161
  constructor(e, t, n) {
159
162
  super(`Request to ${n} failed with status ${e}`), this.name = "RestError", this.status = e, this.body = t;
160
163
  }
161
- }, S = class {
164
+ }, C = class {
162
165
  baseUrl;
163
166
  endpoints;
164
167
  paramNames;
165
168
  methods;
166
169
  headers;
170
+ query;
171
+ init;
172
+ configureRequest;
167
173
  serializeRequest;
168
174
  parseResponse;
175
+ parseRecord;
169
176
  fetchImpl;
170
177
  constructor(e = {}) {
171
178
  this.baseUrl = e.baseUrl ?? "", this.endpoints = {
172
- ...v,
179
+ ...y,
173
180
  ...e.endpoints
174
181
  }, this.paramNames = {
175
- ...y,
182
+ ...b,
176
183
  ...e.paramNames
177
184
  }, this.methods = {
178
- ...b,
185
+ ...x,
179
186
  ...e.methods
180
- }, this.headers = e.headers ?? {}, this.serializeRequest = e.serializeRequest ?? ((e) => e), this.parseResponse = e.parseResponse, this.fetchImpl = e.fetchImpl ?? globalThis.fetch.bind(globalThis);
187
+ }, this.headers = e.headers ?? {}, this.query = e.query ?? {}, this.init = e.init ?? {}, this.configureRequest = e.configureRequest, this.serializeRequest = e.serializeRequest ?? ((e) => e), this.parseResponse = e.parseResponse, this.parseRecord = e.parseRecord, this.fetchImpl = e.fetchImpl ?? globalThis.fetch.bind(globalThis);
181
188
  }
182
189
  serializeSort(e, t) {
183
190
  let n = e?.[0];
184
191
  n && (t.set(this.paramNames.sortBy, String(n.field)), t.set(this.paramNames.sortOrder, n.direction));
185
192
  }
193
+ serializeFilters(e, t) {
194
+ for (let [n, r] of Object.entries(e ?? {})) r != null && r !== "" && t.set(n, String(r));
195
+ }
186
196
  buildListUrl(e) {
187
197
  let t = new URLSearchParams();
188
- t.set(this.paramNames.page, String(e.page)), t.set(this.paramNames.pageSize, String(e.pageSize)), this.serializeSort(e.sort, t);
189
- for (let [n, r] of Object.entries(e.filters ?? {})) r != null && r !== "" && t.set(n, String(r));
190
- return `${this.endpoints.list}?${t.toString()}`;
198
+ return t.set(this.paramNames.page, String(e.page)), t.set(this.paramNames.pageSize, String(e.pageSize)), this.serializeSort(e.sort, t), this.serializeFilters(e.filters, t), v(this.endpoints.list, t);
191
199
  }
192
200
  buildRecordPath(e, t) {
193
201
  return `${e}/${encodeURIComponent(String(t))}`;
@@ -210,44 +218,73 @@ var o = () => {
210
218
  }
211
219
  throw Error("Unrecognised list response. Provide `parseResponse` to map it to { items, total }.");
212
220
  }
213
- async request(e, t = {}) {
214
- let n = `${this.baseUrl}${e}`, r = await this.fetchImpl(n, {
215
- ...t,
221
+ async request(e, t, n = {}) {
222
+ let r = await this.configureRequest?.(t) ?? {}, i = new URLSearchParams();
223
+ for (let [e, t] of Object.entries({
224
+ ...this.query,
225
+ ...r.query
226
+ })) i.set(e, String(t));
227
+ let a = v(`${this.baseUrl}${e}`, i), o = await this.fetchImpl(a, {
228
+ ...this.init,
229
+ ...r.init,
230
+ ...n,
231
+ method: r.method ?? n.method,
216
232
  headers: {
217
233
  "Content-Type": "application/json",
218
234
  ...this.headers,
219
- ...t.headers
235
+ ...r.headers,
236
+ ...n.headers
220
237
  }
221
238
  });
222
- if (!r.ok) throw new x(r.status, await r.text().catch(() => ""), n);
223
- if (r.status === 204) return;
224
- let i = await r.text();
225
- return i === "" ? void 0 : JSON.parse(i);
239
+ if (!o.ok) throw new S(o.status, await o.text().catch(() => ""), a);
240
+ if (o.status === 204) return;
241
+ let s = await o.text();
242
+ return s === "" ? void 0 : JSON.parse(s);
243
+ }
244
+ toRecord(e, t) {
245
+ return this.parseRecord ? this.parseRecord(e, t) : e;
226
246
  }
227
247
  async list(e) {
228
- return this.toPage(await this.request(this.buildListUrl(e)));
248
+ let t = {
249
+ operation: "list",
250
+ query: e
251
+ };
252
+ return this.toPage(await this.request(this.buildListUrl(e), t));
229
253
  }
230
254
  async create(e) {
231
- return await this.request(this.endpoints.create, {
255
+ let t = {
256
+ operation: "create",
257
+ draft: e
258
+ }, n = await this.request(this.endpoints.create, t, {
232
259
  method: this.methods.create,
233
- body: JSON.stringify(this.serializeRequest(e))
260
+ body: JSON.stringify(this.serializeRequest(e, t))
234
261
  });
262
+ return this.toRecord(n, t);
235
263
  }
236
264
  async update(e, t) {
237
- return await this.request(this.buildRecordPath(this.endpoints.update, e), {
265
+ let n = {
266
+ operation: "update",
267
+ id: e,
268
+ draft: t
269
+ }, r = await this.request(this.buildRecordPath(this.endpoints.update, e), n, {
238
270
  method: this.methods.update,
239
- body: JSON.stringify(this.serializeRequest(t))
271
+ body: JSON.stringify(this.serializeRequest(t, n))
240
272
  });
273
+ return this.toRecord(r, n);
241
274
  }
242
275
  async remove(e) {
243
- await this.request(this.buildRecordPath(this.endpoints.remove, e), { method: this.methods.remove });
276
+ let t = {
277
+ operation: "remove",
278
+ id: e
279
+ };
280
+ await this.request(this.buildRecordPath(this.endpoints.remove, e), t, { method: this.methods.remove });
244
281
  }
245
- }, C = class extends Error {
282
+ }, w = class extends Error {
246
283
  operation;
247
284
  constructor(e) {
248
285
  super(`This table's data source does not support "${e}". Provide an \`${e}\` operation to enable it.`), this.name = "UnsupportedOperationError", this.operation = e;
249
286
  }
250
- }, w = class {
287
+ }, T = class {
251
288
  operations;
252
289
  constructor(e) {
253
290
  this.operations = e;
@@ -256,40 +293,40 @@ var o = () => {
256
293
  return typeof this.operations[e] == "function";
257
294
  }
258
295
  async list(e) {
259
- if (!this.operations.list) throw new C("list");
296
+ if (!this.operations.list) throw new w("list");
260
297
  return this.operations.list(e);
261
298
  }
262
299
  async listAll(e) {
263
300
  if (this.operations.listAll) return this.operations.listAll(e);
264
- throw new C("listAll");
301
+ throw new w("listAll");
265
302
  }
266
303
  async create(e) {
267
- if (!this.operations.create) throw new C("create");
304
+ if (!this.operations.create) throw new w("create");
268
305
  return this.operations.create(e);
269
306
  }
270
307
  async update(e, t) {
271
- if (!this.operations.update) throw new C("update");
308
+ if (!this.operations.update) throw new w("update");
272
309
  return this.operations.update(e, t);
273
310
  }
274
311
  async remove(e) {
275
- if (!this.operations.remove) throw new C("remove");
312
+ if (!this.operations.remove) throw new w("remove");
276
313
  return this.operations.remove(e);
277
314
  }
278
- }, T = (e) => e instanceof Error ? e : Error(typeof e == "string" ? e : "Unknown error", { cause: e }), E = (e, t) => {
315
+ }, E = (e) => e instanceof Error ? e : Error(typeof e == "string" ? e : "Unknown error", { cause: e }), D = (e, t) => {
279
316
  if ("dataSource" in t) return t.dataSource;
280
- if ("operations" in t) return new w(t.operations);
317
+ if ("operations" in t) return new T(t.operations);
281
318
  if ("storageKey" in t) return new _(t.storageKey, e, t.initialData ?? [], t.generateId);
282
319
  if ("staticData" in t) return new g(t.staticData, e, t.generateId);
283
- if ("api" in t) return new S(t.api);
320
+ if ("api" in t) return new C(t.api);
284
321
  throw Error("useCrudTable: supply exactly one of `staticData`, `api`, `storageKey`, `operations` or `dataSource`.");
285
- }, D = (o, s) => {
322
+ }, O = (o, s) => {
286
323
  let c = i(void 0), { defaultPageSize: l = 10, optimisticUpdates: u = !1, refreshAfterMutation: d = !0, notifications: f = !0 } = s, p = r(() => s.locale ? {
287
324
  ...e,
288
325
  ...s.locale
289
326
  } : e, [s.locale]), m = i(s);
290
327
  m.current = s;
291
328
  let h = i(null);
292
- h.current === null && (h.current = E(o, s));
329
+ h.current === null && (h.current = D(o, s));
293
330
  let g = h.current, [_, v] = a({
294
331
  loading: !1,
295
332
  error: null,
@@ -319,7 +356,7 @@ var o = () => {
319
356
  loading: !1
320
357
  }));
321
358
  } catch (e) {
322
- let t = T(e);
359
+ let t = E(e);
323
360
  v((e) => ({
324
361
  ...e,
325
362
  loading: !1,
@@ -348,7 +385,7 @@ var o = () => {
348
385
  u,
349
386
  d,
350
387
  C
351
- ]), D = n(async (e) => {
388
+ ]), T = n(async (e) => {
352
389
  v((e) => ({
353
390
  ...e,
354
391
  loading: !0
@@ -365,7 +402,7 @@ var o = () => {
365
402
  return v((e) => ({
366
403
  ...e,
367
404
  loading: !1
368
- })), x("create", T(e)), null;
405
+ })), x("create", E(e)), null;
369
406
  }
370
407
  }, [
371
408
  g,
@@ -389,7 +426,7 @@ var o = () => {
389
426
  return v((e) => ({
390
427
  ...e,
391
428
  loading: !1
392
- })), x("update", T(e)), null;
429
+ })), x("update", E(e)), null;
393
430
  }
394
431
  }, [
395
432
  g,
@@ -414,7 +451,7 @@ var o = () => {
414
451
  return v((e) => ({
415
452
  ...e,
416
453
  loading: !1
417
- })), x("delete", T(e)), !1;
454
+ })), x("delete", E(e)), !1;
418
455
  }
419
456
  }, [
420
457
  g,
@@ -437,7 +474,7 @@ var o = () => {
437
474
  }, []);
438
475
  return r(() => ({
439
476
  refresh: C,
440
- create: D,
477
+ create: T,
441
478
  update: O,
442
479
  remove: k,
443
480
  dataSource: g,
@@ -447,7 +484,7 @@ var o = () => {
447
484
  actionRef: c
448
485
  }), [
449
486
  C,
450
- D,
487
+ T,
451
488
  O,
452
489
  k,
453
490
  g,
@@ -457,4 +494,4 @@ var o = () => {
457
494
  ]);
458
495
  };
459
496
  //#endregion
460
- export { S as a, g as c, p as d, m as f, o as h, C as i, h as l, c as m, D as n, x as o, f as p, w as r, _ as s, T as t, d as u };
497
+ export { C as a, g as c, p as d, m as f, o as h, w as i, h as l, c as m, O as n, S as o, f as p, T as r, _ as s, E as t, d as u };
@@ -0,0 +1 @@
1
+ const e=require("./en_US-Q8nDeJhg.cjs");let t=require("antd"),n=require("react");var r=()=>{let e=globalThis.crypto===void 0?void 0:globalThis.crypto;if(e&&typeof e.randomUUID==`function`)return e.randomUUID();let t=new Uint8Array(16);if(e&&typeof e.getRandomValues==`function`)e.getRandomValues(t);else for(let e=0;e<t.length;e+=1)t[e]=Math.floor(Math.random()*256);t[6]=t[6]&15|64,t[8]=t[8]&63|128;let n=Array.from(t,e=>e.toString(16).padStart(2,`0`)).join(``);return`${n.slice(0,8)}-${n.slice(8,12)}-${n.slice(12,16)}-${n.slice(16,20)}-${n.slice(20)}`},i=/^\d+$/,a=e=>t=>{let n=t.map(t=>t[e]).filter(e=>e!=null);if(n.length===0)return 1;if(n.every(e=>typeof e==`number`)){let e=Math.max(...n.filter(Number.isFinite));return(Number.isFinite(e)?e:0)+1}if(n.every(e=>typeof e==`string`)){let e=n;if(e.every(e=>i.test(e))){let t=Math.max(...e.map(Number));return String(t+1)}return r()}throw Error(`Cannot derive the next id for "${String(e)}": existing keys are neither all numbers nor all strings. Supply an explicit \`generateId\` to the data source.`)},o=(e,t)=>typeof e==`number`&&typeof t==`number`?e-t:typeof e==`boolean`&&typeof t==`boolean`?Number(e)-Number(t):e instanceof Date&&t instanceof Date?e.getTime()-t.getTime():String(e).localeCompare(String(t),void 0,{numeric:!0}),s=(e,t)=>e!=null&&String(e).toLowerCase().includes(String(t).toLowerCase()),c=(e,t)=>{if(!t)return e;let n=Object.entries(t).filter(([,e])=>e!=null&&e!==``);return n.length===0?e:e.filter(e=>n.every(([t,n])=>s(e[t],n)))},l=(e,t)=>!t||t.length===0?e:[...e].sort((e,n)=>{for(let{field:r,direction:i}of t){let t=e[r],a=n[r],s=t==null,c=a==null;if(s&&c)continue;if(s)return 1;if(c)return-1;let l=o(t,a);if(l!==0)return i===`ascend`?l:-l}return 0}),u=(e,t,n)=>{let r=Math.max(0,(t-1)*n);return e.slice(r,r+n)},d=(e,t)=>{let n=l(c(e,t.filters),t.sort);return{items:u(n,t.page,t.pageSize),total:n.length}},f=class{key;generateId;constructor(e,t){this.key=e,this.generateId=t??a(e)}decorate(e,t){return{}}indexOf(e){return this.read().findIndex(t=>t[this.key]===e)}async list(e){return d(this.read(),e)}async listAll(e){return l(c(this.read(),e.filters),e.sort)}async create(e){let t=this.read(),n={[this.key]:this.generateId(t),...e,...this.decorate(e,`create`)};return this.write([...t,n]),n}async update(e,t){let n=this.read(),r=this.indexOf(e);if(r===-1)throw Error(`No record with ${String(this.key)} "${String(e)}"`);let i={...n[r],...t,...this.decorate(t,`update`),[this.key]:e},a=[...n];return a[r]=i,this.write(a),i}async remove(e){let t=this.read();if(this.indexOf(e)===-1)throw Error(`No record with ${String(this.key)} "${String(e)}"`);this.write(t.filter(t=>t[this.key]!==e))}},p=class extends f{records;constructor(e,t,n){super(t,n),this.records=[...e]}read(){return this.records}write(e){this.records=e}},m=class extends f{storageKey;seed;constructor(e,t,n=[],r){super(t,r),this.storageKey=e,this.seed=n}read(){let e;try{e=localStorage.getItem(this.storageKey)}catch{return this.seed}if(e===null)return this.seed;try{let t=JSON.parse(e);return Array.isArray(t)?t:this.seed}catch{return this.seed}}write(e){try{localStorage.setItem(this.storageKey,JSON.stringify(e))}catch(e){throw Error(`Failed to persist to localStorage key "${this.storageKey}": ${e instanceof Error?e.message:String(e)}`)}}decorate(e,t){let n=new Date().toISOString();return t===`create`?{createdAt:n,updatedAt:n}:{updatedAt:n}}},h=(e,t)=>{let n=t.toString();return n===``?e:`${e}${e.includes(`?`)?`&`:`?`}${n}`},g={list:`/list`,create:`/create`,update:`/update`,remove:`/delete`},_={page:`current`,pageSize:`pageSize`,sortBy:`sortBy`,sortOrder:`sortOrder`},v={create:`POST`,update:`PUT`,remove:`DELETE`},y=class extends Error{status;body;constructor(e,t,n){super(`Request to ${n} failed with status ${e}`),this.name=`RestError`,this.status=e,this.body=t}},b=class{baseUrl;endpoints;paramNames;methods;headers;query;init;configureRequest;serializeRequest;parseResponse;parseRecord;fetchImpl;constructor(e={}){this.baseUrl=e.baseUrl??``,this.endpoints={...g,...e.endpoints},this.paramNames={..._,...e.paramNames},this.methods={...v,...e.methods},this.headers=e.headers??{},this.query=e.query??{},this.init=e.init??{},this.configureRequest=e.configureRequest,this.serializeRequest=e.serializeRequest??(e=>e),this.parseResponse=e.parseResponse,this.parseRecord=e.parseRecord,this.fetchImpl=e.fetchImpl??globalThis.fetch.bind(globalThis)}serializeSort(e,t){let n=e?.[0];n&&(t.set(this.paramNames.sortBy,String(n.field)),t.set(this.paramNames.sortOrder,n.direction))}serializeFilters(e,t){for(let[n,r]of Object.entries(e??{}))r!=null&&r!==``&&t.set(n,String(r))}buildListUrl(e){let t=new URLSearchParams;return t.set(this.paramNames.page,String(e.page)),t.set(this.paramNames.pageSize,String(e.pageSize)),this.serializeSort(e.sort,t),this.serializeFilters(e.filters,t),h(this.endpoints.list,t)}buildRecordPath(e,t){return`${e}/${encodeURIComponent(String(t))}`}toPage(e){if(this.parseResponse)return this.parseResponse(e);if(Array.isArray(e))return{items:e,total:e.length};if(typeof e==`object`&&e){let t=e;if(Array.isArray(t.data)){let e=t.data;return{items:e,total:typeof t.total==`number`?t.total:e.length}}}throw Error("Unrecognised list response. Provide `parseResponse` to map it to { items, total }.")}async request(e,t,n={}){let r=await this.configureRequest?.(t)??{},i=new URLSearchParams;for(let[e,t]of Object.entries({...this.query,...r.query}))i.set(e,String(t));let a=h(`${this.baseUrl}${e}`,i),o=await this.fetchImpl(a,{...this.init,...r.init,...n,method:r.method??n.method,headers:{"Content-Type":`application/json`,...this.headers,...r.headers,...n.headers}});if(!o.ok)throw new y(o.status,await o.text().catch(()=>``),a);if(o.status===204)return;let s=await o.text();return s===``?void 0:JSON.parse(s)}toRecord(e,t){return this.parseRecord?this.parseRecord(e,t):e}async list(e){let t={operation:`list`,query:e};return this.toPage(await this.request(this.buildListUrl(e),t))}async create(e){let t={operation:`create`,draft:e},n=await this.request(this.endpoints.create,t,{method:this.methods.create,body:JSON.stringify(this.serializeRequest(e,t))});return this.toRecord(n,t)}async update(e,t){let n={operation:`update`,id:e,draft:t},r=await this.request(this.buildRecordPath(this.endpoints.update,e),n,{method:this.methods.update,body:JSON.stringify(this.serializeRequest(t,n))});return this.toRecord(r,n)}async remove(e){let t={operation:`remove`,id:e};await this.request(this.buildRecordPath(this.endpoints.remove,e),t,{method:this.methods.remove})}},x=class extends Error{operation;constructor(e){super(`This table's data source does not support "${e}". Provide an \`${e}\` operation to enable it.`),this.name=`UnsupportedOperationError`,this.operation=e}},S=class{operations;constructor(e){this.operations=e}supports(e){return typeof this.operations[e]==`function`}async list(e){if(!this.operations.list)throw new x(`list`);return this.operations.list(e)}async listAll(e){if(this.operations.listAll)return this.operations.listAll(e);throw new x(`listAll`)}async create(e){if(!this.operations.create)throw new x(`create`);return this.operations.create(e)}async update(e,t){if(!this.operations.update)throw new x(`update`);return this.operations.update(e,t)}async remove(e){if(!this.operations.remove)throw new x(`remove`);return this.operations.remove(e)}},C=e=>e instanceof Error?e:Error(typeof e==`string`?e:`Unknown error`,{cause:e}),w=(e,t)=>{if(`dataSource`in t)return t.dataSource;if(`operations`in t)return new S(t.operations);if(`storageKey`in t)return new m(t.storageKey,e,t.initialData??[],t.generateId);if(`staticData`in t)return new p(t.staticData,e,t.generateId);if(`api`in t)return new b(t.api);throw Error("useCrudTable: supply exactly one of `staticData`, `api`, `storageKey`, `operations` or `dataSource`.")},T=(r,i)=>{let a=(0,n.useRef)(void 0),{defaultPageSize:o=10,optimisticUpdates:s=!1,refreshAfterMutation:c=!0,notifications:l=!0}=i,u=(0,n.useMemo)(()=>i.locale?{...e.t,...i.locale}:e.t,[i.locale]),d=(0,n.useRef)(i);d.current=i;let f=(0,n.useRef)(null);f.current===null&&(f.current=w(r,i));let p=f.current,[m,h]=(0,n.useState)({loading:!1,error:null,data:[],total:0,page:1,pageSize:o}),{page:g,pageSize:_}=m,v=(0,n.useCallback)((e,n)=>{d.current.onError?.(e,n),l&&t.message.error(n.message)},[l]),y=(0,n.useCallback)((e,n,r)=>{d.current.onSuccess?.(e,n),l&&t.message.success(r)},[l]),b=(0,n.useCallback)(async()=>{h(e=>({...e,loading:!0,error:null}));try{let e={page:g,pageSize:_},t=await p.list(e);h(e=>({...e,data:t.items,total:t.total,loading:!1}))}catch(e){let t=C(e);h(e=>({...e,loading:!1,error:t})),v(`list`,t)}},[p,g,_,v]),x=(0,n.useCallback)(async e=>{if(s){h(e);return}if(c){await b();return}h(e=>({...e,loading:!1}))},[s,c,b]),S=(0,n.useCallback)(async e=>{h(e=>({...e,loading:!0}));try{let t=await p.create(e);return await x(e=>({...e,data:[...e.data,t],total:e.total+1,loading:!1})),y(`create`,t,u.createSuccess),t}catch(e){return h(e=>({...e,loading:!1})),v(`create`,C(e)),null}},[p,x,v,y,u]),T=(0,n.useCallback)(async(e,t)=>{h(e=>({...e,loading:!0}));try{let n=await p.update(e,t);return await x(t=>({...t,data:t.data.map(t=>t[r]===e?n:t),loading:!1})),y(`update`,n,u.updateSuccess),n}catch(e){return h(e=>({...e,loading:!1})),v(`update`,C(e)),null}},[p,x,v,r,y,u]),E=(0,n.useCallback)(async e=>{h(e=>({...e,loading:!0}));try{return await p.remove(e),await x(t=>({...t,data:t.data.filter(t=>t[r]!==e),total:Math.max(0,t.total-1),loading:!1})),y(`delete`,e,u.deleteSuccess),!0}catch(e){return h(e=>({...e,loading:!1})),v(`delete`,C(e)),!1}},[p,x,v,r,y,u]),D=(0,n.useCallback)(e=>{h(t=>({...t,page:e}))},[]),O=(0,n.useCallback)(e=>{h(t=>({...t,pageSize:e,page:1}))},[]);return(0,n.useMemo)(()=>({refresh:b,create:S,update:T,remove:E,dataSource:p,setPage:D,setPageSize:O,state:m,actionRef:a}),[b,S,T,E,p,D,O,m])};Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return c}});
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useCrudTable-40jpmCkr.cjs");exports.toError=e.t,exports.useCrudTable=e.n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useCrudTable-Ex2Imgll.cjs");exports.toError=e.t,exports.useCrudTable=e.n;
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./useCrudTable-DxjnXVlQ.js";
1
+ import { n as e, t } from "./useCrudTable-BVXxakfl.js";
2
2
  export { t as toError, e as useCrudTable };
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useCrudTable-40jpmCkr.cjs");let t=require("react");var n=(n,r,i=[],a)=>{let o=e.n(n,{...a,storageKey:r,initialData:i}),{refresh:s}=o;return(0,t.useEffect)(()=>{s()},[]),o};exports.useLocalStorageCrud=n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./useCrudTable-Ex2Imgll.cjs");let t=require("react");var n=(n,r,i=[],a)=>{let o=e.n(n,{...a,storageKey:r,initialData:i}),{refresh:s}=o;return(0,t.useEffect)(()=>{s()},[]),o};exports.useLocalStorageCrud=n;
@@ -1,4 +1,4 @@
1
- import { n as e } from "./useCrudTable-DxjnXVlQ.js";
1
+ import { n as e } from "./useCrudTable-BVXxakfl.js";
2
2
  import { useEffect as t } from "react";
3
3
  //#region lib/hooks/useLocalStorageCrud.ts
4
4
  var n = (n, r, i = [], a) => {
@@ -0,0 +1,130 @@
1
+ import { FormRule } from 'antd';
2
+ import { FieldType } from '../fields/registry';
3
+ import { EnumOption } from '../fields/types';
4
+ /** File formats the importer can read. */
5
+ export type ImportFormat = 'csv' | 'xls' | 'xlsx';
6
+ /**
7
+ * The column information the importer needs: how to match a header, how to
8
+ * coerce a cell, and how to validate the result.
9
+ */
10
+ export interface ImportColumn {
11
+ /** Header text to match against, and the form label used in error messages. */
12
+ title: string;
13
+ /** The record property this column writes. */
14
+ dataIndex: string;
15
+ /** Drives value coercion (numbers, dates, enums, ...). */
16
+ fieldType?: FieldType;
17
+ /** Labels for `enum` columns, so an import accepts the exported label too. */
18
+ enumOptions?: Record<string, EnumOption>;
19
+ /** Resolved validation rules (registry rules + the column's own), as the form uses. */
20
+ rules?: FormRule[];
21
+ }
22
+ /** A file parsed into a header row and the data rows beneath it. */
23
+ export interface ParsedTable {
24
+ /** The first row, treated as headers. */
25
+ headers: string[];
26
+ /** Every subsequent row, as raw strings. */
27
+ rows: string[][];
28
+ }
29
+ /**
30
+ * Header-to-column mapping: for each header position, the `dataIndex` it feeds,
31
+ * or `null` to ignore that column.
32
+ */
33
+ export type ColumnMapping = (string | null)[];
34
+ /** One data row prepared for creation. */
35
+ export interface PreparedRow {
36
+ /** 1-based row number in the file body (excludes the header), for reporting. */
37
+ rowNumber: number;
38
+ /** The coerced record draft. */
39
+ record: Record<string, unknown>;
40
+ /** Per-field validation errors; empty when the row is valid. */
41
+ errors: {
42
+ field: string;
43
+ message: string;
44
+ }[];
45
+ }
46
+ /** The outcome of creating one prepared row. */
47
+ export interface ImportRowOutcome {
48
+ rowNumber: number;
49
+ ok: boolean;
50
+ /** Failure reason: a validation summary or the create error message. */
51
+ error?: string;
52
+ }
53
+ /** The result of an import run. */
54
+ export interface ImportResult {
55
+ /** Rows created successfully. */
56
+ created: number;
57
+ /** Rows that failed validation. */
58
+ invalid: number;
59
+ /** Rows that failed to create despite being valid. */
60
+ failed: number;
61
+ /** Per-row outcomes, in file order. */
62
+ outcomes: ImportRowOutcome[];
63
+ }
64
+ /**
65
+ * Parse CSV text into rows of string fields. Handles quoted fields, escaped
66
+ * quotes (`""`), embedded commas and newlines, `\r\n`/`\n` endings and a
67
+ * leading UTF-8 BOM.
68
+ */
69
+ export declare const parseCsv: (text: string, delimiter?: string) => string[][];
70
+ /** Split a grid into a header row plus data rows. */
71
+ export declare const toParsedTable: (grid: string[][]) => ParsedTable;
72
+ /** A parser turns raw file bytes/text into a {@link ParsedTable}. */
73
+ export type FileParser = (input: string | ArrayBuffer | Uint8Array) => ParsedTable | Promise<ParsedTable>;
74
+ /**
75
+ * Registered parsers per format. CSV is built in; `xls` and `xlsx` are
76
+ * registered by their own modules so each format ships independently.
77
+ */
78
+ export declare const fileParsers: Partial<Record<ImportFormat, FileParser>>;
79
+ /** Register a parser for a format (used by the xls/xlsx additions). */
80
+ export declare const registerFileParser: (format: ImportFormat, parser: FileParser) => void;
81
+ /** Decode raw bytes as UTF-8 text. */
82
+ export declare const decodeText: (input: ArrayBuffer | Uint8Array) => string;
83
+ /** Infer the import format from a filename extension. */
84
+ export declare const detectFormat: (filename: string) => ImportFormat | undefined;
85
+ /** Parse a file's contents into a {@link ParsedTable} using the registered parser. */
86
+ export declare const parseTable: (input: string | ArrayBuffer | Uint8Array, format: ImportFormat) => Promise<ParsedTable>;
87
+ /**
88
+ * Suggest a header-to-column mapping by matching header text against each
89
+ * column's title (then its `dataIndex`), case- and punctuation-insensitively.
90
+ * Password columns are never targeted. Unmatched headers map to `null`.
91
+ */
92
+ export declare const autoMapColumns: (headers: string[], columns: ImportColumn[]) => ColumnMapping;
93
+ /**
94
+ * Coerce one raw cell into the record shape for a column. Throws when the
95
+ * field's own conversion throws (e.g. malformed JSON), which the caller records
96
+ * as a per-row error.
97
+ */
98
+ export declare const coerceValue: (raw: string, column: ImportColumn) => unknown;
99
+ /**
100
+ * Evaluate the resolved rules for one value, returning the first failure
101
+ * message or `null`. Supports the rule shapes the registry and `formConfig`
102
+ * produce: `required`, `type: 'email' | 'url'`, `pattern`, `len`/`min`/`max`,
103
+ * and custom async `validator`s (which is how the `json` type validates).
104
+ */
105
+ export declare const evaluateRules: (rules: FormRule[] | undefined, value: unknown, label: string) => Promise<string | null>;
106
+ /**
107
+ * Turn parsed rows into validated record drafts using the given mapping.
108
+ * Password columns are excluded even if mapped. Cells that coerce to blank are
109
+ * omitted from the draft so `required` rules see a missing value.
110
+ */
111
+ export declare const prepareRows: (table: ParsedTable, mapping: ColumnMapping, columns: ImportColumn[]) => Promise<PreparedRow[]>;
112
+ /** How the importer creates rows: one at a time, or all at once server-side. */
113
+ export interface ImportSink {
114
+ /** Create one record. */
115
+ create: (draft: Record<string, unknown>) => Promise<unknown>;
116
+ /** Optional batch create for sources that can do it server-side. */
117
+ createMany?: (drafts: Record<string, unknown>[]) => Promise<unknown>;
118
+ }
119
+ /** Options for {@link runImport}. */
120
+ export interface RunImportOptions {
121
+ /** Max simultaneous single-row creates. Defaults to 5. */
122
+ concurrency?: number;
123
+ }
124
+ /**
125
+ * Create the valid prepared rows, reporting each row's outcome. Invalid rows are
126
+ * never sent. Uses `createMany` when the sink offers it; otherwise creates with
127
+ * a bounded pool so a large file does not fire thousands of simultaneous
128
+ * requests. Partial success is honoured: a failing row does not abort the rest.
129
+ */
130
+ export declare const runImport: (prepared: PreparedRow[], sink: ImportSink, options?: RunImportOptions) => Promise<ImportResult>;
@@ -0,0 +1,8 @@
1
+ import { ParsedTable } from './importData';
2
+ /**
3
+ * Parse SpreadsheetML text into a grid of string cells (first Worksheet only).
4
+ * `ss:Index` (1-based) on a row or cell is honoured so sparse files stay aligned.
5
+ */
6
+ export declare const parseSpreadsheetML: (xml: string) => string[][];
7
+ /** Parse SpreadsheetML content (text or bytes) into a {@link ParsedTable}. */
8
+ export declare const parseSpreadsheetMLTable: (input: string | ArrayBuffer | Uint8Array) => ParsedTable;
@@ -0,0 +1,7 @@
1
+ import { ParsedTable } from './importData';
2
+ /**
3
+ * Parse an `.xlsx` workbook's first sheet into a {@link ParsedTable}.
4
+ * Accepts the raw bytes (`ArrayBuffer`/`Uint8Array`) the import dialog reads
5
+ * from the chosen file.
6
+ */
7
+ export declare const parseXlsx: (input: string | ArrayBuffer | Uint8Array) => Promise<ParsedTable>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "antd-crud-table",
3
3
  "private": false,
4
- "version": "0.7.0",
4
+ "version": "0.8.0",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/maifeeulasad/antd-crud-table",
7
7
  "repository": {
@@ -100,6 +100,9 @@
100
100
  "sideEffects": [
101
101
  "*.css"
102
102
  ],
103
+ "dependencies": {
104
+ "to-spreadsheet": "^1.4.0"
105
+ },
103
106
  "scripts": {
104
107
  "dev": "vite",
105
108
  "build:demo": "tsc -b && vite build",
@@ -114,6 +117,8 @@
114
117
  "test": "vitest run",
115
118
  "test:watch": "vitest",
116
119
  "test:coverage": "vitest run --coverage",
120
+ "test:integration": "vitest run --config vitest.integration.config.ts",
121
+ "backend": "node --experimental-strip-types backend/index.ts",
117
122
  "preview": "vite preview"
118
123
  }
119
124
  }