next-recomponents 2.0.41 → 2.0.42
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.d.mts +53 -13
- package/dist/index.d.ts +53 -13
- package/dist/index.js +1149 -18
- package/dist/index.mjs +1154 -19
- package/package.json +1 -1
- package/src/index.tsx +1 -0
- package/src/modal/index.tsx +8 -4
- package/src/pop/color.tsx +1 -1
- package/src/pop/index.tsx +22 -9
- package/src/pop/overlay.tsx +5 -3
- package/src/pop/types.ts +1 -1
- package/src/table/index.tsx +6 -8
- package/src/table-advanced/context.ts +88 -0
- package/src/table-advanced/filter.reducer.ts +19 -0
- package/src/table-advanced/h.table.tsx +579 -0
- package/src/table-advanced/header.tsx +335 -0
- package/src/table-advanced/icons.tsx +167 -0
- package/src/table-advanced/index.tsx +43 -0
- package/src/table-advanced/menu.item.tsx +21 -0
- package/src/table-advanced/searchable.tsx +24 -0
- package/src/table-advanced/sort.reducer.ts +29 -0
- package/src/table-advanced/types.ts +82 -0
package/package.json
CHANGED
package/src/index.tsx
CHANGED
package/src/modal/index.tsx
CHANGED
|
@@ -15,6 +15,7 @@ export default function Modal({
|
|
|
15
15
|
children,
|
|
16
16
|
color = "primary",
|
|
17
17
|
title,
|
|
18
|
+
onClose,
|
|
18
19
|
}: {
|
|
19
20
|
button: ReactElement<React.ComponentPropsWithRef<"button">>;
|
|
20
21
|
children: ReactElement<
|
|
@@ -22,9 +23,12 @@ export default function Modal({
|
|
|
22
23
|
>;
|
|
23
24
|
color?: PopupColor;
|
|
24
25
|
title?: string;
|
|
26
|
+
onClose?: () => Promise<boolean>;
|
|
25
27
|
}) {
|
|
26
28
|
const pop = usePopup();
|
|
27
|
-
const hide = () =>
|
|
29
|
+
const hide = () => {
|
|
30
|
+
pop.close(false);
|
|
31
|
+
};
|
|
28
32
|
|
|
29
33
|
const childrenWithHide = useMemo(
|
|
30
34
|
() => cloneElement(children, { hide }),
|
|
@@ -39,14 +43,14 @@ export default function Modal({
|
|
|
39
43
|
const onClick = props?.onClick;
|
|
40
44
|
|
|
41
45
|
return (
|
|
42
|
-
|
|
46
|
+
<div className="">
|
|
43
47
|
{cloneElement(button, {
|
|
44
48
|
onClick: (e) => {
|
|
45
49
|
onClick?.(e as any);
|
|
46
|
-
pop.modal(childrenWithHide, color, false, true);
|
|
50
|
+
pop.modal(childrenWithHide, color, false, true, onClose);
|
|
47
51
|
},
|
|
48
52
|
})}
|
|
49
53
|
{pop.PopupComponent}
|
|
50
|
-
|
|
54
|
+
</div>
|
|
51
55
|
);
|
|
52
56
|
}
|
package/src/pop/color.tsx
CHANGED
package/src/pop/index.tsx
CHANGED
|
@@ -30,13 +30,21 @@ export default function usePopup() {
|
|
|
30
30
|
[],
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
-
const close = useCallback(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const close = useCallback(
|
|
34
|
+
async (confirmed: boolean, value?: string) => {
|
|
35
|
+
const prev = { ...popup };
|
|
36
|
+
let visible = false;
|
|
37
|
+
if (confirmed) {
|
|
38
|
+
prev.onConfirm?.(value);
|
|
39
|
+
} else if (prev?.onCancel) {
|
|
40
|
+
visible = !Boolean(await prev.onCancel?.());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const data = { ...prev, visible, inputValue: "" };
|
|
44
|
+
setPopup(data);
|
|
45
|
+
},
|
|
46
|
+
[popup],
|
|
47
|
+
);
|
|
40
48
|
|
|
41
49
|
const alert = useCallback(
|
|
42
50
|
(message: string, color: PopupColor = "primary"): Promise<void> =>
|
|
@@ -58,14 +66,19 @@ export default function usePopup() {
|
|
|
58
66
|
color: PopupColor = "primary",
|
|
59
67
|
icons: boolean = false,
|
|
60
68
|
full: boolean = false,
|
|
69
|
+
onClose?: () => Promise<boolean>,
|
|
61
70
|
): Promise<void> =>
|
|
62
71
|
new Promise((resolve) =>
|
|
63
72
|
open({
|
|
64
73
|
type: "modal",
|
|
65
74
|
message,
|
|
66
75
|
color,
|
|
67
|
-
onConfirm: () =>
|
|
68
|
-
|
|
76
|
+
// onConfirm: () => {
|
|
77
|
+
// resolve();
|
|
78
|
+
// },
|
|
79
|
+
onCancel: async () => {
|
|
80
|
+
return await onClose?.();
|
|
81
|
+
},
|
|
69
82
|
icons,
|
|
70
83
|
full,
|
|
71
84
|
}),
|
package/src/pop/overlay.tsx
CHANGED
|
@@ -16,7 +16,7 @@ export function PopupOverlay({
|
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
18
|
<div
|
|
19
|
-
className=
|
|
19
|
+
className="fixed inset-0 flex items-center justify-center z-[1000] overflow-auto p-1"
|
|
20
20
|
style={{ background: "rgba(15,23,42,0.45)", backdropFilter: "blur(2px)" }}
|
|
21
21
|
// onClick={(e) => {
|
|
22
22
|
// if (e.target === e.currentTarget) {
|
|
@@ -33,7 +33,7 @@ export function PopupOverlay({
|
|
|
33
33
|
`}</style>
|
|
34
34
|
|
|
35
35
|
<div
|
|
36
|
-
className={`bg-gradient-to-br ${c.bg} border ${c.border} ${popup.full == true ? " w-
|
|
36
|
+
className={`bg-gradient-to-br ${c.bg} border ${c.border} ${popup.full == true ? " w-screen h-screen mt-10 " : " max-w-sm "} rounded shadow m-2`}
|
|
37
37
|
style={{ animation: "fadeInScale 0.18s ease-out", overflow: "auto" }}
|
|
38
38
|
>
|
|
39
39
|
{/* Header */}
|
|
@@ -77,7 +77,9 @@ export function PopupOverlay({
|
|
|
77
77
|
)}
|
|
78
78
|
|
|
79
79
|
{/* Divider */}
|
|
80
|
-
|
|
80
|
+
{popup.type !== "modal" && (
|
|
81
|
+
<div className={`border-t ${c.border} mt-4`} />
|
|
82
|
+
)}
|
|
81
83
|
|
|
82
84
|
{/* Actions */}
|
|
83
85
|
{popup.type !== "modal" && (
|
package/src/pop/types.ts
CHANGED
package/src/table/index.tsx
CHANGED
|
@@ -9,13 +9,6 @@ import regularExpresions from "../regular-expresions";
|
|
|
9
9
|
|
|
10
10
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
11
11
|
|
|
12
|
-
export interface TableButtonProps extends React.MouseEvent<
|
|
13
|
-
HTMLButtonElement,
|
|
14
|
-
MouseEvent
|
|
15
|
-
> {
|
|
16
|
-
row: Record<string, any>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
12
|
type FooterAggregation = "sum" | "avg" | "count";
|
|
20
13
|
|
|
21
14
|
interface FooterType {
|
|
@@ -23,7 +16,12 @@ interface FooterType {
|
|
|
23
16
|
}
|
|
24
17
|
|
|
25
18
|
type GridDensity = "compact" | "standard" | "comfortable";
|
|
26
|
-
|
|
19
|
+
export interface TableButtonProps extends React.MouseEvent<
|
|
20
|
+
HTMLButtonElement,
|
|
21
|
+
MouseEvent
|
|
22
|
+
> {
|
|
23
|
+
row: Record<string, any>;
|
|
24
|
+
}
|
|
27
25
|
interface TableProps {
|
|
28
26
|
data: any;
|
|
29
27
|
searchable?: boolean;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { useEffect, useMemo, useReducer, useState } from "react";
|
|
2
|
+
import { filterReducer } from "./filter.reducer";
|
|
3
|
+
import { FiltersType, SortType } from "./types";
|
|
4
|
+
import { sortReducer } from "./sort.reducer";
|
|
5
|
+
import useExcel from "../use-excel";
|
|
6
|
+
|
|
7
|
+
export default function useContext({ onSelect }: { onSelect?: boolean }) {
|
|
8
|
+
const excel = useExcel();
|
|
9
|
+
const [editions, setEditions] = useState<any[]>([]);
|
|
10
|
+
const [selected, setSelected] = useState<any[]>([]);
|
|
11
|
+
const [data, setData] = useState<any[]>([]);
|
|
12
|
+
const headers = [...new Set(data.map((b) => Object.keys(b)).flat())];
|
|
13
|
+
|
|
14
|
+
const [currentHeader, setCurrentHeader] = useState<string | null>(null);
|
|
15
|
+
const cols = headers.length;
|
|
16
|
+
const [filters, setFilters] = useReducer(
|
|
17
|
+
filterReducer,
|
|
18
|
+
new Array<FiltersType>(),
|
|
19
|
+
);
|
|
20
|
+
const [searchBy, setSearchBy] = useState<string>("");
|
|
21
|
+
const [sort, setSort] = useReducer(sortReducer, new Array<SortType>());
|
|
22
|
+
|
|
23
|
+
const sortedData: any[] = useMemo(() => {
|
|
24
|
+
return [...data].sort((a, b) => {
|
|
25
|
+
for (const { field, type } of sort.reverse()) {
|
|
26
|
+
const av = a[field];
|
|
27
|
+
const bv = b[field];
|
|
28
|
+
|
|
29
|
+
// nulls/undefined van siempre al final, independiente de ASC/DESC
|
|
30
|
+
if (av == null && bv == null) continue;
|
|
31
|
+
if (av == null) return 1;
|
|
32
|
+
if (bv == null) return -1;
|
|
33
|
+
|
|
34
|
+
let cmp: number;
|
|
35
|
+
if (typeof av === "number" && typeof bv === "number") {
|
|
36
|
+
cmp = av - bv;
|
|
37
|
+
} else {
|
|
38
|
+
cmp = `${av}`.localeCompare(`${bv}`, undefined, { numeric: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (cmp !== 0) {
|
|
42
|
+
return type === "DESC" ? -cmp : cmp;
|
|
43
|
+
}
|
|
44
|
+
// empate: sigue al siguiente campo en context.sort
|
|
45
|
+
}
|
|
46
|
+
return 0;
|
|
47
|
+
});
|
|
48
|
+
}, [data, sort]);
|
|
49
|
+
const filteredData = [...sortedData].filter((d) => {
|
|
50
|
+
if (editions.includes(d?.id)) return true;
|
|
51
|
+
|
|
52
|
+
for (const { field, values } of filters) {
|
|
53
|
+
if (!values.includes(d[field])) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (filters.length == 0) {
|
|
62
|
+
setEditions([]);
|
|
63
|
+
}
|
|
64
|
+
}, [filters]);
|
|
65
|
+
return {
|
|
66
|
+
currentHeader,
|
|
67
|
+
setCurrentHeader,
|
|
68
|
+
sort,
|
|
69
|
+
setSort,
|
|
70
|
+
cols,
|
|
71
|
+
headers,
|
|
72
|
+
data,
|
|
73
|
+
sortedData,
|
|
74
|
+
filters,
|
|
75
|
+
setFilters,
|
|
76
|
+
filteredData,
|
|
77
|
+
setData,
|
|
78
|
+
searchBy,
|
|
79
|
+
setSearchBy,
|
|
80
|
+
selected,
|
|
81
|
+
setSelected,
|
|
82
|
+
editions,
|
|
83
|
+
excel,
|
|
84
|
+
setEditions,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type ContextType = ReturnType<typeof useContext>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FiltersType } from "./types";
|
|
2
|
+
|
|
3
|
+
export const filterReducer = (acc: FiltersType[], b: FiltersType | null) => {
|
|
4
|
+
if (b == null) return [];
|
|
5
|
+
const newAcc: FiltersType[] = [];
|
|
6
|
+
newAcc.push(b);
|
|
7
|
+
return newAcc;
|
|
8
|
+
|
|
9
|
+
// const newAcc = [...acc];
|
|
10
|
+
|
|
11
|
+
// const index = newAcc.findIndex((aa) => aa.field == b.field);
|
|
12
|
+
// if (index >= 0) {
|
|
13
|
+
// newAcc[index].values = b.values;
|
|
14
|
+
// } else {
|
|
15
|
+
// newAcc.push(b);
|
|
16
|
+
// }
|
|
17
|
+
|
|
18
|
+
// return newAcc;
|
|
19
|
+
};
|