@topconsultnpm/sdkui-react 6.20.0-dev1.57 → 6.20.0-dev1.59

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.
@@ -61,18 +61,20 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
61
61
  const touch = touchEvent.touches[0];
62
62
  let state = touchStateMap.get(element);
63
63
  if (!state) {
64
- state = { timeout: null, startX: 0, startY: 0 };
64
+ state = { timeout: null, startX: 0, startY: 0, longPressTriggered: false };
65
65
  touchStateMap.set(element, state);
66
66
  }
67
67
  state.startX = touch.clientX;
68
68
  state.startY = touch.clientY;
69
+ state.longPressTriggered = false;
69
70
  if (state.timeout)
70
71
  clearTimeout(state.timeout);
71
72
  state.timeout = setTimeout(() => {
73
+ if (state)
74
+ state.longPressTriggered = true;
72
75
  // Haptic feedback
73
76
  if ('vibrate' in navigator)
74
77
  navigator.vibrate(50);
75
- // Dispatch synthetic contextmenu event to trigger existing onContextMenu handlers
76
78
  const syntheticEvent = new MouseEvent('contextmenu', {
77
79
  bubbles: true,
78
80
  cancelable: true,
@@ -106,6 +108,17 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
106
108
  state.timeout = null;
107
109
  }
108
110
  };
111
+ // Prevent click event after long-press was triggered
112
+ const handleClick = (e) => {
113
+ const element = e.currentTarget;
114
+ const state = touchStateMap.get(element);
115
+ if (state?.longPressTriggered) {
116
+ e.preventDefault();
117
+ e.stopPropagation();
118
+ e.stopImmediatePropagation();
119
+ state.longPressTriggered = false;
120
+ }
121
+ };
109
122
  // Attach listeners to all matching elements
110
123
  elements.forEach(element => {
111
124
  const el = element;
@@ -117,6 +130,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
117
130
  el.addEventListener('touchmove', handleTouchMove, { passive: true });
118
131
  el.addEventListener('touchend', handleTouchEnd);
119
132
  el.addEventListener('touchcancel', handleTouchEnd);
133
+ el.addEventListener('click', handleClick, { capture: true });
120
134
  });
121
135
  return () => {
122
136
  elements.forEach(element => {
@@ -128,6 +142,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
128
142
  el.removeEventListener('touchmove', handleTouchMove);
129
143
  el.removeEventListener('touchend', handleTouchEnd);
130
144
  el.removeEventListener('touchcancel', handleTouchEnd);
145
+ el.removeEventListener('click', handleClick, { capture: true });
131
146
  });
132
147
  };
133
148
  }, [target, isIOS]);
@@ -369,6 +384,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
369
384
  e.stopPropagation();
370
385
  // if (item.disabled) return;
371
386
  item.onRightIconClick?.();
387
+ handleClose();
372
388
  };
373
389
  return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, onMouseDown: handleClick, onMouseEnter: (e) => !isMobile && handleMouseEnter(item, e, depth + 1), onMouseLeave: () => !isMobile && handleMouseLeave(depth + 1), title: item.tooltip, children: [_jsxs(S.MenuItemContent, { children: [item.icon && _jsx(S.IconWrapper, { children: item.icon }), _jsx(S.MenuItemName, { children: item.name })] }), item.rightIcon && item.onRightIconClick && (_jsx(S.RightIconButton, { onClick: handleRightIconClick, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: item.rightIcon })), item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
374
390
  });
@@ -4,7 +4,8 @@ import { ContextMenu } from '../ContextMenu';
4
4
  import ShowAlert from '../../base/TMAlert';
5
5
  import TMTooltip from '../../base/TMTooltip';
6
6
  import * as S from './styles';
7
- import { IconAdd, IconApply, IconMenuVertical, IconPin, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
7
+ import { IconAdd, IconApply, IconMenuVertical, IconPin, IconSeparator, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
8
+ const Separator = (props) => (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M12 2v20", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" }) }));
8
9
  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
