@topconsultnpm/sdkui-react 6.22.0-t1 → 6.22.0-t2
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/lib/components/NewComponents/ContextMenu/TMContextMenu.js +1 -1
- package/lib/components/NewComponents/ContextMenu/styles.d.ts +45 -43
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +67 -60
- package/lib/components/base/Styled.d.ts +92 -76
- package/lib/components/base/TMButton.d.ts +13 -0
- package/lib/components/base/TMButton.js +137 -5
- package/lib/components/base/TMDataGrid.d.ts +2 -0
- package/lib/components/base/TMDataGrid.js +260 -8
- package/lib/components/base/TMDataGridExportForm.js +39 -30
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMFileManager.js +5 -3
- package/lib/components/base/TMFileManagerDataGridView.js +11 -2
- package/lib/components/base/TMFileManagerThumbnailItems.js +19 -9
- package/lib/components/base/TMFileManagerUtils.d.ts +6 -6
- package/lib/components/base/TMFileManagerUtils.js +37 -1
- package/lib/components/base/TMModal.d.ts +11 -0
- package/lib/components/base/TMModal.js +47 -13
- package/lib/components/base/TMPanel.d.ts +6 -0
- package/lib/components/base/TMPanel.js +138 -25
- package/lib/components/base/TMPopUp.js +3 -0
- package/lib/components/base/TMTooltip.d.ts +2 -1
- package/lib/components/base/TMTooltip.js +24 -8
- package/lib/components/base/TMTreeView.d.ts +13 -7
- package/lib/components/base/TMTreeView.js +108 -67
- package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
- package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
- package/lib/components/choosers/TMDistinctValues.js +149 -142
- package/lib/components/choosers/TMMetadataChooser.js +1 -1
- package/lib/components/choosers/TMQuickSearchInfo.d.ts +13 -0
- package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
- package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
- package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
- package/lib/components/editors/TMDateBox.d.ts +16 -1
- package/lib/components/editors/TMDateBox.js +90 -22
- package/lib/components/editors/TMDropDown.d.ts +3 -0
- package/lib/components/editors/TMDropDown.js +197 -5
- package/lib/components/editors/TMEditorStyled.d.ts +20 -42
- package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
- package/lib/components/editors/TMMetadataEditor.js +27 -23
- package/lib/components/editors/TMTextArea.d.ts +1 -0
- package/lib/components/editors/TMTextArea.js +23 -15
- package/lib/components/editors/TMTextBox.d.ts +2 -0
- package/lib/components/editors/TMTextBox.js +30 -19
- package/lib/components/features/archive/TMArchive.js +17 -3
- package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
- package/lib/components/features/documents/TMDcmtBlog.d.ts +3 -0
- package/lib/components/features/documents/TMDcmtBlog.js +4 -4
- package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
- package/lib/components/features/documents/TMDcmtForm.js +232 -53
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +77 -7
- package/lib/components/features/documents/TMDcmtIcon.js +5 -3
- package/lib/components/features/documents/TMDcmtPreview.d.ts +7 -5
- package/lib/components/features/documents/TMDcmtPreview.js +10 -6
- package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
- package/lib/components/features/documents/TMMasterInfoFields.d.ts +20 -0
- package/lib/components/features/documents/TMMasterInfoFields.js +186 -0
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
- package/lib/components/features/documents/TMMergeToPdfForm.js +30 -5
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +46 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +323 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +370 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +283 -0
- package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
- package/lib/components/features/documents/TMRelationViewer.js +82 -52
- package/lib/components/features/search/TMSearch.js +103 -24
- package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +14 -4
- package/lib/components/features/search/TMSearchQueryPanel.js +152 -57
- package/lib/components/features/search/TMSearchResult.d.ts +16 -0
- package/lib/components/features/search/TMSearchResult.js +438 -145
- package/lib/components/features/search/TMTreeSelector.js +109 -64
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
- package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
- package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +3 -1
- package/lib/components/forms/Login/ChangePasswordInputs.d.ts +3 -1
- package/lib/components/grids/TMBlogAttachments.js +13 -2
- package/lib/components/grids/TMBlogHeader.js +5 -1
- package/lib/components/grids/TMBlogsPost.d.ts +2 -0
- package/lib/components/grids/TMBlogsPost.js +31 -4
- package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
- package/lib/components/grids/TMBlogsPostUtils.js +14 -3
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +68 -93
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +4 -5
- package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
- package/lib/components/layout/panelManager/types.d.ts +3 -0
- package/lib/components/layout/panelManager/utils.js +13 -11
- package/lib/components/query/TMQueryEditor.d.ts +14 -10
- package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
- package/lib/components/sidebar/TMHeader.js +30 -20
- package/lib/components/viewers/TMMidViewer.js +5 -2
- package/lib/components/viewers/TMTidViewer.js +86 -25
- package/lib/css/tm-sdkui.css +1 -1
- package/lib/devextreme-license.d.ts +1 -0
- package/lib/devextreme-license.js +3 -0
- package/lib/helper/Globalization.d.ts +1 -1
- package/lib/helper/SDKUI_Globals.d.ts +110 -0
- package/lib/helper/SDKUI_Globals.js +151 -0
- package/lib/helper/SDKUI_Localizator.d.ts +55 -0
- package/lib/helper/SDKUI_Localizator.js +550 -0
- package/lib/helper/TMAppUpdatedModal.d.ts +2 -0
- package/lib/helper/TMAppUpdatedModal.js +134 -0
- package/lib/helper/TMIcons.d.ts +1 -0
- package/lib/helper/TMIcons.js +3 -0
- package/lib/helper/TMUtils.d.ts +51 -4
- package/lib/helper/TMUtils.js +272 -11
- package/lib/helper/dataGridSearchHelper.d.ts +28 -0
- package/lib/helper/dataGridSearchHelper.js +51 -0
- package/lib/helper/dcmtsHelper.d.ts +20 -0
- package/lib/helper/dcmtsHelper.js +58 -1
- package/lib/helper/helpers.d.ts +23 -1
- package/lib/helper/helpers.js +57 -1
- package/lib/helper/index.d.ts +2 -0
- package/lib/helper/index.js +2 -0
- package/lib/helper/queryHelper.d.ts +6 -1
- package/lib/helper/queryHelper.js +8 -3
- package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
- package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
- package/lib/hooks/useArchiveListForm.d.ts +39 -0
- package/lib/hooks/useArchiveListForm.js +46 -0
- package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
- package/lib/hooks/useCaseFlowApprove.js +157 -0
- package/lib/hooks/useDataUserIdItem.d.ts +1 -0
- package/lib/hooks/useDataUserIdItem.js +1 -0
- package/lib/hooks/useDocumentOperations.d.ts +4 -0
- package/lib/hooks/useDocumentOperations.js +52 -10
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +113 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +760 -0
- package/lib/hooks/useRelatedDocuments.d.ts +1 -0
- package/lib/hooks/useRelatedDocuments.js +22 -27
- package/lib/hooks/useShowDossiersV5.d.ts +12 -0
- package/lib/hooks/useShowDossiersV5.js +37 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
- package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
- package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
- package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
- package/lib/hooks/useTMDistinctValuesSource.js +105 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -2
- package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
- package/lib/services/caseflow/CaseFlowService.js +693 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
- package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
- package/lib/services/caseflow/caseFlowNameCache.js +116 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/index.js +4 -0
- package/lib/services/platform_services.d.ts +1 -1
- package/package.json +9 -5
|
@@ -26,6 +26,7 @@ export interface FileItem {
|
|
|
26
26
|
version?: number;
|
|
27
27
|
isSigned?: number;
|
|
28
28
|
}
|
|
29
|
+
export declare const resolveFileItemUserNames: (item: FileItem, users: Array<UserDescriptor>) => FileItem;
|
|
29
30
|
export interface TMFileManagerTreeViewDirectory {
|
|
30
31
|
id: number;
|
|
31
32
|
text: string;
|
|
@@ -47,15 +48,14 @@ export declare const colors: {
|
|
|
47
48
|
LIGHT_YELLOW: string;
|
|
48
49
|
MEDIUM_GREEN: string;
|
|
49
50
|
};
|
|
50
|
-
export declare const TMFileItemContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").
|
|
51
|
+
export declare const TMFileItemContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
52
|
+
style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
53
|
+
}, {
|
|
51
54
|
$backgroundColor?: string;
|
|
52
55
|
$textColor?: string;
|
|
53
56
|
$bgHoverColor?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
$textColor?: string;
|
|
57
|
-
$bgHoverColor?: string;
|
|
58
|
-
}, never>>> & string;
|
|
57
|
+
}>> & string;
|
|
58
|
+
export declare const getFileItemLinkUrl: (fileItem: FileItem | undefined) => string | undefined;
|
|
59
59
|
export declare const findFileItems: (items: Array<FileItem>, id: number) => FileItem | undefined;
|
|
60
60
|
export declare const setFolderTreeViewItems: (items: Array<FileItem>) => Array<TMFileManagerTreeViewDirectory>;
|
|
61
61
|
export declare const buildFolderHierarchy: (fileSystemTree: WGTreeDescriptor | undefined, draftsFile: SearchResultDescriptor | undefined, archivedDocuments: Array<SearchResultDescriptor> | undefined, participants: Array<UserDescriptor> | undefined) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
|
-
import { associateColumnsToRows, SIGNATURE_EXTENSIONS } from "../../helper";
|
|
2
|
+
import { associateColumnsToRows, SIGNATURE_EXTENSIONS, WHATS_NEWS_FILE_NAME, WHATS_NEWS_LINK_URL } from "../../helper";
|
|
3
3
|
/**
|
|
4
4
|
* Verifica se un'estensione indica che il file è firmato digitalmente.
|
|
5
5
|
* Controlla se l'estensione (es. "pdf.p7m", ".p7m", "p7m") contiene
|
|
@@ -12,6 +12,22 @@ export const isSigned = (ext) => {
|
|
|
12
12
|
const parts = normalized.split('.');
|
|
13
13
|
return parts.some(part => SIGNATURE_EXTENSIONS.has(part));
|
|
14
14
|
};
|
|
15
|
+
// Completa i nomi utente (autore e utente di check-out) di un FileItem quando mancano, risolvendoli dagli ID.
|
|
16
|
+
export const resolveFileItemUserNames = (item, users) => {
|
|
17
|
+
if (!users || users.length === 0)
|
|
18
|
+
return item;
|
|
19
|
+
const isValidUserID = (id) => id !== undefined && Number.isFinite(id) && id > 0;
|
|
20
|
+
const needsUpdaterName = !item.updaterName && isValidUserID(item.updaterID);
|
|
21
|
+
const needsCheckOutUserName = !item.checkOutUserName && isValidUserID(item.checkOutUserID);
|
|
22
|
+
if (!needsUpdaterName && !needsCheckOutUserName)
|
|
23
|
+
return item;
|
|
24
|
+
const resolved = { ...item };
|
|
25
|
+
if (needsUpdaterName)
|
|
26
|
+
resolved.updaterName = users.find(user => user.id === item.updaterID)?.name ?? item.updaterName;
|
|
27
|
+
if (needsCheckOutUserName)
|
|
28
|
+
resolved.checkOutUserName = users.find(user => user.id === item.checkOutUserID)?.name ?? item.checkOutUserName;
|
|
29
|
+
return resolved;
|
|
30
|
+
};
|
|
15
31
|
export var TMFileManagerPageSize;
|
|
16
32
|
(function (TMFileManagerPageSize) {
|
|
17
33
|
TMFileManagerPageSize[TMFileManagerPageSize["Small"] = 30] = "Small";
|
|
@@ -47,6 +63,26 @@ export const TMFileItemContainer = styled.div `
|
|
|
47
63
|
outline: none;
|
|
48
64
|
}
|
|
49
65
|
`;
|
|
66
|
+
// Confronto case-insensitive con il nome del file
|
|
67
|
+
const isWhatsNewsFileName = (name) => (name ?? '').toLowerCase() === WHATS_NEWS_FILE_NAME;
|
|
68
|
+
// Ritorna l'url del link associato al file: un file il cui metadato "description" contiene un url http/https
|
|
69
|
+
// e' un link, quindi non ha un file/documento da scaricare o da aprire nella form: si apre direttamente l'url
|
|
70
|
+
export const getFileItemLinkUrl = (fileItem) => {
|
|
71
|
+
if (!fileItem || fileItem.isDirectory)
|
|
72
|
+
return undefined;
|
|
73
|
+
if (isWhatsNewsFileName(fileItem.name))
|
|
74
|
+
return WHATS_NEWS_LINK_URL;
|
|
75
|
+
const value = fileItem.description?.trim();
|
|
76
|
+
if (!value)
|
|
77
|
+
return undefined;
|
|
78
|
+
try {
|
|
79
|
+
const url = new URL(value);
|
|
80
|
+
return (url.protocol === 'http:' || url.protocol === 'https:') ? url.href : undefined;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
50
86
|
// Function to find a specific file or folder based on its ID (used for finding nested items)
|
|
51
87
|
export const findFileItems = (items, id) => {
|
|
52
88
|
for (let item of items) {
|
|
@@ -14,6 +14,17 @@ interface ITMModal {
|
|
|
14
14
|
askClosingConfirm?: boolean;
|
|
15
15
|
showCloseButton?: boolean;
|
|
16
16
|
showHeader?: boolean;
|
|
17
|
+
/** Se true, ricentra il popup ogni volta che cambiano width/height, annullando lo spostamento manuale */
|
|
18
|
+
recenterOnResize?: boolean;
|
|
19
|
+
/** Contenuto aggiuntivo nella barra del titolo, prima del pulsante di chiusura (es. un menu di opzioni) */
|
|
20
|
+
titleActions?: React.ReactNode;
|
|
21
|
+
/** Dimensioni in px al termine di un ridimensionamento manuale */
|
|
22
|
+
onResized?: (size: {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
}) => void;
|
|
26
|
+
/** A ogni cambio di valore le dimensioni tornano a `width`/`height`, anche se invariate */
|
|
27
|
+
sizeResetToken?: number | string;
|
|
17
28
|
}
|
|
18
29
|
declare const TMModal: React.FC<ITMModal>;
|
|
19
30
|
export default TMModal;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect, useRef } from 'react';
|
|
3
3
|
import { Popup } from 'devextreme-react';
|
|
4
|
+
import { ToolbarItem } from 'devextreme-react/popup';
|
|
4
5
|
import styled from 'styled-components';
|
|
5
6
|
import { TMCard } from './TMLayout';
|
|
6
7
|
import { FontSize, TMColors } from '../../utils/theme';
|
|
7
8
|
import { IconWindowMaximize, IconWindowMinimize, svgToString } from '../../helper';
|
|
9
|
+
/** Valori di `height` con cui il popup si dimensiona sul contenuto (vedi applyContentFillLayout) */
|
|
10
|
+
const CONTENT_DRIVEN_HEIGHTS = ['auto', 'max-content', 'min-content', 'fit-content'];
|
|
8
11
|
const StyledModal = styled.div `
|
|
9
12
|
width: ${props => props.$width};
|
|
10
13
|
height: ${props => props.$height};
|
|
@@ -39,10 +42,13 @@ const StyledModalContext = styled.div `
|
|
|
39
42
|
overflow: auto;
|
|
40
43
|
height: 100%;
|
|
41
44
|
`;
|
|
42
|
-
const TMModal = ({ resizable = true, expandable = false, isModal = true, title = '', toolbar, onClose, children, width = '100%', height = '100%', fontSize = FontSize.defaultFontSize, hidePopup = true, askClosingConfirm = false, showCloseButton = true, showHeader = true }) => {
|
|
45
|
+
const TMModal = ({ resizable = true, expandable = false, isModal = true, title = '', toolbar, onClose, children, width = '100%', height = '100%', fontSize = FontSize.defaultFontSize, hidePopup = true, askClosingConfirm = false, showCloseButton = true, showHeader = true, recenterOnResize = false, titleActions, onResized, sizeResetToken }) => {
|
|
43
46
|
const popupRef = useRef(null);
|
|
44
47
|
const [initialWidth, setInitialWidth] = useState(width);
|
|
45
48
|
const [initialHeight, setInitialHeight] = useState(height);
|
|
49
|
+
// Posizione controllata: un nuovo riferimento oggetto forza DevExtreme a riposizionare (ricentrare).
|
|
50
|
+
// Lasciata invariata durante il drag, così lo spostamento manuale viene preservato
|
|
51
|
+
const [position, setPosition] = useState(undefined);
|
|
46
52
|
const [showPopup, setShowPopup] = useState(false);
|
|
47
53
|
const [isResizing, setIsResizing] = useState(false);
|
|
48
54
|
const [isFullScreen, setIsFullScreen] = useState(false);
|
|
@@ -51,6 +57,26 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
|
|
|
51
57
|
const DEFAULT_MIN_HEIGHT = 400;
|
|
52
58
|
const [minWidth, setMinWidth] = useState(0);
|
|
53
59
|
const [minHeight, setMinHeight] = useState(0);
|
|
60
|
+
/**
|
|
61
|
+
* DevExtreme fissa in px l'altezza del contenuto del popup: se le dimensioni cambiano a popup
|
|
62
|
+
* già aperto (es. cambio step) resta quella del passo precedente e sotto rimane spazio vuoto.
|
|
63
|
+
* Come figlio flex il contenuto riempie il popup senza dipendere da quel calcolo.
|
|
64
|
+
* Non si applica alle altezze dimensionate sul contenuto (`auto`, `max-content`, ...):
|
|
65
|
+
* lì è il contenuto a dare l'altezza al popup e non c'è spazio da riempire.
|
|
66
|
+
*/
|
|
67
|
+
const applyContentFillLayout = () => {
|
|
68
|
+
const content = popupRef.current?.instance()?.content();
|
|
69
|
+
const overlayContent = content?.parentElement;
|
|
70
|
+
if (!content || !overlayContent)
|
|
71
|
+
return;
|
|
72
|
+
const fill = !CONTENT_DRIVEN_HEIGHTS.some(value => initialHeight.trim().startsWith(value));
|
|
73
|
+
overlayContent.style.display = fill ? 'flex' : '';
|
|
74
|
+
overlayContent.style.flexDirection = fill ? 'column' : '';
|
|
75
|
+
content.style.flex = fill ? '1 1 auto' : '';
|
|
76
|
+
// Testata e toolbar inferiore restano alla loro altezza naturale
|
|
77
|
+
overlayContent.querySelectorAll(':scope > .dx-popup-title, :scope > .dx-popup-bottom')
|
|
78
|
+
.forEach(el => { el.style.flexShrink = fill ? '0' : ''; });
|
|
79
|
+
};
|
|
54
80
|
/**
|
|
55
81
|
* Gestore chiamato quando il popup viene mostrato.
|
|
56
82
|
* Calcola e imposta le dimensioni minime del popup in base allo spazio disponibile.
|
|
@@ -59,6 +85,7 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
|
|
|
59
85
|
const handleShown = () => {
|
|
60
86
|
// Usa requestAnimationFrame per attendere il completamento del rendering
|
|
61
87
|
requestAnimationFrame(() => {
|
|
88
|
+
applyContentFillLayout();
|
|
62
89
|
if (popupRef.current && popupRef.current.instance) {
|
|
63
90
|
const instance = popupRef.current.instance();
|
|
64
91
|
if (instance) {
|
|
@@ -85,14 +112,27 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
|
|
|
85
112
|
useEffect(() => {
|
|
86
113
|
setInitialWidth(width);
|
|
87
114
|
setInitialHeight(height);
|
|
88
|
-
|
|
115
|
+
// Al cambio di dimensioni (es. cambio step) ricentra il popup con un nuovo riferimento oggetto,
|
|
116
|
+
// annullando l'eventuale spostamento manuale precedente
|
|
117
|
+
if (recenterOnResize)
|
|
118
|
+
setPosition({ my: 'center', at: 'center', of: window });
|
|
119
|
+
// Il token annulla un ridimensionamento manuale, che non cambia width/height
|
|
120
|
+
}, [width, height, recenterOnResize, sizeResetToken]);
|
|
121
|
+
// Dimensioni, testata e schermo pieno fanno rigenerare geometria ed elementi del popup:
|
|
122
|
+
// il layout flex del contenuto va riapplicato dopo il ridisegno (vedi applyContentFillLayout)
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
const rafId = requestAnimationFrame(() => applyContentFillLayout());
|
|
125
|
+
return () => cancelAnimationFrame(rafId);
|
|
126
|
+
}, [initialWidth, initialHeight, title, isFullScreen, showPopup]);
|
|
89
127
|
const handleResizeStart = () => {
|
|
90
128
|
setIsResizing(true);
|
|
91
129
|
};
|
|
92
130
|
const handleResizeEnd = (e) => {
|
|
93
131
|
setIsResizing(false);
|
|
94
|
-
|
|
95
|
-
|
|
132
|
+
// Le dimensioni arrivano in px: senza unità non sarebbero un valore CSS valido
|
|
133
|
+
setInitialWidth(`${e.width}px`);
|
|
134
|
+
setInitialHeight(`${e.height}px`);
|
|
135
|
+
onResized?.({ width: e.width, height: e.height });
|
|
96
136
|
};
|
|
97
137
|
const onHiding = (e) => {
|
|
98
138
|
if (askClosingConfirm)
|
|
@@ -101,15 +141,9 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
|
|
|
101
141
|
setShowPopup(false);
|
|
102
142
|
onClose && onClose();
|
|
103
143
|
};
|
|
104
|
-
return (_jsx(_Fragment, { children: isModal ? (
|
|
105
|
-
{
|
|
106
|
-
widget: 'dxButton',
|
|
107
|
-
location: 'after',
|
|
108
|
-
options: {
|
|
144
|
+
return (_jsx(_Fragment, { children: isModal ? (_jsxs(Popup, { ref: popupRef, showCloseButton: showHeader ? showCloseButton : false, showTitle: showHeader, animation: undefined, minWidth: minWidth, minHeight: minHeight, maxHeight: '95%', maxWidth: '95%', dragEnabled: !isResizing && !isFullScreen, resizeEnabled: resizable && !isFullScreen, position: expandable && isFullScreen ? { my: 'center', at: 'center', of: window } : position, width: expandable && isFullScreen ? '95%' : initialWidth, height: expandable && isFullScreen ? '95%' : initialHeight, title: title, visible: showPopup, onShown: handleShown, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd, onHiding: onHiding, children: [showHeader && titleActions && (_jsx(ToolbarItem, { toolbar: 'top', location: 'after', render: () => _jsx(_Fragment, { children: titleActions }) })), showHeader && expandable && (_jsx(ToolbarItem, { toolbar: 'top', location: 'after', widget: 'dxButton', options: {
|
|
109
145
|
icon: isFullScreen ? svgToString(_jsx(IconWindowMinimize, {})) : svgToString(_jsx(IconWindowMaximize, {})),
|
|
110
146
|
onClick: () => setIsFullScreen(!isFullScreen)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
] : undefined, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', width: '100%' }, children: [toolbar && (_jsx(StyledModalToolbar, { children: toolbar })), _jsx("div", { style: { flex: 1, overflow: 'hidden', minHeight: 0 }, children: _jsx(TMCard, { showBorder: false, padding: false, scrollY: true, children: children }) })] }) })) : (_jsxs(StyledModal, { "$isModal": isModal, className: "temp-modal", "$fontSize": fontSize, "$width": initialWidth, "$height": initialHeight, children: [toolbar ? _jsx(StyledModalToolbar, { children: toolbar }) : _jsx(_Fragment, {}), _jsx(StyledModalContext, { children: children })] })) }));
|
|
147
|
+
} })), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', width: '100%' }, children: [toolbar && (_jsx(StyledModalToolbar, { children: toolbar })), _jsx("div", { style: { flex: 1, overflow: 'hidden', minHeight: 0 }, children: _jsx(TMCard, { showBorder: false, padding: false, scrollY: true, children: children }) })] })] })) : (_jsxs(StyledModal, { "$isModal": isModal, className: "temp-modal", "$fontSize": fontSize, "$width": initialWidth, "$height": initialHeight, children: [toolbar ? _jsx(StyledModalToolbar, { children: toolbar }) : _jsx(_Fragment, {}), _jsx(StyledModalContext, { children: children })] })) }));
|
|
114
148
|
};
|
|
115
149
|
export default TMModal;
|
|
@@ -10,6 +10,7 @@ export interface ITMPanelProps {
|
|
|
10
10
|
children?: React.ReactNode;
|
|
11
11
|
showHeader?: boolean;
|
|
12
12
|
title?: React.ReactNode;
|
|
13
|
+
enableTitleMarquee?: boolean;
|
|
13
14
|
displayedItemsCount?: number;
|
|
14
15
|
totalItems?: number;
|
|
15
16
|
toolbar?: any;
|
|
@@ -17,9 +18,14 @@ export interface ITMPanelProps {
|
|
|
17
18
|
isVisible?: boolean;
|
|
18
19
|
panelID?: string;
|
|
19
20
|
isActive?: boolean;
|
|
21
|
+
/** Se fornita, in testata compare il bottone di ricarica: finché la Promise è pendente il pannello mostra il loader */
|
|
22
|
+
onRefresh?: () => void | Promise<void>;
|
|
23
|
+
/** Mostra il loader sul contenuto anche per caricamenti non avviati dal bottone di ricarica */
|
|
24
|
+
isRefreshing?: boolean;
|
|
20
25
|
onActivate?: (panelID: string) => void;
|
|
21
26
|
onActiveChanged?: (isActive: boolean) => void;
|
|
22
27
|
onBack?: () => void;
|
|
28
|
+
backCaption?: string;
|
|
23
29
|
onClose?: () => void;
|
|
24
30
|
onHeaderDoubleClick?: () => void;
|
|
25
31
|
onMaximize?: (isMaximized: boolean) => void;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useRef, useState, forwardRef, useImperativeHandle } from 'react';
|
|
3
|
-
import styled from 'styled-components';
|
|
4
|
-
import { getAppModuleGradient, IconArrowLeft, IconClearButton, IconWindowMaximize, IconWindowMinimize, isPositiveNumber, SDKUI_Localizator } from '../../helper';
|
|
3
|
+
import styled, { css, keyframes } from 'styled-components';
|
|
4
|
+
import { getAppModuleGradient, IconArrowLeft, IconClearButton, IconRefresh, IconWindowMaximize, IconWindowMinimize, isPositiveNumber, SDKUI_Localizator } from '../../helper';
|
|
5
5
|
import TMButton from './TMButton';
|
|
6
|
-
import {
|
|
6
|
+
import { LoadIndicator } from 'devextreme-react/load-indicator';
|
|
7
|
+
import { TMExceptionBoxManager } from './TMPopUp';
|
|
8
|
+
import { Gutters, TMColors } from '../../utils/theme';
|
|
7
9
|
const StyledBackButton = styled.button `
|
|
8
10
|
display: flex;
|
|
9
11
|
align-items: center;
|
|
@@ -96,6 +98,110 @@ const StyledPanelContent = styled.div `
|
|
|
96
98
|
outline: none;
|
|
97
99
|
}
|
|
98
100
|
`;
|
|
101
|
+
// Allineata al TABLET_BREAKPOINT (768) di TMDeviceProvider
|
|
102
|
+
const MOBILE_MEDIA_QUERY = '(max-width: 767.98px)';
|
|
103
|
+
// L'eccedenza da scorrere è "larghezza viewport - larghezza testo", ma nessuna delle due
|
|
104
|
+
// è nota al CSS. La si ottiene componendo due percentuali che si risolvono su box diversi:
|
|
105
|
+
// la track (larga quanto il viewport) va a +100% della PROPRIA larghezza, il testo a -100%
|
|
106
|
+
// della SUA. Le due animazioni hanno stessa durata ed easing, quindi lo scostamento netto
|
|
107
|
+
// in ogni istante è esattamente e(t) * (viewport - testo).
|
|
108
|
+
const panelTitleTrackMarquee = keyframes `
|
|
109
|
+
0%, 15% { transform: translateX(0); }
|
|
110
|
+
45%, 55% { transform: translateX(100%); }
|
|
111
|
+
85%, 100% { transform: translateX(0); }
|
|
112
|
+
`;
|
|
113
|
+
const panelTitleTextMarquee = keyframes `
|
|
114
|
+
0%, 15% { transform: translateX(0); }
|
|
115
|
+
45%, 55% { transform: translateX(-100%); }
|
|
116
|
+
85%, 100% { transform: translateX(0); }
|
|
117
|
+
`;
|
|
118
|
+
// Ritaglia il testo in eccesso: è l'unico box con overflow hidden, la track ci scorre dentro
|
|
119
|
+
const StyledPanelTitleViewport = styled.div `
|
|
120
|
+
flex: 1;
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: flex-start;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
padding: 0 8px;
|
|
127
|
+
`;
|
|
128
|
+
// Larga quanto il viewport: è il metro con cui il -100% del testo viene compensato.
|
|
129
|
+
const StyledPanelTitleTrack = styled.div `
|
|
130
|
+
flex: 1;
|
|
131
|
+
min-width: 0;
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
|
|
135
|
+
${({ $marquee }) => $marquee && css `
|
|
136
|
+
@media ${MOBILE_MEDIA_QUERY} {
|
|
137
|
+
animation: ${panelTitleTrackMarquee} 10s ease-in-out infinite;
|
|
138
|
+
|
|
139
|
+
@media (prefers-reduced-motion: reduce) {
|
|
140
|
+
animation: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
`}
|
|
144
|
+
`;
|
|
145
|
+
// Senza $marquee resta il troncamento con i puntini di sempre
|
|
146
|
+
const StyledPanelTitle = styled.div `
|
|
147
|
+
margin: 0;
|
|
148
|
+
white-space: nowrap;
|
|
149
|
+
overflow: hidden;
|
|
150
|
+
text-overflow: ellipsis;
|
|
151
|
+
|
|
152
|
+
${({ $marquee }) => $marquee && css `
|
|
153
|
+
@media ${MOBILE_MEDIA_QUERY} {
|
|
154
|
+
flex: 0 0 auto;
|
|
155
|
+
width: max-content;
|
|
156
|
+
min-width: 100%;
|
|
157
|
+
max-width: none;
|
|
158
|
+
overflow: visible;
|
|
159
|
+
text-overflow: clip;
|
|
160
|
+
animation: ${panelTitleTextMarquee} 10s ease-in-out infinite;
|
|
161
|
+
|
|
162
|
+
@media (prefers-reduced-motion: reduce) {
|
|
163
|
+
animation: none;
|
|
164
|
+
width: auto;
|
|
165
|
+
min-width: 0;
|
|
166
|
+
overflow: hidden;
|
|
167
|
+
text-overflow: ellipsis;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
`}
|
|
171
|
+
`;
|
|
172
|
+
const refreshSpin = keyframes `
|
|
173
|
+
from { transform: rotate(0deg); }
|
|
174
|
+
to { transform: rotate(360deg); }
|
|
175
|
+
`;
|
|
176
|
+
// Fa girare l'icona per tutta la durata del ricaricamento
|
|
177
|
+
const StyledRefreshIcon = styled.span `
|
|
178
|
+
display: flex;
|
|
179
|
+
align-items: center;
|
|
180
|
+
justify-content: center;
|
|
181
|
+
|
|
182
|
+
${({ $isSpinning }) => $isSpinning && css `
|
|
183
|
+
animation: ${refreshSpin} 1s linear infinite;
|
|
184
|
+
|
|
185
|
+
@media (prefers-reduced-motion: reduce) {
|
|
186
|
+
animation: none;
|
|
187
|
+
}
|
|
188
|
+
`}
|
|
189
|
+
`;
|
|
190
|
+
// Copre il solo contenuto del pannello (StyledPanelContent è position: relative con overflow hidden)
|
|
191
|
+
const StyledPanelLoaderOverlay = styled.div `
|
|
192
|
+
position: absolute;
|
|
193
|
+
inset: 0;
|
|
194
|
+
z-index: 10;
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-direction: column;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: center;
|
|
199
|
+
gap: 10px;
|
|
200
|
+
background: rgba(255, 255, 255, 0.65);
|
|
201
|
+
border-bottom-right-radius: 10px;
|
|
202
|
+
border-bottom-left-radius: 10px;
|
|
203
|
+
color: ${TMColors.primaryColor};
|
|
204
|
+
`;
|
|
99
205
|
/**
|
|
100
206
|
* TMPanel - Pannello con supporto Controlled/Uncontrolled
|
|
101
207
|
*
|
|
@@ -103,9 +209,27 @@ const StyledPanelContent = styled.div `
|
|
|
103
209
|
* - Se NON passata → Uncontrolled: gestione interna dello stato attivo (plug-and-play)
|
|
104
210
|
* - Se passata → Controlled: il parent gestisce lo stato tramite onActivate
|
|
105
211
|
*/
|
|
106
|
-
const TMPanel = forwardRef(({ allowMaximize = true, color, backgroundColor, backgroundColorContainer, children, showHeader = true, title, totalItems, displayedItemsCount, toolbar, padding = '5px', isVisible = true, panelID = 'tmpanel', isActive, // Questa prop determinerà la modalità
|
|
107
|
-
onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged }, ref) => {
|
|
212
|
+
const TMPanel = forwardRef(({ allowMaximize = true, color, backgroundColor, backgroundColorContainer, children, showHeader = true, title, enableTitleMarquee = false, totalItems, displayedItemsCount, toolbar, padding = '5px', isVisible = true, panelID = 'tmpanel', isActive, // Questa prop determinerà la modalità
|
|
213
|
+
onRefresh, isRefreshing, onActivate, onBack, backCaption = SDKUI_Localizator.Back, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged }, ref) => {
|
|
108
214
|
const [isMaximized, setIsMaximized] = useState(false);
|
|
215
|
+
const [isRefreshingInternal, setIsRefreshingInternal] = useState(false);
|
|
216
|
+
// Il loader compare sia per il refresh dalla testata sia per i caricamenti segnalati dal contenuto
|
|
217
|
+
const isBusy = isRefreshing || isRefreshingInternal;
|
|
218
|
+
const handleRefresh = useCallback(async () => {
|
|
219
|
+
if (isRefreshingInternal)
|
|
220
|
+
return;
|
|
221
|
+
setIsRefreshingInternal(true);
|
|
222
|
+
// Il finally garantisce che loader e rotellina si fermino anche se il ricaricamento fallisce
|
|
223
|
+
try {
|
|
224
|
+
await onRefresh?.();
|
|
225
|
+
}
|
|
226
|
+
catch (ex) {
|
|
227
|
+
TMExceptionBoxManager.show({ exception: ex });
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
setIsRefreshingInternal(false);
|
|
231
|
+
}
|
|
232
|
+
}, [isRefreshingInternal, onRefresh]);
|
|
109
233
|
// Detect device type (e.g., mobile or desktop)
|
|
110
234
|
const deviceType = useDeviceType();
|
|
111
235
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
@@ -157,6 +281,7 @@ onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged },
|
|
|
157
281
|
handleFocusUncontrolled();
|
|
158
282
|
}
|
|
159
283
|
};
|
|
284
|
+
const titleMarqueeKey = enableTitleMarquee && (typeof title === 'string' || typeof title === 'number') ? String(title) : undefined;
|
|
160
285
|
// handler for external maximize management
|
|
161
286
|
const handleMaximize = () => {
|
|
162
287
|
setIsMaximized(prevState => {
|
|
@@ -188,31 +313,19 @@ onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged },
|
|
|
188
313
|
flexDirection: 'row',
|
|
189
314
|
alignItems: 'center',
|
|
190
315
|
flexShrink: 0
|
|
191
|
-
}, children: _jsxs(StyledBackButton, { "$isActive": currentIsActive, onClick: () => onBack ? onBack() : null, title:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
minWidth: 0,
|
|
197
|
-
overflow: 'hidden',
|
|
198
|
-
padding: '0 8px'
|
|
199
|
-
}, children: _jsxs("div", { style: {
|
|
200
|
-
whiteSpace: 'nowrap',
|
|
201
|
-
overflow: 'hidden',
|
|
202
|
-
textOverflow: 'ellipsis',
|
|
203
|
-
margin: 0
|
|
204
|
-
}, children: [title, isPositiveNumber(displayedItemsCount) && isPositiveNumber(totalItems)
|
|
205
|
-
? ` (${displayedItemsCount} / ${totalItems})`
|
|
206
|
-
: isPositiveNumber(totalItems)
|
|
207
|
-
? ` (${totalItems})`
|
|
208
|
-
: ''] }) }), _jsxs("div", { style: {
|
|
316
|
+
}, children: _jsxs(StyledBackButton, { "$isActive": currentIsActive, onClick: () => onBack ? onBack() : null, title: backCaption, children: [_jsx(IconArrowLeft, {}), !isMobile && _jsx("span", { children: backCaption })] }) }), _jsx(StyledPanelTitleViewport, { children: _jsx(StyledPanelTitleTrack, { "$marquee": enableTitleMarquee, children: _jsxs(StyledPanelTitle, { "$marquee": enableTitleMarquee, children: [title, isPositiveNumber(displayedItemsCount) && isPositiveNumber(totalItems)
|
|
317
|
+
? ` (${displayedItemsCount} / ${totalItems})`
|
|
318
|
+
: isPositiveNumber(totalItems)
|
|
319
|
+
? ` (${totalItems})`
|
|
320
|
+
: ''] }) }, titleMarqueeKey) }), _jsxs("div", { style: {
|
|
209
321
|
display: 'flex',
|
|
210
322
|
flexDirection: 'row',
|
|
211
323
|
alignItems: 'center',
|
|
212
324
|
gap: '5px',
|
|
213
325
|
flexShrink: 0
|
|
214
|
-
}, children: [toolbar, allowMaximize && _jsx(TMButton, { color: 'primaryOutline', caption: isMaximized ? SDKUI_Localizator.Minimize : SDKUI_Localizator.Maximize, icon: isMaximized
|
|
326
|
+
}, children: [toolbar, onRefresh && _jsx(TMButton, { color: 'primaryOutline', caption: SDKUI_Localizator.Refresh, disabled: isBusy, icon: _jsx(StyledRefreshIcon, { "$isSpinning": isBusy, children: _jsx(IconRefresh, {}) }), btnStyle: 'icon', onClick: handleRefresh }), allowMaximize && _jsx(TMButton, { color: 'primaryOutline', caption: isMaximized ? SDKUI_Localizator.Minimize : SDKUI_Localizator.Maximize, icon: isMaximized
|
|
215
327
|
? _jsx(IconWindowMinimize, { fontSize: 16 })
|
|
216
|
-
: _jsx(IconWindowMaximize, { fontSize: 16 }), btnStyle: 'icon', onClick: handleMaximize }), onClose && _jsx(TMButton, { color: 'primaryOutline', caption: SDKUI_Localizator.Close, icon: _jsx(IconClearButton, {}), btnStyle: 'icon', onClick: () => { setIsMaximized(false); onClose?.(); } })] })] }) }),
|
|
328
|
+
: _jsx(IconWindowMaximize, { fontSize: 16 }), btnStyle: 'icon', onClick: handleMaximize }), onClose && _jsx(TMButton, { color: 'primaryOutline', caption: SDKUI_Localizator.Close, icon: _jsx(IconClearButton, {}), btnStyle: 'icon', onClick: () => { setIsMaximized(false); onClose?.(); } })] })] }) }), _jsxs(StyledPanelContent, { "$height": showHeader ? "calc(100% - 40px)" : "100%", "$padding": padding, "$backgroundColor": backgroundColorContainer ?? `#FFFFFF`, children: [children, isBusy &&
|
|
329
|
+
_jsxs(StyledPanelLoaderOverlay, { children: [_jsx(LoadIndicator, { height: 40, width: 40 }), _jsx("div", { children: SDKUI_Localizator.Loading })] })] })] }));
|
|
217
330
|
});
|
|
218
331
|
export default TMPanel;
|
|
@@ -60,6 +60,9 @@ export const sanitizeException = (exception) => {
|
|
|
60
60
|
catch {
|
|
61
61
|
return exception;
|
|
62
62
|
}
|
|
63
|
+
if (plain && typeof plain === 'object' && !Array.isArray(plain) && plain.message === undefined && typeof exception.message === 'string') {
|
|
64
|
+
plain.message = exception.message;
|
|
65
|
+
}
|
|
63
66
|
return redactSensitiveValue(plain);
|
|
64
67
|
};
|
|
65
68
|
const StyledExeptionToolbar = styled.div `
|
|
@@ -9,6 +9,7 @@ interface ITMTooltipProps extends ITooltipOptions {
|
|
|
9
9
|
hideAfterDelay?: boolean;
|
|
10
10
|
parentStyle?: React.CSSProperties;
|
|
11
11
|
childStyle?: React.CSSProperties;
|
|
12
|
+
allowContentInteraction?: boolean;
|
|
12
13
|
}
|
|
13
|
-
declare const TMTooltip: ({ children, position, content, hideAfterDelay, parentStyle, childStyle }: ITMTooltipProps) => React.JSX.Element;
|
|
14
|
+
declare const TMTooltip: ({ children, position, content, hideAfterDelay, parentStyle, childStyle, allowContentInteraction }: ITMTooltipProps) => React.JSX.Element;
|
|
14
15
|
export default TMTooltip;
|
|
@@ -1,20 +1,36 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { Tooltip } from 'devextreme-react/tooltip';
|
|
4
4
|
import { genUniqueId } from '../../helper';
|
|
5
5
|
import { DeviceType, useDeviceType } from './TMDeviceProvider';
|
|
6
|
-
|
|
6
|
+
/** Tempo per spostare il mouse dall'elemento al contenuto del tooltip, quando è interattivo */
|
|
7
|
+
const HIDE_DELAY_MS = 400;
|
|
8
|
+
const TMTooltip = ({ children, position, content, hideAfterDelay, parentStyle, childStyle, allowContentInteraction = false }) => {
|
|
7
9
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
8
|
-
const [id
|
|
9
|
-
|
|
10
|
+
const [id] = useState(() => genUniqueId());
|
|
11
|
+
const hideTimerRef = useRef();
|
|
10
12
|
useEffect(() => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const hide = () => setShowTooltip(false);
|
|
14
|
+
window.addEventListener('click', hide);
|
|
15
|
+
return () => window.removeEventListener('click', hide);
|
|
13
16
|
}, []);
|
|
17
|
+
useEffect(() => { return () => clearTimeout(hideTimerRef.current); }, []);
|
|
14
18
|
const deviceType = useDeviceType();
|
|
15
|
-
|
|
19
|
+
const cancelHide = () => clearTimeout(hideTimerRef.current);
|
|
20
|
+
const show = () => { cancelHide(); setShowTooltip(true); };
|
|
21
|
+
const hide = () => {
|
|
22
|
+
cancelHide();
|
|
23
|
+
if (!allowContentInteraction) {
|
|
24
|
+
setShowTooltip(false);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
hideTimerRef.current = setTimeout(() => setShowTooltip(false), HIDE_DELAY_MS);
|
|
28
|
+
};
|
|
29
|
+
return (_jsxs("div", { style: parentStyle, children: [_jsx("div", { id: `idContainerTooltip${id}`, style: { display: 'flex', alignItems: 'center', height: 'max-content', width: 'max-content', ...childStyle }, onMouseEnter: show, onMouseLeave: hide, onTouchStart: show, onClick: () => { if (deviceType === DeviceType.DESKTOP || !hideAfterDelay)
|
|
16
30
|
return; setTimeout(() => { setShowTooltip(false); }, 1500); }, onTouchEnd: () => { if (deviceType === DeviceType.DESKTOP || !hideAfterDelay)
|
|
17
31
|
return; setTimeout(() => { setShowTooltip(false); }, 1500); }, children: children }), content &&
|
|
18
|
-
_jsx(Tooltip, { target: `#idContainerTooltip${id}`, hideOnOutsideClick: true, visible: showTooltip, position: position ?? 'bottom', onHidden: () => setShowTooltip(false), children:
|
|
32
|
+
_jsx(Tooltip, { target: `#idContainerTooltip${id}`, hideOnOutsideClick: true, visible: showTooltip, position: position ?? 'bottom', onHidden: () => setShowTooltip(false), children: allowContentInteraction
|
|
33
|
+
? _jsx("div", { style: { pointerEvents: 'all' }, onMouseEnter: cancelHide, onMouseLeave: hide, children: content })
|
|
34
|
+
: content })] }));
|
|
19
35
|
};
|
|
20
36
|
export default TMTooltip;
|
|
@@ -31,11 +31,17 @@ interface ITMTreeViewProps {
|
|
|
31
31
|
}
|
|
32
32
|
declare const TMTreeView: ({ dataSource, focusedItem, selectedItems, allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, onItemContextMenu, autoSelectChildren, itemsPerPage, showLoadMoreButton, enableVirtualization }: ITMTreeViewProps) => React.JSX.Element;
|
|
33
33
|
export default TMTreeView;
|
|
34
|
-
export declare const StyledTreeContainer: import("styled-components/dist/types").IStyledComponentBase<"web",
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
export declare const StyledTreeContainer: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
35
|
+
style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
36
|
+
}> & string;
|
|
37
|
+
export declare const StyledItemContent: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
38
|
+
style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
39
|
+
}> & string;
|
|
40
|
+
export declare const StyledTreeNode: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
41
|
+
style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
42
|
+
}, {
|
|
37
43
|
$isSelected?: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
}>> & string;
|
|
45
|
+
export declare const StyledStickyPaginator: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
46
|
+
style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
47
|
+
}> & string;
|