UNPKG

react-smart-data-table

Version:

A smart data table component for React.js meant to be configuration free

756 lines (755 loc) 20.7 kB
import { Component as e, createContext as t, memo as n, use as r, useCallback as i, useEffect as a, useImperativeHandle as o, useMemo as s, useReducer as c, useRef as l, useState as u } from "react"; import d from "clsx"; import { find as f } from "linkifyjs"; import { flatten as p } from "flat"; import m from "escape-string-regexp"; import { snakeCase as h } from "change-case"; import { jsx as g, jsxs as _ } from "react/jsx-runtime"; //#region lib/helpers/file-extensions.ts var v = /* @__PURE__ */ "ase.art.bmp.blp.cd5.cit.cpt.cr2.cut.dds.dib.djvu.egt.exif.gif.gpl.grf.icns.ico.iff.jng.jpeg.jpg.jfif.jp2.jps.lbm.max.miff.mng.msp.nitf.ota.pbm.pc1.pc2.pc3.pcf.pcx.pdn.pgm.PI1.PI2.PI3.pict.pct.pnm.pns.ppm.psb.psd.pdd.psp.px.pxm.pxr.qfx.raw.rle.sct.sgi.rgb.int.bw.tga.tiff.tif.vtf.xbm.xcf.xpm.3dv.amf.ai.awg.cgm.cdr.cmx.dxf.e2d.egt.eps.fs.gbr.odg.svg.stl.vrml.x3d.sxd.v2d.vnd.wmf.emf.art.xar.png.webp.jxr.hdp.wdp.cur.ecw.iff.lbm.liff.nrrd.pam.pcx.pgf.sgi.rgb.rgba.bw.int.inta.sid.ras.sun.tga".split("."), y = "data", ee = "URL detected by the renderer", b = "Select All", x = "Unselect All", S = "Data type is invalid, expected string or array !", te = "Response type is invalid, expected JSON !", ne = "Sampling percentage should be withing the [0, 100] range.", C = "Something went wrong !", re = "DESC", w = "false", T = { key: "default", text: "", invisible: !1, sortable: !1, filterable: !1, isImg: !1 }, E = ([e]) => e, D = (e) => typeof e == "string" || e instanceof String, O = (e) => Array.isArray(e), k = (e) => e && typeof e == "object" && e.constructor === Object || !1, A = (e) => Array.isArray(e) && "length" in e ? !e.length : k(e) ? !Object.keys(e).length : !1, j = (e) => typeof e == "function", M = (e) => typeof e == "number" && Number.isFinite(e), N = (e) => e === void 0, P = (e) => { if (D(e)) { let t = e.search(/[a-z]/); return t === -1 ? e.toUpperCase() : e.substring(0, t + 1).toUpperCase() + e.substring(t + 1); } return ""; }, F = (e, t, n) => { let r = typeof n == "function" ? n : (e, n) => e[t] > n[t] ? 1 : n[t] > e[t] ? -1 : 0; return [...e].sort(r); }, ie = (e) => !(e && /^\d+$/.test(e)), ae = (...e) => { console.error(...e); }; function I(e = 1, t = 1, n = 1) { let r = e - 1 > 0 ? e - 1 : 1, i = e + 1 > t ? t : e + 1, a = 1 + 2 * n, o = 2 + a, s = [{ active: !1, value: 1, text: "<<" }, { active: !1, value: r, text: "<" }]; if (t > o) { e >= a && (s.push({ active: !1, value: 1, text: "1" }), e > a && s.push({ active: !1, value: void 0, text: "..." })); for (let r = -n; r < 2 * n; r += 1) { let n = e + r; n > 0 && n <= t && s.push({ active: e === n, value: n, text: `${n}` }); } t - e > n && (t - e - 1 > n && s.push({ active: !1, value: void 0, text: "..." }), s.push({ active: !1, value: t, text: `${t}` })); } else for (let n = 1; n <= t; n += 1) s.push({ active: e === n, value: n, text: `${n}` }); return s.push({ active: !1, value: i, text: ">" }), s.push({ active: !1, value: t, text: ">>" }), s; } async function L(e, { dataKey: t = y, dataKeyResolver: n, options: r = {} } = {}) { if (O(e)) return e; if (D(e)) { let i = await fetch(e, r), { headers: a, ok: o, status: s, statusText: c } = i; if (o) { let e = a.get("content-type"); if (e && e.includes("application/json")) { let e = await i.json(); return typeof n == "function" ? n(e) : t ? e[t] : e; } throw Error(te); } throw Error(`${s} - ${c}`); } else throw Error(S); } function R(e) { return e.map(P).join(" ").trim(); } function z(e) { return D(e) ? R(h(e).split("_").filter(ie)) : ""; } function B(e, t) { return N(e) ? t : e; } function V(e, t = {}) { let { text: n, invisible: r, sortable: i, filterable: a } = { ...t[e] }; return { key: e, text: B(n, z(e)), invisible: B(r, !1), sortable: B(i, !0), filterable: B(a, !0), isImg: B(r, !1) }; } function oe(e = [], t = 0) { if (!t) return p(E(e)); if (t < 0 || t > 100) throw Error(ne); return p(e.slice(0, Math.ceil(t / 100 * e.length)).reduce((e, t) => ({ ...e, ...t }), {})); } function H(e = [], t = {}, n = [], r = !1, i = 0) { let a = [], o = []; if (e && O(e) && !A(e)) { let s = oe(e.filter((e) => !!e), i); if (A(n) || n.forEach((e) => { a.includes(e) || (o.push(V(e, t)), a.push(e)); }), !r && k(s)) { let e = [...Object.keys(s), ...Object.keys(t)]; for (let n of e) a.includes(n) || (o.push(V(n, t)), a.push(n)); } } return o; } function se(e = []) { let t = []; return e && O(e) && !A(e) && (t = e.filter((e) => k(e) && !A(e)).map((e) => p(e))), t; } function U(e, t, n) { let r = e.toLowerCase(); return t.filter((e) => { let t = Object.keys(e); for (let i = 0, a = t.length; i < a; i += 1) { let a = t[i]; if (n[a]?.filterable !== !1 && String(e[a]).toLowerCase().includes(r)) return !0; } return !1; }); } function W(e, t, n) { return e ? U(e, t, n) : t; } function G(e, t, n) { if (M(n) && Math.sign(n)) { let r = n * (t - 1), i = n * t; return e.slice(r, i); } return e; } function K(e) { let t = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; if (typeof e == "string") { let [n, r] = e.split(":"); if (n && n === "data" && r) { let [e, n] = r.split(";"); if (e) { let [r, i] = e.split("/"), [a] = i.split("+"); if (r === "image" && typeof a == "string" && n) { let [e, r] = n.split(","); if (e === "base64" && t.test(r)) return v.includes(a.toLowerCase()); } } } } return !1; } function ce(e) { let t = K(e); if (t) return t; let n = document.createElement("a"); n.href = String(e); let { pathname: r } = n, i = r.search(/[:?&#]/); i !== -1 && (r = r.substring(0, i)); let a = r.split(".").pop().toLowerCase(); return v.includes(a); } function q(e, t) { let n = { first: void 0, highlight: void 0, last: void 0, value: e }; if (!t) return n; if (RegExp(`.*?${m(t)}.*?`, "i").test(e)) { let n = E(e.toLowerCase().split(t.toLowerCase())).length, r = t.length; return { first: e.substring(0, n), highlight: e.substring(n, n + r), last: e.substring(n + r), value: e }; } return n; } function le({ children: e, content: t, parseBool: n } = {}) { if (n) { let { noWord: r = "No", yesWord: i = "Yes" } = typeof n == "object" ? n : {}; if (t === !0 || e === !0) return i; if (t === !1 || e === !1) return r; } if (t === 0 || e === 0) return "0"; if (t === !1 || e === !1) return w; let r = ""; return t ? r = t : e && (r = e), `${r}`; } //#endregion //#region lib/components/HighlightValue.tsx var J = ({ children: e, filterValue: t = "", "data-testid": n = "highlight-value" }) => { let { first: r, highlight: i, last: a } = s(() => q(String(e), t), [e, t]); return !r && !i && !a ? e : /* @__PURE__ */ _("span", { "data-testid": n, children: [ r, /* @__PURE__ */ g("span", { className: "rsdt rsdt-highlight", children: i }), a ] }); }, Y = n(({ children: e, content: t = "", filterable: n = !0, filterValue: r = "", isImg: a = !1, parseBool: o = !1, parseImg: c = !1, withLinks: l = !1 }) => { let u = s(() => le({ children: e, content: t, parseBool: o }), [ e, t, o ]), d = i(() => n ? /* @__PURE__ */ g(J, { filterValue: r, "data-testid": "cell-value", children: u }) : u, [ r, n, u ]), p = i(({ bypass: e = !1 } = {}) => { if (a || e || ce(u)) { let { style: e, className: t } = typeof c == "boolean" ? { style: void 0, className: void 0 } : c; return /* @__PURE__ */ g("img", { src: u, style: e, className: t, alt: ee, "data-testid": "cell-value" }); } return null; }, [ a, c, u ]), m = i(() => { let e = f(u), t = d(); if (A(e)) return K(u) ? p({ bypass: !0 }) : t; let n = E(e), r = null; return c && n.type === "url" && (r = p()), /* @__PURE__ */ g("a", { href: n.href, onClick: (e) => e.stopPropagation(), children: r || t }); }, [ d, c, p, u ]); return l ? m() : c && p() || d(); }), X = ({ children: e, ...t }) => /* @__PURE__ */ g("table", { ...t, children: e }), ue = n(({ children: e, ...t }) => /* @__PURE__ */ g("tbody", { ...t, children: e })), de = n(({ children: e, ...t }) => /* @__PURE__ */ g("td", { ...t, children: e })), fe = n(({ children: e, ...t }) => /* @__PURE__ */ g("tfoot", { ...t, children: e })), pe = n(({ children: e, ...t }) => /* @__PURE__ */ g("thead", { ...t, children: e })), me = n(({ children: e, ...t }) => /* @__PURE__ */ g("th", { ...t, children: e })), he = n(({ children: e, ...t }) => /* @__PURE__ */ g("tr", { ...t, children: e })); X.Body = ue, X.Cell = de, X.Footer = fe, X.Header = pe, X.HeaderCell = me, X.Row = he; //#endregion //#region lib/helpers/typed-memo.ts var ge = n; //#endregion //#region lib/components/DataRow.tsx function _e({ row: e, rowIndex: t, columns: n, colProperties: r, withLinks: a, filterValue: o, parseBool: s, parseImg: c, onRowClick: l, rowClassName: u, tableData: f }) { let p = i((n) => { l(n, e, t, f); }, [ l, e, t, f ]); return /* @__PURE__ */ g(X.Row, { onClick: p, className: d(u?.(e, t, f)), children: n.map((n) => { let i = r[n.key], l = !i?.invisible, u = i?.transform; return l ? /* @__PURE__ */ g(X.Cell, { "data-column-name": n.key, children: j(u) ? u(e[n.key], t, e) : /* @__PURE__ */ g(Y, { withLinks: a, filterValue: o, parseBool: s, parseImg: c, filterable: i?.filterable, isImg: i?.isImg, children: e[n.key] }) }, `row-${t}-${n.key}`) : null; }) }); } var ve = ge(_e), Z = class extends e { static { this.defaultProps = { logError: () => null, fbComponent: null }; } constructor(e) { super(e), this.state = { hasError: !1, error: null, errorInfo: null }; } componentDidCatch(e, t) { let { logError: n } = this.props; this.setState({ hasError: !0, error: e, errorInfo: t }), typeof n == "function" && n(e, t); } renderDefaultFB() { let { error: e, errorInfo: t } = this.state; return /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("h2", { children: C }), /* @__PURE__ */ _("details", { style: { whiteSpace: "pre-wrap" }, children: [/* @__PURE__ */ g("summary", { children: e && e.toString() }), /* @__PURE__ */ g("p", { children: t.componentStack })] })] }); } render() { let { hasError: e } = this.state, { children: t, fbComponent: n } = this.props; return e ? n || this.renderDefaultFB() : t; } }, ye = n(({ active: e, value: t, text: n, onPageChange: r }) => { let a = i((e) => { r(e, { activePage: t }); }, [r, t]); return /* @__PURE__ */ g("button", { className: d("rsdt", "rsdt-paginate", { active: e }, "button"), type: "button", onClick: a, disabled: N(t), "data-testid": "paginator-item", children: n }); }, ({ active: e, value: t, text: n }, { active: r, value: i, text: a }) => e === r && t === i && n === a), be = n(({ activePage: e, totalPages: t, onPageChange: n }) => { let r = s(() => I(e, t), [e, t]), i = s(() => typeof n == "function" ? n : () => null, [n]); return /* @__PURE__ */ g("div", { className: "rsdt rsdt-paginate", children: r.map(({ active: e, value: t, text: n }, r) => /* @__PURE__ */ g(ye, { active: e, value: t, text: n, onPageChange: i }, N(t) ? `ellipsis-${r}` : n)) }); }, ({ activePage: e, totalPages: t }, { activePage: n, totalPages: r }) => e === n && t === r), Q = ({ locale: { selectAllWord: e = b, unSelectAllWord: t = x } = {}, handleToggleAll: n, ref: r }) => { let [a, s] = u(!1), c = i(() => { typeof n == "function" && n(a), s(!a); }, [n, a]); return o(r, () => ({ setUnchecked: () => { a && s(!1); } })), /* @__PURE__ */ g("span", { className: "rsdt rsdt-column-toggles toggle", children: /* @__PURE__ */ _("label", { htmlFor: "select-all", children: [/* @__PURE__ */ g("input", { type: "checkbox", id: "select-all", value: "select-all", name: "select-all", checked: a, onChange: c, "data-testid": "select-all" }), a ? t : e] }) }); }; Q.displayName = "SelectAll"; //#endregion //#region lib/components/Toggles.tsx var xe = ({ columns: e, colProperties: t, handleColumnToggle: n, handleColumnToggleAll: r, selectAll: a = !1 }) => { let o = typeof a == "object" ? a : {}, s = l(null), c = i(({ target: { value: e } }) => { n(String(e)), s?.current && e && s.current.setUnchecked(); }, [n]), u = i((e) => { let n = t[e]; return !n || !n.invisible; }, [t]); return /* @__PURE__ */ _("nav", { className: "rsdt rsdt-column-toggles", children: [a && /* @__PURE__ */ g(Q, { locale: o?.locale, handleToggleAll: typeof o?.handleToggleAll == "function" ? o?.handleToggleAll : r, ref: s }), e.map(({ key: e, text: t } = T) => /* @__PURE__ */ g("span", { className: "rsdt rsdt-column-toggles toggle", children: /* @__PURE__ */ _("label", { htmlFor: e, children: [/* @__PURE__ */ g("input", { type: "checkbox", id: e, value: e, name: t, checked: u(e), onChange: c }), t] }) }, e))] }); }, Se = { activePage: 1, asyncData: [], colProperties: {}, columns: [], isLoading: !1, prevFilterValue: "", sorting: { key: "", dir: "" } }, Ce = t(Se), we = () => r(Ce), $ = /* @__PURE__ */ function(e) { return e.FetchStart = "FETCH_START", e.FetchSuccess = "FETCH_SUCCESS", e.FetchError = "FETCH_ERROR", e.SetSorting = "SET_SORTING", e.SetActivePage = "SET_ACTIVE_PAGE", e.ToggleColumn = "TOGGLE_COLUMN", e.ToggleAllColumns = "TOGGLE_ALL_COLUMNS", e.ResetPageForFilter = "RESET_PAGE_FOR_FILTER", e; }($ || {}); //#endregion //#region lib/hooks/useTableReducer.ts function Te(e, t) { switch (t.type) { case $.FetchStart: return { ...e, isLoading: !0 }; case $.FetchSuccess: return { ...e, asyncData: t.asyncData, columns: t.columns, isLoading: !1 }; case $.FetchError: return { ...e, isLoading: !1 }; case $.SetSorting: { let { key: n } = t.column, r = e.sorting.key === n ? e.sorting.dir : "", i; return i = r ? r === "ASC" ? re : "" : "ASC", { ...e, sorting: { key: n, dir: i } }; } case $.SetActivePage: return { ...e, activePage: t.activePage }; case $.ToggleColumn: { let { key: n } = t, r = e.colProperties[n] ?? { ...T, key: n }; return { ...e, colProperties: { ...e.colProperties, [n]: { ...r, invisible: !r.invisible } } }; } case $.ToggleAllColumns: { let n = { ...e.colProperties }; for (let { key: e } of t.columns) n[e] = { ...n[e] ?? { ...T, key: e }, invisible: t.isChecked }; return { ...e, colProperties: n }; } case $.ResetPageForFilter: return { ...e, activePage: 1, prevFilterValue: t.filterValue }; default: return e; } } function Ee(e = {}) { return c(Te, { ...Se, colProperties: e }); } //#endregion //#region lib/hooks/useAsyncData.ts function De({ data: e, dataKey: t, dataKeyResolver: n, dataRequestOptions: r, headers: i, orderedHeaders: o, hideUnordered: s, dataSampling: c, dispatch: u }) { let d = l({ headers: i, orderedHeaders: o, hideUnordered: s, dataSampling: c }); d.current = { headers: i, orderedHeaders: o, hideUnordered: s, dataSampling: c }, a(() => { D(e) && (async () => { u({ type: $.FetchStart }); try { let i = await L(e, { dataKey: t, dataKeyResolver: n, options: r }), a = d.current, o = H(i, a.headers, a.orderedHeaders, a.hideUnordered, a.dataSampling); u({ type: $.FetchSuccess, asyncData: i, columns: o }); } catch (e) { u({ type: $.FetchError }), ae(e); } })(); }, [ e, t, n, r, u ]); } //#endregion //#region lib/hooks/useColumns.ts function Oe({ resolvedData: e, stateColumns: t, headers: n, orderedHeaders: r, hideUnordered: i, dataSampling: a, dynamic: o }) { return s(() => !o && !A(t) ? t : H(e, n, r, i, a), [ e, t, n, r, i, a, o ]); } //#endregion //#region lib/hooks/useRows.ts function ke({ resolvedData: e, sorting: t, colProperties: n, filterValue: r, activePage: i, perPage: a }) { let o = s(() => se(e), [e]), c = s(() => { let { dir: e, key: r } = t; if (!e) return o; let i = F(o, r, typeof n[r]?.sortable == "function" && n[r].sortable); return e === "ASC" ? i : i.reverse(); }, [ o, t, n ]), l = s(() => W(r, c, n), [ r, c, n ]); return { filteredRows: l, visibleRows: s(() => G(l, i, a), [ l, i, a ]) }; } //#endregion //#region lib/SmartDataTable.tsx var Ae = {}, je = [], Me = {}, Ne = () => null; function Pe({ className: e = "", data: t, dataKey: n = y, dataKeyResolver: r = null, dataRequestOptions: o = Me, dataSampling: c = 0, dynamic: u = !1, emptyTable: f = null, filterValue: p = "", headers: m = Ae, hideUnordered: h = !1, loader: v = null, name: ee = "reactsmartdatatable", onRowClick: b = Ne, orderedHeaders: x = je, paginator: S = be, parseBool: te = !1, parseImg: ne = !1, perPage: C = 0, rowClassName: re, sortable: w = !1, withFooter: T = !1, withHeader: E = !0, withLinks: O = !1, withToggles: k = !1 }) { let [j, M] = Ee(m), { activePage: N, asyncData: P, colProperties: F, columns: ie, isLoading: ae, sorting: I } = j, L = l(p); a(() => { p !== L.current && (L.current = p, M({ type: $.ResetPageForFilter, filterValue: p })); }, [p, M]), De({ data: t, dataKey: n, dataKeyResolver: r, dataRequestOptions: o, headers: m, orderedHeaders: x, hideUnordered: h, dataSampling: c, dispatch: M }); let R = s(() => D(t) ? P : t, [t, P]), z = Oe({ resolvedData: R, stateColumns: ie, headers: m, orderedHeaders: x, hideUnordered: h, dataSampling: c, dynamic: u }), { filteredRows: B, visibleRows: V } = ke({ resolvedData: R, sorting: I, colProperties: F, filterValue: p, activePage: N, perPage: C }), oe = i((e, { activePage: t }) => { M({ type: $.SetActivePage, activePage: t }); }, [M]), H = i((e) => { M({ type: $.SetSorting, column: e }); }, [M]), se = i((e) => { M({ type: $.ToggleColumn, key: e }); }, [M]), U = i((e) => (t) => { M({ type: $.ToggleAllColumns, columns: e, isChecked: t }); }, [M]), W = i((e, t, n, r) => { typeof b == "function" && b(e, { rowData: t, rowIndex: n, tableData: r }); }, [b]), G = s(() => C > 0 ? Math.ceil(B.length / C) : 0, [B.length, C]), K = s(() => U(z), [U, z]), ce = (e) => { let { key: t, dir: n } = I, r = "rsdt-sortable-icon"; return t === e.key && n && (r = n === "ASC" ? "rsdt-sortable-asc" : "rsdt-sortable-desc"), /* @__PURE__ */ g("i", { className: d("rsdt", r), onClick: () => H(e), onKeyDown: () => H(e), role: "button", tabIndex: 0, "aria-label": "sorting column" }); }, q = () => { let e = z.map((e) => { let t = F[e.key]; return !t || !t.invisible ? /* @__PURE__ */ _(X.HeaderCell, { "data-column-name": e.key, children: [/* @__PURE__ */ g("span", { children: e.text }), /* @__PURE__ */ g("span", { className: "rsdt rsdt-sortable", children: w && e.sortable ? ce(e) : null })] }, e.key) : null; }); return /* @__PURE__ */ g(X.Row, { children: e }); }, le = () => { let e = V.map((e, t) => /* @__PURE__ */ g(Z, { children: /* @__PURE__ */ g(ve, { row: e, rowIndex: t, columns: z, colProperties: F, withLinks: O, filterValue: p, parseBool: te, parseImg: ne, onRowClick: W, rowClassName: re, tableData: B }) }, `row-${t}`)); return /* @__PURE__ */ g(X.Body, { children: e }); }, J = () => k ? /* @__PURE__ */ g(Z, { children: /* @__PURE__ */ g(xe, { columns: z, colProperties: F, handleColumnToggle: se, handleColumnToggleAll: K, selectAll: (typeof k == "object" ? k : {})?.selectAll }) }) : null, Y = () => !C || C <= 0 || !G ? null : /* @__PURE__ */ g(Z, { children: /* @__PURE__ */ g(S, { totalPages: G, activePage: N, onPageChange: oe }) }); return ae ? v : A(B) ? f : /* @__PURE__ */ g(Ce, { value: j, children: /* @__PURE__ */ _("section", { className: "rsdt rsdt-container", children: [ J(), /* @__PURE__ */ _(X, { "data-table-name": ee, className: e, children: [ E && /* @__PURE__ */ g(X.Header, { children: q() }), le(), T && /* @__PURE__ */ g(X.Footer, { children: q() }) ] }), Y() ] }) }); } //#endregion //#region lib/index.ts var Fe = Pe; //#endregion export { Y as CellValue, Y as TableCell, Z as ErrorBoundary, J as HighlightValue, be as Paginator, Q as SelectAll, xe as Toggles, Fe as default, we as useSmartDataTableContext };