10
  const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 100, }) => {
10
11
  const percentToPixels = (percent, containerSize) => {
@@ -77,7 +78,9 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
77
78
  const validItemIds = Array.isArray(settings.itemIds) ? settings.itemIds : [];
78
79
  if (validItemIds.length > 0) {
79
80
  // Check if any ID looks like the old format (contains language-specific text or is too long)
80
- const hasOldFormatIds = validItemIds.some(id => typeof id === 'string' && (id.length > 20 || id.includes(' ')));
81
+ const hasOldFormatIds = validItemIds.some(id => typeof id === 'string' &&
82
+ !id.startsWith('separator-') &&
83
+ (id.length > 20 || id.includes(' ')));
81
84
  if (hasOldFormatIds) {
82
85
  console.warn('FloatingMenuBar: Detected old name-based configuration, resetting to defaults');
83
86
  resetFloatingBarSettings();
@@ -193,11 +196,22 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
193
196
  }, [state.items]);
194
197
  // Restore items on mount from savedItemIds
195
198
  useEffect(() => {
196
- if (contextMenuItems.length > 0) {
199
+ if (contextMenuItems.length > 0 || initialConfig.savedItemIds.length > 0) {
197
200
  const flatItems = flattenMenuItems(contextMenuItems);
198
201
  // Restore items in the saved order from localStorage
199
202
  const restoredItems = initialConfig.savedItemIds
200
- .map((id) => flatItems.find(item => item.id === id))
203
+ .map((id) => {
204
+ if (id.startsWith('separator-')) {
205
+ return {
206
+ id,
207
+ name: 'Separator',
208
+ icon: _jsx(Separator, {}),
209
+ onClick: () => { },
210
+ isSeparator: true,
211
+ };
212
+ }
213
+ return flatItems.find(item => item.id === id);
214
+ })
201
215
  .filter((item) => item !== undefined);
202
216
  if (restoredItems.length > 0) {
203
217
  setState(s => ({ ...s, items: restoredItems }));
@@ -250,6 +264,39 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
250
264
  onClick: foundItem?.onClick
251
265
  };
252
266
  }, [contextMenuItems]);
267
+ // Remove trailing separators from items array
268
+ const removeTrailingSeparators = useCallback((items) => {
269
+ const result = [...items];
270
+ while (result.length > 0 && result.at(-1)?.isSeparator) {
271
+ result.pop();
272
+ }
273
+ return result;
274
+ }, []);
275
+ // Create a new separator item
276
+ const createSeparator = useCallback(() => {
277
+ const separatorId = `separator-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
278
+ return {
279
+ id: separatorId,
280
+ name: 'Separator',
281
+ icon: _jsx(Separator, {}),
282
+ onClick: () => { },
283
+ isSeparator: true,
284
+ };
285
+ }, []);
286
+ // Add separator to items
287
+ const addSeparator = useCallback(() => {
288
+ if (state.items.length >= maxItems) {
289
+ ShowAlert({
290
+ mode: 'warning',
291
+ title: 'Limite Massimo Raggiunto',
292
+ message: `Hai raggiunto il massimo di ${maxItems} elementi. Rimuovine uno prima di aggiungerne altri.`,
293
+ duration: 4000,
294
+ });
295
+ return;
296
+ }
297
+ const separator = createSeparator();
298
+ setState(s => ({ ...s, items: [...s.items, separator] }));
299
+ }, [state.items.length, maxItems, createSeparator]);
253
300
  const getPinContextMenuItems = useCallback(() => {
254
301
  const flatItems = flattenMenuItems(contextMenuItems);
255
302
  const currentItemIds = new Set(state.items.map(i => i.id));
@@ -273,8 +320,17 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
273
320
  return pinItem;
274
321
  });
275
322
  };
276
- return createPinItems(contextMenuItems);
277
- }, [contextMenuItems, flattenMenuItems, togglePin, state.items]);
323
+ const pinItems = createPinItems(contextMenuItems);
324
+ // Add separator option at the end
325
+ pinItems.push({
326
+ id: 'add-separator',
327
+ name: SDKUI_Localizator.Add + ' separatore',
328
+ icon: _jsx(IconSeparator, {}),
329
+ onClick: addSeparator,
330
+ beginGroup: true
331
+ });
332
+ return pinItems;
333
+ }, [contextMenuItems, flattenMenuItems, togglePin, state.items, addSeparator]);
278
334
  const getContextMenuItemsWithPinIcons = useCallback(() => {
279
335
  const flatItems = flattenMenuItems(contextMenuItems);
280
336
  const currentItemIds = new Set(state.items.map(i => i.id));
@@ -470,9 +526,10 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
470
526
  return { ...s, isConfigMode: true };
471
527
  }
472
528
  else {
473
- // Exiting edit mode (applying changes) - clear snapshot
529
+ // Exiting edit mode (applying changes) - clean up trailing separators and clear snapshot
474
530
  stateSnapshot.current = null;
475
- return { ...s, isConfigMode: false };
531
+ const cleanedItems = removeTrailingSeparators(s.items);
532
+ return { ...s, isConfigMode: false, items: cleanedItems };
476
533
  }
477
534
  });
478
535
  };
@@ -480,54 +537,52 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
480
537
  useEffect(() => {
481
538
  if (!state.isConfigMode || !floatingRef.current)
482
539
  return;
540
+ // Use double requestAnimationFrame to ensure the DOM has fully updated with new buttons
483
541
  requestAnimationFrame(() => {
484
- if (!floatingRef.current)
485
- return;
486
- const floating = floatingRef.current.getBoundingClientRect();
487
- let newX = state.position.x;
488
- let newY = state.position.y;
489
- let needsUpdate = false;
490
- if (isConstrained && containerRef.current) {
491
- const container = containerRef.current.getBoundingClientRect();
492
- if (state.orientation === 'horizontal') {
493
- if (state.position.x + floating.width > container.width) {
494
- newX = Math.max(0, container.width - floating.width);
495
- needsUpdate = true;
496
- }
542
+ requestAnimationFrame(() => {
543
+ if (!floatingRef.current)
544
+ return;
545
+ const floating = floatingRef.current.getBoundingClientRect();
546
+ const containerWidth = isConstrained && containerRef.current
547
+ ? containerRef.current.getBoundingClientRect().width
548
+ : window.innerWidth;
549
+ const containerHeight = isConstrained && containerRef.current
550
+ ? containerRef.current.getBoundingClientRect().height
551
+ : window.innerHeight;
552
+ // Use current pixel position
553
+ let newPixelX = pixelPosition.x;
554
+ let newPixelY = pixelPosition.y;
555
+ let needsUpdate = false;
556
+ // Check horizontal overflow
557
+ if (newPixelX + floating.width > containerWidth) {
558
+ newPixelX = Math.max(0, containerWidth - floating.width);
559
+ needsUpdate = true;
497
560
  }
498
- else {
499
- if (state.position.y + floating.height > container.height) {
500
- newY = Math.max(0, container.height - floating.height);
501
- needsUpdate = true;
502
- }
561
+ // Check vertical overflow
562
+ if (newPixelY + floating.height > containerHeight) {
563
+ newPixelY = Math.max(0, containerHeight - floating.height);
564
+ needsUpdate = true;
503
565
  }
504
- }
505
- else {
506
- if (state.orientation === 'horizontal') {
507
- if (state.position.x + floating.width > window.innerWidth) {
508
- newX = Math.max(0, window.innerWidth - floating.width - 10);
509
- needsUpdate = true;
566
+ if (needsUpdate) {
567
+ // Update pixel position immediately
568
+ setPixelPosition({ x: newPixelX, y: newPixelY });
569
+ // Convert to percentage for state
570
+ const newPercentagePosition = {
571
+ x: pixelsToPercent(newPixelX, containerWidth),
572
+ y: pixelsToPercent(newPixelY, containerHeight),
573
+ };
574
+ setState(s => ({
575
+ ...s,
576
+ position: newPercentagePosition,
577
+ }));
578
+ // Update snapshot position to the corrected position so Undo restores to visible position
579
+ if (stateSnapshot.current) {
580
+ stateSnapshot.current.position = newPercentagePosition;
510
581
  }
511
582
  }
512
- else {
513
- if (state.position.y + floating.height > window.innerHeight) {
514
- newY = Math.max(0, window.innerHeight - floating.height - 10);
515
- needsUpdate = true;
516
- }
517
- }
518
- }
519
- if (needsUpdate) {
520
- setState(s => ({
521
- ...s,
522
- position: { x: newX, y: newY },
523
- }));
524
- // Update snapshot position to the corrected position so Undo restores to visible position
525
- if (stateSnapshot.current) {
526
- stateSnapshot.current.position = { x: newX, y: newY };
527
- }
528
- }
583
+ });
529
584
  });
530
- }, [state.isConfigMode, state.orientation, isConstrained]);
585
+ }, [state.isConfigMode, state.orientation, isConstrained, state.items, pixelPosition.x, pixelPosition.y]);
531
586
  const handleUndo = () => {
532
587
  if (stateSnapshot.current) {
533
588
  setState(s => ({
@@ -670,6 +725,10 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
670
725
  onClick: toggleOrientation,
671
726
  },
672
727
  ], trigger: "right", children: _jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onDoubleClick: handleGripDoubleClick, children: _jsx(IconDraggableDots, {}) }) })) : (_jsx(S.GripHandle, { "$orientation": state.orientation, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, onDoubleClick: handleGripDoubleClick, children: _jsx(IconDraggableDots, {}) })), _jsx(S.Separator, { "$orientation": state.orientation }), state.items.map((item, index) => {
728
+ // Handle separator items
729
+ if (item.isSeparator) {
730
+ return (_jsxs(S.DraggableItem, { "$isDragging": state.draggedItemIndex === index, "$isDragOver": dragOverIndex === index && state.draggedItemIndex !== index, draggable: state.isConfigMode, onDragStart: (e) => handleDragStart(e, index), onDragEnter: (e) => handleDragEnter(e, index), onDragOver: handleDragOver, onDragLeave: (e) => handleDragLeave(e, index), onDrop: (e) => handleDrop(e, index), onDragEnd: handleDragEnd, children: [_jsx(S.ItemSeparator, { "$orientation": state.orientation, "$isConfigMode": state.isConfigMode }), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
731
+ }
673
732
  // Get current state (disabled and onClick) from contextMenuItems
674
733
  const currentState = getCurrentItemState(item.id);
675
734
  const isDisabled = currentState.disabled || false;
@@ -24,6 +24,10 @@ export declare const GripHandle: import("styled-components/dist/types").IStyledC
24
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
25
  $orientation: "horizontal" | "vertical";
26
26
  }>> & string;
27
+ export declare const ItemSeparator: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
28
+ $orientation: "horizontal" | "vertical";
29
+ $isConfigMode: boolean;
30
+ }>> & string;
27
31
  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>, {
28
32
  $isActive?: boolean;
29
33
  }>> & string;
@@ -102,6 +102,45 @@ export const Separator = styled.div `
102
102
  margin: ${props => props.$orientation === 'horizontal' ? '0 4px' : '4px 0'};
103
103
  flex-shrink: 0;
104
104
  `;
105
+ export const ItemSeparator = styled.div `
106
+ flex-shrink: 0;
107
+ transition: all 0.2s ease;
108
+
109
+ ${props => props.$isConfigMode ? `
110
+ /* Edit mode: look exactly like MenuButton */
111
+ display: flex;
112
+ align-items: center;
113
+ justify-content: center;
114
+ width: 34px;
115
+ height: 34px;
116
+ background: transparent;
117
+ border-radius: 8px;
118
+ cursor: grab;
119
+ position: relative;
120
+
121
+ &::before {
122
+ content: '';
123
+ background: rgba(255, 255, 255, 0.25);
124
+ width: ${props.$orientation === 'horizontal' ? '2px' : '100%'};
125
+ height: ${props.$orientation === 'horizontal' ? '20px' : '2px'};
126
+ border-radius: 1px;
127
+ }
128
+
129
+ &:hover {
130
+ background: rgba(255, 255, 255, 0.2);
131
+ }
132
+
133
+ &:active {
134
+ opacity: 0.8;
135
+ }
136
+ ` : `
137
+ /* Normal mode: simple line with tight spacing */
138
+ background: rgba(255, 255, 255, 0.25);
139
+ width: ${props.$orientation === 'horizontal' ? '1px' : '100%'};
140
+ height: ${props.$orientation === 'horizontal' ? '24px' : '1px'};
141
+ margin: ${props.$orientation === 'horizontal' ? '0 2px' : '2px 0'};
142
+ `}
143
+ `;
105
144
  export const MenuButton = styled.button `
106
145
  display: flex;
107
146
  align-items: center;
@@ -6,6 +6,7 @@ export interface TMFloatingMenuItem {
6
6
  onClick: () => void;
7
7
  disabled?: boolean;
8
8
  isPinned?: boolean;
9
+ isSeparator?: boolean;
9
10
  }
10
11
  export interface TMFloatingMenuBarProps {
11
12
  containerRef: React.RefObject<HTMLElement | null>;
@@ -320,7 +320,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
320
320
  // other properties
321
321
  disabled: disabled, autoNavigateToFocusedRow: autoNavigateToFocusedRow, focusedRowKey: focusedRowKey, columnHidingEnabled: columnHidingEnabled, columnResizingMode: columnResizingMode, columnAutoWidth: columnAutoWidth, allowColumnResizing: allowColumnResizing, allowColumnReordering: allowColumnReordering, showBorders: showBorders, showRowLines: showRowLines, showColumnLines: showColumnLines, showColumnHeaders: showColumnHeaders, rowAlternationEnabled: rowAlternationEnabled, wordWrapEnabled: wordWrapEnabled, noDataText: noDataText,
322
322
  // styles
323
- width: width, height: height, style: { userSelect: 'none' }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column }, column.caption + index.toString()))), sorting && _jsx(Sorting, { ...sorting }), selection && _jsx(Selection, { ...selection }), scrolling && _jsx(Scrolling, { ...scrolling }), summary && _jsx(Summary, { ...summary }), showHeaderFilter && _jsx(HeaderFilter, { visible: true, ...headerFilter }), rowDragging && _jsx(RowDragging, { ...rowDragging }), filterRow && _jsx(FilterRow, { ...filterRow }), showFilterPanel && _jsx(FilterPanel, { visible: true }), showHeaderColumnChooser && _jsxs(ColumnChooser, { height: "400px", enabled: !showHeaderColumnChooser, mode: "select", children: [_jsx(Position, { my: "center", at: "center", of: window }), _jsx(ColumnChooserSearch, { enabled: true }), _jsx(ColumnChooserSelection, { allowSelectAll: false, selectByClick: true, recursive: true })] }), stateStoring && _jsx(StateStoring, { ...stateStoring }), groupPanel && _jsx(GroupPanel, { ...groupPanel }), _jsx(Grouping, { contextMenuEnabled: true, ...grouping }), _jsx(LoadPanel, { enabled: showLoadPanel }), _jsx(SearchPanel, { visible: showSearchPanel, searchVisibleColumnsOnly: true, highlightSearchText: true }), editing && _jsx(Editing, { ...editing }), paging && _jsx(Paging, { ...paging }), pager && _jsx(Pager, { ...pager, visible: totalRecordCount > pageSize }), masterDetail && _jsx(MasterDetail, { ...masterDetail })] }) }), counterConfig.show && _jsx("div", { style: { width: "100%", height: "25px", display: "flex", alignItems: "center", gap: "15px", backgroundColor: "#e0e0e0" }, children: _jsx(TMCounterContainer, { items: counterValues, bgColorContainer: counterConfig.bgColorContainer, bgColorItem: counterConfig.bgColorItem, hoverColorItem: counterConfig.hoverColorItem, textColorItem: counterConfig.textColorItem }) }), customContextMenuItems && (_jsx(TMContextMenu, { items: processCustomContextMenuItems(customContextMenuItems, customContextMenuRowKey), externalControl: {
323
+ width: width, height: height, style: { userSelect: 'none' }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column }, column.caption + index.toString()))), sorting && _jsx(Sorting, { ...sorting }), selection && _jsx(Selection, { ...selection }), scrolling && _jsx(Scrolling, { ...scrolling }), summary && _jsx(Summary, { ...summary }), showHeaderFilter && _jsx(HeaderFilter, { visible: true, ...headerFilter }), rowDragging && _jsx(RowDragging, { ...rowDragging }), filterRow && _jsx(FilterRow, { ...filterRow }), showFilterPanel && _jsx(FilterPanel, { visible: true }), showHeaderColumnChooser && _jsxs(ColumnChooser, { height: "400px", enabled: !showHeaderColumnChooser, mode: "select", children: [_jsx(Position, { my: "center", at: "center", of: window }), _jsx(ColumnChooserSearch, { enabled: true }), _jsx(ColumnChooserSelection, { allowSelectAll: false, selectByClick: true, recursive: true })] }), stateStoring && _jsx(StateStoring, { ...stateStoring }), groupPanel && _jsx(GroupPanel, { ...groupPanel }), _jsx(Grouping, { contextMenuEnabled: true, ...grouping }), _jsx(LoadPanel, { enabled: showLoadPanel }), _jsx(SearchPanel, { visible: showSearchPanel, searchVisibleColumnsOnly: true, highlightSearchText: true }), editing && _jsx(Editing, { ...editing }), paging && _jsx(Paging, { ...paging }), pager && _jsx(Pager, { ...pager, visible: totalRecordCount > pageSize }), masterDetail && _jsx(MasterDetail, { ...masterDetail })] }) }), counterConfig.show && _jsx("div", { style: { width: "100%", height: "25px", display: "flex", alignItems: "center", gap: "15px", backgroundColor: "#e0e0e0" }, children: _jsx(TMCounterContainer, { items: counterValues, bgColorContainer: counterConfig.bgColorContainer, bgColorItem: counterConfig.bgColorItem, hoverColorItem: counterConfig.hoverColorItem, textColorItem: counterConfig.textColorItem }) }), customContextMenuItems && (_jsx(TMContextMenu, { target: ".dx-data-row", items: processCustomContextMenuItems(customContextMenuItems, customContextMenuRowKey), externalControl: {
324
324
  visible: customContextMenuVisible,
325
325
  position: customContextMenuPosition,
326
326
  onClose: () => setCustomContextMenuVisible(false)
@@ -145,8 +145,8 @@ export const TMFileViewer = ({ fileBlob, isResizingActive }) => {
145
145
  setFormattedXml(undefined);
146
146
  const fileName = fileBlob.name || '';
147
147
  const fileExtension = fileName.split('.').pop()?.toLowerCase() || '';
148
- const isConfigFile = ['config', 'cfg'].includes(fileExtension);
149
- if (fileBlob.type.includes("xml") && !isConfigFile) {
148
+ const isTextBasedFile = ['config', 'cfg', 'sql'].includes(fileExtension);
149
+ if (fileBlob.type.includes("xml") && !isTextBasedFile) {
150
150
  fileBlob.text().then((text) => {
151
151
  const parser = new DOMParser();
152
152
  const xmlDoc = parser.parseFromString(text, "application/xml");
@@ -165,7 +165,7 @@ export const TMFileViewer = ({ fileBlob, isResizingActive }) => {
165
165
  });
166
166
  setBlobUrl(undefined);
167
167
  }
168
- else if (isConfigFile) {
168
+ else if (isTextBasedFile) {
169
169
  fileBlob.text().then((text) => {
170
170
  const escapedText = text
171
171
  .replace(/&/g, "&amp;")
@@ -92,7 +92,25 @@ const TMSignatureInfoContent = (props) => {
92
92
  if (!signerInfo) {
93
93
  return null;
94
94
  }
95
- return (_jsxs("div", { style: { lineHeight: "1.5em", overflowY: "auto", maxHeight: "500px", paddingRight: "8px", boxSizing: "border-box", userSelect: 'text' }, children: [signerInfo.shA256 && (_jsxs("div", { style: {
95
+ return (_jsxs("div", { style: { lineHeight: "1.5em", overflowY: "auto", maxHeight: "500px", paddingRight: "8px", boxSizing: "border-box", userSelect: 'text' }, children: [signerInfo.signers && signerInfo.signers.length > 0 ? (_jsxs("div", { children: [_jsxs("h4", { style: { margin: '0 0 12px 0', color: '#0078d4', fontSize: '16px' }, children: ["Firme digitali (", signerInfo.signers.length, ")"] }), signerInfo.signers.map((signer, idx) => (_jsxs("div", { style: {
96
+ border: "1px solid #d0d0d0",
97
+ borderRadius: "8px",
98
+ padding: "16px",
99
+ marginBottom: "12px",
100
+ background: "linear-gradient(135deg, #ffffff 0%, #f9f9f9 100%)",
101
+ boxShadow: "0 2px 4px rgba(0,0,0,0.08)",
102
+ userSelect: 'text',
103
+ }, children: [_jsxs("h3", { style: { margin: "0 0 12px", color: "#0078d4", fontSize: '15px', fontWeight: '600' }, children: ["Firma ", signer.levelAndIndex] }), _jsxs("div", { style: {
104
+ display: 'grid',
105
+ gap: '10px',
106
+ fontSize: '13px'
107
+ }, children: [_jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Intestatario:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info1 ?? '-' })] }), _jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Riferimento temporale:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info2 ?? '-' })] }), _jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Dettagli:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info3 ?? '-' })] })] })] }, idx)))] })) : (_jsx("div", { style: {
108
+ padding: '20px',
109
+ textAlign: 'center',
110
+ color: '#666',
111
+ background: '#f5f5f5',
112
+ borderRadius: '8px'
113
+ }, children: "Nessuna firma trovata" })), signerInfo.shA256 && (_jsxs("div", { style: {
96
114
  marginBottom: '12px',
97
115
  padding: '16px',
98
116
  background: '#f5f5f5',
@@ -117,24 +135,6 @@ const TMSignatureInfoContent = (props) => {
117
135
  gap: '4px',
118
136
  transition: 'all 0.2s ease',
119
137
  color: copiedHash ? '#155724' : '#666'
120
- }, title: "Copia", children: [_jsx(IconCopy, { width: 16, height: 16 }), copiedHash && _jsx("span", { style: { fontSize: '11px' }, children: "Copiato" })] })] }), _jsx("div", { style: { color: '#333' }, children: getHashValue() })] })] })), signerInfo.signers && signerInfo.signers.length > 0 ? (_jsxs("div", { children: [_jsxs("h4", { style: { margin: '0 0 12px 0', color: '#0078d4', fontSize: '16px' }, children: ["Firme digitali (", signerInfo.signers.length, ")"] }), signerInfo.signers.map((signer, idx) => (_jsxs("div", { style: {
121
- border: "1px solid #d0d0d0",
122
- borderRadius: "8px",
123
- padding: "16px",
124
- marginBottom: "12px",
125
- background: "linear-gradient(135deg, #ffffff 0%, #f9f9f9 100%)",
126
- boxShadow: "0 2px 4px rgba(0,0,0,0.08)",
127
- userSelect: 'text',
128
- }, children: [_jsxs("h3", { style: { margin: "0 0 12px", color: "#0078d4", fontSize: '15px', fontWeight: '600' }, children: ["Firma ", signer.levelAndIndex] }), _jsxs("div", { style: {
129
- display: 'grid',
130
- gap: '10px',
131
- fontSize: '13px'
132
- }, children: [_jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Intestatario:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info1 ?? '-' })] }), _jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Riferimento temporale:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info2 ?? '-' })] }), _jsxs("div", { children: [_jsx("strong", { style: { color: '#555' }, children: "Dettagli:" }), _jsx("div", { style: { marginTop: '4px', color: '#333' }, children: signer.info3 ?? '-' })] })] })] }, idx)))] })) : (_jsx("div", { style: {
133
- padding: '20px',
134
- textAlign: 'center',
135
- color: '#666',
136
- background: '#f5f5f5',
137
- borderRadius: '8px'
138
- }, children: "Nessuna firma trovata" }))] }));
138
+ }, title: "Copia", children: [_jsx(IconCopy, { width: 16, height: 16 }), copiedHash && _jsx("span", { style: { fontSize: '11px' }, children: "Copiato" })] })] }), _jsx("div", { style: { color: '#333' }, children: getHashValue() })] })] }))] }));
139
139
  };
