ar-design 0.4.15 → 0.4.16
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/assets/css/components/form/upload/{list.css → list-and-gird.css} +22 -5
- package/dist/assets/css/components/form/upload/styles.css +3 -3
- package/dist/components/data-display/table/FilterPopup.d.ts +11 -7
- package/dist/components/data-display/table/FilterPopup.js +14 -14
- package/dist/components/data-display/table/IProps.d.ts +8 -6
- package/dist/components/data-display/table/PropertiesPopup.d.ts +14 -10
- package/dist/components/data-display/table/PropertiesPopup.js +19 -19
- package/dist/components/data-display/table/THeadCell.d.ts +23 -14
- package/dist/components/data-display/table/THeadCell.js +7 -7
- package/dist/components/data-display/table/{Editable.d.ts → body/Editable.d.ts} +1 -1
- package/dist/components/data-display/table/{Editable.js → body/Editable.js} +3 -3
- package/dist/components/data-display/table/body/TBody.d.ts +28 -0
- package/dist/components/data-display/table/body/TBody.js +143 -0
- package/dist/components/data-display/table/header/ActionButtons.d.ts +7 -0
- package/dist/components/data-display/table/header/ActionButtons.js +60 -0
- package/dist/components/data-display/table/header/Header.d.ts +9 -0
- package/dist/components/data-display/table/header/Header.js +10 -0
- package/dist/components/data-display/table/index.js +34 -179
- package/dist/components/form/select/index.js +6 -2
- package/dist/components/form/upload/List.js +1 -1
- package/dist/libs/core/application/hooks/index.d.ts +7 -31
- package/dist/libs/core/application/hooks/index.js +8 -180
- package/dist/libs/core/application/hooks/useNotification.d.ts +16 -0
- package/dist/libs/core/application/hooks/useNotification.js +23 -0
- package/dist/libs/core/application/hooks/useTranslation.d.ts +7 -0
- package/dist/libs/core/application/hooks/useTranslation.js +21 -0
- package/dist/libs/core/application/hooks/useValidation.d.ts +7 -0
- package/dist/libs/core/application/hooks/useValidation.js +147 -0
- package/package.json +1 -1
- package/dist/components/data-display/table/Actions.d.ts +0 -5
- package/dist/components/data-display/table/Actions.js +0 -3
|
@@ -11,23 +11,40 @@
|
|
|
11
11
|
width: max-content !important;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
> ul
|
|
14
|
+
> ul {
|
|
15
15
|
display: flex;
|
|
16
16
|
flex-wrap: wrap;
|
|
17
17
|
gap: 0.75rem;
|
|
18
18
|
|
|
19
19
|
&.list {
|
|
20
20
|
flex-direction: column;
|
|
21
|
-
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
&.row,
|
|
23
|
+
&.column {
|
|
24
|
+
margin: 0;
|
|
25
|
+
|
|
26
|
+
> li {
|
|
27
|
+
width: 100%;
|
|
28
|
+
}
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
&.grid {
|
|
30
33
|
flex-direction: row;
|
|
34
|
+
|
|
35
|
+
&.row {
|
|
36
|
+
margin: 0;
|
|
37
|
+
|
|
38
|
+
> li {
|
|
39
|
+
max-width: calc(100% / 4);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&.column {
|
|
44
|
+
> li {
|
|
45
|
+
width: 100%;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
> li {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import React, { Dispatch, MutableRefObject, ReactNode, SetStateAction } from "react";
|
|
2
2
|
interface IProps {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
refs: {
|
|
4
|
+
tableContent: MutableRefObject<HTMLDivElement | null>;
|
|
5
|
+
buttons: MutableRefObject<(HTMLSpanElement | null)[]>;
|
|
6
|
+
};
|
|
7
|
+
states: {
|
|
8
|
+
open: {
|
|
9
|
+
get: boolean;
|
|
10
|
+
set: Dispatch<SetStateAction<boolean>>;
|
|
11
|
+
};
|
|
7
12
|
};
|
|
8
|
-
|
|
13
|
+
children: ReactNode;
|
|
9
14
|
coordinate: {
|
|
10
15
|
x: number;
|
|
11
16
|
y: number;
|
|
12
17
|
};
|
|
13
|
-
buttons: MutableRefObject<(HTMLSpanElement | null)[]>;
|
|
14
18
|
}
|
|
15
|
-
declare const FilterPopup: ({ children,
|
|
19
|
+
declare const FilterPopup: ({ children, refs, states, coordinate }: IProps) => false | React.ReactPortal;
|
|
16
20
|
export default FilterPopup;
|
|
@@ -1,58 +1,58 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import React, { useEffect, useRef } from "react";
|
|
3
3
|
import ReactDOM from "react-dom";
|
|
4
|
-
const FilterPopup = ({ children,
|
|
4
|
+
const FilterPopup = ({ children, refs, states, coordinate }) => {
|
|
5
5
|
// refs
|
|
6
6
|
const _arTableFilterPopup = useRef(null);
|
|
7
7
|
// methods
|
|
8
8
|
const handleClickOutSide = (event) => {
|
|
9
9
|
const target = event.target;
|
|
10
10
|
const clickedInsidePopup = _arTableFilterPopup.current && _arTableFilterPopup.current.contains(target);
|
|
11
|
-
const isOneOfButtons = buttons.current.some((button) => button === target || button?.contains(target));
|
|
11
|
+
const isOneOfButtons = refs.buttons.current.some((button) => button === target || button?.contains(target));
|
|
12
12
|
if (!clickedInsidePopup && !isOneOfButtons)
|
|
13
13
|
handleClose();
|
|
14
14
|
};
|
|
15
15
|
const handleKeys = (event) => {
|
|
16
16
|
const key = event.key;
|
|
17
17
|
if (key === "Escape")
|
|
18
|
-
open.set(false);
|
|
18
|
+
states.open.set(false);
|
|
19
19
|
};
|
|
20
|
-
const handleOpen = () => open.set(true);
|
|
21
|
-
const handleClose = () => open.set(false);
|
|
20
|
+
const handleOpen = () => states.open.set(true);
|
|
21
|
+
const handleClose = () => states.open.set(false);
|
|
22
22
|
// useEffects
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
buttons.current.map((button) => {
|
|
24
|
+
refs.buttons.current.map((button) => {
|
|
25
25
|
if (button)
|
|
26
26
|
button.addEventListener("click", handleOpen);
|
|
27
27
|
});
|
|
28
28
|
return () => {
|
|
29
|
-
buttons.current.map((button) => {
|
|
29
|
+
refs.buttons.current.map((button) => {
|
|
30
30
|
if (button)
|
|
31
31
|
button.removeEventListener("click", handleOpen);
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
|
-
}, [buttons]);
|
|
34
|
+
}, [refs.buttons]);
|
|
35
35
|
useEffect(() => {
|
|
36
|
-
const firstFilterButton = buttons.current[0];
|
|
36
|
+
const firstFilterButton = refs.buttons.current[0];
|
|
37
37
|
if (firstFilterButton) {
|
|
38
38
|
const rect = firstFilterButton.getBoundingClientRect();
|
|
39
39
|
coordinate.x = rect.left;
|
|
40
40
|
coordinate.y = rect.top + rect.height;
|
|
41
41
|
}
|
|
42
|
-
if (tableContent.current) {
|
|
43
|
-
tableContent.current.addEventListener("scroll", handleClose);
|
|
42
|
+
if (refs.tableContent.current) {
|
|
43
|
+
refs.tableContent.current.addEventListener("scroll", handleClose);
|
|
44
44
|
}
|
|
45
45
|
document.addEventListener("click", handleClickOutSide);
|
|
46
46
|
document.addEventListener("keydown", handleKeys);
|
|
47
47
|
return () => {
|
|
48
48
|
document.removeEventListener("click", handleClickOutSide);
|
|
49
49
|
document.removeEventListener("keydown", handleKeys);
|
|
50
|
-
if (tableContent.current) {
|
|
51
|
-
tableContent.current.removeEventListener("scroll", handleClose);
|
|
50
|
+
if (refs.tableContent.current) {
|
|
51
|
+
refs.tableContent.current.removeEventListener("scroll", handleClose);
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
}, []);
|
|
55
|
-
return (open.get &&
|
|
55
|
+
return (states.open.get &&
|
|
56
56
|
ReactDOM.createPortal(React.createElement("div", { ref: _arTableFilterPopup, className: "ar-table-filter-popup", style: { top: coordinate.y, left: coordinate.x } }, children), document.body));
|
|
57
57
|
};
|
|
58
58
|
export default FilterPopup;
|
|
@@ -7,6 +7,12 @@ export type FilterValue = {
|
|
|
7
7
|
value: string | number | boolean;
|
|
8
8
|
operator: FilterOperator;
|
|
9
9
|
};
|
|
10
|
+
export type Actions = {
|
|
11
|
+
import?: ImportActionType;
|
|
12
|
+
export?: ExportActionType;
|
|
13
|
+
create?: CreateActionType;
|
|
14
|
+
delete?: DeleteActionType;
|
|
15
|
+
};
|
|
10
16
|
export type Sort<T> = {
|
|
11
17
|
key: keyof T;
|
|
12
18
|
direction: "asc" | "desc" | null;
|
|
@@ -16,6 +22,7 @@ export type SearchedParam = {
|
|
|
16
22
|
};
|
|
17
23
|
export type Config<T> = {
|
|
18
24
|
isServerSide?: boolean;
|
|
25
|
+
isProperties?: boolean;
|
|
19
26
|
isSearchable?: boolean;
|
|
20
27
|
scroll?: {
|
|
21
28
|
maxHeight: number;
|
|
@@ -68,12 +75,7 @@ interface IProps<T> extends IChildren {
|
|
|
68
75
|
description?: string;
|
|
69
76
|
data: T[];
|
|
70
77
|
columns: TableColumnType<T>[];
|
|
71
|
-
actions?:
|
|
72
|
-
import?: ImportActionType;
|
|
73
|
-
export?: ExportActionType;
|
|
74
|
-
create?: CreateActionType;
|
|
75
|
-
delete?: DeleteActionType;
|
|
76
|
-
};
|
|
78
|
+
actions?: Actions;
|
|
77
79
|
rowBackgroundColor?: (item: T) => string;
|
|
78
80
|
selections?: (selectionItems: T[]) => void;
|
|
79
81
|
previousSelections?: T[];
|
|
@@ -2,22 +2,26 @@ import React, { Dispatch, MutableRefObject, SetStateAction } from "react";
|
|
|
2
2
|
import { TableColumnType } from "../../../libs/types";
|
|
3
3
|
import { Sort } from "./IProps";
|
|
4
4
|
interface IProps<T> {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
refs: {
|
|
6
|
+
tableContent: MutableRefObject<HTMLDivElement | null>;
|
|
7
|
+
buttons: MutableRefObject<(HTMLSpanElement | null)[]>;
|
|
8
8
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
states: {
|
|
10
|
+
open: {
|
|
11
|
+
get: boolean;
|
|
12
|
+
set: Dispatch<SetStateAction<boolean>>;
|
|
13
|
+
};
|
|
14
|
+
sort: {
|
|
15
|
+
get: Sort<T>[];
|
|
16
|
+
set: Dispatch<SetStateAction<Sort<T>[]>>;
|
|
17
|
+
currentColumn: TableColumnType<T> | null;
|
|
18
|
+
};
|
|
13
19
|
};
|
|
14
|
-
tableContent: MutableRefObject<HTMLDivElement | null>;
|
|
15
20
|
coordinate: {
|
|
16
21
|
x: number;
|
|
17
22
|
y: number;
|
|
18
23
|
};
|
|
19
|
-
buttons: MutableRefObject<(HTMLSpanElement | null)[]>;
|
|
20
24
|
}
|
|
21
|
-
declare function PropertiesPopup<T extends object>({
|
|
25
|
+
declare function PropertiesPopup<T extends object>({ refs, states, coordinate }: IProps<T>): false | React.ReactPortal;
|
|
22
26
|
declare const _default: typeof PropertiesPopup;
|
|
23
27
|
export default _default;
|
|
@@ -3,7 +3,7 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, } from "react";
|
|
|
3
3
|
import ReactDOM from "react-dom";
|
|
4
4
|
import { ARIcon } from "../../icons";
|
|
5
5
|
import { ExtractKey } from "./Helpers";
|
|
6
|
-
function PropertiesPopup({
|
|
6
|
+
function PropertiesPopup({ refs, states, coordinate }) {
|
|
7
7
|
// refs
|
|
8
8
|
const _arTablePropertiesPopup = useRef(null);
|
|
9
9
|
// methods
|
|
@@ -11,7 +11,7 @@ function PropertiesPopup({ open, sort, tableContent, coordinate, buttons }) {
|
|
|
11
11
|
(event) => {
|
|
12
12
|
const target = event.target;
|
|
13
13
|
const clickedInsidePopup = _arTablePropertiesPopup.current && _arTablePropertiesPopup.current.contains(target);
|
|
14
|
-
const isOneOfButtons = buttons.current.some((button) => button === target || button?.contains(target));
|
|
14
|
+
const isOneOfButtons = refs.buttons.current.some((button) => button === target || button?.contains(target));
|
|
15
15
|
if (!clickedInsidePopup && !isOneOfButtons)
|
|
16
16
|
handleClose();
|
|
17
17
|
};
|
|
@@ -20,7 +20,7 @@ function PropertiesPopup({ open, sort, tableContent, coordinate, buttons }) {
|
|
|
20
20
|
return (columnKey, direction) => {
|
|
21
21
|
if (!columnKey)
|
|
22
22
|
return;
|
|
23
|
-
sort.set((prev) => {
|
|
23
|
+
states.sort.set((prev) => {
|
|
24
24
|
const index = prev.findIndex((s) => s.key === columnKey);
|
|
25
25
|
if (index !== -1)
|
|
26
26
|
return [{ key: columnKey, direction }];
|
|
@@ -31,46 +31,46 @@ function PropertiesPopup({ open, sort, tableContent, coordinate, buttons }) {
|
|
|
31
31
|
const handleKeys = (event) => {
|
|
32
32
|
const key = event.key;
|
|
33
33
|
if (key === "Escape")
|
|
34
|
-
open.set(false);
|
|
34
|
+
states.open.set(false);
|
|
35
35
|
};
|
|
36
|
-
const handleOpen = () => open.set(true);
|
|
37
|
-
const handleClose = () => open.set(false);
|
|
36
|
+
const handleOpen = () => states.open.set(true);
|
|
37
|
+
const handleClose = () => states.open.set(false);
|
|
38
38
|
// useEffects
|
|
39
39
|
useEffect(() => {
|
|
40
|
-
buttons.current.map((button) => {
|
|
40
|
+
refs.buttons.current.map((button) => {
|
|
41
41
|
if (button)
|
|
42
42
|
button.addEventListener("click", handleOpen);
|
|
43
43
|
});
|
|
44
44
|
return () => {
|
|
45
|
-
buttons.current.map((button) => {
|
|
45
|
+
refs.buttons.current.map((button) => {
|
|
46
46
|
if (button)
|
|
47
47
|
button.removeEventListener("click", handleOpen);
|
|
48
48
|
});
|
|
49
49
|
};
|
|
50
|
-
}, [buttons]);
|
|
50
|
+
}, [refs.buttons]);
|
|
51
51
|
useEffect(() => {
|
|
52
|
-
const firstFilterButton = buttons.current[0];
|
|
52
|
+
const firstFilterButton = refs.buttons.current[0];
|
|
53
53
|
if (firstFilterButton) {
|
|
54
54
|
const rect = firstFilterButton.getBoundingClientRect();
|
|
55
55
|
coordinate.x = rect.left;
|
|
56
56
|
coordinate.y = rect.top + rect.height;
|
|
57
57
|
}
|
|
58
|
-
if (tableContent.current) {
|
|
59
|
-
tableContent.current.addEventListener("scroll", handleClose);
|
|
58
|
+
if (refs.tableContent.current) {
|
|
59
|
+
refs.tableContent.current.addEventListener("scroll", handleClose);
|
|
60
60
|
}
|
|
61
61
|
document.addEventListener("click", handleClickOutSide);
|
|
62
62
|
document.addEventListener("keydown", handleKeys);
|
|
63
63
|
return () => {
|
|
64
64
|
document.removeEventListener("click", handleClickOutSide);
|
|
65
65
|
document.removeEventListener("keydown", handleKeys);
|
|
66
|
-
if (tableContent.current) {
|
|
67
|
-
tableContent.current.removeEventListener("scroll", handleClose);
|
|
66
|
+
if (refs.tableContent.current) {
|
|
67
|
+
refs.tableContent.current.removeEventListener("scroll", handleClose);
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
}, []);
|
|
71
|
-
const currentKey = ExtractKey(sort.currentColumn?.key);
|
|
72
|
-
const currentSort = sort.get?.find((s) => s.key === currentKey);
|
|
73
|
-
return (open.get &&
|
|
71
|
+
const currentKey = ExtractKey(states.sort.currentColumn?.key);
|
|
72
|
+
const currentSort = states.sort.get?.find((s) => s.key === currentKey);
|
|
73
|
+
return (states.open.get &&
|
|
74
74
|
ReactDOM.createPortal(React.createElement("div", { ref: _arTablePropertiesPopup, className: "ar-table-properties-popup", style: { top: coordinate.y, left: coordinate.x } },
|
|
75
75
|
React.createElement("ul", null,
|
|
76
76
|
currentSort && (!currentSort.direction || currentSort.direction === "desc") && (React.createElement("li", { onClick: () => handleSort(currentKey, "asc") },
|
|
@@ -82,8 +82,8 @@ function PropertiesPopup({ open, sort, tableContent, coordinate, buttons }) {
|
|
|
82
82
|
React.createElement(ARIcon, { icon: "ArrowDown" })),
|
|
83
83
|
React.createElement("span", null, "Sort Descending"))),
|
|
84
84
|
currentSort && currentSort.direction && (React.createElement("li", { onClick: () => {
|
|
85
|
-
sort.set((prev) => prev.filter((s) => s.key !== currentKey));
|
|
86
|
-
open.set(false);
|
|
85
|
+
states.sort.set((prev) => prev.filter((s) => s.key !== currentKey));
|
|
86
|
+
states.open.set(false);
|
|
87
87
|
} },
|
|
88
88
|
React.createElement("span", null,
|
|
89
89
|
React.createElement(ARIcon, { icon: "ChevronExpand" })),
|
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import React, { Dispatch, SetStateAction } from "react";
|
|
2
2
|
import { TableColumnType } from "../../../libs/types";
|
|
3
|
-
import { Sort } from "./IProps";
|
|
4
|
-
declare const MemoizedTHeadCell: <T>({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
set: Dispatch<SetStateAction<boolean>>;
|
|
3
|
+
import { Config, Sort } from "./IProps";
|
|
4
|
+
declare const MemoizedTHeadCell: <T>({ refs, states, columns, config, }: {
|
|
5
|
+
refs: {
|
|
6
|
+
propertiesButton: React.MutableRefObject<(HTMLSpanElement | null)[]>;
|
|
8
7
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
states: {
|
|
9
|
+
open: {
|
|
10
|
+
get: boolean;
|
|
11
|
+
set: Dispatch<SetStateAction<boolean>>;
|
|
12
|
+
};
|
|
13
|
+
sort: {
|
|
14
|
+
get: Sort<T>[];
|
|
15
|
+
set: Dispatch<SetStateAction<Sort<T>[]>>;
|
|
16
|
+
};
|
|
17
|
+
sortCurrentColumn: {
|
|
18
|
+
set: React.Dispatch<React.SetStateAction<TableColumnType<T> | null>>;
|
|
19
|
+
};
|
|
20
|
+
propertiesButtonCoordinate: {
|
|
21
|
+
set: React.Dispatch<React.SetStateAction<{
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
}>>;
|
|
25
|
+
};
|
|
12
26
|
};
|
|
13
27
|
columns: TableColumnType<T>[];
|
|
14
|
-
|
|
15
|
-
setSortCurrentColumn: React.Dispatch<React.SetStateAction<TableColumnType<T> | null>>;
|
|
16
|
-
setPropertiesButtonCoordinate: React.Dispatch<React.SetStateAction<{
|
|
17
|
-
x: number;
|
|
18
|
-
y: number;
|
|
19
|
-
}>>;
|
|
28
|
+
config: Config<T>;
|
|
20
29
|
}) => React.JSX.Element;
|
|
21
30
|
declare const THeadCell: typeof MemoizedTHeadCell;
|
|
22
31
|
export default THeadCell;
|
|
@@ -2,10 +2,10 @@ import React, { memo } from "react";
|
|
|
2
2
|
import Button from "../../form/button";
|
|
3
3
|
import { ARIcon } from "../../icons";
|
|
4
4
|
import { ExtractKey } from "./Helpers";
|
|
5
|
-
const MemoizedTHeadCell = function ({
|
|
5
|
+
const MemoizedTHeadCell = function ({ refs, states, columns, config, }) {
|
|
6
6
|
return (React.createElement(React.Fragment, null, columns.map((c, cIndex) => {
|
|
7
7
|
const { isProperties = true } = c.config ?? {};
|
|
8
|
-
const _direction = sort.get.find((s) => s.key === c.key)?.direction;
|
|
8
|
+
const _direction = states.sort.get.find((s) => s.key === c.key)?.direction;
|
|
9
9
|
let _className = [];
|
|
10
10
|
if (c.config?.sticky)
|
|
11
11
|
_className.push(`sticky-${c.config.sticky}`);
|
|
@@ -30,25 +30,25 @@ const MemoizedTHeadCell = function ({ open, sort, columns, propertiesButton, set
|
|
|
30
30
|
_direction === "asc" && React.createElement(ARIcon, { icon: "ArrowUp" }),
|
|
31
31
|
_direction === "desc" && React.createElement(ARIcon, { icon: "ArrowDown" })),
|
|
32
32
|
c.title),
|
|
33
|
-
isProperties && (React.createElement("span", { ref: (element) => (propertiesButton.current[cIndex] = element), className: "properties-field", onClick: (event) => {
|
|
33
|
+
config.isProperties && isProperties && (React.createElement("span", { ref: (element) => (refs.propertiesButton.current[cIndex] = element), className: "properties-field", onClick: (event) => {
|
|
34
34
|
event.stopPropagation();
|
|
35
35
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
36
36
|
const screenCenterX = window.innerWidth / 2;
|
|
37
37
|
const coordinateX = rect.x > screenCenterX ? rect.x + rect.width - 225 : rect.x;
|
|
38
38
|
const coordinateY = rect.y + rect.height;
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
states.sortCurrentColumn.set(c);
|
|
40
|
+
states.propertiesButtonCoordinate.set({
|
|
41
41
|
x: coordinateX,
|
|
42
42
|
y: coordinateY,
|
|
43
43
|
});
|
|
44
|
-
sort.set((prev) => {
|
|
44
|
+
states.sort.set((prev) => {
|
|
45
45
|
const key = ExtractKey(c.key);
|
|
46
46
|
const index = prev.findIndex((s) => s.key === key);
|
|
47
47
|
if (index === -1)
|
|
48
48
|
return [...prev, { key, direction: null }];
|
|
49
49
|
return prev;
|
|
50
50
|
});
|
|
51
|
-
open.set(true);
|
|
51
|
+
states.open.set(true);
|
|
52
52
|
} },
|
|
53
53
|
React.createElement(Button, { variant: "borderless", icon: {
|
|
54
54
|
element: React.createElement(ARIcon, { size: 16, icon: "ThreeDotsVertical", fill: "var(--dark)", strokeWidth: 0 }),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import React, { useEffect, useState } from "react";
|
|
3
|
-
import Input from "
|
|
4
|
-
import DatePicker from "
|
|
5
|
-
import Select from "
|
|
3
|
+
import Input from "../../../form/input";
|
|
4
|
+
import DatePicker from "../../../form/date-picker";
|
|
5
|
+
import Select from "../../../form/select";
|
|
6
6
|
const Editable = function ({ c, item, trackByValue, onEditable, validation }) {
|
|
7
7
|
// variables
|
|
8
8
|
const key = c.key;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TableColumnType } from "../../../../libs/types";
|
|
3
|
+
import { Config } from "../IProps";
|
|
4
|
+
interface IProps<T> {
|
|
5
|
+
data: T[];
|
|
6
|
+
columns: TableColumnType<T>[];
|
|
7
|
+
states: {
|
|
8
|
+
showSubitems: {
|
|
9
|
+
get: {
|
|
10
|
+
[key: string]: boolean;
|
|
11
|
+
};
|
|
12
|
+
set: React.Dispatch<React.SetStateAction<{
|
|
13
|
+
[key: string]: boolean;
|
|
14
|
+
}>>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
methods: {
|
|
18
|
+
trackBy?: (item: T) => string;
|
|
19
|
+
selections?: (selectionItems: T[]) => void;
|
|
20
|
+
onDnD?: (item: T[]) => void;
|
|
21
|
+
onEditable?: (item: T, trackByValue: string) => void;
|
|
22
|
+
rowBackgroundColor?: (item: T) => string;
|
|
23
|
+
};
|
|
24
|
+
config: Config<T>;
|
|
25
|
+
}
|
|
26
|
+
declare function TBody<T extends object>({ data, columns, methods, states, config }: IProps<T>): React.JSX.Element | React.JSX.Element[];
|
|
27
|
+
declare const _default: typeof TBody;
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React, { Fragment, memo, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { ARIcon } from "../../../icons";
|
|
3
|
+
import Checkbox from "../../../form/checkbox";
|
|
4
|
+
import Editable from "./Editable";
|
|
5
|
+
function TBody({ data, columns, methods, states, config }) {
|
|
6
|
+
// refs
|
|
7
|
+
const _tBodyTR = useRef([]);
|
|
8
|
+
const _checkboxItems = useRef([]);
|
|
9
|
+
// refs -> Selection
|
|
10
|
+
const _selectionItems = useRef([]);
|
|
11
|
+
// states
|
|
12
|
+
const [_, setTriggerForRender] = useState(false);
|
|
13
|
+
const [rowHeights, setRowHeights] = useState([]);
|
|
14
|
+
// variables
|
|
15
|
+
const _subrowSelector = config.subrow?.selector ?? "subitems";
|
|
16
|
+
const _subrowButton = config.subrow?.button ?? true;
|
|
17
|
+
// methods
|
|
18
|
+
const renderRow = (item, index, deph) => {
|
|
19
|
+
const isHasSubitems = _subrowSelector in item;
|
|
20
|
+
return (React.createElement(Fragment, { key: `row-${index}` },
|
|
21
|
+
React.createElement("tr", { ref: (element) => {
|
|
22
|
+
_tBodyTR.current[index] = element;
|
|
23
|
+
}, ...(methods.rowBackgroundColor ? { style: { backgroundColor: methods.rowBackgroundColor(item) } } : {}), ...(methods.onDnD && data.length > 1 ? { className: "draggable", draggable: true } : {}) },
|
|
24
|
+
methods.selections && (React.createElement("td", { className: "flex justify-content-center sticky-left", "data-sticky-position": "left" },
|
|
25
|
+
React.createElement(Checkbox, { key: Date.now(), ref: (element) => (_checkboxItems.current[index] = element), variant: "filled", color: "green", checked: _selectionItems.current.some((selectionItem) => methods.trackBy?.(selectionItem) === methods.trackBy?.(item)), onChange: (event) => {
|
|
26
|
+
const key = methods.trackBy?.(item);
|
|
27
|
+
if (event.target.checked) {
|
|
28
|
+
if (!_selectionItems.current.some((_item) => methods.trackBy?.(_item) === key)) {
|
|
29
|
+
_selectionItems.current = [..._selectionItems.current, item];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
_selectionItems.current = _selectionItems.current.filter((_item) => methods.trackBy?.(_item) !== key);
|
|
34
|
+
}
|
|
35
|
+
methods.selections?.(_selectionItems.current);
|
|
36
|
+
setTriggerForRender((prev) => !prev);
|
|
37
|
+
} }))),
|
|
38
|
+
isHasSubitems && _subrowButton ? (React.createElement("td", null, item[_subrowSelector] && (React.createElement("div", { className: "subitem-open-button-wrapper" },
|
|
39
|
+
React.createElement("span", { className: `subitem-open-button ${(states.showSubitems.get[index] && "opened") ?? ""}`, onClick: () => {
|
|
40
|
+
states.showSubitems.set((prev) => ({
|
|
41
|
+
...prev,
|
|
42
|
+
[`${index}`]: !prev[`${index}`],
|
|
43
|
+
}));
|
|
44
|
+
} }))))) : isHasSubitems && _subrowButton ? (React.createElement("td", { style: { width: 0, minWidth: 0 } })) : null,
|
|
45
|
+
columns.map((column, cIndex) => {
|
|
46
|
+
return renderCell({
|
|
47
|
+
item,
|
|
48
|
+
column,
|
|
49
|
+
index,
|
|
50
|
+
cIndex,
|
|
51
|
+
depth: deph * (config.isTreeView ? 1.75 : 0),
|
|
52
|
+
level: 0,
|
|
53
|
+
height: rowHeights[index] ?? 0,
|
|
54
|
+
});
|
|
55
|
+
})),
|
|
56
|
+
states.showSubitems.get[index] && item[_subrowSelector] && (React.createElement(SubitemList, { items: item[_subrowSelector], columns: columns, index: index, depth: 1.5 }))));
|
|
57
|
+
};
|
|
58
|
+
const renderCell = ({ item, column, index, cIndex, depth, level, height = 0, isSubrows = false }) => {
|
|
59
|
+
let render;
|
|
60
|
+
// `column.key` bir string ise
|
|
61
|
+
if (typeof column.key !== "object")
|
|
62
|
+
render = column.render ? column.render(item) : item[column.key];
|
|
63
|
+
// `column.key` bir nesne ise ve `nestedKey` mevcutsa
|
|
64
|
+
else if (typeof column.key === "object") {
|
|
65
|
+
const _item = item[column.key.field];
|
|
66
|
+
if (_item && typeof _item === "object") {
|
|
67
|
+
render = column.render ? column.render(item) : _item[column.key.nestedKey];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else
|
|
71
|
+
render = null;
|
|
72
|
+
const _className = [];
|
|
73
|
+
if (column.config?.alignContent)
|
|
74
|
+
_className.push(`align-content-${column.config.alignContent}`);
|
|
75
|
+
if (column.config?.sticky)
|
|
76
|
+
_className.push(`sticky-${column.config.sticky}`);
|
|
77
|
+
if (column.config?.textWrap)
|
|
78
|
+
_className.push(`text-${column.config.textWrap}`);
|
|
79
|
+
return (React.createElement("td", { key: `cell-${index}-${cIndex}`, className: _className.join(" "), style: {
|
|
80
|
+
...(column.config?.sticky ? { height } : {}),
|
|
81
|
+
...(column.config?.width
|
|
82
|
+
? { width: column.config.width, minWidth: column.config.width, maxWidth: column.config.width }
|
|
83
|
+
: {}),
|
|
84
|
+
}, "data-sticky-position": column.config?.sticky },
|
|
85
|
+
React.createElement("div", { style: { paddingLeft: `${depth == 0 ? 1 : depth}rem` }, className: "table-cell" },
|
|
86
|
+
config.isTreeView && cIndex === 0 && (React.createElement(React.Fragment, null,
|
|
87
|
+
isSubrows &&
|
|
88
|
+
Array.from({ length: level }).map((_, i) => {
|
|
89
|
+
if (i > 0)
|
|
90
|
+
i *= 1.655;
|
|
91
|
+
return (React.createElement("div", { key: `last-before-${i}`, style: { left: `${i + 0.65}rem` }, className: "last-before" }));
|
|
92
|
+
}),
|
|
93
|
+
React.createElement("div", { className: "before" }))),
|
|
94
|
+
React.isValidElement(render) ? (render) : column.editable && methods.onEditable ? (React.createElement(Editable, { c: column, item: item, trackByValue: methods.trackBy?.(item) ?? "", onEditable: methods.onEditable, validation: config.validation })) : (render),
|
|
95
|
+
config.isTreeView && cIndex === 0 && (React.createElement("div", { className: "after" },
|
|
96
|
+
React.createElement("div", { className: "circle" }))))));
|
|
97
|
+
};
|
|
98
|
+
const SubitemList = ({ items, columns, index, depth, level = 1 }) => {
|
|
99
|
+
if (config.subrow?.render) {
|
|
100
|
+
return (React.createElement("tr", { className: `subrow-item ${_subrowButton ? "type-b" : "type-a"}`, "data-level": level },
|
|
101
|
+
_subrowButton && React.createElement("td", { style: { ...config.subrow.render.styles, width: 0, minWidth: 0 } }),
|
|
102
|
+
React.createElement("td", { colSpan: columns.length || 1, style: { ...config.subrow.render.styles, padding: "7.5px 7.5px 7.5px 0" } }, config.subrow?.render.element(items) ?? React.createElement(React.Fragment, null))));
|
|
103
|
+
}
|
|
104
|
+
return items.map((subitem, subindex) => {
|
|
105
|
+
const _subitem = subitem[_subrowSelector];
|
|
106
|
+
const isHasSubitems = _subrowSelector in subitem;
|
|
107
|
+
return (React.createElement(Fragment, { key: `subitem-${index}-${subindex}-${Math.random()}` },
|
|
108
|
+
React.createElement("tr", { className: `subrow-item ${_subrowButton ? "type-b" : "type-a"}`, "data-level": level },
|
|
109
|
+
isHasSubitems && _subrowButton ? (React.createElement("td", null,
|
|
110
|
+
React.createElement("div", { className: "subitem-open-button-wrapper" },
|
|
111
|
+
React.createElement("span", { className: `${(states.showSubitems.get[`${index}.${subindex}`] && "opened") ?? ""} ${!_subitem && "passive"}`, onClick: () => {
|
|
112
|
+
if (!_subitem)
|
|
113
|
+
return;
|
|
114
|
+
states.showSubitems.set((prev) => ({
|
|
115
|
+
...prev,
|
|
116
|
+
[`${index}.${subindex}`]: !prev[`${index}.${subindex}`],
|
|
117
|
+
}));
|
|
118
|
+
} })))) : !isHasSubitems && _subrowButton ? (React.createElement("td", { style: { width: 0, minWidth: 0 } })) : null,
|
|
119
|
+
!config.subrow?.render ? (columns.map((column, cIndex) => renderCell({
|
|
120
|
+
item: subitem,
|
|
121
|
+
column,
|
|
122
|
+
index,
|
|
123
|
+
cIndex,
|
|
124
|
+
depth: depth * (config.isTreeView ? 2.25 : 1.75),
|
|
125
|
+
level,
|
|
126
|
+
height: 0,
|
|
127
|
+
isSubrows: true,
|
|
128
|
+
}))) : (React.createElement("td", { colSpan: columns.length || 1 }, config.subrow?.render.element(items) ?? React.createElement(React.Fragment, null)))),
|
|
129
|
+
states.showSubitems.get[`${index}.${subindex}`] && _subitem && (React.createElement(SubitemList, { items: _subitem, columns: columns, index: subindex, depth: depth + 0.75, level: level + 1 }))));
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
// useEffects
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
const heights = _tBodyTR.current.map((el) => (el ? el.getBoundingClientRect().height : 0));
|
|
135
|
+
setRowHeights(heights);
|
|
136
|
+
}, [data]);
|
|
137
|
+
return data.length > 0 ? (data.map((item, index) => React.createElement(React.Fragment, { key: index }, renderRow(item, index, 1)))) : (React.createElement("tr", null,
|
|
138
|
+
React.createElement("td", { colSpan: columns.length || 1 },
|
|
139
|
+
React.createElement("div", { className: "no-item" },
|
|
140
|
+
React.createElement(ARIcon, { icon: "Inbox-Fill", fill: "var(--gray-300)", size: 64, style: { position: "relative", zIndex: 1 } }),
|
|
141
|
+
React.createElement("span", null, "No Data")))));
|
|
142
|
+
}
|
|
143
|
+
export default memo(TBody);
|