next-recomponents 1.2.6 → 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
@@ -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";
@@ -64,86 +51,76 @@ export default function HTable({
64
51
  : JSON.stringify(d[key])
65
52
  : d[key];
66
53
  obj[key] = {
54
+ index: trkey,
67
55
  originalData: content,
68
56
  cellTypeOf: cellTypeOf,
69
57
  title: content,
70
58
  content,
71
59
  name: key,
60
+ exclude: false,
72
61
  };
73
62
  }
74
63
  return obj;
75
64
  });
76
-
77
65
  setMapedData(newData);
78
66
  }, [data]);
79
67
  return (
80
- <table {...props} className="w-full border-collapse table-auto">
81
- <thead className="bg-gray-800 text-white">
82
- <tr>
83
- {head.map((h, key) => {
84
- const items = [
85
- ...new Set<string>(
86
- mapedData.map((item: any) => item[h]?.content)
87
- ),
88
- ];
89
- return (
90
- <th
91
- key={key}
92
- className="whitespace-nowrap overflow-hidden text-ellipsis max-w-[200px] border-b p-5"
93
- >
94
- <div
95
- className="cursor-pointer flex "
96
- onClick={(e) => {
97
- setSelectedFilter(key == selectedFilter ? null : key);
98
- }}
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"
99
77
  >
100
- <div className="text-white w-full bg-black rounded p-1 flex justify-center">
101
- {h}{" "}
102
- {filters[h]?.length != items.length && (
103
- <div className="text-red-300">
104
- <FilterOffIcon />
105
- </div>
106
- )}
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>
107
94
  </div>
108
- </div>
109
95
 
110
- <FilterMenu
111
- filters={filters}
112
- setFilters={setFilters}
113
- items={items}
114
- h={h}
115
- mapedData={mapedData}
116
- index={key}
117
- selectedFilter={selectedFilter}
118
- setSelectedFilter={setSelectedFilter}
119
- />
120
- </th>
121
- );
122
- })}
123
- </tr>
124
- </thead>
125
- <tbody className="divide-y divide-gray-200">
126
- {mapedData
127
- .filter((md: any) => {
128
- for (let datum of Object.keys(md)) {
129
- if (
130
- !filters[datum]
131
- .map((d: any) => `${d}`.toLowerCase())
132
- .includes(`${md[datum]?.content}`.toLowerCase())
133
- ) {
134
- 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;
135
115
  }
136
116
  }
137
- return true;
138
- })
139
- .map((md: any, trKey: number) => {
140
- const color = trKey % 2 == 0 ? "bg-white" : "bg-gray-100";
117
+
141
118
  return (
142
119
  <tr
143
120
  onDoubleClick={(e) => {
144
121
  modalRef.current?.showModal();
145
122
  }}
146
- key={trKey}
123
+ key={md?.id?.content || trKey}
147
124
  onClick={(e) => setSelected(trKey)}
148
125
  className={[
149
126
  "hover:bg-green-100 ",
@@ -152,38 +129,47 @@ export default function HTable({
152
129
  ].join(" ")}
153
130
  >
154
131
  {head.map((h, tdKey: number) => {
132
+ const item = md[h];
133
+ const id = trKey + "-" + (md?.id?.content || tdKey) + "-" + h;
155
134
  return (
156
135
  <TD
157
- key={tdKey}
136
+ key={id}
158
137
  index={trKey}
159
138
  symbols={symbols}
160
- item={md[h]}
139
+ handlers={props.handlers}
140
+ item={item}
161
141
  color={color}
142
+ mapedData={mapedData}
143
+ setMapedData={setMapedData}
162
144
  />
163
145
  );
164
146
  })}
165
147
  </tr>
166
148
  );
167
149
  })}
168
- </tbody>
169
- <tfoot className="bg-gray-800 text-white">
170
- <tr>
171
- {head.map((h, fkey) => {
172
- return (
173
- <th key={fkey} className="text-right border-b max-w-[200px] p-5 ">
174
- {totals && totals.includes(h) && (
175
- <div className="flex justify-between text-white w-full bg-black rounded p-1">
176
- <div className="p-1">
177
- {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>
178
165
  </div>
179
- <div className="p-1">{mapedTotals[h]}</div>
180
- </div>
181
- )}
182
- </th>
183
- );
184
- })}
185
- </tr>
186
- </tfoot>
187
- </table>
166
+ )}
167
+ </th>
168
+ );
169
+ })}
170
+ </tr>
171
+ </tfoot>
172
+ </table>
173
+ </>
188
174
  );
189
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
  }