@topconsultnpm/sdkui-react 6.19.0-dev2.53 → 6.19.0-dev2.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -5,6 +5,8 @@ import styled from 'styled-components';
|
|
|
5
5
|
import Toppy from '../../../assets/Toppy-generico.png';
|
|
6
6
|
import { DeviceType } from '../../base/TMDeviceProvider';
|
|
7
7
|
import ToppySpeechBubble from './ToppySpeechBubble';
|
|
8
|
+
import { SDKUI_Localizator } from '../../../helper';
|
|
9
|
+
import { IconWindowMaximize } from '../../../helper/TMIcons';
|
|
8
10
|
/**
|
|
9
11
|
* Styled component per il contenitore di Toppy
|
|
10
12
|
* Gestisce il posizionamento, le dimensioni e le animazioni
|
|
@@ -107,6 +109,45 @@ const ToppyButton = styled.div.attrs((props) => ({
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
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
|
+
`;
|
|
110
151
|
/**
|
|
111
152
|
* Overlay trasparente per bloccare le interazioni durante il drag
|
|
112
153
|
* Previene problemi di performance con iframe e altri elementi interattivi
|
|
@@ -141,6 +182,9 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
|
|
|
141
182
|
// Ref e stato per tracciare le dimensioni della speech bubble
|
|
142
183
|
const bubbleRef = useRef(null);
|
|
143
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);
|
|
144
188
|
const isMobile = deviceType === DeviceType.MOBILE;
|
|
145
189
|
/**
|
|
146
190
|
* Effect per aggiornare le dimensioni della bubble quando cambia il contenuto
|
|
@@ -386,7 +430,29 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
|
|
|
386
430
|
}, [isDragging]);
|
|
387
431
|
// Renderizza l'overlay solo durante il drag
|
|
388
432
|
const renderDragOverlay = isDragging && _jsx(DragOverlay, {});
|
|
389
|
-
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 })),
|
|
433
|
+
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) => {
|
|
434
|
+
isExpandButtonDraggingRef.current = false;
|
|
435
|
+
expandButtonMouseDownPosRef.current = { x: e.clientX, y: e.clientY };
|
|
436
|
+
}, onMouseMove: (e) => {
|
|
437
|
+
if (!expandButtonMouseDownPosRef.current)
|
|
438
|
+
return;
|
|
439
|
+
const deltaX = Math.abs(e.clientX - expandButtonMouseDownPosRef.current.x);
|
|
440
|
+
const deltaY = Math.abs(e.clientY - expandButtonMouseDownPosRef.current.y);
|
|
441
|
+
// Considera drag solo se il movimento supera 3px
|
|
442
|
+
if (deltaX > 3 || deltaY > 3) {
|
|
443
|
+
isExpandButtonDraggingRef.current = true;
|
|
444
|
+
}
|
|
445
|
+
}, onMouseUp: () => {
|
|
446
|
+
expandButtonMouseDownPosRef.current = null;
|
|
447
|
+
}, onClick: (e) => {
|
|
448
|
+
if (isExpandButtonDraggingRef.current) {
|
|
449
|
+
e.stopPropagation();
|
|
450
|
+
e.preventDefault();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
e.stopPropagation();
|
|
454
|
+
toggleCollapse(e);
|
|
455
|
+
}, 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 })] })] }));
|
|
390
456
|
// Renderizza nel document.body usando un Portal se usePortal è true, altrimenti renderizza normalmente
|
|
391
457
|
return usePortal ? ReactDOM.createPortal(toppyContent, document.body) : toppyContent;
|
|
392
458
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef } from 'react';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import { SDKUI_Localizator } from '../../../helper';
|
|
5
|
+
import { IconCloseOutline } from '../../../helper/TMIcons';
|
|
5
6
|
// Styled component
|
|
6
7
|
const Bubble = styled.div `
|
|
7
8
|
position: absolute;
|
|
@@ -63,25 +64,8 @@ const CloseButton = styled.button `
|
|
|
63
64
|
justify-content: center;
|
|
64
65
|
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
65
66
|
z-index: 10001;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
&::after {
|
|
69
|
-
content: '';
|
|
70
|
-
position: absolute;
|
|
71
|
-
width: 11px;
|
|
72
|
-
height: 2px;
|
|
73
|
-
background: white;
|
|
74
|
-
border-radius: 2px;
|
|
75
|
-
transition: all 0.3s ease;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
&::before {
|
|
79
|
-
transform: rotate(45deg);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
&::after {
|
|
83
|
-
transform: rotate(-45deg);
|
|
84
|
-
}
|
|
67
|
+
color: white;
|
|
68
|
+
font-size: 14px;
|
|
85
69
|
|
|
86
70
|
&:hover {
|
|
87
71
|
background: linear-gradient(135deg, #764ba2 0%, #f093fb 100%);
|
|
@@ -90,7 +74,7 @@ const CloseButton = styled.button `
|
|
|
90
74
|
}
|
|
91
75
|
|
|
92
76
|
&:active {
|
|
93
|
-
transform:
|
|
77
|
+
transform: scale(0.95);
|
|
94
78
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.4);
|
|
95
79
|
}
|
|
96
80
|
|
|
@@ -101,6 +85,33 @@ const CloseButton = styled.button `
|
|
|
101
85
|
`;
|
|
102
86
|
// Componente con forwardRef
|
|
103
87
|
const ToppySpeechBubble = forwardRef(({ align = 'right', children, className, onClose }, ref) => {
|
|
104
|
-
|
|
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(IconCloseOutline, {}) })), children] }));
|
|
105
116
|
});
|
|
106
117
|
export default ToppySpeechBubble;
|