@juv/codego-react-ui 3.0.8 → 3.1.1
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/dist/index.cjs +138 -66
- package/dist/index.d.cts +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.global.js +6712 -72
- package/dist/index.js +137 -66
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1996,6 +1996,61 @@ function MetricRow({ items, divided = true, className }) {
|
|
|
1996
1996
|
|
|
1997
1997
|
// src/components/ui/data-grid.tsx
|
|
1998
1998
|
import * as React24 from "react";
|
|
1999
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
2000
|
+
|
|
2001
|
+
// src/components/tools/decryptPayload.ts
|
|
2002
|
+
import CryptoJS from "crypto-js";
|
|
2003
|
+
function getLaravelSecretKey() {
|
|
2004
|
+
const viteKey = import.meta.env["VITE_LARAVEL_KEY"];
|
|
2005
|
+
const legacyKey = globalThis?.process?.env?.REACT_APP_LARAVEL_KEY;
|
|
2006
|
+
const key = viteKey || legacyKey;
|
|
2007
|
+
if (!key) {
|
|
2008
|
+
throw new Error("Missing Laravel decryption key. Set VITE_LARAVEL_KEY in your .env.");
|
|
2009
|
+
}
|
|
2010
|
+
return key;
|
|
2011
|
+
}
|
|
2012
|
+
function parseLaravelKey(secretKey) {
|
|
2013
|
+
if (secretKey.startsWith("base64:")) {
|
|
2014
|
+
return CryptoJS.enc.Base64.parse(secretKey.slice("base64:".length));
|
|
2015
|
+
}
|
|
2016
|
+
return CryptoJS.enc.Utf8.parse(secretKey);
|
|
2017
|
+
}
|
|
2018
|
+
function parseLaravelEncryptedPayload(payload) {
|
|
2019
|
+
let jsonStr = payload;
|
|
2020
|
+
try {
|
|
2021
|
+
jsonStr = atob(payload);
|
|
2022
|
+
} catch {
|
|
2023
|
+
}
|
|
2024
|
+
return JSON.parse(jsonStr);
|
|
2025
|
+
}
|
|
2026
|
+
function decryptLaravelPayload(payload) {
|
|
2027
|
+
const secretKey = getLaravelSecretKey();
|
|
2028
|
+
const parsed = parseLaravelEncryptedPayload(payload);
|
|
2029
|
+
if (parsed.tag) {
|
|
2030
|
+
throw new Error("Unsupported Laravel cipher (AEAD tag present). Expected AES-*-CBC payload.");
|
|
2031
|
+
}
|
|
2032
|
+
const key = parseLaravelKey(secretKey);
|
|
2033
|
+
const expectedMac = CryptoJS.HmacSHA256(parsed.iv + parsed.value, key).toString();
|
|
2034
|
+
if (expectedMac !== parsed.mac) {
|
|
2035
|
+
throw new Error("Invalid payload MAC (wrong key or tampered payload).");
|
|
2036
|
+
}
|
|
2037
|
+
const iv = CryptoJS.enc.Base64.parse(parsed.iv);
|
|
2038
|
+
const ciphertext = CryptoJS.enc.Base64.parse(parsed.value);
|
|
2039
|
+
const cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext });
|
|
2040
|
+
const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
|
|
2041
|
+
iv,
|
|
2042
|
+
mode: CryptoJS.mode.CBC,
|
|
2043
|
+
padding: CryptoJS.pad.Pkcs7
|
|
2044
|
+
});
|
|
2045
|
+
const plaintext = decrypted.toString(CryptoJS.enc.Utf8);
|
|
2046
|
+
if (!plaintext) {
|
|
2047
|
+
throw new Error("Decryption produced empty plaintext (wrong key/cipher).");
|
|
2048
|
+
}
|
|
2049
|
+
console.log("Decrypted payload:", plaintext);
|
|
2050
|
+
return JSON.parse(plaintext);
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
// src/components/ui/data-grid.tsx
|
|
1999
2054
|
import axios from "axios";
|
|
2000
2055
|
import { ChevronUp, ChevronDown as ChevronDown4, ChevronsUpDown, ChevronLeft as ChevronLeft5, ChevronRight as ChevronRight7, Search as Search4, Settings2, Check as Check5, Eye, Pencil, Trash, Loader2, X as X7 } from "lucide-react";
|
|
2001
2056
|
|
|
@@ -4729,7 +4784,7 @@ Input.displayName = "Input";
|
|
|
4729
4784
|
|
|
4730
4785
|
// src/components/ui/data-grid.tsx
|
|
4731
4786
|
import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4732
|
-
function useServerDataGrid({ url, params }) {
|
|
4787
|
+
function useServerDataGrid({ url, params, encrypt }) {
|
|
4733
4788
|
const [data, setData] = React24.useState([]);
|
|
4734
4789
|
const [columns, setColumns] = React24.useState([]);
|
|
4735
4790
|
const [currentPage, setCurrentPage] = React24.useState(1);
|
|
@@ -4743,23 +4798,26 @@ function useServerDataGrid({ url, params }) {
|
|
|
4743
4798
|
setError(null);
|
|
4744
4799
|
axios.get(url, { params: { ...params, page: currentPage } }).then(({ data: res }) => {
|
|
4745
4800
|
if (cancelled) return;
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
const
|
|
4749
|
-
const
|
|
4750
|
-
const
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4801
|
+
const payload = encrypt ? decryptLaravelPayload(res) : res;
|
|
4802
|
+
setData(payload.data);
|
|
4803
|
+
const rawTotal = payload.total;
|
|
4804
|
+
const rawPerPage = payload.per_page;
|
|
4805
|
+
const rawLastPage = payload.last_page;
|
|
4806
|
+
const lastPage = rawLastPage ?? Math.ceil(rawTotal / rawPerPage);
|
|
4807
|
+
const pg = payload.pagination ?? {
|
|
4808
|
+
first_page_url: payload.first_page_url ?? `${url}?page=1`,
|
|
4809
|
+
last_page_url: payload.last_page_url ?? `${url}?page=${lastPage}`,
|
|
4810
|
+
last_page: lastPage,
|
|
4811
|
+
next_page_url: payload.next_page_url !== void 0 ? payload.next_page_url : currentPage < lastPage ? `${url}?page=${currentPage + 1}` : null,
|
|
4812
|
+
prev_page_url: payload.prev_page_url !== void 0 ? payload.prev_page_url : currentPage > 1 ? `${url}?page=${currentPage - 1}` : null,
|
|
4755
4813
|
per_page: rawPerPage,
|
|
4756
4814
|
total: rawTotal,
|
|
4757
|
-
links:
|
|
4815
|
+
links: payload.links ?? []
|
|
4758
4816
|
};
|
|
4759
4817
|
setPagination(pg);
|
|
4760
|
-
if (
|
|
4818
|
+
if (payload.data.length > 0) {
|
|
4761
4819
|
setColumns(
|
|
4762
|
-
Object.keys(
|
|
4820
|
+
Object.keys(payload.data[0]).map((key) => ({
|
|
4763
4821
|
key,
|
|
4764
4822
|
header: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
|
|
4765
4823
|
}))
|
|
@@ -4788,23 +4846,26 @@ function useServerDataGrid({ url, params }) {
|
|
|
4788
4846
|
};
|
|
4789
4847
|
}
|
|
4790
4848
|
function DGModalShell({ title, onClose, children, footer }) {
|
|
4791
|
-
return
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
/* @__PURE__ */ jsxs27("div", { className: "
|
|
4801
|
-
/* @__PURE__ */
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4849
|
+
return createPortal2(
|
|
4850
|
+
/* @__PURE__ */ jsx28(
|
|
4851
|
+
"div",
|
|
4852
|
+
{
|
|
4853
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
4854
|
+
style: { background: "rgba(0,0,0,0.5)" },
|
|
4855
|
+
onMouseDown: (e) => {
|
|
4856
|
+
if (e.target === e.currentTarget) onClose();
|
|
4857
|
+
},
|
|
4858
|
+
children: /* @__PURE__ */ jsxs27("div", { className: "relative w-full max-w-lg rounded-2xl border border-border bg-card shadow-2xl flex flex-col max-h-[90vh]", children: [
|
|
4859
|
+
/* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border shrink-0", children: [
|
|
4860
|
+
/* @__PURE__ */ jsx28("h2", { className: "text-base font-semibold", children: title }),
|
|
4861
|
+
/* @__PURE__ */ jsx28("button", { onClick: onClose, className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx28(X7, { className: "h-4 w-4" }) })
|
|
4862
|
+
] }),
|
|
4863
|
+
/* @__PURE__ */ jsx28("div", { className: "overflow-y-auto px-6 py-4 flex-1", children }),
|
|
4864
|
+
footer && /* @__PURE__ */ jsx28("div", { className: "px-6 py-4 border-t border-border shrink-0 flex justify-end gap-2", children: footer })
|
|
4865
|
+
] })
|
|
4866
|
+
}
|
|
4867
|
+
),
|
|
4868
|
+
document.body
|
|
4808
4869
|
);
|
|
4809
4870
|
}
|
|
4810
4871
|
function DGFieldRenderer({ field, value, onChange }) {
|
|
@@ -5118,7 +5179,10 @@ function DataGrid({
|
|
|
5118
5179
|
)
|
|
5119
5180
|
] })
|
|
5120
5181
|
} : null;
|
|
5121
|
-
const visibleCols = [
|
|
5182
|
+
const visibleCols = defaultActions?.position === "first" ? [
|
|
5183
|
+
...actionsCol ? [actionsCol] : [],
|
|
5184
|
+
...columns.filter((c) => !hiddenCols.includes(String(c.key)))
|
|
5185
|
+
] : [
|
|
5122
5186
|
...columns.filter((c) => !hiddenCols.includes(String(c.key))),
|
|
5123
5187
|
...actionsCol ? [actionsCol] : []
|
|
5124
5188
|
];
|
|
@@ -5258,7 +5322,7 @@ function DataGrid({
|
|
|
5258
5322
|
),
|
|
5259
5323
|
serverPagination && (() => {
|
|
5260
5324
|
const { pagination, currentPage: cp, goToPage } = serverPagination;
|
|
5261
|
-
const totalServerPages = Math.ceil(pagination.total / pagination.per_page);
|
|
5325
|
+
const totalServerPages = pagination.last_page ?? Math.ceil(pagination.total / pagination.per_page);
|
|
5262
5326
|
const pageLinks = Array.from({ length: totalServerPages }, (_, i) => i + 1);
|
|
5263
5327
|
return /* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
5264
5328
|
/* @__PURE__ */ jsxs27("span", { className: "text-xs text-muted-foreground", children: [
|
|
@@ -9369,10 +9433,11 @@ function Stepper({
|
|
|
9369
9433
|
|
|
9370
9434
|
// src/components/ui/table.tsx
|
|
9371
9435
|
import * as React44 from "react";
|
|
9436
|
+
import { createPortal as createPortal4 } from "react-dom";
|
|
9372
9437
|
import axios2 from "axios";
|
|
9373
9438
|
import { ChevronLeft as ChevronLeft6, ChevronRight as ChevronRight9, Search as Search5, Trash2 as Trash23, ChevronsUpDown as ChevronsUpDown2, ChevronUp as ChevronUp2, ChevronDown as ChevronDown7, X as X13, Eye as Eye2, Pencil as Pencil2, Trash as Trash3, Loader2 as Loader22 } from "lucide-react";
|
|
9374
9439
|
import { Fragment as Fragment15, jsx as jsx55, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
9375
|
-
function useServerTable({ url, params }) {
|
|
9440
|
+
function useServerTable({ url, params, encrypt }) {
|
|
9376
9441
|
const [data, setData] = React44.useState([]);
|
|
9377
9442
|
const [columns, setColumns] = React44.useState([]);
|
|
9378
9443
|
const [currentPage, setCurrentPage] = React44.useState(1);
|
|
@@ -9388,23 +9453,26 @@ function useServerTable({ url, params }) {
|
|
|
9388
9453
|
params: { ...params, page: currentPage }
|
|
9389
9454
|
}).then(({ data: res }) => {
|
|
9390
9455
|
if (cancelled) return;
|
|
9391
|
-
|
|
9392
|
-
|
|
9393
|
-
const
|
|
9394
|
-
const
|
|
9395
|
-
const
|
|
9396
|
-
|
|
9397
|
-
|
|
9398
|
-
|
|
9399
|
-
|
|
9456
|
+
const payload = encrypt ? decryptLaravelPayload(res) : res;
|
|
9457
|
+
setData(payload.data);
|
|
9458
|
+
const rawTotal = payload.total;
|
|
9459
|
+
const rawPerPage = payload.per_page;
|
|
9460
|
+
const rawLastPage = payload.last_page;
|
|
9461
|
+
const lastPage = rawLastPage ?? Math.ceil(rawTotal / rawPerPage);
|
|
9462
|
+
const pg = payload.pagination ?? {
|
|
9463
|
+
first_page_url: payload.first_page_url ?? `${url}?page=1`,
|
|
9464
|
+
last_page_url: payload.last_page_url ?? `${url}?page=${lastPage}`,
|
|
9465
|
+
last_page: lastPage,
|
|
9466
|
+
next_page_url: payload.next_page_url !== void 0 ? payload.next_page_url : currentPage < lastPage ? `${url}?page=${currentPage + 1}` : null,
|
|
9467
|
+
prev_page_url: payload.prev_page_url !== void 0 ? payload.prev_page_url : currentPage > 1 ? `${url}?page=${currentPage - 1}` : null,
|
|
9400
9468
|
per_page: rawPerPage,
|
|
9401
9469
|
total: rawTotal,
|
|
9402
|
-
links:
|
|
9470
|
+
links: payload.links ?? []
|
|
9403
9471
|
};
|
|
9404
9472
|
setPagination(pg);
|
|
9405
|
-
if (
|
|
9473
|
+
if (payload.data.length > 0) {
|
|
9406
9474
|
setColumns(
|
|
9407
|
-
Object.keys(
|
|
9475
|
+
Object.keys(payload.data[0]).map((key) => ({
|
|
9408
9476
|
key,
|
|
9409
9477
|
title: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
|
|
9410
9478
|
}))
|
|
@@ -9433,23 +9501,26 @@ function useServerTable({ url, params }) {
|
|
|
9433
9501
|
};
|
|
9434
9502
|
}
|
|
9435
9503
|
function ModalShell({ title, onClose, children, footer }) {
|
|
9436
|
-
return
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
/* @__PURE__ */ jsxs48("div", { className: "
|
|
9446
|
-
/* @__PURE__ */
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9504
|
+
return createPortal4(
|
|
9505
|
+
/* @__PURE__ */ jsx55(
|
|
9506
|
+
"div",
|
|
9507
|
+
{
|
|
9508
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
9509
|
+
style: { background: "rgba(0,0,0,0.5)" },
|
|
9510
|
+
onMouseDown: (e) => {
|
|
9511
|
+
if (e.target === e.currentTarget) onClose();
|
|
9512
|
+
},
|
|
9513
|
+
children: /* @__PURE__ */ jsxs48("div", { className: "relative w-full max-w-lg rounded-2xl border border-border bg-card shadow-2xl flex flex-col max-h-[90vh]", children: [
|
|
9514
|
+
/* @__PURE__ */ jsxs48("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border shrink-0", children: [
|
|
9515
|
+
/* @__PURE__ */ jsx55("h2", { className: "text-base font-semibold", children: title }),
|
|
9516
|
+
/* @__PURE__ */ jsx55("button", { onClick: onClose, className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx55(X13, { className: "h-4 w-4" }) })
|
|
9517
|
+
] }),
|
|
9518
|
+
/* @__PURE__ */ jsx55("div", { className: "overflow-y-auto px-6 py-4 flex-1", children }),
|
|
9519
|
+
footer && /* @__PURE__ */ jsx55("div", { className: "px-6 py-4 border-t border-border shrink-0 flex justify-end gap-2", children: footer })
|
|
9520
|
+
] })
|
|
9521
|
+
}
|
|
9522
|
+
),
|
|
9523
|
+
document.body
|
|
9453
9524
|
);
|
|
9454
9525
|
}
|
|
9455
9526
|
function FieldRenderer({ field, value, onChange }) {
|
|
@@ -9792,7 +9863,7 @@ function Table({
|
|
|
9792
9863
|
)
|
|
9793
9864
|
] })
|
|
9794
9865
|
};
|
|
9795
|
-
return [...columns, actionsCol];
|
|
9866
|
+
return defaultActions.position === "first" ? [actionsCol, ...columns] : [...columns, actionsCol];
|
|
9796
9867
|
}, [columns, defaultActions]);
|
|
9797
9868
|
const handleSort = (key) => {
|
|
9798
9869
|
if (sortKey !== key) {
|
|
@@ -9888,9 +9959,9 @@ function Table({
|
|
|
9888
9959
|
}
|
|
9889
9960
|
),
|
|
9890
9961
|
/* @__PURE__ */ jsxs48("span", { className: "text-xs text-muted-foreground", children: [
|
|
9891
|
-
filteredData.length,
|
|
9962
|
+
serverPagination ? serverPagination.pagination.total : filteredData.length,
|
|
9892
9963
|
" ",
|
|
9893
|
-
filteredData.length === 1 ? "row" : "rows",
|
|
9964
|
+
(serverPagination ? serverPagination.pagination.total : filteredData.length) === 1 ? "row" : "rows",
|
|
9894
9965
|
search && ` \xB7 filtered from ${tableData.length}`
|
|
9895
9966
|
] })
|
|
9896
9967
|
] })
|
|
@@ -10064,7 +10135,7 @@ function Table({
|
|
|
10064
10135
|
] }),
|
|
10065
10136
|
serverPagination && (() => {
|
|
10066
10137
|
const { pagination: pagination2, currentPage: cp, goToPage } = serverPagination;
|
|
10067
|
-
const totalServerPages = Math.ceil(pagination2.total / pagination2.per_page);
|
|
10138
|
+
const totalServerPages = pagination2.last_page ?? Math.ceil(pagination2.total / pagination2.per_page);
|
|
10068
10139
|
const pageLinks = Array.from({ length: totalServerPages }, (_, i) => i + 1);
|
|
10069
10140
|
return /* @__PURE__ */ jsxs48("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
10070
10141
|
/* @__PURE__ */ jsxs48("span", { className: "text-xs text-muted-foreground", children: [
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"registry": "https://registry.npmjs.org/",
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "3.
|
|
7
|
+
"version": "3.1.1",
|
|
8
8
|
"description": "Reusable React UI components",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"main": "dist/index.js",
|
|
@@ -31,8 +31,9 @@
|
|
|
31
31
|
"@types/leaflet": "^1.9.21",
|
|
32
32
|
"@types/leaflet.markercluster": "^1.5.6",
|
|
33
33
|
"@vitejs/plugin-react": "^5.0.4",
|
|
34
|
-
"axios": "
|
|
34
|
+
"axios": ">=1",
|
|
35
35
|
"clsx": "^2.1.1",
|
|
36
|
+
"crypto-js": "^4.2.0",
|
|
36
37
|
"date-fns": "^4.1.0",
|
|
37
38
|
"leaflet": "^1.9.4",
|
|
38
39
|
"leaflet.markercluster": "^1.5.3",
|