140
140
  export default TMSignatureInfoContent;
@@ -276,4 +276,5 @@ export declare function IconCtrlWorkflow(props: React.SVGProps<SVGSVGElement>):
276
276
  export declare function IconBackhandIndexPointingRight(props: Readonly<React.SVGProps<SVGSVGElement>>): import("react/jsx-runtime").JSX.Element;
277
277
  export declare function IconMoveToFolder(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
278
278
  export declare function IconCustom(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
279
+ export declare function IconSeparator(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
279
280
  export { Icon123, IconABC, IconAccessPoint, IconAddressBook, IconSignCert, IconServerService, IconActivity, IconActivityLog, IconAdd, IconAddCircleOutline, IconAll, IconApply, IconApplyAndClose, IconArchive, IconArchiveDoc, IconArrowDown, IconArrowLeft, IconArrowRight, IconArrowUp, IconAtSign, IconAttachment, IconAutoConfig, IconBackward, IconBasket, IconBoard, IconBoxArchiveIn, IconBxInfo, IconBxLock, IconCalendar, IconCloseCircle, IconCloseOutline, IconCloud, IconCircleInfo, IconClear, IconColumns, IconCommand, IconCopy, IconCount, IconCrown, IconDashboard, IconDcmtType, IconDcmtTypeOnlyMetadata, IconDcmtTypeSys, IconDelete, IconDetails, IconDown, IconDownload, IconDotsVerticalCircleOutline, IconDuplicate, IconEdit, IconEqual, IconEqualNot, IconEraser, IconExpandRight, IconExport, IconFastBackward, IconFoldeAdd, IconFolderSearch, IconFolderZip, IconFastForward, IconFastSearch, IconFileDots, IconFilter, IconForceStop, IconForward, IconFreeze, IconFreeSearch, IconGreaterThan, IconGreaterThanOrEqual, IconHistory, IconImport, IconTag, IconInfo, IconInsertAbove, IconInsertBelow, IconHeart, IconHide, IconLanguage, IconLeft, IconLessThan, IconLessThanOrEqual, IconLock, IconLockClosed, IconLogin, IconLink, IconLogout, IconMail, IconMapping, IconMic, IconMenuHorizontal, IconMenuKebab, IconMenuVertical, IconMetadata, IconMetadata_Computed, IconMetadata_DataList, IconMetadata_Date, IconMetadata_DynamicDataList, IconMetadata_Numerator, IconMetadata_Numeric, IconMetadata_Special, IconMetadata_Text, IconMetadata_User, IconMonitor, IconOpenInNew, IconNotification, IconPassword, IconPencil, IconPlatform, IconPlay, IconPreview, IconPrinter, IconPrintOutline, IconProcess, IconProgressAbortRequested, IconProgressCompleted, IconProgressNotCompleted, IconProgressReady, IconProgressRunning, IconProgressStarted, IconRefresh, IconReset, IconRecentlyViewed, IconRight, IconSave, IconSearch, IconSelected, IconSettings, IconShow, IconSort, IconStop, IconStopwatch, IconSuccess, IconAlarmPlus, IconHourglass, IconNone, IconNotStarted, IconProgress, IconSuccessCirlce, IconSuitcase, IconSupport, IconUndo, IconUnFreeze, IconUp, IconUpdate, IconUpload, IconUser, IconUserProfile, IconVisible, IconWarning, IconWeb, IconWifi, IconWindowMaximize, IconWindowMinimize, IconWorkflow, IconWorkspace, IconUserGroup, IconUserGroupOutline, IconUserLevelMember, IconUserLevelAdministrator, IconUserLevelSystemAdministrator, IconUserLevelAutonomousAdministrator, IconDraggabledots, IconRelation, IconEasy, IconSum, IconDisk, IconDataList, IconPalette, IconFormatPageSplit, IconPaste, IconFileSearch, IconStar, IconStarRemove, IconSearchCheck, IconLightningFill, IconArrowUnsorted, IconArrowSortedUp, IconArrowSortedDown, IconConvertFilePdf, IconExportTo, IconSharedDcmt, IconShare, IconBatchUpdate, IconCheckFile, IconStatistics, IconSubstFile, IconAdvanced, IconSync, IconSavedQuery, IconSignature, IconSignaturePencil, IconRecursiveOps, IconCheckIn, IconTree, IconGrid, IconList, IconFolder, IconFolderOpen, IconFactory, IconTest, IconCheck, IconUncheck, IconSortAsc, IconSortDesc, IconRoundFileUpload, IconSortAscLetters, IconSortDescLetters, IconRotate, IconSortAscNumbers, IconSortDescNumbers, IconSortAscClock, IconSortDescClock, IconLayerGroup, IconBell, IconBellCheck, IconBellOutline, IconBellCheckOutline, IconEnvelopeOpenText, IconChangeUser, IconUserCheck, IconRelationManyToMany, IconRelationOneToMany, IconUserExpired, IconKey, IconZoomInLinear, IconZoomOutLinear, IconMenuCAWorkingGroups, IconCADossier, IconMenuCACaseflow, IconMenuDashboard, IconMenuCAAreas, IconMenuTask, IconMenuSearch, IconMenuFullTextSearch, IconMenuFavourite, IconSAPLogin, IconSAPLogin2, IconView, IconNewSignature };
@@ -690,4 +690,7 @@ export function IconMoveToFolder(props) {
690
690
  export function IconCustom(props) {
691
691
  return (_jsx("svg", { fontSize: props.fontSize ?? FONTSIZE, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", ...props, children: _jsx("path", { fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeMiterlimit: "10", strokeWidth: "1.5", d: "M14 17h6m-3 3v-6M5.6 4h2.8A1.6 1.6 0 0 1 10 5.6v2.8A1.6 1.6 0 0 1 8.4 10H5.6A1.6 1.6 0 0 1 4 8.4V5.6A1.6 1.6 0 0 1 5.6 4m0 10h2.8a1.6 1.6 0 0 1 1.6 1.6v2.8A1.6 1.6 0 0 1 8.4 20H5.6A1.6 1.6 0 0 1 4 18.4v-2.8A1.6 1.6 0 0 1 5.6 14m10-10h2.8A1.6 1.6 0 0 1 20 5.6v2.8a1.6 1.6 0 0 1-1.6 1.6h-2.8A1.6 1.6 0 0 1 14 8.4V5.6A1.6 1.6 0 0 1 15.6 4" }) }));
692
692
  }
693
+ export function IconSeparator(props) {
694
+ return (_jsx("svg", { fontSize: props.fontSize ?? FONTSIZE, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", style: { transform: 'rotate(90deg)', ...props.style }, ...props, children: _jsxs("g", { fill: "currentColor", children: [_jsx("path", { d: "M16 5a1 1 0 1 0 0-2H8a1 1 0 1 0 0 2zm0 2a1 1 0 1 1 0 2H8a1 1 0 1 1 0-2zm1 5a1 1 0 0 1-1 1H8a1 1 0 1 1 0-2h8a1 1 0 0 1 1 1m-1 9a1 1 0 1 0 0-2H8a1 1 0 1 0 0 2z", opacity: ".5" }), _jsx("path", { fillRule: "evenodd", d: "M21 16a1 1 0 0 1-1 1H4a1 1 0 1 1 0-2h16a1 1 0 0 1 1 1", clipRule: "evenodd" })] }) }));
695
+ }
693
696
  export { Icon123, IconABC, IconAccessPoint, IconAddressBook, IconSignCert, IconServerService, IconActivity, IconActivityLog, IconAdd, IconAddCircleOutline, IconAll, IconApply, IconApplyAndClose, IconArchive, IconArchiveDoc, IconArrowDown, IconArrowLeft, IconArrowRight, IconArrowUp, IconAtSign, IconAttachment, IconAutoConfig, IconBackward, IconBasket, IconBoard, IconBoxArchiveIn, IconBxInfo, IconBxLock, IconCalendar, IconCloseCircle, IconCloseOutline, IconCloud, IconCircleInfo, IconClear, IconColumns, IconCommand, IconCopy, IconCount, IconCrown, IconDashboard, IconDcmtType, IconDcmtTypeOnlyMetadata, IconDcmtTypeSys, IconDelete, IconDetails, IconDown, IconDownload, IconDotsVerticalCircleOutline, IconDuplicate, IconEdit, IconEqual, IconEqualNot, IconEraser, IconExpandRight, IconExport, IconFastBackward, IconFoldeAdd, IconFolderSearch, IconFolderZip, IconFastForward, IconFastSearch, IconFileDots, IconFilter, IconForceStop, IconForward, IconFreeze, IconFreeSearch, IconGreaterThan, IconGreaterThanOrEqual, IconHistory, IconImport, IconTag, IconInfo, IconInsertAbove, IconInsertBelow, IconHeart, IconHide, IconLanguage, IconLeft, IconLessThan, IconLessThanOrEqual, IconLock, IconLockClosed, IconLogin, IconLink, IconLogout, IconMail, IconMapping, IconMic, IconMenuHorizontal, IconMenuKebab, IconMenuVertical, IconMetadata, IconMetadata_Computed, IconMetadata_DataList, IconMetadata_Date, IconMetadata_DynamicDataList, IconMetadata_Numerator, IconMetadata_Numeric, IconMetadata_Special, IconMetadata_Text, IconMetadata_User, IconMonitor, IconOpenInNew, IconNotification, IconPassword, IconPencil, IconPlatform, IconPlay, IconPreview, IconPrinter, IconPrintOutline, IconProcess, IconProgressAbortRequested, IconProgressCompleted, IconProgressNotCompleted, IconProgressReady, IconProgressRunning, IconProgressStarted, IconRefresh, IconReset, IconRecentlyViewed, IconRight, IconSave, IconSearch, IconSelected, IconSettings, IconShow, IconSort, IconStop, IconStopwatch, IconSuccess, IconAlarmPlus, IconHourglass, IconNone, IconNotStarted, IconProgress, IconSuccessCirlce, IconSuitcase, IconSupport, IconUndo, IconUnFreeze, IconUp, IconUpdate, IconUpload, IconUser, IconUserProfile, IconVisible, IconWarning, IconWeb, IconWifi, IconWindowMaximize, IconWindowMinimize, IconWorkflow, IconWorkspace, IconUserGroup, IconUserGroupOutline, IconUserLevelMember, IconUserLevelAdministrator, IconUserLevelSystemAdministrator, IconUserLevelAutonomousAdministrator, IconDraggabledots, IconRelation, IconEasy, IconSum, IconDisk, IconDataList, IconPalette, IconFormatPageSplit, IconPaste, IconFileSearch, IconStar, IconStarRemove, IconSearchCheck, IconLightningFill, IconArrowUnsorted, IconArrowSortedUp, IconArrowSortedDown, IconConvertFilePdf, IconExportTo, IconSharedDcmt, IconShare, IconBatchUpdate, IconCheckFile, IconStatistics, IconSubstFile, IconAdvanced, IconSync, IconSavedQuery, IconSignature, IconSignaturePencil, IconRecursiveOps, IconCheckIn, IconTree, IconGrid, IconList, IconFolder, IconFolderOpen, IconFactory, IconTest, IconCheck, IconUncheck, IconSortAsc, IconSortDesc, IconRoundFileUpload, IconSortAscLetters, IconSortDescLetters, IconRotate, IconSortAscNumbers, IconSortDescNumbers, IconSortAscClock, IconSortDescClock, IconLayerGroup, IconBell, IconBellCheck, IconBellOutline, IconBellCheckOutline, IconEnvelopeOpenText, IconChangeUser, IconUserCheck, IconRelationManyToMany, IconRelationOneToMany, IconUserExpired, IconKey, IconZoomInLinear, IconZoomOutLinear, IconMenuCAWorkingGroups, IconCADossier, IconMenuCACaseflow, IconMenuDashboard, IconMenuCAAreas, IconMenuTask, IconMenuSearch, IconMenuFullTextSearch, IconMenuFavourite, IconSAPLogin, IconSAPLogin2, IconView, IconNewSignature };
@@ -505,7 +505,8 @@ export const extensionHandler = (fileExt) => {
505
505
  case 'txt': return FileExtensionHandler.READY_TO_SHOW;
506
506
  case 'config':
507
507
  case 'cfg':
508
- case 'json': return FileExtensionHandler.READY_TO_SHOW;
508
+ case 'json':
509
+ case 'sql': return FileExtensionHandler.READY_TO_SHOW;
509
510
  default: return FileExtensionHandler.NONE;
510
511
  }
511
512
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.20.0-dev1.57",
3
+ "version": "6.20.0-dev1.59",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -40,7 +40,7 @@
40
40
  "lib"
41
41
  ],
42
42
  "dependencies": {
43
- "@topconsultnpm/sdk-ts": "6.20.0-dev1.3",
43
+ "@topconsultnpm/sdk-ts": "6.20.0-dev1.4",
44
44
  "buffer": "^6.0.3",
45
45
  "devextreme": "25.1.7",
46
46
  "devextreme-react": "25.1.7",