@topconsultnpm/sdkui-react 6.20.0-dev1.19 → 6.20.0-dev1.20
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/styles.js +8 -4
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +3 -3
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +8 -0
- package/lib/components/NewComponents/FloatingMenuBar/styles.js +23 -12
- package/lib/components/features/documents/TMDcmtPreview.js +37 -18
- package/package.json +1 -1
|
@@ -78,9 +78,8 @@ export const MenuItem = styled.div `
|
|
|
78
78
|
opacity: ${props => props.$disabled ? 0.4 : 1};
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
/*
|
|
81
|
+
/* Right icon button hidden by default, shown on hover */
|
|
82
82
|
& .right-icon-btn {
|
|
83
|
-
opacity: 1 !important;
|
|
84
83
|
cursor: pointer !important;
|
|
85
84
|
}
|
|
86
85
|
|
|
@@ -89,6 +88,11 @@ export const MenuItem = styled.div `
|
|
|
89
88
|
background: linear-gradient(90deg, #f0f7ff 0%, #e6f2ff 100%);
|
|
90
89
|
color: #0066cc;
|
|
91
90
|
`}
|
|
91
|
+
|
|
92
|
+
/* Show right icon on hover */
|
|
93
|
+
& .right-icon-btn {
|
|
94
|
+
opacity: 1 !important;
|
|
95
|
+
}
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
&:active {
|
|
@@ -157,8 +161,8 @@ export const RightIconButton = styled.button.attrs({
|
|
|
157
161
|
margin-left: 8px;
|
|
158
162
|
border-radius: 6px;
|
|
159
163
|
font-size: 14px;
|
|
160
|
-
opacity:
|
|
161
|
-
transition:
|
|
164
|
+
opacity: 0 !important;
|
|
165
|
+
transition: opacity 0.15s ease, background 0.15s ease, transform 0.15s ease;
|
|
162
166
|
|
|
163
167
|
&:hover {
|
|
164
168
|
background: rgba(0, 0, 0, 0.05);
|
|
@@ -4,7 +4,7 @@ import { ContextMenu } from '../ContextMenu';
|
|
|
4
4
|
import Notification from '../Notification';
|
|
5
5
|
import TMTooltip from '../../base/TMTooltip';
|
|
6
6
|
import * as S from './styles';
|
|
7
|
-
import { IconApply, IconMenuKebab, IconMenuVertical,
|
|
7
|
+
import { IconApply, IconMenuKebab, IconMenuVertical, IconPencil, IconPin } from '../../../helper';
|
|
8
8
|
const IconDraggableDots = (props) => (_jsx("svg", { fontSize: 18, viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M9 3a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm10-18a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0z" }) }));
|
|
9
9
|
const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = 'floatingMenuBar-config', isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 8, }) => {
|
|
10
10
|
const loadConfig = () => {
|
|
@@ -347,7 +347,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
|
|
|
347
347
|
setState(s => ({ ...s, draggedItemIndex: null }));
|
|
348
348
|
setDragOverIndex(null);
|
|
349
349
|
};
|
|
350
|
-
return (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { "$visible": state.isConfigMode }), _jsxs(S.FloatingContainer, { ref: floatingRef, "$x": state.position.x, "$y": state.position.y, "$orientation": state.orientation, "$isDragging": state.isDragging, "$isConfigMode": state.isConfigMode, "$isConstrained": isConstrained, children: [_jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, children: _jsx(IconDraggableDots, {}) }), _jsx(S.
|
|
350
|
+
return (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { "$visible": state.isConfigMode }), _jsxs(S.FloatingContainer, { ref: floatingRef, "$x": state.position.x, "$y": state.position.y, "$orientation": state.orientation, "$isDragging": state.isDragging, "$isConfigMode": state.isConfigMode, "$isConstrained": isConstrained, children: [_jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, children: _jsx(IconDraggableDots, {}) }), _jsx(S.Separator, { "$orientation": state.orientation }), state.items.map((item, index) => {
|
|
351
351
|
// Get current state (disabled and onClick) from contextMenuItems
|
|
352
352
|
const currentState = getCurrentItemState(item.name);
|
|
353
353
|
const isDisabled = currentState.disabled || false;
|
|
@@ -365,6 +365,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], storageKey = '
|
|
|
365
365
|
currentOnClick();
|
|
366
366
|
}
|
|
367
367
|
}, disabled: isDisabled, children: item.icon }) })), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
|
|
368
|
-
}), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: enhancedContextMenuItems(), trigger: "left", children: _jsx(S.
|
|
368
|
+
}), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: enhancedContextMenuItems(), trigger: "left", children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) }, Array.from(pinnedItemIds).join(','))), _jsx(S.ConfigButton, { onClick: toggleConfigMode, "$isActive": state.isConfigMode, children: state.isConfigMode ? _jsx(IconApply, {}) : _jsx(IconPencil, {}) }), !state.isConfigMode && (_jsx(S.OrientationToggle, { "$orientation": state.orientation, onClick: toggleOrientation, children: _jsx(IconMenuKebab, {}) }))] }), showMaxItemsNotification && (_jsx("div", { style: { position: 'fixed', top: '20px', left: '50%', transform: 'translateX(-50%)', zIndex: 100001 }, children: _jsx(Notification, { title: "Maximum Items Reached", message: `You have reached the maximum number of pinned items (${maxItems}). Please unpin an item before adding a new one.`, mode: "warning", position: "top-center", duration: 4000, closable: true, stopOnMouseEnter: true, hasProgress: true, onClose: () => setShowMaxItemsNotification(false) }) }))] }));
|
|
369
369
|
};
|
|
370
370
|
export default TMFloatingMenuBar;
|
|
@@ -21,12 +21,20 @@ export declare const FloatingContainer: import("styled-components/dist/types").I
|
|
|
21
21
|
export declare const GripHandle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
22
22
|
$orientation: "horizontal" | "vertical";
|
|
23
23
|
}>> & string;
|
|
24
|
+
export declare const Separator: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
25
|
+
$orientation: "horizontal" | "vertical";
|
|
26
|
+
}>> & string;
|
|
24
27
|
export declare const MenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
|
|
25
28
|
$isActive?: boolean;
|
|
26
29
|
}>> & string;
|
|
27
30
|
export declare const ConfigButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
|
|
28
31
|
$isActive?: boolean;
|
|
29
32
|
}>> & string;
|
|
33
|
+
export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
|
|
34
|
+
$isActive?: boolean;
|
|
35
|
+
}, "ref"> & {
|
|
36
|
+
ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
|
|
37
|
+
}, never>> & string;
|
|
30
38
|
export declare const RemoveButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
31
39
|
export declare const OrientationToggle: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
|
|
32
40
|
$orientation: "horizontal" | "vertical";
|
|
@@ -55,7 +55,7 @@ export const FloatingContainer = styled.div.attrs(props => ({
|
|
|
55
55
|
transition: none;
|
|
56
56
|
|
|
57
57
|
&:hover {
|
|
58
|
-
background: linear-gradient(135deg, #
|
|
58
|
+
background: linear-gradient(135deg, #0071BC 0%, #1B1464 100%);
|
|
59
59
|
border: 1px solid #667eea;
|
|
60
60
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3),
|
|
61
61
|
0 6px 16px rgba(0, 0, 0, 0.2);
|
|
@@ -98,6 +98,13 @@ export const GripHandle = styled.div `
|
|
|
98
98
|
height: 14px;
|
|
99
99
|
}
|
|
100
100
|
`;
|
|
101
|
+
export const Separator = styled.div `
|
|
102
|
+
background: rgba(255, 255, 255, 0.25);
|
|
103
|
+
width: ${props => props.$orientation === 'horizontal' ? '1px' : '100%'};
|
|
104
|
+
height: ${props => props.$orientation === 'horizontal' ? '24px' : '1px'};
|
|
105
|
+
margin: ${props => props.$orientation === 'horizontal' ? '0 4px' : '4px 0'};
|
|
106
|
+
flex-shrink: 0;
|
|
107
|
+
`;
|
|
101
108
|
export const MenuButton = styled.button `
|
|
102
109
|
display: flex;
|
|
103
110
|
align-items: center;
|
|
@@ -110,16 +117,15 @@ export const MenuButton = styled.button `
|
|
|
110
117
|
color: white;
|
|
111
118
|
font-size: 16px;
|
|
112
119
|
cursor: pointer;
|
|
113
|
-
transition:
|
|
120
|
+
transition: background 0.2s ease;
|
|
114
121
|
position: relative;
|
|
115
122
|
|
|
116
123
|
&:hover:not(:disabled) {
|
|
117
124
|
background: rgba(255, 255, 255, 0.2);
|
|
118
|
-
transform: scale(1.1);
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
&:active:not(:disabled) {
|
|
122
|
-
|
|
128
|
+
opacity: 0.8;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
&:disabled {
|
|
@@ -131,14 +137,15 @@ export const MenuButton = styled.button `
|
|
|
131
137
|
svg {
|
|
132
138
|
width: 18px;
|
|
133
139
|
height: 18px;
|
|
140
|
+
transform: translateY(2px);
|
|
134
141
|
}
|
|
135
142
|
`;
|
|
136
143
|
export const ConfigButton = styled.button `
|
|
137
144
|
display: flex;
|
|
138
145
|
align-items: center;
|
|
139
146
|
justify-content: center;
|
|
140
|
-
width:
|
|
141
|
-
height:
|
|
147
|
+
width: 28px;
|
|
148
|
+
height: 28px;
|
|
142
149
|
background: ${props => props.$isActive
|
|
143
150
|
? 'rgba(0, 0, 0, 0.2)'
|
|
144
151
|
: 'rgba(0, 0, 0, 0.1)'};
|
|
@@ -147,9 +154,9 @@ export const ConfigButton = styled.button `
|
|
|
147
154
|
: 'rgba(255, 255, 255, 0.15)'};
|
|
148
155
|
border-radius: 8px;
|
|
149
156
|
color: white;
|
|
150
|
-
font-size:
|
|
157
|
+
font-size: 14px;
|
|
151
158
|
cursor: pointer;
|
|
152
|
-
transition:
|
|
159
|
+
transition: background 0.2s ease, border-color 0.2s ease;
|
|
153
160
|
position: relative;
|
|
154
161
|
|
|
155
162
|
&:hover {
|
|
@@ -157,16 +164,20 @@ export const ConfigButton = styled.button `
|
|
|
157
164
|
? 'rgba(0, 0, 0, 0.25)'
|
|
158
165
|
: 'rgba(0, 0, 0, 0.15)'};
|
|
159
166
|
border-color: rgba(255, 255, 255, 0.35);
|
|
160
|
-
transform: scale(1.05);
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
&:active {
|
|
164
|
-
|
|
170
|
+
opacity: 0.8;
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
svg {
|
|
168
|
-
width:
|
|
169
|
-
height:
|
|
174
|
+
width: 16px;
|
|
175
|
+
height: 16px;
|
|
176
|
+
}
|
|
177
|
+
`;
|
|
178
|
+
export const ContextMenuButton = styled(MenuButton) `
|
|
179
|
+
svg {
|
|
180
|
+
transform: translateY(0);
|
|
170
181
|
}
|
|
171
182
|
`;
|
|
172
183
|
export const RemoveButton = styled.button `
|
|
@@ -19,20 +19,30 @@ let Document = null;
|
|
|
19
19
|
let Page = null;
|
|
20
20
|
let pdfjs = null;
|
|
21
21
|
let isPdfLibraryLoaded = false;
|
|
22
|
+
let loadingPromise = null;
|
|
22
23
|
const loadPdfLibrary = async () => {
|
|
23
24
|
if (isPdfLibraryLoaded)
|
|
24
25
|
return;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
if (loadingPromise)
|
|
27
|
+
return loadingPromise;
|
|
28
|
+
loadingPromise = (async () => {
|
|
29
|
+
try {
|
|
30
|
+
const reactPdf = await import('react-pdf');
|
|
31
|
+
Document = reactPdf.Document;
|
|
32
|
+
Page = reactPdf.Page;
|
|
33
|
+
pdfjs = reactPdf.pdfjs;
|
|
34
|
+
pdfjs.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
35
|
+
isPdfLibraryLoaded = true;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error('Failed to load react-pdf library:', error);
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
loadingPromise = null;
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
45
|
+
return loadingPromise;
|
|
36
46
|
};
|
|
37
47
|
const ErrorContent = ({ error, isAbortError, onRetry }) => {
|
|
38
48
|
if (isAbortError) {
|
|
@@ -183,16 +193,25 @@ export const TMFileViewer = ({ fileBlob, isResizingActive }) => {
|
|
|
183
193
|
window.removeEventListener('resize', checkIsMobile);
|
|
184
194
|
};
|
|
185
195
|
}, []);
|
|
186
|
-
useEffect(() => {
|
|
187
|
-
if (isMobile && fileType === 'application/pdf' && !isPdfLibraryLoaded && !pdfLibraryLoading) {
|
|
188
|
-
setPdfLibraryLoading(true);
|
|
189
|
-
loadPdfLibrary().finally(() => setPdfLibraryLoading(false));
|
|
190
|
-
}
|
|
191
|
-
}, [isMobile, fileType, pdfLibraryLoading]);
|
|
192
196
|
useEffect(() => {
|
|
193
197
|
if (fileBlob) {
|
|
194
|
-
|
|
198
|
+
const blobType = fileBlob.type;
|
|
199
|
+
setFileType(blobType);
|
|
195
200
|
setFormattedXml(undefined);
|
|
201
|
+
// Load PDF library immediately if it's a PDF file on mobile
|
|
202
|
+
if (isMobile && blobType === 'application/pdf' && !isPdfLibraryLoaded && !pdfLibraryLoading) {
|
|
203
|
+
setPdfLibraryLoading(true);
|
|
204
|
+
loadPdfLibrary()
|
|
205
|
+
.then(() => {
|
|
206
|
+
console.log('PDF library loaded successfully');
|
|
207
|
+
})
|
|
208
|
+
.catch((error) => {
|
|
209
|
+
console.error('Failed to load PDF library:', error);
|
|
210
|
+
})
|
|
211
|
+
.finally(() => {
|
|
212
|
+
setPdfLibraryLoading(false);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
196
215
|
const fileName = fileBlob.name || '';
|
|
197
216
|
const fileExtension = fileName.split('.').pop()?.toLowerCase() || '';
|
|
198
217
|
const isConfigFile = ['config', 'cfg'].includes(fileExtension);
|