next-recomponents 1.2.5 → 1.2.7

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.
@@ -5,35 +5,35 @@ import { FilterOffIcon } from "./filters";
5
5
  export default function FilterMenu({
6
6
  h,
7
7
  mapedData,
8
+ setMapedData,
8
9
  selectedFilter,
9
10
  index,
10
- filters,
11
- setFilters,
12
11
  setSelectedFilter,
13
- items,
14
12
  }: {
15
13
  h: string;
16
14
  mapedData: any[];
15
+ setMapedData: any;
17
16
  selectedFilter: number | null;
18
17
  index: number;
19
- filters: any;
20
- setFilters: Dispatch<any>;
21
18
  setSelectedFilter: Dispatch<any>;
22
- items: any[];
23
19
  }) {
24
- const [visibleFloat, setVisibleFloat] = useState(false);
25
20
  const [text, setText] = useState("");
26
21
  const [newMapedData, setNewMapedData] = useState<Array<any>>([]);
27
22
 
28
23
  useEffect(() => {
29
24
  setNewMapedData(
30
- [...new Set<string>(mapedData.map((md: any) => md[h]?.content))].filter(
31
- (item) => {
32
- return item && `${item}`.toLowerCase().includes(text.toLowerCase());
33
- }
34
- )
25
+ [
26
+ ...new Set<string>(
27
+ mapedData
28
+ .filter((md) => md.__visible__ === true)
29
+ .map((md: any) => md[h])
30
+ ),
31
+ ].filter((item) => {
32
+ return item && `${item}`.toLowerCase().includes(text.toLowerCase());
33
+ })
35
34
  );
36
35
  }, [mapedData, text]);
36
+
37
37
  useEffect(() => {
38
38
  setText("");
39
39
  }, [selectedFilter]);
@@ -46,56 +46,25 @@ export default function FilterMenu({
46
46
  style={{ zIndex: 9999999 }}
47
47
  >
48
48
  <div className="flex flex-col items-start text-black">
49
- {filters[h].length != items.length && (
50
- <div
51
- className="flex gap-1 w-full hover:bg-gray-100 p-3 cursor-pointer"
52
- onClick={(e) => {
53
- const newFilters = { ...filters };
54
- newFilters[h] = [...items];
55
- setFilters(newFilters);
56
- }}
57
- >
58
- <div className="text-red-500">
59
- <FilterOffIcon />
60
- </div>{" "}
61
- Limpiar filtro de "{h}"
62
- </div>
63
- )}
64
- {/* <div
65
- className="flex w-full items-center flex-row justify-between hover:bg-gray-100 p-3 cursor-pointer"
66
- onPointerEnter={() => {
67
- setVisibleFloat(true);
68
- }}
69
- onPointerLeave={(e) => {
70
- setVisibleFloat(false);
49
+ <div
50
+ className="flex gap-1 w-full hover:bg-gray-100 p-3 cursor-pointer"
51
+ onClick={(e) => {
52
+ const nmd = [...mapedData];
53
+ setMapedData(
54
+ nmd.map((d) => {
55
+ const newd = { ...d };
56
+ newd[h].exclude = false;
57
+ return newd;
58
+ })
59
+ );
60
+ setSelectedFilter(null);
71
61
  }}
72
62
  >
73
- Filtros de Texto <ArrowIcon />
74
- {visibleFloat && (
75
- <div className="absolute -right-[200px] border shadow w-[200px] bg-white flex flex-col items-start">
76
- <div className="hover:bg-gray-100 w-full text-left p-2">
77
- Es igual
78
- </div>
79
- <div className="hover:bg-gray-100 w-full text-left p-2">
80
- No es igual
81
- </div>
82
- <hr />
83
- <div className="hover:bg-gray-100 w-full text-left p-2">
84
- Empieza con
85
- </div>
86
- <div className="hover:bg-gray-100 w-full text-left p-2">
87
- Termina con
88
- </div>
89
- <hr />
90
- <div className="hover:bg-gray-100 w-full text-left p-2">
91
- Contiene
92
- </div>
93
- <div className="hover:bg-gray-100 w-full text-left p-2">
94
- No contiene
95
- </div>
96
- </div>
97
- )}
98
- </div> */}
63
+ <div className="text-red-500">
64
+ <FilterOffIcon />
65
+ </div>{" "}
66
+ Limpiar filtros
67
+ </div>
99
68
  <div className="flex w-full items-center flex-row justify-between hover:bg-gray-100 p-3 cursor-pointer">
100
69
  <Input
101
70
  label={null}
@@ -103,7 +72,6 @@ export default function FilterMenu({
103
72
  placeholder="Buscar..."
104
73
  value={text}
105
74
  onChange={(e) => {
106
- setFilters({ ...filters, [h]: [] });
107
75
  setText(e.target.value);
108
76
  }}
109
77
  />
@@ -117,46 +85,60 @@ export default function FilterMenu({
117
85
  <label>
118
86
  <input
119
87
  type="checkbox"
120
- checked={filters[h].length == items.length}
88
+ checked={mapedData
89
+ .map((d) => d[h].exclude)
90
+ .every((d) => d === false)}
121
91
  onChange={(e) => {
122
- const newFilters = { ...filters };
123
- if (filters[h].length == items.length) {
124
- newFilters[h] = [];
125
- } else {
126
- newFilters[h] = [...items];
127
- }
128
- setFilters(newFilters);
92
+ const nmd = [...mapedData];
93
+ setMapedData(
94
+ nmd.map((d) => {
95
+ const newd = { ...d };
96
+ newd[h].exclude = false;
97
+ return newd;
98
+ })
99
+ );
129
100
  }}
130
101
  />{" "}
131
102
  (Seleccionar todo)
132
103
  </label>
133
104
  </div>
134
- {newMapedData.map((item: string, key: number) => {
135
- const checked = filters[h]?.find((i: any) => i == item);
105
+ {newMapedData.map((item: Record<string, any>, key: number) => {
106
+ const excludeds = mapedData.filter((d) => {
107
+ const obj = Object.keys(d).map((i) => {
108
+ return d[i].exclude === true;
109
+ });
110
+
111
+ return obj.some((o) => o === true);
112
+ });
113
+ const finded = excludeds.find(
114
+ (e) => e[item.name].content == item.content
115
+ );
116
+ const disabled =
117
+ finded &&
118
+ Object.keys(finded)
119
+ .map((k) => {
120
+ if (k == item.name) return false;
121
+ return finded[k]?.exclude;
122
+ })
123
+ .some((i) => i === true);
124
+
136
125
  return (
137
126
  <div
138
127
  className="flex gap-2 items-center justify-start"
139
- key={item}
128
+ key={item.content}
140
129
  >
141
130
  <label>
142
131
  <input
143
132
  type="checkbox"
144
- checked={!!checked}
133
+ checked={!item.exclude}
134
+ disabled={disabled}
145
135
  onChange={(e) => {
146
- const newFilters = { ...filters };
147
- newFilters[h] = newFilters[h] || [];
148
- const index = newFilters[h].findIndex(
149
- (nf: any) => nf == item
150
- );
151
- if (index >= 0) {
152
- newFilters[h].splice(index, 1);
153
- } else {
154
- newFilters[h].push(item);
155
- }
156
- setFilters(newFilters);
136
+ const n = [...newMapedData];
137
+ n[key].exclude = !item.exclude;
138
+ setNewMapedData(n);
157
139
  }}
158
140
  />{" "}
159
- {item}
141
+ {item.content}
160
142
  </label>
161
143
  </div>
162
144
  );
@@ -166,7 +148,9 @@ export default function FilterMenu({
166
148
  <div className="w-full p-1">
167
149
  <div className="flex flex-row gap-2 justify-end w-full ">
168
150
  <button
169
- onClick={(e) => setSelectedFilter(null)}
151
+ onClick={(e) => {
152
+ setSelectedFilter(null);
153
+ }}
170
154
  className="p-1 border rounded shadow hover:bg-gray-100"
171
155
  >
172
156
  Aceptar
package/src/table/h.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useRef, useState } from "react";
1
+ import React, { useEffect, useMemo, useRef, useState } from "react";
2
2
  import { TableProps } from ".";
3
3
  import TD from "./td";
4
4
  import { FilterOffIcon } from "./filters";
@@ -16,13 +16,12 @@ export default function HTable({
16
16
  const [selected, setSelected] = useState<number | null>(null);
17
17
  const [selectedFilter, setSelectedFilter] = useState<number | null>(null);
18
18
  const modalRef = useRef<HTMLDialogElement>(null);
19
- const [filters, setFilters] = useState<any>({});
20
19
  const head = useMemo(() => {
21
20
  return [...new Set<string>(data.map((d: any) => Object.keys(d)).flat())];
22
21
  }, [data]);
23
22
 
24
23
  const mapedTotals = useMemo(() => {
25
- return mapedData.reduce((acc: any, md: any) => {
24
+ return mapedData?.reduce((acc: any, md: any) => {
26
25
  head.forEach((h) => {
27
26
  const value = isNaN(+md[h]?.content) ? 0 : +md[h]?.content;
28
27
  if (acc[h]) {
@@ -35,21 +34,9 @@ export default function HTable({
35
34
  }, {});
36
35
  }, [mapedData]);
37
36
 
38
- useEffect(() => {
39
- setFilters({
40
- ...head.reduce((acc, hh) => {
41
- const newAcc: any = { ...acc };
42
- newAcc[hh] = [
43
- ...new Set<string>(mapedData.map((md: any) => md[hh]?.content)),
44
- ];
45
- return newAcc;
46
- }, {}),
47
- });
48
- }, [mapedData, head]);
49
-
50
37
  useEffect(() => {
51
38
  const newData = data.map((d: any, trkey: number) => {
52
- const obj: any = {};
39
+ const obj: any = { __visible__: true };
53
40
  for (let key in d) {
54
41
  const typeOf = typeof d[key];
55
42
  const isObject = typeOf == "object";
@@ -59,89 +46,81 @@ export default function HTable({
59
46
  cellTypeOf == "date"
60
47
  ? d[key].split("T").join(" ").split(".")[0]
61
48
  : cellTypeOf == "object"
62
- ? JSON.stringify(d[key])
49
+ ? React.isValidElement(d[key])
50
+ ? d[key]
51
+ : JSON.stringify(d[key])
63
52
  : d[key];
64
53
  obj[key] = {
54
+ index: trkey,
65
55
  originalData: content,
66
56
  cellTypeOf: cellTypeOf,
67
57
  title: content,
68
58
  content,
69
59
  name: key,
60
+ exclude: false,
70
61
  };
71
62
  }
72
63
  return obj;
73
64
  });
74
-
75
65
  setMapedData(newData);
76
66
  }, [data]);
77
67
  return (
78
- <table {...props} className="w-full border-collapse table-auto">
79
- <thead className="bg-gray-800 text-white">
80
- <tr>
81
- {head.map((h, key) => {
82
- const items = [
83
- ...new Set<string>(
84
- mapedData.map((item: any) => item[h]?.content)
85
- ),
86
- ];
87
- return (
88
- <th
89
- key={key}
90
- className="whitespace-nowrap overflow-hidden text-ellipsis max-w-[200px] border-b p-5"
91
- >
92
- <div
93
- className="cursor-pointer flex "
94
- onClick={(e) => {
95
- setSelectedFilter(key == selectedFilter ? null : key);
96
- }}
68
+ <>
69
+ <table {...props} className="w-full border-collapse table-auto">
70
+ <thead className="bg-gray-800 text-white">
71
+ <tr>
72
+ {head.map((h, key) => {
73
+ return (
74
+ <th
75
+ key={h}
76
+ className="whitespace-nowrap overflow-hidden text-ellipsis max-w-[200px] border-b p-5"
97
77
  >
98
- <div className="text-white w-full bg-black rounded p-1 flex justify-center">
99
- {h}{" "}
100
- {filters[h]?.length != items.length && (
101
- <div className="text-red-300">
102
- <FilterOffIcon />
103
- </div>
104
- )}
78
+ <div
79
+ className="cursor-pointer flex "
80
+ onClick={(e) => {
81
+ setSelectedFilter(key == selectedFilter ? null : key);
82
+ }}
83
+ >
84
+ <div className="text-white w-full bg-black rounded p-1 flex justify-center">
85
+ {h}{" "}
86
+ {!mapedData
87
+ .map((d: any) => d[h].exclude)
88
+ .every((d: any) => d === false) && (
89
+ <div className="text-red-300">
90
+ <FilterOffIcon />
91
+ </div>
92
+ )}
93
+ </div>
105
94
  </div>
106
- </div>
107
95
 
108
- <FilterMenu
109
- filters={filters}
110
- setFilters={setFilters}
111
- items={items}
112
- h={h}
113
- mapedData={mapedData}
114
- index={key}
115
- selectedFilter={selectedFilter}
116
- setSelectedFilter={setSelectedFilter}
117
- />
118
- </th>
119
- );
120
- })}
121
- </tr>
122
- </thead>
123
- <tbody className="divide-y divide-gray-200">
124
- {mapedData
125
- .filter((md: any) => {
126
- for (let datum of Object.keys(md)) {
127
- if (
128
- !filters[datum]
129
- .map((d: any) => `${d}`.toLowerCase())
130
- .includes(`${md[datum]?.content}`.toLowerCase())
131
- ) {
132
- return false;
96
+ <FilterMenu
97
+ h={h}
98
+ mapedData={mapedData}
99
+ setMapedData={setMapedData}
100
+ index={key}
101
+ selectedFilter={selectedFilter}
102
+ setSelectedFilter={setSelectedFilter}
103
+ />
104
+ </th>
105
+ );
106
+ })}
107
+ </tr>
108
+ </thead>
109
+ <tbody className="divide-y divide-gray-200">
110
+ {mapedData.map((md: any, trKey: number) => {
111
+ const color = trKey % 2 == 0 ? "bg-white" : "bg-gray-100";
112
+ for (let d in md) {
113
+ if (md[d].exclude === true) {
114
+ return null;
133
115
  }
134
116
  }
135
- return true;
136
- })
137
- .map((md: any, trKey: number) => {
138
- const color = trKey % 2 == 0 ? "bg-white" : "bg-gray-100";
117
+
139
118
  return (
140
119
  <tr
141
120
  onDoubleClick={(e) => {
142
121
  modalRef.current?.showModal();
143
122
  }}
144
- key={trKey}
123
+ key={md?.id?.content || trKey}
145
124
  onClick={(e) => setSelected(trKey)}
146
125
  className={[
147
126
  "hover:bg-green-100 ",
@@ -150,38 +129,47 @@ export default function HTable({
150
129
  ].join(" ")}
151
130
  >
152
131
  {head.map((h, tdKey: number) => {
132
+ const item = md[h];
133
+ const id = trKey + "-" + (md?.id?.content || tdKey) + "-" + h;
153
134
  return (
154
135
  <TD
155
- key={tdKey}
136
+ key={id}
156
137
  index={trKey}
157
138
  symbols={symbols}
158
- item={md[h]}
139
+ handlers={props.handlers}
140
+ item={item}
159
141
  color={color}
142
+ mapedData={mapedData}
143
+ setMapedData={setMapedData}
160
144
  />
161
145
  );
162
146
  })}
163
147
  </tr>
164
148
  );
165
149
  })}
166
- </tbody>
167
- <tfoot className="bg-gray-800 text-white">
168
- <tr>
169
- {head.map((h, fkey) => {
170
- return (
171
- <th key={fkey} className="text-right border-b max-w-[200px] p-5 ">
172
- {totals && totals.includes(h) && (
173
- <div className="flex justify-between text-white w-full bg-black rounded p-1">
174
- <div className="p-1">
175
- {symbols && symbols[h] && symbols[h]}
150
+ </tbody>
151
+ <tfoot className="bg-gray-800 text-white">
152
+ <tr>
153
+ {head.map((h, fkey) => {
154
+ return (
155
+ <th
156
+ key={fkey}
157
+ className="text-right border-b max-w-[200px] p-5 "
158
+ >
159
+ {totals && totals.includes(h) && (
160
+ <div className="flex justify-between text-white w-full bg-black rounded p-1">
161
+ <div className="p-1">
162
+ {symbols && symbols[h] && symbols[h]}
163
+ </div>
164
+ <div className="p-1">{mapedTotals[h]}</div>
176
165
  </div>
177
- <div className="p-1">{mapedTotals[h]}</div>
178
- </div>
179
- )}
180
- </th>
181
- );
182
- })}
183
- </tr>
184
- </tfoot>
185
- </table>
166
+ )}
167
+ </th>
168
+ );
169
+ })}
170
+ </tr>
171
+ </tfoot>
172
+ </table>
173
+ </>
186
174
  );
187
175
  }
@@ -15,6 +15,7 @@ export interface TableProps
15
15
  totals?: Array<string>;
16
16
  symbols?: Record<string, ReactNode>;
17
17
  exportName?: string;
18
+ handlers?: Record<string, ReactNode>;
18
19
  }
19
20
 
20
21
  export default function Table(props: TableProps) {
@@ -24,24 +25,27 @@ export default function Table(props: TableProps) {
24
25
  return (
25
26
  <div className="bg-gray-200 border rounded shadow p-1">
26
27
  {props?.exportName && props.data.length > 0 && (
27
- <button
28
- className="p-2 border rounded shadow bg-green-800 text-white flex gap-1"
29
- onClick={(e) =>
30
- exported.export(
31
- mapedData.map((md: any) => {
32
- for (let i of Object.keys(md)) {
33
- md[i] = md[i].content;
34
- }
35
- return md;
36
- }),
37
- props.exportName
38
- )
39
- }
40
- >
41
- <ExcelIcon /> Exportar
42
- </button>
28
+ <>
29
+ <button
30
+ className="p-2 border rounded shadow bg-green-800 text-white flex gap-1"
31
+ onClick={(e) =>
32
+ exported.export(
33
+ mapedData.map((md: any) => {
34
+ const { __visible__, ...newMd } = md;
35
+ for (let i of Object.keys(newMd)) {
36
+ newMd[i] = newMd[i].content;
37
+ }
38
+ return newMd;
39
+ }),
40
+ props.exportName
41
+ )
42
+ }
43
+ >
44
+ <ExcelIcon /> Exportar
45
+ </button>
46
+ </>
43
47
  )}
44
- {isArray && (
48
+ {isArray ? (
45
49
  <HTable
46
50
  {...{
47
51
  ...props,
@@ -49,6 +53,10 @@ export default function Table(props: TableProps) {
49
53
  setMapedData,
50
54
  }}
51
55
  />
56
+ ) : (
57
+ <div className=" p-5 border rounded shadow bg-yellw-500">
58
+ No es un array
59
+ </div>
52
60
  )}
53
61
  </div>
54
62
  );
package/src/table/td.tsx CHANGED
@@ -6,9 +6,18 @@ interface TDProps
6
6
  HTMLTableCellElement
7
7
  > {
8
8
  index: number;
9
- item: { cellTypeOf: string; content: string; title: string; name: string };
9
+ item: {
10
+ cellTypeOf: string;
11
+ content: string;
12
+ title: string;
13
+ name: string;
14
+ index: number;
15
+ };
10
16
  color: string;
11
17
  symbols: Record<string, any> | undefined;
18
+ handlers: Record<string, any> | undefined;
19
+ mapedData?: any;
20
+ setMapedData?: (data: any) => void;
12
21
  }
13
22
  export default function TD({
14
23
  className,
@@ -16,7 +25,9 @@ export default function TD({
16
25
  index,
17
26
  color,
18
27
  symbols,
19
-
28
+ handlers,
29
+ mapedData,
30
+ setMapedData,
20
31
  ...props
21
32
  }: TDProps) {
22
33
  const [isHidded, setIsHidded] = useState(false);
@@ -57,18 +68,46 @@ export default function TD({
57
68
  ["number", "money"].includes(item?.cellTypeOf) && "text-right",
58
69
  ].join(" ")}
59
70
  >
60
- <div className={symbols && symbols[item?.name] && "flex justify-between"}>
71
+ {handlers && handlers[item?.name] ? (
61
72
  <div>
62
- {symbols &&
63
- symbols[item?.name] &&
64
- (isNode
65
- ? React.cloneElement(symbols[item?.name], {
66
- ...newProps,
67
- })
68
- : symbols[item?.name])}
73
+ {React.Children.map(handlers[item?.name], (child) => {
74
+ if (React.isValidElement(child)) {
75
+ const oldProps: any = child?.props || {};
76
+ const alteredProps = {
77
+ ...oldProps,
78
+ value: item?.content,
79
+ onChange: (e: any) => {
80
+ const newData = [...mapedData];
81
+ newData[index][item?.name].content = e.target.value;
82
+ setMapedData?.(newData);
83
+ e.item = item;
84
+ oldProps?.onChange?.(e);
85
+ },
86
+ };
87
+ return React.cloneElement(child as any, {
88
+ ...alteredProps,
89
+ });
90
+ }
91
+ })}
92
+ </div>
93
+ ) : (
94
+ <div
95
+ className={symbols && symbols[item?.name] && "flex justify-between"}
96
+ >
97
+ <div>
98
+ {symbols &&
99
+ React.Children.map(symbols[item?.name], (child) => {
100
+ if (React.isValidElement(child)) {
101
+ return React.cloneElement(child, {
102
+ ...newProps,
103
+ });
104
+ }
105
+ return child;
106
+ })}
107
+ </div>
108
+ <div>{item?.content}</div>
69
109
  </div>
70
- <div>{item?.content}</div>
71
- </div>
110
+ )}
72
111
  </td>
73
112
  );
74
113
  }