@topconsultnpm/sdkui-react 6.20.0-dev1.49 → 6.20.0-dev1.50
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 +3 -6
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +116 -30
- package/lib/helper/SDKUI_Globals.d.ts +1 -0
- package/lib/helper/SDKUI_Globals.js +1 -1
- package/lib/helper/SDKUI_Localizator.d.ts +1 -1
- package/lib/helper/SDKUI_Localizator.js +1 -1
- package/package.json +1 -1
|
@@ -136,7 +136,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, externalControl, ke
|
|
|
136
136
|
};
|
|
137
137
|
// iOS-specific touch handlers for long press
|
|
138
138
|
const handleTouchStart = (e) => {
|
|
139
|
-
if (!isIOS)
|
|
139
|
+
if (!isIOS || trigger !== 'right')
|
|
140
140
|
return;
|
|
141
141
|
const touch = e.touches[0];
|
|
142
142
|
touchStartPos.current = { x: touch.clientX, y: touch.clientY };
|
|
@@ -158,7 +158,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, externalControl, ke
|
|
|
158
158
|
}, 500);
|
|
159
159
|
};
|
|
160
160
|
const handleTouchMove = (e) => {
|
|
161
|
-
if (!isIOS || !touchStartPos.current)
|
|
161
|
+
if (!isIOS || trigger !== 'right' || !touchStartPos.current)
|
|
162
162
|
return;
|
|
163
163
|
const touch = e.touches[0];
|
|
164
164
|
const moveThreshold = 10; // pixels
|
|
@@ -174,7 +174,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, externalControl, ke
|
|
|
174
174
|
}
|
|
175
175
|
};
|
|
176
176
|
const handleTouchEnd = () => {
|
|
177
|
-
if (!isIOS)
|
|
177
|
+
if (!isIOS || trigger !== 'right')
|
|
178
178
|
return;
|
|
179
179
|
if (longPressTimeoutRef.current) {
|
|
180
180
|
clearTimeout(longPressTimeoutRef.current);
|
|
@@ -198,9 +198,6 @@ const TMContextMenu = ({ items, trigger = 'right', children, externalControl, ke
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
else {
|
|
201
|
-
// Close menu if item has onClick (actual action) or keepOpenOnClick is false
|
|
202
|
-
// This allows pin icon clicks (onRightIconClick) to keep menu open while
|
|
203
|
-
// clicking the item itself closes it
|
|
204
201
|
if (item.onClick || !keepOpenOnClick) {
|
|
205
202
|
handleClose();
|
|
206
203
|
}
|
|
@@ -7,6 +7,24 @@ import * as S from './styles';
|
|
|
7
7
|
import { IconAdd, IconApply, IconMenuVertical, IconPin, IconUndo, SDKUI_Globals, SDKUI_Localizator } 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 = [], isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 100, }) => {
|
|
10
|
+
const percentToPixels = (percent, containerSize) => {
|
|
11
|
+
return (percent / 100) * containerSize;
|
|
12
|
+
};
|
|
13
|
+
const pixelsToPercent = (pixels, containerSize) => {
|
|
14
|
+
return (pixels / containerSize) * 100;
|
|
15
|
+
};
|
|
16
|
+
const isPixelFormat = (pos) => {
|
|
17
|
+
return pos.x > 100 || pos.y > 100;
|
|
18
|
+
};
|
|
19
|
+
const migrateToPercentage = (pixelPos) => {
|
|
20
|
+
const container = containerRef.current?.getBoundingClientRect();
|
|
21
|
+
const containerWidth = isConstrained && container ? container.width : window.innerWidth;
|
|
22
|
+
const containerHeight = isConstrained && container ? container.height : window.innerHeight;
|
|
23
|
+
return {
|
|
24
|
+
x: pixelsToPercent(pixelPos.x, containerWidth),
|
|
25
|
+
y: pixelsToPercent(pixelPos.y, containerHeight),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
10
28
|
const getDefaultConfig = () => ({
|
|
11
29
|
orientation: 'horizontal',
|
|
12
30
|
savedItemIds: [],
|
|
@@ -33,10 +51,10 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
33
51
|
const hasValidPosition = settings.position &&
|
|
34
52
|
typeof settings.position.x === 'number' &&
|
|
35
53
|
typeof settings.position.y === 'number' &&
|
|
36
|
-
!isNaN(settings.position.x) &&
|
|
37
|
-
!isNaN(settings.position.y) &&
|
|
38
|
-
isFinite(settings.position.x) &&
|
|
39
|
-
isFinite(settings.position.y);
|
|
54
|
+
!Number.isNaN(settings.position.x) &&
|
|
55
|
+
!Number.isNaN(settings.position.y) &&
|
|
56
|
+
Number.isFinite(settings.position.x) &&
|
|
57
|
+
Number.isFinite(settings.position.y);
|
|
40
58
|
if (!hasValidPosition) {
|
|
41
59
|
console.warn('FloatingMenuBar: Invalid position, resetting to defaults');
|
|
42
60
|
resetFloatingBarSettings();
|
|
@@ -66,12 +84,23 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
66
84
|
return getDefaultConfig();
|
|
67
85
|
}
|
|
68
86
|
}
|
|
69
|
-
//
|
|
70
|
-
|
|
87
|
+
// Migrate old pixel-based position to percentage-based
|
|
88
|
+
let finalPosition = settings.position;
|
|
89
|
+
if (isPixelFormat(settings.position) || settings.positionFormat === 'pixels') {
|
|
90
|
+
console.log('FloatingMenuBar: Migrating pixel-based position to percentage-based');
|
|
91
|
+
finalPosition = migrateToPercentage(settings.position);
|
|
92
|
+
// Save migrated position immediately
|
|
93
|
+
SDKUI_Globals.userSettings.searchSettings.floatingMenuBar = {
|
|
94
|
+
orientation: validOrientation,
|
|
95
|
+
itemIds: validItemIds,
|
|
96
|
+
position: finalPosition,
|
|
97
|
+
positionFormat: 'percentage',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
71
100
|
return {
|
|
72
101
|
orientation: validOrientation,
|
|
73
102
|
savedItemIds: validItemIds,
|
|
74
|
-
position:
|
|
103
|
+
position: finalPosition,
|
|
75
104
|
};
|
|
76
105
|
}
|
|
77
106
|
catch (error) {
|
|
@@ -88,7 +117,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
88
117
|
};
|
|
89
118
|
const initialConfig = loadConfig();
|
|
90
119
|
const [state, setState] = useState({
|
|
91
|
-
position: initialConfig.position,
|
|
120
|
+
position: initialConfig.position, // Stored as percentage
|
|
92
121
|
isDragging: false,
|
|
93
122
|
isConfigMode: false,
|
|
94
123
|
orientation: initialConfig.orientation,
|
|
@@ -98,6 +127,8 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
98
127
|
const floatingRef = useRef(null);
|
|
99
128
|
const dragOffset = useRef({ x: 0, y: 0 });
|
|
100
129
|
const [dragOverIndex, setDragOverIndex] = useState(null);
|
|
130
|
+
const [pixelPosition, setPixelPosition] = useState({ x: 0, y: 0 }); // Calculated pixel position
|
|
131
|
+
const containerSizeRef = useRef({ width: 0, height: 0 });
|
|
101
132
|
const stateSnapshot = useRef(null);
|
|
102
133
|
const floatingBarItemIds = useRef(new Set());
|
|
103
134
|
const floatingBarItemNames = useRef(new Set());
|
|
@@ -105,6 +136,39 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
105
136
|
floatingBarItemIds.current = new Set(state.items.map(i => i.id));
|
|
106
137
|
floatingBarItemNames.current = new Set(state.items.map(i => i.name));
|
|
107
138
|
}, [state.items]);
|
|
139
|
+
// Calculate pixel position from percentage when container size or position changes
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
const updatePixelPosition = () => {
|
|
142
|
+
if (!containerRef.current || !floatingRef.current)
|
|
143
|
+
return;
|
|
144
|
+
const container = containerRef.current.getBoundingClientRect();
|
|
145
|
+
const floating = floatingRef.current.getBoundingClientRect();
|
|
146
|
+
const containerWidth = isConstrained ? container.width : window.innerWidth;
|
|
147
|
+
const containerHeight = isConstrained ? container.height : window.innerHeight;
|
|
148
|
+
containerSizeRef.current = { width: containerWidth, height: containerHeight };
|
|
149
|
+
let newX = percentToPixels(state.position.x, containerWidth);
|
|
150
|
+
let newY = percentToPixels(state.position.y, containerHeight);
|
|
151
|
+
newX = Math.max(0, Math.min(newX, containerWidth - floating.width));
|
|
152
|
+
newY = Math.max(0, Math.min(newY, containerHeight - floating.height));
|
|
153
|
+
setPixelPosition({ x: newX, y: newY });
|
|
154
|
+
};
|
|
155
|
+
updatePixelPosition();
|
|
156
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
157
|
+
updatePixelPosition();
|
|
158
|
+
});
|
|
159
|
+
if (containerRef.current) {
|
|
160
|
+
resizeObserver.observe(containerRef.current);
|
|
161
|
+
}
|
|
162
|
+
if (!isConstrained) {
|
|
163
|
+
window.addEventListener('resize', updatePixelPosition);
|
|
164
|
+
}
|
|
165
|
+
return () => {
|
|
166
|
+
resizeObserver.disconnect();
|
|
167
|
+
if (!isConstrained) {
|
|
168
|
+
window.removeEventListener('resize', updatePixelPosition);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}, [state.position, isConstrained]);
|
|
108
172
|
const flattenMenuItems = useCallback((items, parentPath = '') => {
|
|
109
173
|
const result = [];
|
|
110
174
|
items.forEach((item, index) => {
|
|
@@ -243,15 +307,15 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
243
307
|
if (isConstrained) {
|
|
244
308
|
// For absolute positioning, offset is relative to container
|
|
245
309
|
dragOffset.current = {
|
|
246
|
-
x: e.clientX - containerRect.left -
|
|
247
|
-
y: e.clientY - containerRect.top -
|
|
310
|
+
x: e.clientX - containerRect.left - pixelPosition.x,
|
|
311
|
+
y: e.clientY - containerRect.top - pixelPosition.y,
|
|
248
312
|
};
|
|
249
313
|
}
|
|
250
314
|
else {
|
|
251
315
|
// For fixed positioning, offset is relative to viewport
|
|
252
316
|
dragOffset.current = {
|
|
253
|
-
x: e.clientX -
|
|
254
|
-
y: e.clientY -
|
|
317
|
+
x: e.clientX - pixelPosition.x,
|
|
318
|
+
y: e.clientY - pixelPosition.y,
|
|
255
319
|
};
|
|
256
320
|
}
|
|
257
321
|
}
|
|
@@ -284,14 +348,26 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
284
348
|
newX = Math.max(0, Math.min(newX, window.innerWidth - floating.width));
|
|
285
349
|
newY = Math.max(0, Math.min(newY, window.innerHeight - floating.height));
|
|
286
350
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
position: { x: newX, y: newY },
|
|
290
|
-
}));
|
|
351
|
+
// Update pixel position directly during drag
|
|
352
|
+
setPixelPosition({ x: newX, y: newY });
|
|
291
353
|
}, [state.isDragging, containerRef, isConstrained]);
|
|
292
354
|
const handleMouseUp = useCallback(() => {
|
|
293
|
-
|
|
294
|
-
|
|
355
|
+
if (state.isDragging && containerSizeRef.current.width > 0) {
|
|
356
|
+
// Convert final pixel position to percentage before updating state
|
|
357
|
+
const percentagePosition = {
|
|
358
|
+
x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
|
|
359
|
+
y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
|
|
360
|
+
};
|
|
361
|
+
setState(s => ({
|
|
362
|
+
...s,
|
|
363
|
+
isDragging: false,
|
|
364
|
+
position: percentagePosition,
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
setState(s => ({ ...s, isDragging: false }));
|
|
369
|
+
}
|
|
370
|
+
}, [state.isDragging, pixelPosition]);
|
|
295
371
|
// Touch event handlers for tablet support
|
|
296
372
|
const handleTouchStart = (e) => {
|
|
297
373
|
if (state.isConfigMode)
|
|
@@ -301,14 +377,14 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
301
377
|
if (containerRect) {
|
|
302
378
|
if (isConstrained) {
|
|
303
379
|
dragOffset.current = {
|
|
304
|
-
x: touch.clientX - containerRect.left -
|
|
305
|
-
y: touch.clientY - containerRect.top -
|
|
380
|
+
x: touch.clientX - containerRect.left - pixelPosition.x,
|
|
381
|
+
y: touch.clientY - containerRect.top - pixelPosition.y,
|
|
306
382
|
};
|
|
307
383
|
}
|
|
308
384
|
else {
|
|
309
385
|
dragOffset.current = {
|
|
310
|
-
x: touch.clientX -
|
|
311
|
-
y: touch.clientY -
|
|
386
|
+
x: touch.clientX - pixelPosition.x,
|
|
387
|
+
y: touch.clientY - pixelPosition.y,
|
|
312
388
|
};
|
|
313
389
|
}
|
|
314
390
|
}
|
|
@@ -333,14 +409,24 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
333
409
|
newX = Math.max(0, Math.min(newX, window.innerWidth - floating.width));
|
|
334
410
|
newY = Math.max(0, Math.min(newY, window.innerHeight - floating.height));
|
|
335
411
|
}
|
|
336
|
-
|
|
337
|
-
...s,
|
|
338
|
-
position: { x: newX, y: newY },
|
|
339
|
-
}));
|
|
412
|
+
setPixelPosition({ x: newX, y: newY });
|
|
340
413
|
}, [state.isDragging, containerRef, isConstrained]);
|
|
341
414
|
const handleTouchEnd = useCallback(() => {
|
|
342
|
-
|
|
343
|
-
|
|
415
|
+
if (state.isDragging && containerSizeRef.current.width > 0) {
|
|
416
|
+
const percentagePosition = {
|
|
417
|
+
x: pixelsToPercent(pixelPosition.x, containerSizeRef.current.width),
|
|
418
|
+
y: pixelsToPercent(pixelPosition.y, containerSizeRef.current.height),
|
|
419
|
+
};
|
|
420
|
+
setState(s => ({
|
|
421
|
+
...s,
|
|
422
|
+
isDragging: false,
|
|
423
|
+
position: percentagePosition,
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
setState(s => ({ ...s, isDragging: false }));
|
|
428
|
+
}
|
|
429
|
+
}, [state.isDragging, pixelPosition]);
|
|
344
430
|
useEffect(() => {
|
|
345
431
|
if (state.isDragging) {
|
|
346
432
|
document.addEventListener('mousemove', handleMouseMove);
|
|
@@ -366,6 +452,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
366
452
|
orientation: state.orientation,
|
|
367
453
|
itemIds: state.items.map(item => item.id),
|
|
368
454
|
position: state.position,
|
|
455
|
+
positionFormat: 'percentage',
|
|
369
456
|
};
|
|
370
457
|
}
|
|
371
458
|
catch (error) {
|
|
@@ -375,7 +462,6 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
375
462
|
const toggleConfigMode = () => {
|
|
376
463
|
setState(s => {
|
|
377
464
|
if (!s.isConfigMode) {
|
|
378
|
-
// Entering edit mode - save snapshot
|
|
379
465
|
stateSnapshot.current = {
|
|
380
466
|
items: [...s.items],
|
|
381
467
|
orientation: s.orientation,
|
|
@@ -570,7 +656,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
570
656
|
setState(s => ({ ...s, draggedItemIndex: null }));
|
|
571
657
|
setDragOverIndex(null);
|
|
572
658
|
};
|
|
573
|
-
return (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { "$visible": state.isConfigMode }), _jsxs(S.FloatingContainer, { ref: floatingRef, "$x":
|
|
659
|
+
return (_jsxs(_Fragment, { children: [_jsx(S.Overlay, { "$visible": state.isConfigMode }), _jsxs(S.FloatingContainer, { ref: floatingRef, "$x": pixelPosition.x, "$y": pixelPosition.y, "$orientation": state.orientation, "$isDragging": state.isDragging, "$isConfigMode": state.isConfigMode, "$isConstrained": isConstrained, onContextMenu: (e) => e.preventDefault(), children: [!state.isConfigMode ? (_jsx(ContextMenu, { items: [
|
|
574
660
|
{
|
|
575
661
|
name: SDKUI_Localizator.Configure,
|
|
576
662
|
onClick: () => {
|
|
@@ -106,7 +106,7 @@ export class FloatingMenuBarSettings {
|
|
|
106
106
|
constructor() {
|
|
107
107
|
this.orientation = 'horizontal';
|
|
108
108
|
this.itemIds = ['rel-det', 'rel-mst', 'dl'];
|
|
109
|
-
this.position = { x:
|
|
109
|
+
this.position = { x: 1, y: 90 };
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
export class ArchivingSettings {
|
|
@@ -204,7 +204,7 @@ export declare class SDKUI_Localizator {
|
|
|
204
204
|
static get DownloadXMLAttachments(): string;
|
|
205
205
|
static get Draft(): string;
|
|
206
206
|
static get Drafts(): string;
|
|
207
|
-
static get DropFileHere(): "Ziehen Sie Ihre Datei hierher" | "Drop your file here" | "Suelta tu archivo aquí" | "Déposez votre fichier ici" | "Solte seu arquivo aqui";
|
|
207
|
+
static get DropFileHere(): "Ziehen Sie Ihre Datei hierher" | "Drop your file here" | "Suelta tu archivo aquí" | "Déposez votre fichier ici" | "Solte seu arquivo aqui" | "Trascina qui il tuo file";
|
|
208
208
|
static get DropFileToShare(): string;
|
|
209
209
|
static get Duplicate(): "Duplikat" | "Duplicate" | "Duplicar" | "Dupliquer" | "Duplicado" | "Duplica";
|
|
210
210
|
static get Duplicate_ConfirmFor1(): "Möchten Sie '{{0}}' duplizieren?" | "Are you sure you want to duplicate '{{0}}'?" | "¿Estás seguro de que deseas duplicar '{{0}}'?" | "Êtes-vous sûr de vouloir dupliquer '{{0}}'?" | "Você tem certeza que deseja duplicar '{{0}}'?" | "Sei sicuro di voler duplicare '{{0}}'?";
|
|
@@ -1996,7 +1996,7 @@ export class SDKUI_Localizator {
|
|
|
1996
1996
|
case CultureIDs.Es_ES: return "Suelta tu archivo aquí";
|
|
1997
1997
|
case CultureIDs.Fr_FR: return "Déposez votre fichier ici";
|
|
1998
1998
|
case CultureIDs.Pt_PT: return "Solte seu arquivo aqui";
|
|
1999
|
-
default: return "
|
|
1999
|
+
default: return "Trascina qui il tuo file";
|
|
2000
2000
|
}
|
|
2001
2001
|
}
|
|
2002
2002
|
static get DropFileToShare() {
|