@inceptionbg/iui 2.0.15 → 2.0.17
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/NoAccessPage-BmizYfw0.js +2 -0
- package/dist/{NoAccessPage-DBq5IzIf.js.map → NoAccessPage-BmizYfw0.js.map} +1 -1
- package/dist/NotFoundPage-Cv544vAr.js +2 -0
- package/dist/{NotFoundPage-DM-I96ar.js.map → NotFoundPage-Cv544vAr.js.map} +1 -1
- package/dist/index.d.ts +160 -91
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/iui.css +1 -1
- package/package.json +4 -7
- package/src/assets/icons/duotone/faBell.ts +17 -0
- package/src/assets/icons/duotone/faPen.ts +18 -0
- package/src/assets/icons/duotone/faTrashCan.ts +18 -0
- package/src/assets/icons/light/faBell.ts +15 -0
- package/src/assets/icons/light/faEnvelope.ts +15 -0
- package/src/assets/icons/regular/faEllipsisVertical.ts +15 -0
- package/src/assets/icons/solid/faEnvelopeDot.ts +15 -0
- package/src/components/Button/SplitButton.tsx +5 -5
- package/src/components/Dialog/Dialog.tsx +3 -3
- package/src/components/Header/Components/ModuleSelect.tsx +5 -5
- package/src/components/Header/Components/Notifications.tsx +208 -0
- package/src/components/Header/Components/UserMenu.tsx +15 -14
- package/src/components/Header/Header.tsx +5 -4
- package/src/components/Inputs/NumberInput.tsx +3 -0
- package/src/components/Inputs/Selects/components/SelectWrapper.tsx +48 -29
- package/src/components/Inputs/TextInput.tsx +1 -0
- package/src/components/List/ListItem.tsx +1 -1
- package/src/components/Loader/ProgressBar.tsx +1 -1
- package/src/components/Menu/Menu.tsx +3 -0
- package/src/components/Pullover/Pullover.tsx +38 -39
- package/src/components/Table/Table.tsx +23 -32
- package/{idea/Table/Components/Columns → src/components/Table/components/columns}/ColumnsList.tsx +12 -14
- package/src/components/Table/components/columns/TableColumnsEdit.tsx +112 -0
- package/src/components/Table/components/edit/TableEditRow.tsx +26 -21
- package/src/components/Table/components/header/TableHeaderRow.tsx +2 -1
- package/src/components/Table/components/items/TableItemActions.tsx +18 -13
- package/src/components/Table/components/print/TablePrint.tsx +1 -5
- package/src/components/Table/components/templates/CreateTemplateDialog.tsx +48 -0
- package/src/components/Table/components/templates/TableTemplates.tsx +24 -4
- package/src/components/Table/contexts/TableContext.tsx +34 -33
- package/src/components/Table/hooks/localHooks/useLocalTableColumns.tsx +27 -28
- package/src/components/Table/hooks/localHooks/useLocalTableData.tsx +17 -11
- package/src/components/Table/hooks/localHooks/useLocalTableKeyboard.ts +8 -6
- package/src/components/Table/hooks/useTableColumns.ts +16 -10
- package/src/components/Table/hooks/useTableEdit.tsx +24 -2
- package/src/components/Table/hooks/useTablePrint.ts +12 -4
- package/src/components/Table/hooks/useTableSelect.ts +1 -1
- package/src/components/Tabs/Tabs.tsx +1 -0
- package/src/components/Tooltip/Tooltip.tsx +81 -14
- package/src/hooks/useIsMenuOpen.ts +3 -3
- package/src/hooks/usePopupControl.ts +9 -4
- package/src/index.ts +24 -5
- package/src/styles/App.scss +1 -0
- package/src/styles/components/_badge.scss +8 -1
- package/src/styles/components/_header.scss +18 -8
- package/src/styles/components/_list.scss +1 -1
- package/src/styles/components/_notifications.scss +71 -0
- package/src/styles/components/_page.scss +1 -0
- package/src/styles/components/_pullover.scss +1 -1
- package/src/styles/components/_sidebar.scss +1 -3
- package/src/styles/components/_table.scss +110 -57
- package/src/styles/variables/_variables.scss +9 -0
- package/src/types/IHeader.ts +1 -1
- package/src/types/IKeyboard.ts +0 -5
- package/src/types/IMenu.ts +2 -2
- package/src/types/INotifications.ts +15 -0
- package/src/types/IPopup.ts +2 -2
- package/src/types/ITable.ts +36 -32
- package/src/utils/i18n/i18nIUICyrilic.ts +12 -0
- package/src/utils/i18n/i18nIUILatin.ts +13 -0
- package/src/utils/i18n/i18nIUIMe.ts +12 -0
- package/src/utils/objectUtils.ts +19 -0
- package/src/utils/tableUtils.ts +1 -1
- package/dist/NoAccessPage-DBq5IzIf.js +0 -2
- package/dist/NotFoundPage-DM-I96ar.js +0 -2
- package/idea/Notifications.tsx +0 -245
- package/idea/Table/Components/Columns/SetColumnsList.tsx +0 -113
|
@@ -11,22 +11,24 @@ import {
|
|
|
11
11
|
IPaginationControl,
|
|
12
12
|
ITable,
|
|
13
13
|
ITableColumnsData,
|
|
14
|
+
ITableDataActions,
|
|
14
15
|
ITableEdit,
|
|
15
16
|
ITableSelectedAction,
|
|
16
17
|
} from '../../../types/ITable';
|
|
17
18
|
import { useLocalTablePagination } from '../hooks/localHooks/useLocalTablePagination';
|
|
18
|
-
import { useLocalTableColumns } from '../hooks/localHooks/useLocalTableColumns';
|
|
19
19
|
import { useLocalTableData } from '../hooks/localHooks/useLocalTableData';
|
|
20
|
+
import { useTranslation } from 'react-i18next';
|
|
20
21
|
|
|
21
|
-
interface ITableContext extends ITable {
|
|
22
|
+
interface ITableContext<T = unknown> extends ITable<T> {
|
|
22
23
|
columnData: ITableColumnsData;
|
|
23
24
|
selectActions: ITableSelectedAction[];
|
|
24
|
-
dataActions?:
|
|
25
|
+
dataActions?: ITableDataActions<T> & {
|
|
25
26
|
hasItemActions: boolean;
|
|
26
27
|
isEditable: boolean;
|
|
27
28
|
isDeletable: boolean;
|
|
29
|
+
filteredActions: ITableSelectedAction[];
|
|
28
30
|
};
|
|
29
|
-
editable?: ITableEdit & {
|
|
31
|
+
editable?: ITableEdit<T> & {
|
|
30
32
|
isAdding: boolean;
|
|
31
33
|
setIsAdding: Dispatch<SetStateAction<boolean>>;
|
|
32
34
|
};
|
|
@@ -36,17 +38,13 @@ interface ITableContext extends ITable {
|
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
const TableContext = createContext<ITableContext
|
|
41
|
+
const TableContext = createContext<ITableContext<any>>({
|
|
40
42
|
columnData: { columns: [], defaultColumns: [] },
|
|
41
43
|
data: [],
|
|
42
44
|
selectActions: [],
|
|
43
45
|
});
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
children: ReactNode;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const TableProvider = ({
|
|
47
|
+
export const TableProvider = <T,>({
|
|
50
48
|
columnData,
|
|
51
49
|
data: initialData,
|
|
52
50
|
dataActions,
|
|
@@ -55,51 +53,54 @@ export const TableProvider = ({
|
|
|
55
53
|
children,
|
|
56
54
|
rowSelect,
|
|
57
55
|
...rest
|
|
58
|
-
}:
|
|
56
|
+
}: ITable<T> & { children: ReactNode }) => {
|
|
57
|
+
const { t } = useTranslation();
|
|
59
58
|
const [isAdding, setIsAdding] = useState(false);
|
|
60
59
|
|
|
61
|
-
const selectActions = useMemo(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
const selectActions = useMemo(() => {
|
|
61
|
+
const actions = (rowSelect?.actions ?? []).filter(e => !e.hidden);
|
|
62
|
+
if (rest.itemDeleteData?.hasAccess) {
|
|
63
|
+
actions.push({
|
|
64
|
+
label: t('Delete'),
|
|
65
|
+
onClick: e => rest.itemDeleteData!.setItemToDeleteUuids([...e]),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return actions;
|
|
69
|
+
}, [rowSelect?.actions, rest.itemDeleteData, t]);
|
|
70
|
+
|
|
65
71
|
const updatedDataActions = useMemo(() => {
|
|
66
|
-
const isEditable = Boolean(dataActions?.
|
|
67
|
-
const isDeletable = Boolean(
|
|
68
|
-
const
|
|
72
|
+
const isEditable = Boolean(dataActions?.hasEditAccess);
|
|
73
|
+
const isDeletable = Boolean(rest.itemDeleteData?.hasAccess);
|
|
74
|
+
const filteredActions = dataActions?.actions?.().filter(e => e.hasAccess) ?? [];
|
|
69
75
|
return {
|
|
70
|
-
|
|
71
|
-
actions:
|
|
72
|
-
|
|
76
|
+
hasEditAccess: isEditable,
|
|
77
|
+
actions: dataActions?.actions,
|
|
78
|
+
filteredActions,
|
|
79
|
+
hasItemActions: isEditable || isDeletable || filteredActions.length > 0,
|
|
73
80
|
isEditable,
|
|
74
81
|
isDeletable,
|
|
75
82
|
};
|
|
76
|
-
}, [dataActions]);
|
|
83
|
+
}, [dataActions, rest.itemDeleteData?.hasAccess]);
|
|
77
84
|
|
|
78
85
|
const localPagination = useLocalTablePagination({
|
|
79
86
|
defaultLimit: footer?.customPagination?.defaultLimit,
|
|
80
87
|
});
|
|
81
|
-
const data = useLocalTableData({
|
|
88
|
+
const data = useLocalTableData<T>({
|
|
82
89
|
initialData,
|
|
83
90
|
localPagination,
|
|
84
91
|
controledPagination: !!footer?.paginationControl,
|
|
85
92
|
dataActions: updatedDataActions,
|
|
93
|
+
isDeletable: updatedDataActions.isDeletable,
|
|
86
94
|
rowSelect,
|
|
87
95
|
});
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
columnData,
|
|
91
|
-
hasSelect: selectActions.length > 0,
|
|
92
|
-
data,
|
|
93
|
-
rowSelect,
|
|
94
|
-
hasItemActions: updatedDataActions.hasItemActions,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const tableContextValue: ITableContext = {
|
|
97
|
+
const tableContextValue: ITableContext<T> = {
|
|
98
98
|
...rest,
|
|
99
99
|
data,
|
|
100
100
|
dataActions: updatedDataActions,
|
|
101
101
|
columnData,
|
|
102
102
|
selectActions,
|
|
103
|
+
rowSelect,
|
|
103
104
|
};
|
|
104
105
|
|
|
105
106
|
if (editable) tableContextValue.editable = { ...editable, isAdding, setIsAdding };
|
|
@@ -107,7 +108,7 @@ export const TableProvider = ({
|
|
|
107
108
|
tableContextValue.footer = {
|
|
108
109
|
...footer,
|
|
109
110
|
paginationControl: footer?.paginationControl ?? localPagination,
|
|
110
|
-
totalRows: footer?.totalRows ?? initialData
|
|
111
|
+
totalRows: footer?.totalRows ?? initialData?.length ?? 0,
|
|
111
112
|
noTotalRows: footer?.totalRows === undefined,
|
|
112
113
|
};
|
|
113
114
|
|
|
@@ -1,38 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { ITableColumn } from '../../../../types/ITable';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Checkbox } from '../../../Inputs/Checkbox';
|
|
5
|
+
import { useTableContext } from '../../contexts/TableContext';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
columnData: ITableColumnsData;
|
|
8
|
-
hasSelect: boolean;
|
|
9
|
-
data: ITable['data'];
|
|
10
|
-
rowSelect: ITable['rowSelect'];
|
|
11
|
-
hasItemActions?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const useLocalTableColumns = ({
|
|
15
|
-
columnData: { defaultColumns, setColumns },
|
|
16
|
-
hasSelect,
|
|
17
|
-
data,
|
|
18
|
-
rowSelect,
|
|
19
|
-
hasItemActions,
|
|
20
|
-
}: Props) => {
|
|
7
|
+
export const useLocalTableColumns = () => {
|
|
21
8
|
const { t } = useTranslation();
|
|
22
9
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
const {
|
|
11
|
+
columnData: { columns },
|
|
12
|
+
selectActions,
|
|
13
|
+
data,
|
|
14
|
+
rowSelect,
|
|
15
|
+
dataActions: { hasItemActions } = {},
|
|
16
|
+
} = useTableContext();
|
|
17
|
+
|
|
18
|
+
const visibleColumns = useMemo(() => {
|
|
19
|
+
const hasSelect = rowSelect && selectActions.length > 0;
|
|
20
|
+
const filteredColumns = columns.filter(column => !column.hidden);
|
|
26
21
|
|
|
27
22
|
let newCols: ITableColumn[] = [];
|
|
28
23
|
|
|
29
24
|
// Select Column
|
|
30
|
-
if (hasSelect
|
|
25
|
+
if (hasSelect) {
|
|
31
26
|
const selectableData = data.filter(e => !e.disableSelect);
|
|
32
27
|
const selectedSome =
|
|
33
|
-
!!rowSelect
|
|
28
|
+
!!rowSelect?.selectedRows.size &&
|
|
34
29
|
selectableData.some(e => !rowSelect.selectedRows.has(e.uuid));
|
|
35
|
-
const selectedAll = !!rowSelect
|
|
30
|
+
const selectedAll = !!rowSelect?.selectedRows.size && !selectedSome;
|
|
36
31
|
|
|
37
32
|
const selectColumn: ITableColumn = {
|
|
38
33
|
id: 'select',
|
|
@@ -42,7 +37,7 @@ export const useLocalTableColumns = ({
|
|
|
42
37
|
setValue={() => {
|
|
43
38
|
selectedAll
|
|
44
39
|
? rowSelect.setSelectedRows(new Set<string>())
|
|
45
|
-
: rowSelect
|
|
40
|
+
: rowSelect?.setSelectedRows(oldValue => {
|
|
46
41
|
let newSet = new Set(oldValue);
|
|
47
42
|
selectableData.forEach(e => newSet.add(e.uuid!));
|
|
48
43
|
return newSet;
|
|
@@ -57,15 +52,19 @@ export const useLocalTableColumns = ({
|
|
|
57
52
|
newCols.push(selectColumn);
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
newCols = newCols.concat(
|
|
61
|
-
|
|
55
|
+
newCols = newCols.concat(filteredColumns);
|
|
56
|
+
// Actions Column
|
|
57
|
+
if (hasItemActions) {
|
|
62
58
|
newCols.push({
|
|
63
59
|
id: 'actions',
|
|
64
60
|
label: t('Actions'),
|
|
65
61
|
align: 'center',
|
|
66
62
|
className: 'actions-col',
|
|
67
63
|
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return newCols;
|
|
67
|
+
}, [columns, selectActions.length, data, rowSelect, hasItemActions, t]);
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
}, [defaultColumns, setColumns, hasSelect, data, rowSelect, hasItemActions, t]);
|
|
69
|
+
return { visibleColumns };
|
|
71
70
|
};
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
IPaginationControl,
|
|
4
|
+
ITable,
|
|
5
|
+
ITableDataActions,
|
|
6
|
+
ITableDataItem,
|
|
7
|
+
} from '../../../../types/ITable';
|
|
3
8
|
import { Checkbox } from '../../../Inputs/Checkbox';
|
|
4
9
|
import { TableItemActions } from '../../components/items/TableItemActions';
|
|
5
10
|
|
|
6
|
-
interface Props {
|
|
7
|
-
initialData: ITableDataItem[];
|
|
11
|
+
interface Props<T> {
|
|
12
|
+
initialData: ITableDataItem<T>[];
|
|
8
13
|
controledPagination: boolean;
|
|
9
14
|
localPagination: IPaginationControl;
|
|
10
|
-
dataActions?:
|
|
15
|
+
dataActions?: ITableDataActions<T>;
|
|
16
|
+
isDeletable: boolean;
|
|
11
17
|
rowSelect: ITable['rowSelect'];
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
export const useLocalTableData = ({
|
|
20
|
+
export const useLocalTableData = <T,>({
|
|
15
21
|
initialData,
|
|
16
22
|
controledPagination,
|
|
17
23
|
localPagination,
|
|
18
24
|
dataActions,
|
|
25
|
+
isDeletable,
|
|
19
26
|
rowSelect,
|
|
20
|
-
}: Props) => {
|
|
21
|
-
const [data, setData] = useState<ITableDataItem[]>(initialData);
|
|
27
|
+
}: Props<T>) => {
|
|
28
|
+
const [data, setData] = useState<ITableDataItem<T>[]>(initialData);
|
|
22
29
|
|
|
23
30
|
useEffect(() => {
|
|
24
31
|
const newData =
|
|
@@ -29,11 +36,9 @@ export const useLocalTableData = ({
|
|
|
29
36
|
localPagination.offset * localPagination.limit + localPagination.limit
|
|
30
37
|
);
|
|
31
38
|
|
|
32
|
-
const additionalDataActions = dataActions?.actions?.filter(e => e.hasAccess) ?? [];
|
|
39
|
+
const additionalDataActions = dataActions?.actions?.().filter(e => e.hasAccess) ?? [];
|
|
33
40
|
const withActions = Boolean(
|
|
34
|
-
dataActions?.
|
|
35
|
-
dataActions?.delete?.hasAccess ||
|
|
36
|
-
additionalDataActions.length
|
|
41
|
+
dataActions?.hasEditAccess || isDeletable || additionalDataActions.length
|
|
37
42
|
);
|
|
38
43
|
|
|
39
44
|
const withAdditionalColumns = Boolean(rowSelect || withActions);
|
|
@@ -71,6 +76,7 @@ export const useLocalTableData = ({
|
|
|
71
76
|
localPagination.limit,
|
|
72
77
|
localPagination.offset,
|
|
73
78
|
rowSelect,
|
|
79
|
+
isDeletable,
|
|
74
80
|
dataActions,
|
|
75
81
|
]);
|
|
76
82
|
|
|
@@ -7,13 +7,14 @@ import { useTableContext } from '../../contexts/TableContext';
|
|
|
7
7
|
export const useLocalTableKeyboard = () => {
|
|
8
8
|
const [focusedRow, setFocusedRow] = useState<ITableDataItem | null>(null);
|
|
9
9
|
|
|
10
|
-
const { keyboard, data, editable, dataActions, rowSelect, footer } =
|
|
10
|
+
const { keyboard, data, editable, itemDeleteData, dataActions, rowSelect, footer } =
|
|
11
|
+
useTableContext();
|
|
11
12
|
|
|
12
13
|
useEffect(() => {
|
|
13
14
|
if (keyboard?.enabled) {
|
|
14
15
|
const isEditing = !!editable?.selectedItem;
|
|
15
16
|
const isAdding = !!editable?.isAdding;
|
|
16
|
-
const isEditDisabled = !editable || keyboard?.actions
|
|
17
|
+
const isEditDisabled = !editable || keyboard?.actions?.editDisabled;
|
|
17
18
|
const isAddDisabled = !!editable?.addDisabled;
|
|
18
19
|
const isMoveDisabled = !!keyboard?.actions?.moveDisabled;
|
|
19
20
|
const isBulkAction =
|
|
@@ -55,7 +56,7 @@ export const useLocalTableKeyboard = () => {
|
|
|
55
56
|
ctrl: true,
|
|
56
57
|
disabled: isEditing || isEditDisabled || !focusedRow,
|
|
57
58
|
onAction: () => {
|
|
58
|
-
editable?.setSelectedItem(focusedRow
|
|
59
|
+
editable?.setSelectedItem(focusedRow);
|
|
59
60
|
},
|
|
60
61
|
},
|
|
61
62
|
{
|
|
@@ -83,10 +84,9 @@ export const useLocalTableKeyboard = () => {
|
|
|
83
84
|
},
|
|
84
85
|
{
|
|
85
86
|
code: 'Delete',
|
|
86
|
-
disabled:
|
|
87
|
+
disabled: !dataActions?.isDeletable || isEditing || !focusedRow,
|
|
87
88
|
onAction: () =>
|
|
88
|
-
|
|
89
|
-
keyboard?.actions.delete?.setItemToDeleteUuids(
|
|
89
|
+
itemDeleteData?.setItemToDeleteUuids(
|
|
90
90
|
isBulkAction ? Array.from(rowSelect.selectedRows) : [focusedRow!.uuid]
|
|
91
91
|
),
|
|
92
92
|
},
|
|
@@ -162,6 +162,8 @@ export const useLocalTableKeyboard = () => {
|
|
|
162
162
|
editable,
|
|
163
163
|
keyboard,
|
|
164
164
|
dataActions?.hasItemActions,
|
|
165
|
+
dataActions?.isDeletable,
|
|
166
|
+
itemDeleteData,
|
|
165
167
|
focusedRow,
|
|
166
168
|
footer,
|
|
167
169
|
rowSelect,
|
|
@@ -1,28 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useLayoutEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { ITableColumn, ITableColumnsData } from '../../../types/ITable';
|
|
3
3
|
|
|
4
4
|
export interface ITableColumnsProps {
|
|
5
5
|
defaultColumns: ITableColumn[];
|
|
6
|
-
|
|
6
|
+
enableEdit?: boolean;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export const useTableColumns = ({
|
|
10
10
|
defaultColumns,
|
|
11
|
-
|
|
11
|
+
enableEdit,
|
|
12
12
|
}: ITableColumnsProps): ITableColumnsData => {
|
|
13
|
-
const [columns, setColumns] = useState<ITableColumn[]>(
|
|
13
|
+
const [columns, setColumns] = useState<ITableColumn[]>([]);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const availableColumns = useMemo(
|
|
16
|
+
() => defaultColumns.filter(e => !e.unavailable),
|
|
17
|
+
[defaultColumns]
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
useLayoutEffect(() => {
|
|
21
|
+
setColumns(availableColumns);
|
|
22
|
+
}, [availableColumns]);
|
|
18
23
|
|
|
19
24
|
const columnData = useMemo(
|
|
20
25
|
() => ({
|
|
21
|
-
defaultColumns,
|
|
26
|
+
defaultColumns: availableColumns,
|
|
22
27
|
columns,
|
|
23
|
-
setColumns,
|
|
28
|
+
setColumns: enableEdit ? setColumns : undefined,
|
|
24
29
|
}),
|
|
25
|
-
[
|
|
30
|
+
[availableColumns, columns, enableEdit]
|
|
26
31
|
);
|
|
32
|
+
|
|
27
33
|
return columnData;
|
|
28
34
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import { ITableEdit } from '../../../types/ITable';
|
|
2
|
+
import { ITableDataItem, ITableEdit } from '../../../types/ITable';
|
|
3
3
|
import { deleteProps, hasValue } from '../../../utils/objectUtils';
|
|
4
4
|
import { Select } from '../../Inputs/Selects/Select';
|
|
5
5
|
import { TextInput } from '../../Inputs/TextInput';
|
|
6
6
|
import { DateInput } from '../../Inputs/DateInput/DateInput';
|
|
7
|
+
import { NumberInput } from '../../Inputs/NumberInput';
|
|
7
8
|
|
|
8
9
|
interface BaseItemProps<T> {
|
|
9
10
|
id: keyof T;
|
|
@@ -20,7 +21,7 @@ interface SelectProps<T> extends BaseItemProps<T> {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export const useTableEdit = <T extends Record<string, any>>() => {
|
|
23
|
-
const [selectedItem, setSelectedItem] = useState<T | null>(null);
|
|
24
|
+
const [selectedItem, setSelectedItem] = useState<ITableDataItem<T> | null>(null);
|
|
24
25
|
const [editData, setEditData] = useState<Partial<T>>({});
|
|
25
26
|
|
|
26
27
|
// Text
|
|
@@ -43,6 +44,26 @@ export const useTableEdit = <T extends Record<string, any>>() => {
|
|
|
43
44
|
),
|
|
44
45
|
});
|
|
45
46
|
|
|
47
|
+
// Number
|
|
48
|
+
const numberEditCell = ({
|
|
49
|
+
placeholder,
|
|
50
|
+
required,
|
|
51
|
+
id,
|
|
52
|
+
additionalClearIds = [],
|
|
53
|
+
}: BaseItemProps<T>) => ({
|
|
54
|
+
value: (
|
|
55
|
+
<NumberInput
|
|
56
|
+
placeholder={placeholder}
|
|
57
|
+
required={required}
|
|
58
|
+
value={editData[id]}
|
|
59
|
+
setValue={e =>
|
|
60
|
+
setEditData(e ? { ...editData, [id]: e } : deleteProps(editData as T, [id]))
|
|
61
|
+
}
|
|
62
|
+
onClear={() => deleteProps(editData as T, [id, ...additionalClearIds])}
|
|
63
|
+
/>
|
|
64
|
+
),
|
|
65
|
+
});
|
|
66
|
+
|
|
46
67
|
// Date
|
|
47
68
|
const dateEditCell = ({
|
|
48
69
|
id,
|
|
@@ -105,6 +126,7 @@ export const useTableEdit = <T extends Record<string, any>>() => {
|
|
|
105
126
|
return {
|
|
106
127
|
editable: returnEditable,
|
|
107
128
|
textEditCell,
|
|
129
|
+
numberEditCell,
|
|
108
130
|
dateEditCell,
|
|
109
131
|
selectEditCell,
|
|
110
132
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import { IGetPrintData, IPrintData } from '../../../types/ITable';
|
|
1
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { IGetPrintData, IPrintData, ITableDataItem } from '../../../types/ITable';
|
|
3
3
|
import { usePopupControl } from '../../../hooks/usePopupControl';
|
|
4
4
|
|
|
5
5
|
type Props<T> = {
|
|
6
6
|
getPrintData: IGetPrintData<T>;
|
|
7
|
+
createTableData?: (data: T[]) => ITableDataItem<T>[];
|
|
7
8
|
totalRows?: number;
|
|
8
9
|
};
|
|
9
10
|
|
|
@@ -12,6 +13,7 @@ const defaultData = { items: [], totalRows: 0 };
|
|
|
12
13
|
|
|
13
14
|
export const useTablePrint = <T>({
|
|
14
15
|
getPrintData,
|
|
16
|
+
createTableData,
|
|
15
17
|
totalRows: initialTotalRows = 0,
|
|
16
18
|
}: Props<T>) => {
|
|
17
19
|
const printPopupControl = usePopupControl();
|
|
@@ -58,13 +60,19 @@ export const useTablePrint = <T>({
|
|
|
58
60
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
61
|
}, [printPopupControl.control.isOpen, initialTotalRows, offset]);
|
|
60
62
|
|
|
61
|
-
const loaded = data.items
|
|
63
|
+
const loaded = data.items?.length;
|
|
62
64
|
const progress = data.totalRows ? (loaded / data.totalRows) * 100 : 0;
|
|
63
65
|
|
|
66
|
+
const tableData = useMemo(
|
|
67
|
+
() => (!isLoading ? (createTableData?.(data.items) ?? []) : []),
|
|
68
|
+
[isLoading, data.items, createTableData]
|
|
69
|
+
);
|
|
70
|
+
|
|
64
71
|
const printData: Pick<
|
|
65
72
|
IPrintData<T>,
|
|
66
|
-
'printPopupControl' | 'isLoading' | 'progress' | 'items'
|
|
73
|
+
'tableData' | 'printPopupControl' | 'isLoading' | 'progress' | 'items'
|
|
67
74
|
> = {
|
|
75
|
+
tableData,
|
|
68
76
|
printPopupControl,
|
|
69
77
|
isLoading,
|
|
70
78
|
progress,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useMemo, useState } from 'react';
|
|
2
2
|
import { ITableSelectedAction } from '../../../types/ITable';
|
|
3
3
|
|
|
4
|
-
export const useTableSelect = (
|
|
4
|
+
export const useTableSelect = (actions: ITableSelectedAction[] = []) => {
|
|
5
5
|
const [selectedRows, setSelectedRows] = useState(new Set<string>());
|
|
6
6
|
|
|
7
7
|
const rowSelect = useMemo(
|
|
@@ -103,31 +103,98 @@ const setAbsolutePosition = (
|
|
|
103
103
|
) => {
|
|
104
104
|
const containerRect = containerEl.getBoundingClientRect();
|
|
105
105
|
const tooltipRect = targetEl.getBoundingClientRect();
|
|
106
|
+
const margin = 16; // Distance from container
|
|
107
|
+
const screenPadding = 8; // Minimum distance from screen edges
|
|
106
108
|
|
|
107
109
|
if (position === 'bottom' || position === 'top') {
|
|
108
|
-
const bottom = Math.floor(containerRect.bottom +
|
|
109
|
-
const top = Math.floor(containerRect.top - tooltipRect.height -
|
|
110
|
-
|
|
110
|
+
const bottom = Math.floor(containerRect.bottom + margin);
|
|
111
|
+
const top = Math.floor(containerRect.top - tooltipRect.height - margin);
|
|
112
|
+
let leftCenter = Math.floor(
|
|
111
113
|
containerRect.left + containerRect.width / 2 - tooltipRect.width / 2
|
|
112
114
|
);
|
|
115
|
+
|
|
116
|
+
// Check if tooltip overflows horizontally and adjust
|
|
117
|
+
if (leftCenter < screenPadding) {
|
|
118
|
+
targetEl.style.width = `${tooltipRect.width + leftCenter}px`;
|
|
119
|
+
leftCenter = screenPadding;
|
|
120
|
+
} else if (leftCenter + tooltipRect.width > window.innerWidth - screenPadding) {
|
|
121
|
+
leftCenter = window.innerWidth - tooltipRect.width - screenPadding;
|
|
122
|
+
}
|
|
123
|
+
|
|
113
124
|
const reverse =
|
|
114
125
|
position === 'top' ? top < 0 : bottom + tooltipRect.height > window.innerHeight;
|
|
115
126
|
|
|
116
127
|
setNewPosition(reverse ? (position === 'bottom' ? 'top' : 'bottom') : '');
|
|
117
128
|
|
|
118
|
-
|
|
119
|
-
position === 'bottom' ? (reverse ? top : bottom) : reverse ? bottom : top
|
|
120
|
-
|
|
129
|
+
let finalTop =
|
|
130
|
+
position === 'bottom' ? (reverse ? top : bottom) : reverse ? bottom : top;
|
|
131
|
+
|
|
132
|
+
// Ensure tooltip doesn't go above screen
|
|
133
|
+
if (finalTop < screenPadding) {
|
|
134
|
+
finalTop = screenPadding;
|
|
135
|
+
}
|
|
136
|
+
// Ensure tooltip doesn't go below screen
|
|
137
|
+
if (finalTop + tooltipRect.height > window.innerHeight - screenPadding) {
|
|
138
|
+
finalTop = window.innerHeight - tooltipRect.height - screenPadding;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
targetEl.style.top = `${finalTop}px`;
|
|
121
142
|
targetEl.style.left = `${leftCenter}px`;
|
|
122
143
|
} else if (position === 'right') {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
144
|
+
let finalTop = Math.floor(
|
|
145
|
+
containerRect.top + containerRect.height / 2 - tooltipRect.height / 2
|
|
146
|
+
);
|
|
147
|
+
let finalLeft = Math.floor(containerRect.right + margin);
|
|
148
|
+
|
|
149
|
+
// Check if tooltip overflows vertically and adjust
|
|
150
|
+
if (finalTop < screenPadding) {
|
|
151
|
+
finalTop = screenPadding;
|
|
152
|
+
} else if (finalTop + tooltipRect.height > window.innerHeight - screenPadding) {
|
|
153
|
+
finalTop = window.innerHeight - tooltipRect.height - screenPadding;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Check if tooltip overflows to the right and flip to left
|
|
157
|
+
if (finalLeft + tooltipRect.width > window.innerWidth - screenPadding) {
|
|
158
|
+
finalLeft = Math.floor(containerRect.left - tooltipRect.width - margin);
|
|
159
|
+
setNewPosition('left');
|
|
160
|
+
|
|
161
|
+
// If it still overflows on the left, position it at the edge
|
|
162
|
+
if (finalLeft < screenPadding) {
|
|
163
|
+
finalLeft = screenPadding;
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
setNewPosition('');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
targetEl.style.top = `${finalTop}px`;
|
|
170
|
+
targetEl.style.left = `${finalLeft}px`;
|
|
127
171
|
} else if (position === 'left') {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
172
|
+
let finalTop = Math.floor(
|
|
173
|
+
containerRect.top + containerRect.height / 2 - tooltipRect.height / 2
|
|
174
|
+
);
|
|
175
|
+
let finalLeft = Math.floor(containerRect.left - tooltipRect.width - margin);
|
|
176
|
+
|
|
177
|
+
// Check if tooltip overflows vertically and adjust
|
|
178
|
+
if (finalTop < screenPadding) {
|
|
179
|
+
finalTop = screenPadding;
|
|
180
|
+
} else if (finalTop + tooltipRect.height > window.innerHeight - screenPadding) {
|
|
181
|
+
finalTop = window.innerHeight - tooltipRect.height - screenPadding;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check if tooltip overflows to the left and flip to right
|
|
185
|
+
if (finalLeft < screenPadding) {
|
|
186
|
+
finalLeft = Math.floor(containerRect.right + margin);
|
|
187
|
+
setNewPosition('right');
|
|
188
|
+
|
|
189
|
+
// If it still overflows on the right, position it at the edge
|
|
190
|
+
if (finalLeft + tooltipRect.width > window.innerWidth - screenPadding) {
|
|
191
|
+
finalLeft = window.innerWidth - tooltipRect.width - screenPadding;
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
setNewPosition('');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
targetEl.style.top = `${finalTop}px`;
|
|
198
|
+
targetEl.style.left = `${finalLeft}px`;
|
|
132
199
|
}
|
|
133
200
|
};
|
|
@@ -4,8 +4,8 @@ export const useIsMenuOpen = () => {
|
|
|
4
4
|
const [isOpen, setIsOpen] = useState(false);
|
|
5
5
|
|
|
6
6
|
return {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
isOpen,
|
|
8
|
+
onOpen: () => setIsOpen(true),
|
|
9
|
+
onClose: () => setTimeout(() => setIsOpen(false)),
|
|
10
10
|
};
|
|
11
11
|
};
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { useCallback, useRef, useState } from 'react';
|
|
2
|
-
import { IPopupControl,
|
|
2
|
+
import { IPopupControl, IPopupControlRef } from '../types/IPopup';
|
|
3
3
|
|
|
4
|
-
export const usePopupControl: (
|
|
4
|
+
export const usePopupControl: (props?: {
|
|
5
|
+
onCloseCallback?: () => void;
|
|
6
|
+
}) => IPopupControl = props => {
|
|
5
7
|
const [isOpen, setIsOpen] = useState(false);
|
|
6
8
|
|
|
7
|
-
const controlRef = useRef<
|
|
9
|
+
const controlRef = useRef<IPopupControlRef>(null);
|
|
8
10
|
|
|
9
11
|
const onOpen = useCallback(() => controlRef.current?.onOpen(), []);
|
|
10
|
-
const onClose = useCallback(() =>
|
|
12
|
+
const onClose = useCallback(() => {
|
|
13
|
+
controlRef.current?.onClose();
|
|
14
|
+
props?.onCloseCallback?.();
|
|
15
|
+
}, [props]);
|
|
11
16
|
|
|
12
17
|
return {
|
|
13
18
|
control: { controlRef, isOpen, setIsOpen },
|