@topconsultnpm/sdkui-react 6.19.0-test.1 → 6.19.0-test2
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/assets/IconsS4t/add.svg +12 -12
- package/lib/assets/IconsS4t/aggiorna.svg +18 -18
- package/lib/assets/IconsS4t/bookmark.svg +42 -42
- package/lib/assets/IconsS4t/cancella.svg +15 -15
- package/lib/assets/IconsS4t/check-box.svg +19 -19
- package/lib/assets/IconsS4t/down-arrow-signBook.svg +40 -40
- package/lib/assets/IconsS4t/down.svg +28 -28
- package/lib/assets/IconsS4t/edit-file.svg +19 -19
- package/lib/assets/IconsS4t/edita.svg +32 -32
- package/lib/assets/IconsS4t/firma.svg +19 -19
- package/lib/assets/IconsS4t/icona_download.svg +16 -16
- package/lib/assets/IconsS4t/info.svg +51 -51
- package/lib/assets/IconsS4t/left.svg +20 -20
- package/lib/assets/IconsS4t/line.svg +40 -40
- package/lib/assets/IconsS4t/more.svg +19 -19
- package/lib/assets/IconsS4t/plus.svg +23 -23
- package/lib/assets/IconsS4t/printer.svg +49 -49
- package/lib/assets/IconsS4t/radio-on-button.svg +25 -25
- package/lib/assets/IconsS4t/rectangle.svg +41 -41
- package/lib/assets/IconsS4t/redo.svg +19 -19
- package/lib/assets/IconsS4t/right-arrow-signBook-finish.svg +40 -40
- package/lib/assets/IconsS4t/right-arrow-signBook.svg +40 -40
- package/lib/assets/IconsS4t/right.svg +22 -22
- package/lib/assets/IconsS4t/searchbar.svg +21 -21
- package/lib/assets/IconsS4t/text-box.svg +36 -36
- package/lib/assets/IconsS4t/tick.svg +8 -8
- package/lib/assets/IconsS4t/trash-white.svg +10 -10
- package/lib/assets/IconsS4t/undo.svg +19 -19
- package/lib/assets/IconsS4t/up.svg +32 -32
- package/lib/assets/IconsS4t/video-streaming.svg +2 -2
- package/lib/assets/IconsS4t/zoom-in.svg +58 -58
- package/lib/assets/IconsS4t/zoom-out.svg +56 -56
- package/lib/assets/icomoon.svg +96 -96
- package/lib/assets/italy.svg +16 -16
- package/lib/assets/six.svg +3 -3
- package/lib/assets/thumbnails/index.ts +39 -39
- package/lib/assets/topmedia-six.svg +65 -65
- package/lib/assets/topmeida-six-bianco.svg +65 -65
- package/lib/components/base/Styled.js +302 -302
- package/lib/components/base/TMAccordion.js +43 -43
- package/lib/components/base/TMAccordionNew.d.ts +28 -0
- package/lib/components/base/TMAccordionNew.js +326 -0
- package/lib/components/base/TMAreaManager.js +23 -23
- package/lib/components/base/TMButton.d.ts +1 -0
- package/lib/components/base/TMButton.js +136 -136
- package/lib/components/base/TMClosableList.js +46 -46
- package/lib/components/base/TMConfirm.js +20 -20
- package/lib/components/base/TMContextMenu.js +4 -4
- package/lib/components/base/TMContextMenuOLD.js +25 -25
- package/lib/components/base/TMCounterBar.js +32 -32
- package/lib/components/base/TMCounterContainer.js +30 -30
- package/lib/components/base/TMCustomButton.d.ts +1 -1
- package/lib/components/base/TMCustomButton.js +90 -35
- package/lib/components/base/TMDataGridExportForm.d.ts +1 -1
- package/lib/components/base/TMDataGridExportForm.js +9 -3
- package/lib/components/base/TMDropDownMenu.js +24 -24
- package/lib/components/base/TMFileManager.js +12 -3
- package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -0
- package/lib/components/base/TMFileManagerDataGridView.js +12 -3
- package/lib/components/base/TMFileManagerThumbnailItems.d.ts +2 -0
- package/lib/components/base/TMFileManagerThumbnailItems.js +12 -2
- package/lib/components/base/TMFileManagerThumbnailsView.d.ts +2 -0
- package/lib/components/base/TMFileManagerThumbnailsView.js +2 -2
- package/lib/components/base/TMFileManagerUtils.js +19 -19
- package/lib/components/base/TMFloatingToolbar.js +34 -34
- package/lib/components/base/TMLayout.js +44 -44
- package/lib/components/base/TMList.js +34 -34
- package/lib/components/base/TMModal.d.ts +2 -0
- package/lib/components/base/TMModal.js +79 -34
- package/lib/components/base/TMPanel.js +57 -57
- package/lib/components/base/TMPopUp.js +186 -117
- package/lib/components/base/TMProgressBar.js +20 -20
- package/lib/components/base/TMResizableMenu.js +28 -28
- package/lib/components/base/TMRightSidebar.js +40 -40
- package/lib/components/base/TMSpinner.js +121 -121
- package/lib/components/base/TMTab.js +11 -11
- package/lib/components/base/TMToggleButton.js +36 -36
- package/lib/components/base/TMToolbarCard.js +35 -35
- package/lib/components/base/TMTooltip.d.ts +1 -1
- package/lib/components/base/TMTooltip.js +1 -1
- package/lib/components/base/TMTreeView.js +16 -16
- package/lib/components/base/TMUserAvatar.js +7 -7
- package/lib/components/base/TMWaitPanel.js +30 -24
- package/lib/components/choosers/TMCultureIDPicker.js +35 -35
- package/lib/components/choosers/TMDataListItemChooser.js +1 -1
- package/lib/components/choosers/TMDataListItemPicker.js +54 -54
- package/lib/components/choosers/TMDcmtTypeChooser.js +2 -2
- package/lib/components/choosers/TMMetadataChooser.d.ts +4 -1
- package/lib/components/choosers/TMMetadataChooser.js +31 -8
- package/lib/components/choosers/TMUserChooser.d.ts +4 -0
- package/lib/components/choosers/TMUserChooser.js +21 -5
- package/lib/components/editors/TMCheckBox.js +24 -24
- package/lib/components/editors/TMDateBox.d.ts +1 -1
- package/lib/components/editors/TMDropDown.js +43 -43
- package/lib/components/editors/TMEditorStyled.js +71 -71
- package/lib/components/editors/TMHtmlContentDisplay.js +16 -16
- package/lib/components/editors/TMLocalizedTextBox.js +31 -31
- package/lib/components/editors/TMMetadataValues.js +62 -21
- package/lib/components/editors/TMRadioButton.js +39 -39
- package/lib/components/editors/TMSummary.js +39 -39
- package/lib/components/editors/TMTextArea.d.ts +1 -0
- package/lib/components/editors/TMTextArea.js +56 -22
- package/lib/components/editors/TMTextBox.js +53 -23
- package/lib/components/editors/TMTextExpression.js +36 -28
- package/lib/components/features/assistant/ToppyDraggableHelpCenter.d.ts +30 -0
- package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +471 -0
- package/lib/components/features/assistant/ToppySpeechBubble.d.ts +9 -0
- package/lib/components/features/assistant/ToppySpeechBubble.js +117 -0
- package/lib/components/features/blog/TMBlogCommentForm.d.ts +2 -0
- package/lib/components/features/blog/TMBlogCommentForm.js +21 -9
- package/lib/components/features/documents/TMDcmtBlog.js +1 -1
- package/lib/components/features/documents/TMDcmtForm.js +321 -62
- package/lib/components/features/documents/TMDcmtIcon.js +17 -12
- package/lib/components/features/documents/TMDcmtPreview.js +75 -38
- package/lib/components/features/documents/TMFileUploader.js +21 -21
- package/lib/components/features/documents/TMRelationViewer.js +56 -23
- package/lib/components/features/search/TMSavedQuerySelector.js +52 -52
- package/lib/components/features/search/TMSearch.js +2 -2
- package/lib/components/features/search/TMSearchQueryEditor.js +14 -14
- package/lib/components/features/search/TMSearchQueryPanel.js +40 -58
- package/lib/components/features/search/TMSearchResult.js +160 -35
- package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +2 -1
- package/lib/components/features/search/TMSearchResultsMenuItems.js +117 -60
- package/lib/components/features/search/TMSignSettingsForm.d.ts +9 -0
- package/lib/components/features/search/TMSignSettingsForm.js +621 -0
- package/lib/components/features/search/TMTreeSelector.js +66 -66
- package/lib/components/features/tasks/TMTaskForm.js +42 -36
- package/lib/components/features/tasks/TMTasksAgenda.js +4 -4
- package/lib/components/features/tasks/TMTasksCalendar.js +2 -2
- package/lib/components/features/tasks/TMTasksHeader.js +1 -1
- package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -1
- package/lib/components/features/tasks/TMTasksUtils.js +18 -3
- package/lib/components/features/tasks/TMTasksUtilsView.js +26 -4
- package/lib/components/features/tasks/TMTasksView.js +12 -6
- package/lib/components/features/wg/TMWGsCopyMoveForm.js +9 -9
- package/lib/components/features/workflow/TMWorkflowPopup.js +44 -44
- package/lib/components/features/workflow/diagram/ConnectionComponent.js +29 -29
- package/lib/components/features/workflow/diagram/ConnectionForm.js +10 -10
- package/lib/components/features/workflow/diagram/DiagramItemComponent.js +57 -57
- package/lib/components/features/workflow/diagram/DiagramItemForm.js +40 -35
- package/lib/components/features/workflow/diagram/DiagramItemSvgContent.js +12 -12
- package/lib/components/features/workflow/diagram/RecipientList.js +39 -39
- package/lib/components/features/workflow/diagram/WFDiagram.js +317 -285
- package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.js +4 -4
- package/lib/components/forms/Login/Chooser.js +35 -35
- package/lib/components/forms/Login/Menu.js +22 -22
- package/lib/components/forms/Login/SelectBox.js +46 -46
- package/lib/components/forms/Login/TMLoginForm.js +14 -14
- package/lib/components/forms/Login/TextBox.js +57 -57
- package/lib/components/forms/TMResultDialog.js +8 -2
- package/lib/components/forms/TMSaveForm.js +3 -11
- package/lib/components/grids/TMBlogAttachments.d.ts +0 -14
- package/lib/components/grids/TMBlogAttachments.js +10 -5
- package/lib/components/grids/TMBlogsPost.d.ts +8 -3
- package/lib/components/grids/TMBlogsPost.js +100 -39
- package/lib/components/grids/TMBlogsPostUtils.d.ts +1 -0
- package/lib/components/grids/TMBlogsPostUtils.js +32 -11
- package/lib/components/grids/TMRecentsManager.js +51 -51
- package/lib/components/grids/TMValidationItemsList.js +48 -48
- package/lib/components/index.d.ts +2 -1
- package/lib/components/index.js +2 -1
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +14 -14
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +0 -1
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +36 -35
- package/lib/components/layout/panelManager/types.d.ts +1 -0
- package/lib/components/pages/TMPage.js +1 -1
- package/lib/components/query/TMQueryEditor.js +17 -17
- package/lib/components/query/TMQuerySummary.d.ts +1 -0
- package/lib/components/query/TMQuerySummary.js +15 -15
- package/lib/components/settings/SettingsAppearance.js +9 -1
- package/lib/components/sidebar/TMCommandsPanel.js +10 -10
- package/lib/components/sidebar/TMHeader.js +307 -307
- package/lib/components/sidebar/TMSidebar.js +24 -24
- package/lib/components/sidebar/TMSidebarItem.js +21 -21
- package/lib/components/viewers/TMDataListItemViewer.d.ts +1 -1
- package/lib/components/viewers/TMMidViewer.d.ts +1 -1
- package/lib/components/viewers/TMTidViewer.d.ts +1 -1
- package/lib/components/wizard/TMStepIndicator.js +102 -102
- package/lib/components/wizard/TMWizard.js +29 -29
- package/lib/helper/GlobalStyles.d.ts +2 -0
- package/lib/helper/GlobalStyles.js +10 -0
- package/lib/helper/Globalization.d.ts +1 -0
- package/lib/helper/Globalization.js +30 -0
- package/lib/helper/SDKUI_Globals.d.ts +2 -0
- package/lib/helper/SDKUI_Globals.js +9 -1
- package/lib/helper/SDKUI_Localizator.d.ts +50 -2
- package/lib/helper/SDKUI_Localizator.js +502 -22
- package/lib/helper/TMCustomSearchBar.js +1 -1
- package/lib/helper/TMIcons.d.ts +4 -1
- package/lib/helper/TMIcons.js +14 -2
- package/lib/helper/TMToppyMessage.d.ts +1 -0
- package/lib/helper/TMToppyMessage.js +33 -32
- package/lib/helper/TMUtils.d.ts +42 -4
- package/lib/helper/TMUtils.js +227 -60
- package/lib/helper/dcmtsHelper.d.ts +2 -1
- package/lib/helper/dcmtsHelper.js +56 -17
- package/lib/helper/helpers.d.ts +1 -1
- package/lib/helper/helpers.js +12 -17
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/hooks/useDcmtOperations.d.ts +1 -1
- package/lib/hooks/useDcmtOperations.js +10 -6
- package/lib/hooks/useRelatedDocuments.js +35 -26
- package/lib/ts/types.d.ts +3 -1
- package/package.json +54 -54
- package/lib/components/features/assistant/ToppyHelpCenter.d.ts +0 -12
- package/lib/components/features/assistant/ToppyHelpCenter.js +0 -173
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useEffect } from 'react';
|
|
3
|
+
import ReactDOM from 'react-dom';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
import Toppy from '../../../assets/Toppy-generico.png';
|
|
6
|
+
import { DeviceType } from '../../base/TMDeviceProvider';
|
|
7
|
+
import ToppySpeechBubble from './ToppySpeechBubble';
|
|
8
|
+
import { SDKUI_Localizator } from '../../../helper';
|
|
9
|
+
import { IconWindowMaximize } from '../../../helper/TMIcons';
|
|
10
|
+
/**
|
|
11
|
+
* Styled component per il contenitore di Toppy
|
|
12
|
+
* Gestisce il posizionamento, le dimensioni e le animazioni
|
|
13
|
+
*/
|
|
14
|
+
const ToppyButton = styled.div.attrs((props) => ({
|
|
15
|
+
style: {
|
|
16
|
+
// Applica left/top come stili inline per evitare la generazione di troppe classi CSS
|
|
17
|
+
...(props.$x !== undefined && props.$y !== undefined
|
|
18
|
+
? {
|
|
19
|
+
left: `${props.$x}px`,
|
|
20
|
+
top: `${props.$y}px`,
|
|
21
|
+
bottom: 'auto',
|
|
22
|
+
right: 'auto',
|
|
23
|
+
}
|
|
24
|
+
: {}),
|
|
25
|
+
// Cursore applicato come stile inline
|
|
26
|
+
cursor: props.$isDragging ? 'grabbing' : 'grab',
|
|
27
|
+
},
|
|
28
|
+
})) `
|
|
29
|
+
/* Visibilità controllata dalla prop */
|
|
30
|
+
display: ${(props) => (props.$isVisible ? 'flex' : 'none')};
|
|
31
|
+
position: ${(props) => props.$usePortal ? 'fixed' : 'absolute'};
|
|
32
|
+
|
|
33
|
+
/* Posizionamento di default quando non è draggato (x e y non sono definiti) */
|
|
34
|
+
${(props) => props.$x === undefined || props.$y === undefined
|
|
35
|
+
? `
|
|
36
|
+
bottom: ${props.$isMobile ? '0px' : '-20px'};
|
|
37
|
+
${props.$align === 'left' ? 'left: 10px;' : 'right: 10px;'};
|
|
38
|
+
`
|
|
39
|
+
: ''}
|
|
40
|
+
|
|
41
|
+
/* Z-index alto per assicurare che sia sempre in primo piano */
|
|
42
|
+
z-index: 2147483647;
|
|
43
|
+
background-color: transparent;
|
|
44
|
+
border: none;
|
|
45
|
+
padding: 0;
|
|
46
|
+
outline: none;
|
|
47
|
+
|
|
48
|
+
/* Dimensioni dinamiche in base allo stato collassato e al tipo di dispositivo
|
|
49
|
+
Usa min() per adattarsi su schermi piccoli */
|
|
50
|
+
width: ${(props) => {
|
|
51
|
+
if (props.$isMobile) {
|
|
52
|
+
return props.$isCollapsed ? 'min(40px, 100%)' : '80px';
|
|
53
|
+
}
|
|
54
|
+
return props.$isCollapsed ? 'min(60px, 100%)' : '120px';
|
|
55
|
+
}};
|
|
56
|
+
height: ${(props) => {
|
|
57
|
+
if (props.$isMobile) {
|
|
58
|
+
return props.$isCollapsed ? 'min(45px, 100%)' : '95px';
|
|
59
|
+
}
|
|
60
|
+
return props.$isCollapsed ? 'min(70px, 100%)' : '140px';
|
|
61
|
+
}};
|
|
62
|
+
max-width: 100%;
|
|
63
|
+
max-height: 100%;
|
|
64
|
+
|
|
65
|
+
user-select: none;
|
|
66
|
+
|
|
67
|
+
img {
|
|
68
|
+
/* Dimensioni dell'immagine in base allo stato collassato e al tipo di dispositivo */
|
|
69
|
+
width: ${(props) => {
|
|
70
|
+
if (props.$isMobile) {
|
|
71
|
+
return props.$isCollapsed ? '40px' : '80px';
|
|
72
|
+
}
|
|
73
|
+
return props.$isCollapsed ? '60px' : '120px';
|
|
74
|
+
}};
|
|
75
|
+
height: ${(props) => {
|
|
76
|
+
if (props.$isMobile) {
|
|
77
|
+
return props.$isCollapsed ? '40px' : '95px';
|
|
78
|
+
}
|
|
79
|
+
return props.$isCollapsed ? '60px' : '140px';
|
|
80
|
+
}};
|
|
81
|
+
pointer-events: ${(props) => (props.$isMobile ? 'auto' : 'none')};
|
|
82
|
+
border-radius: 50%; /* Rende l'immagine circolare */
|
|
83
|
+
/* Rotazione leggera in base all'allineamento */
|
|
84
|
+
transform: ${(props) => props.$isCollapsed
|
|
85
|
+
? 'rotate(0deg)'
|
|
86
|
+
: props.$align === 'left' ? 'rotate(20deg)' : 'rotate(-20deg)'};
|
|
87
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
88
|
+
|
|
89
|
+
/* Animazione di pulsazione quando è collassato per attirare l'attenzione */
|
|
90
|
+
${(props) => props.$isCollapsed && `animation: toppyPulse 1.5s infinite;`}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Keyframes per l'animazione di pulsazione */
|
|
94
|
+
@keyframes toppyPulse {
|
|
95
|
+
0% {
|
|
96
|
+
/* Dimensione normale all'inizio */
|
|
97
|
+
transform: scale(1) rotate(0deg);
|
|
98
|
+
box-shadow: 0 0 0 rgba(0, 113, 188, 0.5);
|
|
99
|
+
}
|
|
100
|
+
50% {
|
|
101
|
+
/* Ingrandimento e glow al 50% dell'animazione */
|
|
102
|
+
transform: scale(1.1) rotate(0deg);
|
|
103
|
+
box-shadow: 0 0 15px 5px rgba(0, 113, 188, 0.6);
|
|
104
|
+
}
|
|
105
|
+
100% {
|
|
106
|
+
/* Ritorno alla dimensione normale */
|
|
107
|
+
transform: scale(1) rotate(0deg);
|
|
108
|
+
box-shadow: 0 0 0 rgba(0, 113, 188, 0.5);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
112
|
+
/**
|
|
113
|
+
* Pulsante di espansione quando Toppy è minimizzato
|
|
114
|
+
*/
|
|
115
|
+
const ExpandButton = styled.button `
|
|
116
|
+
position: absolute;
|
|
117
|
+
top: -8px;
|
|
118
|
+
right: -8px;
|
|
119
|
+
width: 24px;
|
|
120
|
+
height: 24px;
|
|
121
|
+
border-radius: 50%;
|
|
122
|
+
border: 2px solid rgba(255, 255, 255, 0.9);
|
|
123
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
124
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 20px rgba(118, 75, 162, 0.2);
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
130
|
+
z-index: 10001;
|
|
131
|
+
color: white;
|
|
132
|
+
font-size: 14px;
|
|
133
|
+
|
|
134
|
+
&:hover {
|
|
135
|
+
background: linear-gradient(135deg, #764ba2 0%, #f093fb 100%);
|
|
136
|
+
box-shadow: 0 6px 20px rgba(118, 75, 162, 0.6), 0 0 30px rgba(240, 147, 251, 0.4);
|
|
137
|
+
border-color: rgba(255, 255, 255, 1);
|
|
138
|
+
transform: scale(1.1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&:active {
|
|
142
|
+
transform: scale(0.95);
|
|
143
|
+
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
&:focus {
|
|
147
|
+
outline: none;
|
|
148
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 0 3px rgba(102, 126, 234, 0.2);
|
|
149
|
+
}
|
|
150
|
+
`;
|
|
151
|
+
/**
|
|
152
|
+
* Overlay trasparente per bloccare le interazioni durante il drag
|
|
153
|
+
* Previene problemi di performance con iframe e altri elementi interattivi
|
|
154
|
+
*/
|
|
155
|
+
const DragOverlay = styled.div `
|
|
156
|
+
position: fixed;
|
|
157
|
+
top: 0;
|
|
158
|
+
left: 0;
|
|
159
|
+
right: 0;
|
|
160
|
+
bottom: 0;
|
|
161
|
+
z-index: 2147483646;
|
|
162
|
+
cursor: grabbing;
|
|
163
|
+
`;
|
|
164
|
+
/**
|
|
165
|
+
* Componente ToppyDraggableHelpCenter
|
|
166
|
+
*
|
|
167
|
+
* Renderizza un assistente virtuale (Toppy) draggable che può mostrare contenuti
|
|
168
|
+
* in una speech bubble. Il componente può essere trascinato all'interno del suo
|
|
169
|
+
* contenitore e può essere collassato/espanso con un doppio click.
|
|
170
|
+
*/
|
|
171
|
+
const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onToppyImageClick, initialIsCollapsed, isVisible = true, usePortal = false, }) => {
|
|
172
|
+
// Ref per il contenitore principale
|
|
173
|
+
const buttonRef = useRef(null);
|
|
174
|
+
// Stato per controllare se il componente è collassato o espanso
|
|
175
|
+
const [isCollapsed, setIsCollapsed] = useState(initialIsCollapsed ?? false);
|
|
176
|
+
// Stato per tracciare se il componente è in fase di trascinamento
|
|
177
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
178
|
+
// Posizione corrente del componente (null = posizione di default)
|
|
179
|
+
const [position, setPosition] = useState(null);
|
|
180
|
+
// Offset del mouse rispetto all'angolo superiore sinistro del componente durante il drag
|
|
181
|
+
const dragOffset = useRef({ x: 0, y: 0 });
|
|
182
|
+
// Ref e stato per tracciare le dimensioni della speech bubble
|
|
183
|
+
const bubbleRef = useRef(null);
|
|
184
|
+
const [bubbleSize, setBubbleSize] = useState({ width: 0, height: 0 });
|
|
185
|
+
// Ref per tracciare il dragging dell'ExpandButton
|
|
186
|
+
const isExpandButtonDraggingRef = useRef(false);
|
|
187
|
+
const expandButtonMouseDownPosRef = useRef(null);
|
|
188
|
+
const isMobile = deviceType === DeviceType.MOBILE;
|
|
189
|
+
/**
|
|
190
|
+
* Effect per aggiornare le dimensioni della bubble quando cambia il contenuto
|
|
191
|
+
* o lo stato di collassamento. Necessario per calcolare correttamente i limiti
|
|
192
|
+
* di trascinamento.
|
|
193
|
+
*/
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (bubbleRef.current) {
|
|
196
|
+
const rect = bubbleRef.current.getBoundingClientRect();
|
|
197
|
+
setBubbleSize({ width: rect.width, height: rect.height });
|
|
198
|
+
}
|
|
199
|
+
}, [content, isCollapsed]);
|
|
200
|
+
/**
|
|
201
|
+
* Effect per verificare e aggiustare la posizione quando cambia lo stato di collassamento
|
|
202
|
+
*/
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
if (!buttonRef.current || !position)
|
|
205
|
+
return;
|
|
206
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
207
|
+
// Spazio extra occupato dalla bubble quando non è collassato
|
|
208
|
+
// Include anche l'offset dei bottoni che sporgono dalla bubble (8px)
|
|
209
|
+
const closeButtonOffset = 8;
|
|
210
|
+
const extraHeight = !isCollapsed ? bubbleSize.height + closeButtonOffset : 0;
|
|
211
|
+
const extraWidth = !isCollapsed ? bubbleSize.width + closeButtonOffset : 0;
|
|
212
|
+
let minX = 0;
|
|
213
|
+
let maxX;
|
|
214
|
+
let maxY;
|
|
215
|
+
const bubbleBuffer = 5;
|
|
216
|
+
const buttonOffset = 8; // Spazio extra per i bottoni posizionati a -8px
|
|
217
|
+
const minY = buttonOffset; // Limite minimo per evitare che i bottoni superiori escano
|
|
218
|
+
if (usePortal) {
|
|
219
|
+
// Calcola i limiti usando le dimensioni del viewport
|
|
220
|
+
maxX = window.innerWidth - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
|
|
221
|
+
maxY = window.innerHeight - rect.height + 20;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
// Calcola i limiti usando le dimensioni del parent
|
|
225
|
+
const parent = buttonRef.current.offsetParent;
|
|
226
|
+
if (!parent)
|
|
227
|
+
return;
|
|
228
|
+
const parentRect = parent.getBoundingClientRect();
|
|
229
|
+
maxX = parentRect.width - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
|
|
230
|
+
maxY = parentRect.height - rect.height + 20;
|
|
231
|
+
}
|
|
232
|
+
if (!isCollapsed) {
|
|
233
|
+
if (align === 'right') {
|
|
234
|
+
minX = Math.max(0, extraWidth - rect.width);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
maxX = Math.min(maxX, (usePortal ? window.innerWidth : buttonRef.current.offsetParent?.getBoundingClientRect().width || 0) - extraWidth);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Verifica se la posizione corrente è fuori dai limiti
|
|
241
|
+
const isOutOfBounds = position.x < minX ||
|
|
242
|
+
position.x > maxX ||
|
|
243
|
+
position.y < Math.max(minY, extraHeight + bubbleBuffer) ||
|
|
244
|
+
position.y > maxY;
|
|
245
|
+
// Se è fuori dai limiti, aggiusta la posizione
|
|
246
|
+
if (isOutOfBounds) {
|
|
247
|
+
const adjustedX = Math.max(minX, Math.min(position.x, maxX));
|
|
248
|
+
const adjustedY = Math.max(Math.max(minY, extraHeight + bubbleBuffer), Math.min(position.y, maxY));
|
|
249
|
+
setPosition({ x: adjustedX, y: adjustedY });
|
|
250
|
+
}
|
|
251
|
+
}, [isCollapsed, bubbleSize, usePortal, align]);
|
|
252
|
+
/**
|
|
253
|
+
* Effect per resettare la posizione quando il parent o la finestra vengono ridimensionati
|
|
254
|
+
*/
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (!buttonRef.current || !position)
|
|
257
|
+
return;
|
|
258
|
+
const handleResize = () => {
|
|
259
|
+
if (!buttonRef.current || !position)
|
|
260
|
+
return;
|
|
261
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
262
|
+
// Include anche l'offset dei bottoni che sporgono dalla bubble (8px)
|
|
263
|
+
const closeButtonOffset = 8;
|
|
264
|
+
const extraHeight = !isCollapsed ? bubbleSize.height + closeButtonOffset : 0;
|
|
265
|
+
const extraWidth = !isCollapsed ? bubbleSize.width + closeButtonOffset : 0;
|
|
266
|
+
let minX = 0;
|
|
267
|
+
let maxX;
|
|
268
|
+
let maxY;
|
|
269
|
+
const bubbleBuffer = 5;
|
|
270
|
+
const buttonOffset = 8; // Spazio extra per i bottoni posizionati a -8px
|
|
271
|
+
const minY = buttonOffset; // Limite minimo per evitare che i bottoni superiori escano
|
|
272
|
+
if (usePortal) {
|
|
273
|
+
maxX = window.innerWidth - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
|
|
274
|
+
maxY = window.innerHeight - rect.height + 20;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const parent = buttonRef.current.offsetParent;
|
|
278
|
+
if (!parent)
|
|
279
|
+
return;
|
|
280
|
+
const parentRect = parent.getBoundingClientRect();
|
|
281
|
+
maxX = parentRect.width - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
|
|
282
|
+
maxY = parentRect.height - rect.height + 20;
|
|
283
|
+
}
|
|
284
|
+
if (!isCollapsed) {
|
|
285
|
+
if (align === 'right') {
|
|
286
|
+
minX = Math.max(0, extraWidth - rect.width);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
maxX = Math.min(maxX, (usePortal ? window.innerWidth : buttonRef.current.offsetParent?.getBoundingClientRect().width || 0) - extraWidth);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const isOutOfBounds = position.x < minX ||
|
|
293
|
+
position.x > maxX ||
|
|
294
|
+
position.y < Math.max(minY, extraHeight + bubbleBuffer) ||
|
|
295
|
+
position.y > maxY;
|
|
296
|
+
if (isOutOfBounds) {
|
|
297
|
+
setPosition(null);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
// Observer per il parent se non usa Portal
|
|
301
|
+
let resizeObserver;
|
|
302
|
+
if (!usePortal) {
|
|
303
|
+
const parent = buttonRef.current.offsetParent;
|
|
304
|
+
if (parent) {
|
|
305
|
+
resizeObserver = new ResizeObserver(handleResize);
|
|
306
|
+
resizeObserver.observe(parent);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
window.addEventListener('resize', handleResize);
|
|
310
|
+
return () => {
|
|
311
|
+
resizeObserver?.disconnect();
|
|
312
|
+
window.removeEventListener('resize', handleResize);
|
|
313
|
+
};
|
|
314
|
+
}, [position, isCollapsed, bubbleSize, align, usePortal]);
|
|
315
|
+
/**
|
|
316
|
+
* Effect per impostare automaticamente lo stato collassato su dispositivi mobile
|
|
317
|
+
* se non è stato specificato un valore iniziale.
|
|
318
|
+
*/
|
|
319
|
+
useEffect(() => {
|
|
320
|
+
if (initialIsCollapsed === undefined && deviceType === DeviceType.MOBILE) {
|
|
321
|
+
setIsCollapsed(true);
|
|
322
|
+
}
|
|
323
|
+
}, [deviceType, initialIsCollapsed]);
|
|
324
|
+
/**
|
|
325
|
+
* Gestisce il toggle dello stato collassato/espanso
|
|
326
|
+
* Chiamato dal doppio click sul componente
|
|
327
|
+
*/
|
|
328
|
+
const toggleCollapse = (e) => {
|
|
329
|
+
e?.stopPropagation();
|
|
330
|
+
setIsCollapsed(!isCollapsed);
|
|
331
|
+
onToppyImageClick?.();
|
|
332
|
+
};
|
|
333
|
+
/**
|
|
334
|
+
* Gestisce l'inizio del trascinamento
|
|
335
|
+
* Salva la posizione relativa del mouse rispetto al componente (offset)
|
|
336
|
+
* per mantenere il punto di presa durante il trascinamento
|
|
337
|
+
*/
|
|
338
|
+
const handleMouseDown = (e) => {
|
|
339
|
+
if (!buttonRef.current)
|
|
340
|
+
return;
|
|
341
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
342
|
+
// Calcola l'offset tra il punto di click e l'angolo superiore sinistro del componente
|
|
343
|
+
dragOffset.current = {
|
|
344
|
+
x: e.clientX - rect.left,
|
|
345
|
+
y: e.clientY - rect.top,
|
|
346
|
+
};
|
|
347
|
+
setIsDragging(true);
|
|
348
|
+
e.preventDefault();
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* Gestisce il movimento durante il trascinamento
|
|
352
|
+
* Calcola la nuova posizione rispettando i limiti del parent o viewport
|
|
353
|
+
* e tenendo conto delle dimensioni della speech bubble quando espansa
|
|
354
|
+
*/
|
|
355
|
+
const handleMouseMove = (e) => {
|
|
356
|
+
if (!isDragging || !buttonRef.current)
|
|
357
|
+
return;
|
|
358
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
359
|
+
// Spazio extra occupato dalla bubble quando non è collassato
|
|
360
|
+
// Include anche l'offset dei bottoni che sporgono dalla bubble (8px)
|
|
361
|
+
const closeButtonOffset = 8;
|
|
362
|
+
const extraHeight = !isCollapsed ? bubbleSize.height + closeButtonOffset : 0;
|
|
363
|
+
const extraWidth = !isCollapsed ? bubbleSize.width + closeButtonOffset : 0;
|
|
364
|
+
let minX = 0;
|
|
365
|
+
let maxX;
|
|
366
|
+
let maxY;
|
|
367
|
+
let newX;
|
|
368
|
+
let newY;
|
|
369
|
+
const bubbleBuffer = 5;
|
|
370
|
+
const buttonOffset = 8; // Spazio extra per i bottoni posizionati a -8px
|
|
371
|
+
const minY = buttonOffset; // Limite minimo per evitare che i bottoni superiori escano
|
|
372
|
+
if (usePortal) {
|
|
373
|
+
// Calcola i limiti usando il viewport
|
|
374
|
+
maxX = window.innerWidth - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
|
|
375
|
+
maxY = window.innerHeight - rect.height + 20;
|
|
376
|
+
if (!isCollapsed) {
|
|
377
|
+
if (align === 'right') {
|
|
378
|
+
minX = Math.max(0, extraWidth - rect.width);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
maxX = Math.min(maxX, window.innerWidth - extraWidth);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
newX = Math.max(minX, Math.min(e.clientX - dragOffset.current.x, maxX));
|
|
385
|
+
newY = Math.max(Math.max(minY, extraHeight + bubbleBuffer), Math.min(e.clientY - dragOffset.current.y, maxY));
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
// Calcola i limiti usando il parent
|
|
389
|
+
const parent = buttonRef.current.offsetParent;
|
|
390
|
+
if (!parent)
|
|
391
|
+
return;
|
|
392
|
+
const parentRect = parent.getBoundingClientRect();
|
|
393
|
+
maxX = parentRect.width - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
|
|
394
|
+
maxY = parentRect.height - rect.height + 20;
|
|
395
|
+
if (!isCollapsed) {
|
|
396
|
+
if (align === 'right') {
|
|
397
|
+
minX = Math.max(0, extraWidth - rect.width);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
maxX = Math.min(maxX, parentRect.width - extraWidth);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
newX = Math.max(minX, Math.min(e.clientX - parentRect.left - dragOffset.current.x, maxX));
|
|
404
|
+
newY = Math.max(Math.max(minY, extraHeight + bubbleBuffer), Math.min(e.clientY - parentRect.top - dragOffset.current.y, maxY));
|
|
405
|
+
}
|
|
406
|
+
setPosition({ x: newX, y: newY });
|
|
407
|
+
};
|
|
408
|
+
/**
|
|
409
|
+
* Gestisce il rilascio del mouse alla fine del trascinamento
|
|
410
|
+
* Se il movimento è stato minimo (< 5px), viene interpretato come un click
|
|
411
|
+
* e viene chiamato il callback onToppyImageClick
|
|
412
|
+
*/
|
|
413
|
+
const handleMouseUp = (e) => {
|
|
414
|
+
if (isDragging) {
|
|
415
|
+
setIsDragging(false);
|
|
416
|
+
const rect = buttonRef.current?.getBoundingClientRect();
|
|
417
|
+
if (rect) {
|
|
418
|
+
// Calcola la distanza totale del movimento usando il teorema di Pitagora
|
|
419
|
+
const moveDistance = Math.hypot(e.clientX - (rect.left + dragOffset.current.x), e.clientY - (rect.top + dragOffset.current.y));
|
|
420
|
+
// Se il movimento è stato minimo, trattalo come un click
|
|
421
|
+
if (moveDistance < 5 && onToppyImageClick) {
|
|
422
|
+
onToppyImageClick();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* Effect per gestire gli event listener durante il trascinamento
|
|
429
|
+
* Gli eventi sono registrati sul document per catturare il movimento
|
|
430
|
+
* anche quando il mouse esce dal componente
|
|
431
|
+
*/
|
|
432
|
+
useEffect(() => {
|
|
433
|
+
if (isDragging) {
|
|
434
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
435
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
436
|
+
return () => {
|
|
437
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
438
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
return undefined;
|
|
442
|
+
}, [isDragging]);
|
|
443
|
+
// Renderizza l'overlay solo durante il drag
|
|
444
|
+
const renderDragOverlay = isDragging && _jsx(DragOverlay, {});
|
|
445
|
+
const toppyContent = (_jsxs(_Fragment, { children: [renderDragOverlay, _jsxs(ToppyButton, { ref: buttonRef, "$align": align, "$isDragging": isDragging, "$x": position?.x, "$y": position?.y, "$isVisible": isVisible, "$isCollapsed": isCollapsed, "$isMobile": isMobile, "$usePortal": usePortal, onMouseDown: !isMobile ? handleMouseDown : undefined, onContextMenu: (e) => e.preventDefault(), onDoubleClick: !isMobile ? toggleCollapse : undefined, children: [(content && !isCollapsed) && (_jsx(ToppySpeechBubble, { ref: bubbleRef, align: align, onClose: toggleCollapse, children: content })), (content && isCollapsed) && (_jsx(ExpandButton, { onMouseDown: (e) => {
|
|
446
|
+
isExpandButtonDraggingRef.current = false;
|
|
447
|
+
expandButtonMouseDownPosRef.current = { x: e.clientX, y: e.clientY };
|
|
448
|
+
}, onMouseMove: (e) => {
|
|
449
|
+
if (!expandButtonMouseDownPosRef.current)
|
|
450
|
+
return;
|
|
451
|
+
const deltaX = Math.abs(e.clientX - expandButtonMouseDownPosRef.current.x);
|
|
452
|
+
const deltaY = Math.abs(e.clientY - expandButtonMouseDownPosRef.current.y);
|
|
453
|
+
// Considera drag solo se il movimento supera 3px
|
|
454
|
+
if (deltaX > 3 || deltaY > 3) {
|
|
455
|
+
isExpandButtonDraggingRef.current = true;
|
|
456
|
+
}
|
|
457
|
+
}, onMouseUp: () => {
|
|
458
|
+
expandButtonMouseDownPosRef.current = null;
|
|
459
|
+
}, onClick: (e) => {
|
|
460
|
+
if (isExpandButtonDraggingRef.current) {
|
|
461
|
+
e.stopPropagation();
|
|
462
|
+
e.preventDefault();
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
e.stopPropagation();
|
|
466
|
+
toggleCollapse(e);
|
|
467
|
+
}, onContextMenu: (e) => e.preventDefault(), "aria-label": SDKUI_Localizator.Maximize, title: SDKUI_Localizator.Maximize, type: "button", children: _jsx(IconWindowMaximize, {}) })), _jsx("img", { src: Toppy, alt: "Toppy Help", draggable: false, onClick: isMobile ? toggleCollapse : undefined })] })] }));
|
|
468
|
+
// Renderizza nel document.body usando un Portal se usePortal è true, altrimenti renderizza normalmente
|
|
469
|
+
return usePortal ? ReactDOM.createPortal(toppyContent, document.body) : toppyContent;
|
|
470
|
+
};
|
|
471
|
+
export default ToppyDraggableHelpCenter;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ToppySpeechBubbleProps {
|
|
3
|
+
align?: 'left' | 'right';
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
onClose?: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare const ToppySpeechBubble: React.ForwardRefExoticComponent<ToppySpeechBubbleProps & React.RefAttributes<HTMLDivElement>>;
|
|
9
|
+
export default ToppySpeechBubble;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { SDKUI_Localizator } from '../../../helper';
|
|
5
|
+
import { IconWindowMinimize } from '../../../helper/TMIcons';
|
|
6
|
+
// Styled component
|
|
7
|
+
const Bubble = styled.div `
|
|
8
|
+
position: absolute;
|
|
9
|
+
bottom: 145px;
|
|
10
|
+
${({ $align }) => ($align === 'left' ? 'left: 0px;' : 'right: 0px;')}
|
|
11
|
+
width: max-content;
|
|
12
|
+
padding: 10px;
|
|
13
|
+
background: linear-gradient(180deg, rgba(0, 113, 188, 0.45) 0%,rgba(27, 20, 100, 0.65) 100%);
|
|
14
|
+
border-radius: 18px;
|
|
15
|
+
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.18);
|
|
16
|
+
font-size: 14px;
|
|
17
|
+
line-height: 1.4;
|
|
18
|
+
color: #333;
|
|
19
|
+
z-index: 10000;
|
|
20
|
+
|
|
21
|
+
&::after {
|
|
22
|
+
transform: ${({ $align }) => ($align === 'left' ? 'skewX(15deg)' : 'skewX(-15deg)')};
|
|
23
|
+
content: "";
|
|
24
|
+
position: absolute;
|
|
25
|
+
top: 100%;
|
|
26
|
+
${({ $align }) => ($align === 'left' ? 'left: 20px;' : 'right: 15px;')}
|
|
27
|
+
border-width: 32px 32px 0 0;
|
|
28
|
+
border-style: solid;
|
|
29
|
+
border-color: #FFFFFF transparent;
|
|
30
|
+
display: block;
|
|
31
|
+
width: 0;
|
|
32
|
+
height: 0;
|
|
33
|
+
z-index: 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&::before {
|
|
37
|
+
transform: ${({ $align }) => ($align === 'left' ? 'skewX(15deg)' : 'skewX(-15deg)')};
|
|
38
|
+
content: "";
|
|
39
|
+
position: absolute;
|
|
40
|
+
top: 100%;
|
|
41
|
+
${({ $align }) => ($align === 'left' ? 'left: 20px;' : 'right: 15px;')}
|
|
42
|
+
border-width: 32px 32px 0 0;
|
|
43
|
+
border-style: solid;
|
|
44
|
+
border-color: rgba(27, 20, 100, 0.65) transparent;
|
|
45
|
+
display: block;
|
|
46
|
+
width: 0;
|
|
47
|
+
height: 0;
|
|
48
|
+
z-index: 2;
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
const CloseButton = styled.button `
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: -8px;
|
|
54
|
+
right: -8px;
|
|
55
|
+
width: 24px;
|
|
56
|
+
height: 24px;
|
|
57
|
+
border-radius: 50%;
|
|
58
|
+
border: 2px solid rgba(255, 255, 255, 0.9);
|
|
59
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
60
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 20px rgba(118, 75, 162, 0.2);
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
66
|
+
z-index: 10001;
|
|
67
|
+
color: white;
|
|
68
|
+
font-size: 14px;
|
|
69
|
+
|
|
70
|
+
&:hover {
|
|
71
|
+
background: linear-gradient(135deg, #764ba2 0%, #f093fb 100%);
|
|
72
|
+
box-shadow: 0 6px 20px rgba(118, 75, 162, 0.6), 0 0 30px rgba(240, 147, 251, 0.4);
|
|
73
|
+
border-color: rgba(255, 255, 255, 1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&:active {
|
|
77
|
+
transform: scale(0.95);
|
|
78
|
+
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&:focus {
|
|
82
|
+
outline: none;
|
|
83
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4), 0 0 0 3px rgba(102, 126, 234, 0.2);
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
// Componente con forwardRef
|
|
87
|
+
const ToppySpeechBubble = forwardRef(({ align = 'right', children, className, onClose }, ref) => {
|
|
88
|
+
const isDraggingRef = React.useRef(false);
|
|
89
|
+
const mouseDownPosRef = React.useRef(null);
|
|
90
|
+
const handleMouseDown = (e) => {
|
|
91
|
+
isDraggingRef.current = false;
|
|
92
|
+
mouseDownPosRef.current = { x: e.clientX, y: e.clientY };
|
|
93
|
+
};
|
|
94
|
+
const handleMouseMove = (e) => {
|
|
95
|
+
if (!mouseDownPosRef.current)
|
|
96
|
+
return;
|
|
97
|
+
const deltaX = Math.abs(e.clientX - mouseDownPosRef.current.x);
|
|
98
|
+
const deltaY = Math.abs(e.clientY - mouseDownPosRef.current.y);
|
|
99
|
+
// Considera drag solo se il movimento supera 3px
|
|
100
|
+
if (deltaX > 3 || deltaY > 3) {
|
|
101
|
+
isDraggingRef.current = true;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const handleClick = (e) => {
|
|
105
|
+
if (isDraggingRef.current) {
|
|
106
|
+
e.stopPropagation();
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
onClose?.();
|
|
111
|
+
};
|
|
112
|
+
const handleMouseUp = () => {
|
|
113
|
+
mouseDownPosRef.current = null;
|
|
114
|
+
};
|
|
115
|
+
return (_jsxs(Bubble, { ref: ref, "$align": align, className: className, children: [onClose && (_jsx(CloseButton, { onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onClick: handleClick, "aria-label": SDKUI_Localizator.Minimize, title: SDKUI_Localizator.Minimize, type: "button", children: _jsx(IconWindowMinimize, {}) })), children] }));
|
|
116
|
+
});
|
|
117
|
+
export default ToppySpeechBubble;
|
|
@@ -6,12 +6,14 @@ interface TMBlogCommentFormProps {
|
|
|
6
6
|
participants: Array<UserDescriptor>;
|
|
7
7
|
onClose: () => void;
|
|
8
8
|
showAttachmentsSection?: boolean;
|
|
9
|
+
removeAndEditAttachment?: boolean;
|
|
9
10
|
selectedAttachments?: Array<FileItem>;
|
|
10
11
|
selectedAttachmentDid?: Array<number>;
|
|
11
12
|
allFileItems?: FileItem;
|
|
12
13
|
allArchivedDocumentsFileItems?: Array<FileItem>;
|
|
13
14
|
onFilterCreated?: (predicate: (post: BlogPost) => boolean) => void;
|
|
14
15
|
refreshCallback?: () => Promise<void>;
|
|
16
|
+
isCommentRequired?: boolean;
|
|
15
17
|
}
|
|
16
18
|
declare const TMBlogCommentForm: (props: TMBlogCommentFormProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
19
|
export default TMBlogCommentForm;
|