@juv/codego-react-ui 3.1.0 → 3.1.2
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 +136 -57
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.global.js +6708 -61
- package/dist/index.js +135 -57
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1997,6 +1997,60 @@ function MetricRow({ items, divided = true, className }) {
|
|
|
1997
1997
|
// src/components/ui/data-grid.tsx
|
|
1998
1998
|
import * as React24 from "react";
|
|
1999
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
|
|
2000
2054
|
import axios from "axios";
|
|
2001
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";
|
|
2002
2056
|
|
|
@@ -4730,7 +4784,7 @@ Input.displayName = "Input";
|
|
|
4730
4784
|
|
|
4731
4785
|
// src/components/ui/data-grid.tsx
|
|
4732
4786
|
import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4733
|
-
function useServerDataGrid({ url, params }) {
|
|
4787
|
+
function useServerDataGrid({ url, params, encrypt }) {
|
|
4734
4788
|
const [data, setData] = React24.useState([]);
|
|
4735
4789
|
const [columns, setColumns] = React24.useState([]);
|
|
4736
4790
|
const [currentPage, setCurrentPage] = React24.useState(1);
|
|
@@ -4744,25 +4798,26 @@ function useServerDataGrid({ url, params }) {
|
|
|
4744
4798
|
setError(null);
|
|
4745
4799
|
axios.get(url, { params: { ...params, page: currentPage } }).then(({ data: res }) => {
|
|
4746
4800
|
if (cancelled) return;
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
const
|
|
4750
|
-
const
|
|
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;
|
|
4751
4806
|
const lastPage = rawLastPage ?? Math.ceil(rawTotal / rawPerPage);
|
|
4752
|
-
const pg =
|
|
4753
|
-
first_page_url:
|
|
4754
|
-
last_page_url:
|
|
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}`,
|
|
4755
4810
|
last_page: lastPage,
|
|
4756
|
-
next_page_url:
|
|
4757
|
-
prev_page_url:
|
|
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,
|
|
4758
4813
|
per_page: rawPerPage,
|
|
4759
4814
|
total: rawTotal,
|
|
4760
|
-
links:
|
|
4815
|
+
links: payload.links ?? []
|
|
4761
4816
|
};
|
|
4762
4817
|
setPagination(pg);
|
|
4763
|
-
if (
|
|
4818
|
+
if (payload.data.length > 0) {
|
|
4764
4819
|
setColumns(
|
|
4765
|
-
Object.keys(
|
|
4820
|
+
Object.keys(payload.data[0]).map((key) => ({
|
|
4766
4821
|
key,
|
|
4767
4822
|
header: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
|
|
4768
4823
|
}))
|
|
@@ -5023,9 +5078,9 @@ function DataGrid({
|
|
|
5023
5078
|
const [viewItem, setViewItem] = React24.useState(null);
|
|
5024
5079
|
const [editItem, setEditItem] = React24.useState(null);
|
|
5025
5080
|
const [deleteItem, setDeleteItem] = React24.useState(null);
|
|
5026
|
-
const [tableData, setTableData] = React24.useState(data);
|
|
5081
|
+
const [tableData, setTableData] = React24.useState(data ?? []);
|
|
5027
5082
|
React24.useEffect(() => {
|
|
5028
|
-
setTableData(data);
|
|
5083
|
+
setTableData(data ?? []);
|
|
5029
5084
|
}, [data]);
|
|
5030
5085
|
const actionIdKey = defaultActions?.idKey ?? (typeof rowKey === "string" ? rowKey : "id");
|
|
5031
5086
|
const autoFields = React24.useMemo(() => {
|
|
@@ -5070,7 +5125,7 @@ function DataGrid({
|
|
|
5070
5125
|
document.addEventListener("mousedown", handler);
|
|
5071
5126
|
return () => document.removeEventListener("mousedown", handler);
|
|
5072
5127
|
}, []);
|
|
5073
|
-
let processed = data.filter(
|
|
5128
|
+
let processed = (data ?? []).filter(
|
|
5074
5129
|
(row) => Object.entries(filters).every(([k, v]) => {
|
|
5075
5130
|
if (!v) return true;
|
|
5076
5131
|
const cell = String(row[k] ?? "").toLowerCase();
|
|
@@ -5268,7 +5323,16 @@ function DataGrid({
|
|
|
5268
5323
|
serverPagination && (() => {
|
|
5269
5324
|
const { pagination, currentPage: cp, goToPage } = serverPagination;
|
|
5270
5325
|
const totalServerPages = pagination.last_page ?? Math.ceil(pagination.total / pagination.per_page);
|
|
5271
|
-
const
|
|
5326
|
+
const pills = [];
|
|
5327
|
+
if (totalServerPages <= 7) {
|
|
5328
|
+
for (let i = 1; i <= totalServerPages; i++) pills.push(i);
|
|
5329
|
+
} else if (cp <= 4) {
|
|
5330
|
+
pills.push(1, 2, 3, 4, 5, -1, totalServerPages);
|
|
5331
|
+
} else if (cp >= totalServerPages - 3) {
|
|
5332
|
+
pills.push(1, -1, totalServerPages - 4, totalServerPages - 3, totalServerPages - 2, totalServerPages - 1, totalServerPages);
|
|
5333
|
+
} else {
|
|
5334
|
+
pills.push(1, -1, cp - 1, cp, cp + 1, -2, totalServerPages);
|
|
5335
|
+
}
|
|
5272
5336
|
return /* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
5273
5337
|
/* @__PURE__ */ jsxs27("span", { className: "text-xs text-muted-foreground", children: [
|
|
5274
5338
|
pagination.total,
|
|
@@ -5287,18 +5351,20 @@ function DataGrid({
|
|
|
5287
5351
|
children: /* @__PURE__ */ jsx28(ChevronLeft5, { className: "h-4 w-4" })
|
|
5288
5352
|
}
|
|
5289
5353
|
),
|
|
5290
|
-
|
|
5291
|
-
"
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5354
|
+
pills.map(
|
|
5355
|
+
(p, i) => p < 0 ? /* @__PURE__ */ jsx28("span", { className: "px-1 text-muted-foreground text-xs", children: "\u2026" }, p - i) : /* @__PURE__ */ jsx28(
|
|
5356
|
+
"button",
|
|
5357
|
+
{
|
|
5358
|
+
onClick: () => goToPage(p),
|
|
5359
|
+
className: cn(
|
|
5360
|
+
"flex h-8 w-8 items-center justify-center rounded-lg border text-xs font-medium transition-colors",
|
|
5361
|
+
p === cp ? "border-primary bg-primary text-primary-foreground shadow-sm" : "border-border text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
5362
|
+
),
|
|
5363
|
+
children: p
|
|
5364
|
+
},
|
|
5365
|
+
p
|
|
5366
|
+
)
|
|
5367
|
+
),
|
|
5302
5368
|
/* @__PURE__ */ jsx28(
|
|
5303
5369
|
"button",
|
|
5304
5370
|
{
|
|
@@ -9382,7 +9448,7 @@ import { createPortal as createPortal4 } from "react-dom";
|
|
|
9382
9448
|
import axios2 from "axios";
|
|
9383
9449
|
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";
|
|
9384
9450
|
import { Fragment as Fragment15, jsx as jsx55, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
9385
|
-
function useServerTable({ url, params }) {
|
|
9451
|
+
function useServerTable({ url, params, encrypt }) {
|
|
9386
9452
|
const [data, setData] = React44.useState([]);
|
|
9387
9453
|
const [columns, setColumns] = React44.useState([]);
|
|
9388
9454
|
const [currentPage, setCurrentPage] = React44.useState(1);
|
|
@@ -9398,25 +9464,26 @@ function useServerTable({ url, params }) {
|
|
|
9398
9464
|
params: { ...params, page: currentPage }
|
|
9399
9465
|
}).then(({ data: res }) => {
|
|
9400
9466
|
if (cancelled) return;
|
|
9401
|
-
|
|
9402
|
-
|
|
9403
|
-
const
|
|
9404
|
-
const
|
|
9467
|
+
const payload = encrypt ? decryptLaravelPayload(res) : res;
|
|
9468
|
+
setData(payload.data);
|
|
9469
|
+
const rawTotal = payload.total;
|
|
9470
|
+
const rawPerPage = payload.per_page;
|
|
9471
|
+
const rawLastPage = payload.last_page;
|
|
9405
9472
|
const lastPage = rawLastPage ?? Math.ceil(rawTotal / rawPerPage);
|
|
9406
|
-
const pg =
|
|
9407
|
-
first_page_url:
|
|
9408
|
-
last_page_url:
|
|
9473
|
+
const pg = payload.pagination ?? {
|
|
9474
|
+
first_page_url: payload.first_page_url ?? `${url}?page=1`,
|
|
9475
|
+
last_page_url: payload.last_page_url ?? `${url}?page=${lastPage}`,
|
|
9409
9476
|
last_page: lastPage,
|
|
9410
|
-
next_page_url:
|
|
9411
|
-
prev_page_url:
|
|
9477
|
+
next_page_url: payload.next_page_url !== void 0 ? payload.next_page_url : currentPage < lastPage ? `${url}?page=${currentPage + 1}` : null,
|
|
9478
|
+
prev_page_url: payload.prev_page_url !== void 0 ? payload.prev_page_url : currentPage > 1 ? `${url}?page=${currentPage - 1}` : null,
|
|
9412
9479
|
per_page: rawPerPage,
|
|
9413
9480
|
total: rawTotal,
|
|
9414
|
-
links:
|
|
9481
|
+
links: payload.links ?? []
|
|
9415
9482
|
};
|
|
9416
9483
|
setPagination(pg);
|
|
9417
|
-
if (
|
|
9484
|
+
if (payload.data.length > 0) {
|
|
9418
9485
|
setColumns(
|
|
9419
|
-
Object.keys(
|
|
9486
|
+
Object.keys(payload.data[0]).map((key) => ({
|
|
9420
9487
|
key,
|
|
9421
9488
|
title: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
|
|
9422
9489
|
}))
|
|
@@ -9755,9 +9822,9 @@ function Table({
|
|
|
9755
9822
|
const [viewItem, setViewItem] = React44.useState(null);
|
|
9756
9823
|
const [editItem, setEditItem] = React44.useState(null);
|
|
9757
9824
|
const [deleteItem, setDeleteItem] = React44.useState(null);
|
|
9758
|
-
const [tableData, setTableData] = React44.useState(data);
|
|
9825
|
+
const [tableData, setTableData] = React44.useState(data ?? []);
|
|
9759
9826
|
React44.useEffect(() => {
|
|
9760
|
-
setTableData(data);
|
|
9827
|
+
setTableData(data ?? []);
|
|
9761
9828
|
}, [data]);
|
|
9762
9829
|
const actionIdKey = defaultActions?.idKey ?? idKey;
|
|
9763
9830
|
const autoFields = React44.useMemo(() => {
|
|
@@ -10080,7 +10147,16 @@ function Table({
|
|
|
10080
10147
|
serverPagination && (() => {
|
|
10081
10148
|
const { pagination: pagination2, currentPage: cp, goToPage } = serverPagination;
|
|
10082
10149
|
const totalServerPages = pagination2.last_page ?? Math.ceil(pagination2.total / pagination2.per_page);
|
|
10083
|
-
const
|
|
10150
|
+
const pills = [];
|
|
10151
|
+
if (totalServerPages <= 7) {
|
|
10152
|
+
for (let i = 1; i <= totalServerPages; i++) pills.push(i);
|
|
10153
|
+
} else if (cp <= 4) {
|
|
10154
|
+
pills.push(1, 2, 3, 4, 5, -1, totalServerPages);
|
|
10155
|
+
} else if (cp >= totalServerPages - 3) {
|
|
10156
|
+
pills.push(1, -1, totalServerPages - 4, totalServerPages - 3, totalServerPages - 2, totalServerPages - 1, totalServerPages);
|
|
10157
|
+
} else {
|
|
10158
|
+
pills.push(1, -1, cp - 1, cp, cp + 1, -2, totalServerPages);
|
|
10159
|
+
}
|
|
10084
10160
|
return /* @__PURE__ */ jsxs48("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
10085
10161
|
/* @__PURE__ */ jsxs48("span", { className: "text-xs text-muted-foreground", children: [
|
|
10086
10162
|
pagination2.total,
|
|
@@ -10099,18 +10175,20 @@ function Table({
|
|
|
10099
10175
|
children: /* @__PURE__ */ jsx55(ChevronLeft6, { className: "h-4 w-4" })
|
|
10100
10176
|
}
|
|
10101
10177
|
),
|
|
10102
|
-
|
|
10103
|
-
"
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10178
|
+
pills.map(
|
|
10179
|
+
(p, i) => p < 0 ? /* @__PURE__ */ jsx55("span", { className: "px-1 text-muted-foreground text-xs", children: "\u2026" }, p - i) : /* @__PURE__ */ jsx55(
|
|
10180
|
+
"button",
|
|
10181
|
+
{
|
|
10182
|
+
onClick: () => goToPage(p),
|
|
10183
|
+
className: cn(
|
|
10184
|
+
"flex h-8 w-8 items-center justify-center rounded-lg border text-xs font-medium transition-colors",
|
|
10185
|
+
p === cp ? "border-primary bg-primary text-primary-foreground shadow-sm" : "border-border text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
10186
|
+
),
|
|
10187
|
+
children: p
|
|
10188
|
+
},
|
|
10189
|
+
p
|
|
10190
|
+
)
|
|
10191
|
+
),
|
|
10114
10192
|
/* @__PURE__ */ jsx55(
|
|
10115
10193
|
"button",
|
|
10116
10194
|
{
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"registry": "https://registry.npmjs.org/",
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "3.1.
|
|
7
|
+
"version": "3.1.2",
|
|
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",
|