@topconsultnpm/sdkui-react 6.20.0-dev1.61 → 6.20.0-dev1.63

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.
@@ -20,6 +20,41 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
20
20
  const longPressTimeoutRef = useRef(null);
21
21
  const touchStartPos = useRef(null);
22
22
  const { openLeft, openUp, isCalculated } = useMenuPosition(menuRef, menuState.position);
23
+ // Adjust menu position on mobile to prevent overflow
24
+ useEffect(() => {
25
+ if (!isMobile || !menuState.visible || !menuRef.current)
26
+ return;
27
+ const adjustPosition = () => {
28
+ const menuElement = menuRef.current;
29
+ if (!menuElement)
30
+ return;
31
+ const menuRect = menuElement.getBoundingClientRect();
32
+ const viewportHeight = window.innerHeight;
33
+ const currentY = menuState.position.y;
34
+ // Check if menu overflows bottom of viewport
35
+ const menuBottom = currentY + menuRect.height;
36
+ const overflowBottom = menuBottom - viewportHeight;
37
+ if (overflowBottom > 0) {
38
+ // Calculate new Y position to fit menu in viewport
39
+ let newY = currentY - overflowBottom - 10; // 10px padding from edge
40
+ // Ensure menu doesn't go above viewport top
41
+ if (newY < 10) {
42
+ newY = 10;
43
+ }
44
+ // Only update if position actually changed
45
+ if (newY !== currentY) {
46
+ setMenuState(prev => ({
47
+ ...prev,
48
+ position: { ...prev.position, y: newY }
49
+ }));
50
+ }
51
+ }
52
+ };
53
+ // Wait for menu to render before adjusting
54
+ requestAnimationFrame(() => {
55
+ requestAnimationFrame(adjustPosition);
56
+ });
57
+ }, [isMobile, menuState.visible, menuState.position.y]);
23
58
  const handleClose = () => {
24
59
  if (externalControl) {
25
60
  externalControl.onClose();
@@ -1,8 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState, forwardRef, useRef, useImperativeHandle } from 'react';
3
3
  import styled from 'styled-components';
4
- import ContextMenu from 'devextreme-react/context-menu';
5
- import { FontSize, TMColors } from '../../utils/theme';
4
+ import { ContextMenu as TMContextMenu } from '../NewComponents/ContextMenu';
5
+ import { TMColors } from '../../utils/theme';
6
6
  import { genUniqueId } from '../../helper';
7
7
  const StyledContent = styled.div `
8
8
  cursor: pointer;
@@ -22,14 +22,6 @@ const StyledContent = styled.div `
22
22
  border-bottom-color: ${TMColors.primary};
23
23
  }
24
24
  `;
25
- const StyledMenuItem = styled.div `
26
- display: flex;
27
- align-items: center;
28
- justify-content: space-between;
29
- gap: 6px;
30
- width: 100%;
31
- font-size: ${FontSize.defaultFontSize};
32
- `;
33
25
  const TMDropDownMenu = forwardRef(({ content, items, disabled = false, color = TMColors.text_normal, backgroundColor = TMColors.default_background, borderRadius, onMenuShown }, ref) => {
34
26
  const [id, setID] = useState('');
35
27
  const dropDownMenuElementRef = useRef(null); // Ref all'elemento DOM div principale
@@ -39,7 +31,32 @@ const TMDropDownMenu = forwardRef(({ content, items, disabled = false, color = T
39
31
  dropDownMenuElementRef.current?.focus();
40
32
  },
41
33
  }));
42
- const renderItemTemplate = (itemData) => (_jsxs(StyledMenuItem, { children: [itemData.icon && _jsx("div", { style: { display: 'flex', alignItems: 'center' }, children: itemData.icon }), _jsx("span", { style: { flexGrow: 1 }, children: itemData.text }), itemData.items && _jsx("span", { className: "dx-icon-spinright dx-icon", style: { marginLeft: '10px' } })] }));
43
- return (_jsxs(_Fragment, { children: [_jsx(StyledContent, { id: `idContainer${id}`, ref: dropDownMenuElementRef, tabIndex: disabled ? -1 : 0, "$disabled": disabled, "$color": color, "$backgroundColor": backgroundColor, "$borderRadius": borderRadius, children: content }), _jsx(ContextMenu, { target: `#idContainer${id}`, dataSource: items, showEvent: 'click', itemRender: renderItemTemplate, onShown: (e) => onMenuShown?.(), onHidden: (e) => dropDownMenuElementRef.current?.focus() })] }));
34
+ // Converter function: ITMDropDownMenuItem -> TMContextMenuItemProps
35
+ const convertToContextMenuItems = (dropDownItems) => {
36
+ if (!dropDownItems)
37
+ return [];
38
+ return dropDownItems.map(item => ({
39
+ name: item.text,
40
+ icon: item.icon,
41
+ disabled: item.disabled,
42
+ beginGroup: item.beginGroup,
43
+ onClick: item.onClick,
44
+ submenu: item.items ? convertToContextMenuItems(item.items) : undefined,
45
+ }));
46
+ };
47
+ const [menuVisible, setMenuVisible] = useState(false);
48
+ const handleMenuOpen = () => {
49
+ setMenuVisible(true);
50
+ onMenuShown?.();
51
+ };
52
+ const handleMenuClose = () => {
53
+ setMenuVisible(false);
54
+ dropDownMenuElementRef.current?.focus();
55
+ };
56
+ return (_jsxs(_Fragment, { children: [_jsx(StyledContent, { id: `idContainer${id}`, ref: dropDownMenuElementRef, tabIndex: disabled ? -1 : 0, "$disabled": disabled, "$color": color, "$backgroundColor": backgroundColor, "$borderRadius": borderRadius, onClick: !disabled ? handleMenuOpen : undefined, children: content }), _jsx(TMContextMenu, { items: convertToContextMenuItems(items), target: `#idContainer${id}`, trigger: "left", externalControl: {
57
+ visible: menuVisible,
58
+ position: { x: 0, y: 0 },
59
+ onClose: handleMenuClose,
60
+ } })] }));
44
61
  });
45
62
  export default TMDropDownMenu;
@@ -133,7 +133,7 @@ onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged },
133
133
  };
134
134
  return (_jsxs(StyledPanelContainer, { ref: panelRef, "$isMaximized": onMaximize ? false : isMaximized, style: {
135
135
  visibility: isVisible ? 'visible' : 'hidden',
136
- }, tabIndex: -1, onFocus: !isControlled ? handleFocusUncontrolled : undefined, onBlur: !isControlled ? handleBlurUncontrolled : undefined, onClick: handleActivation, children: [showHeader &&
136
+ }, tabIndex: -1, onFocus: !isControlled ? handleFocusUncontrolled : undefined, onBlur: !isControlled ? handleBlurUncontrolled : undefined, onClick: handleActivation, onContextMenu: (e) => e.preventDefault(), children: [showHeader &&
137
137
  _jsx(StyledPanelHeader, { "$backgroundColor": backgroundColor, "$color": color, "$isActive": currentIsActive, onDoubleClick: () => {
138
138
  if (onHeaderDoubleClick)
139
139
  onHeaderDoubleClick();
@@ -593,7 +593,7 @@ const TMSearchResult = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, a
593
593
  currentTIDHasDetailRelations, canArchiveMasterRelation, canArchiveDetailRelation,
594
594
  hasManyToManyRelation, customButtonsLayout
595
595
  ]);
596
- const searchResutlToolbar = _jsxs(_Fragment, { children: [(dcmtsReturned != dcmtsFound) && _jsx("p", { style: { backgroundColor: `white`, color: TMColors.primaryColor, textAlign: 'center', padding: '1px 4px', borderRadius: '3px', display: 'flex' }, children: `${dcmtsReturned}/${dcmtsFound} restituiti` }), context === SearchResultContext.FAVORITES_AND_RECENTS &&
596
+ const searchResutlToolbar = _jsxs(_Fragment, { children: [(dcmtsReturned != dcmtsFound) && _jsx("p", { style: { textAlign: 'center', padding: '1px 4px', borderRadius: '3px', display: 'flex' }, children: `${dcmtsReturned}/${dcmtsFound} restituiti` }), context === SearchResultContext.FAVORITES_AND_RECENTS &&
597
597
  _jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconDelete, { color: 'white' }), caption: "Rimuovi da " + (selectedSearchResult?.category === "Favorites" ? '"Preferiti"' : '"Recenti"'), disabled: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length <= 0, onClick: removeDcmtFromFavsOrRecents }) }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick: onRefreshSearchAsync }), _jsx(TMContextMenu, { items: floatingMenuItems, trigger: "left", children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) })] });
598
598
  const tmSearchResult = useMemo(() => (!searchResults || searchResults.length <= 0)
599
599
  ? _jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%' }, children: [_jsx(IconBoard, { fontSize: 96 }), _jsx("div", { style: { fontSize: "15px", marginTop: "10px" }, children: SDKUI_Localizator.NoDcmtFound }), openAddDocumentForm && _jsx("div", { style: { marginTop: "10px" }, children: _jsx(TMButton, { fontSize: "15px", icon: _jsx("i", { className: 'dx-icon-share' }), caption: SDKUI_Localizator.Share, onClick: openAddDocumentForm }) })] })
@@ -1,9 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import styled from 'styled-components';
3
3
  import { useCallback, useEffect, useState } from 'react';
4
- import ReactDOMServer from 'react-dom/server';
5
4
  import { DcmtTypeListCacheService } from '@topconsultnpm/sdk-ts';
6
- import ContextMenu from 'devextreme-react/context-menu';
5
+ import { ContextMenu as TMContextMenu } from '../NewComponents/ContextMenu';
7
6
  import { IconDelete, SDKUI_Localizator, IconApply, IconInfo, IconCloseOutline } from '../../helper';
8
7
  import { TMColors } from '../../utils/theme';
9
8
  import { DeviceType } from '../base/TMDeviceProvider';
@@ -62,11 +61,15 @@ const StyledRecentTidItem = styled.div `
62
61
  margin-bottom: 0;
63
62
  }
64
63
  `;
65
- const iconDelete = () => ReactDOMServer.renderToString(_jsx(IconDelete, {}));
66
64
  const TMRecentsManager = ({ deviceType, mruTIDs, currentMruTID, accessFilter = 'all', onSelectedTID, onDeletedTID }) => {
67
65
  const [showDcmtTypeChooser, setShowDcmtTypeChooser] = useState(false);
68
66
  const [recentDcmtTypes, setRecentDcmtTypes] = useState([]);
69
67
  const [infoDTD, setInfoDTD] = useState();
68
+ const [contextMenuState, setContextMenuState] = useState({
69
+ visible: false,
70
+ position: { x: 0, y: 0 },
71
+ tid: null
72
+ });
70
73
  // Handler for the cache refresh event
71
74
  const handleCacheRefresh = useCallback(async () => {
72
75
  // Retrieve all document types without metadata from the refreshed cache
@@ -114,7 +117,10 @@ const TMRecentsManager = ({ deviceType, mruTIDs, currentMruTID, accessFilter = '
114
117
  textOverflow: 'ellipsis'
115
118
  }, children: `${SDKUI_Localizator.AllDcmtTypes} (${DcmtTypeListCacheService.CacheCount(true, accessFilter)})` }) }) }, 0), recentDcmtTypes.map((dtd) => {
116
119
  const isCurrent = currentMruTID == dtd.id;
117
- return (_jsxs(StyledRecentTidItem, { id: `tid-${dtd.id}`, "$isMobile": isMobile, onClick: () => { onSelectedTID?.(dtd.id ?? 0); }, children: [_jsxs(StyledDivHorizontal, { style: { alignItems: 'center', gap: 8, width: '100%' }, children: [!isMobile && (_jsx("span", { className: "info-icon", style: {
120
+ return (_jsxs(StyledRecentTidItem, { id: `tid-${dtd.id}`, "$isMobile": isMobile, onClick: () => { onSelectedTID?.(dtd.id ?? 0); }, onContextMenu: (e) => {
121
+ e.preventDefault();
122
+ setContextMenuState({ visible: true, position: { x: e.clientX, y: e.clientY }, tid: dtd.id ?? null });
123
+ }, children: [_jsxs(StyledDivHorizontal, { style: { alignItems: 'center', gap: 8, width: '100%' }, children: [!isMobile && (_jsx("span", { className: "info-icon", style: {
118
124
  marginRight: 4,
119
125
  display: 'flex',
120
126
  alignItems: 'center'
@@ -135,20 +141,24 @@ const TMRecentsManager = ({ deviceType, mruTIDs, currentMruTID, accessFilter = '
135
141
  fontWeight: 'bold',
136
142
  marginLeft: 8,
137
143
  visibility: isCurrent ? 'visible' : 'hidden'
138
- }, children: _jsx(IconApply, { fontSize: 24, color: 'green' }) })] }), _jsx(ContextMenu, { dataSource: [
144
+ }, children: _jsx(IconApply, { fontSize: 24, color: 'green' }) })] }), contextMenuState.tid === dtd.id && (_jsx(TMContextMenu, { items: [
139
145
  {
140
- text: SDKUI_Localizator.Remove,
141
- icon: iconDelete(),
146
+ name: SDKUI_Localizator.Remove,
147
+ icon: _jsx(IconDelete, {}),
142
148
  onClick: () => { onDeletedTID?.(dtd.id ?? 0); }
143
149
  },
144
150
  ...(isMobile ? [
145
151
  {
146
- text: SDKUI_Localizator.About,
147
- icon: ReactDOMServer.renderToString(_jsx(IconInfo, { color: TMColors.info })),
152
+ name: SDKUI_Localizator.About,
153
+ icon: _jsx(IconInfo, { color: TMColors.info }),
148
154
  onClick: () => { setInfoDTD(dtd); }
149
155
  }
150
156
  ] : [])
151
- ], target: `#tid-${dtd.id}` })] }, dtd.id));
157
+ ], target: `#tid-${dtd.id}`, externalControl: {
158
+ visible: contextMenuState.visible,
159
+ position: contextMenuState.position,
160
+ onClose: () => setContextMenuState({ visible: false, position: { x: 0, y: 0 }, tid: null })
161
+ } }))] }, dtd.id));
152
162
  })] }), showDcmtTypeChooser &&
153
163
  _jsx(TMDcmtTypeChooserForm, { accessFilter: accessFilter, onClose: () => setShowDcmtTypeChooser(false), onChoose: (tids) => { onSelectedTID?.(tids?.[0] ?? 0); } }), _jsxs(StyledOffCanvasPanel, { ref: panelRef, "$isOpen": isMobile && infoDTD !== undefined, children: [_jsxs(StyledDivHorizontal, { style: { gap: 10, padding: '10px 8px', width: '100%', alignItems: 'center' }, children: [_jsx("p", { style: { fontSize: '1.1rem', fontWeight: 'bold' }, children: `${SDKUI_Localizator.DcmtType} - ${SDKUI_Localizator.About}` }), _jsx(IconCloseOutline, { style: { marginLeft: 'auto', cursor: 'pointer' }, onClick: () => setInfoDTD(undefined) })] }), renderDTDTooltipContent(infoDTD)] })] }));
154
164
  };
@@ -16,6 +16,7 @@ export * from './base/TMTreeView';
16
16
  export * from './base/TMPanel';
17
17
  export * from './base/TMResizableMenu';
18
18
  export * from './base/TMAccordionNew';
19
+ export * from './NewComponents/ContextMenu';
19
20
  export { default as CounterBar } from './base/TMCounterBar';
20
21
  export { default as TMProgressBar } from './base/TMProgressBar';
21
22
  export { default as TMSpinner } from './base/TMSpinner';
@@ -17,6 +17,7 @@ export * from './base/TMTreeView';
17
17
  export * from './base/TMPanel';
18
18
  export * from './base/TMResizableMenu';
19
19
  export * from './base/TMAccordionNew';
20
+ export * from './NewComponents/ContextMenu';
20
21
  export { default as CounterBar } from './base/TMCounterBar';
21
22
  export { default as TMProgressBar } from './base/TMProgressBar';
22
23
  export { default as TMSpinner } from './base/TMSpinner';
@@ -84,6 +84,7 @@ export declare class SDKUI_Localizator {
84
84
  static get CancelCheckOut(): string;
85
85
  static get CassettoDoganaleExportMRN(): "MRN-Erholung für den Export" | "MRN recovery for export" | "Recuperación MRN para exportación" | "Récupération MRN pour l'export" | "Recuperação MRN para exportação" | "Recupero MRN per Export";
86
86
  static get CassettoDoganaleExportVU(): "Wiederherstellung des Ausreisevisums" | "Exit Visa Recovery" | "Recuperación de Visa de Salida" | "Sortie Récupération Visa" | "Recuperação de Visto de Saída" | "Recupero Visto Uscire per Export";
87
+ static get CassettoDoganaleExportEUR1(): "EUR1-Erholung für den Export" | "EUR1 recovery for export" | "Recuperación EUR1 para exportación" | "Récupération EUR1 pour l'export" | "Recuperação EUR1 para exportação" | "Recupero EUR1 per Export";
87
88
  static get CassettoDoganaleImportMRN(): "MRN-Erholung für den Import" | "MRN recovery for import" | "Recuperación MRN para importación" | "Récupération MRN à l'import" | "Recuperação MRN para importação" | "Recupero MRN per Import";
88
89
  static get CassettoDoganalePlus_UserName(): "STD-Benutzer des ADM-Portals" | "STD User of the ADM Portal" | "Usuario STD del Portal ADM" | "Utilisateur STD du portail ADM" | "Utilizador DST do Portal ADM" | "Utente STD del Portale ADM";
89
90
  static get Cancel(): "Abbrechen" | "Cancel" | "Anular" | "Annuler" | "Cancelar" | "Annulla";
@@ -246,6 +247,8 @@ export declare class SDKUI_Localizator {
246
247
  static get ExpertMode(): "Expertenmodus" | "Expert mode" | "Modo experto" | "Mode expert" | "Modo especialista" | "Modalità esperto";
247
248
  static get Expiring(): "Ablaufend" | "Expiring" | "Por vencer" | "Expirant" | "Vencendo" | "In scadenza";
248
249
  static get Export(): "Exportieren" | "Export" | "Exportar" | "Exporter" | "Esporta";
250
+ static get ExportEUR1(): "Exportieren EUR1" | "Export EUR1" | "Exportar EUR1" | "Exporter EUR1" | "Export - EUR1";
251
+ static get ExportEUR1OutputFile(): "Dateipfad für den Export (EUR1)" | "File Path for Export (EUR1)" | "Ruta de archivo para exportación (EUR1)" | "Chemin du fichier à exporter (EUR1)" | "Caminho do arquivo para exportação (EUR1)" | "Percorso del File per Export (EUR1)";
249
252
  static get ExportTo(): string;
250
253
  static get ExportMRN(): "Exportieren MRN" | "Export MRN" | "Exportar MRN" | "Exporter MRN";
251
254
  static get ExportMRNDayBack(): "Anzahl der Tage für die Exportdatenwiederherstellung (MRN)" | "Number of days for export data recovery (MRN)" | "Número de días para la recuperación de datos de exportación (MRN)" | "Nombre de jours pour la récupération des données d'exportation (MRN)" | "Número de dias para recuperação de dados de exportação (MRN)" | "Numero di giorni per il recupero dei dati di Export (MRN)";
@@ -795,6 +795,16 @@ export class SDKUI_Localizator {
795
795
  default: return "Recupero Visto Uscire per Export";
796
796
  }
797
797
  }
798
+ static get CassettoDoganaleExportEUR1() {
799
+ switch (this._cultureID) {
800
+ case CultureIDs.De_DE: return "EUR1-Erholung für den Export";
801
+ case CultureIDs.En_US: return "EUR1 recovery for export";
802
+ case CultureIDs.Es_ES: return "Recuperación EUR1 para exportación";
803
+ case CultureIDs.Fr_FR: return "Récupération EUR1 pour l'export";
804
+ case CultureIDs.Pt_PT: return "Recuperação EUR1 para exportação";
805
+ default: return "Recupero EUR1 per Export";
806
+ }
807
+ }
798
808
  static get CassettoDoganaleImportMRN() {
799
809
  switch (this._cultureID) {
800
810
  case CultureIDs.De_DE: return "MRN-Erholung für den Import";
@@ -2427,6 +2437,26 @@ export class SDKUI_Localizator {
2427
2437
  default: return "Esporta";
2428
2438
  }
2429
2439
  }
2440
+ static get ExportEUR1() {
2441
+ switch (this._cultureID) {
2442
+ case CultureIDs.De_DE: return "Exportieren EUR1";
2443
+ case CultureIDs.En_US: return "Export EUR1";
2444
+ case CultureIDs.Es_ES: return "Exportar EUR1";
2445
+ case CultureIDs.Fr_FR: return "Exporter EUR1";
2446
+ case CultureIDs.Pt_PT: return "Exportar EUR1";
2447
+ default: return "Export - EUR1";
2448
+ }
2449
+ }
2450
+ static get ExportEUR1OutputFile() {
2451
+ switch (this._cultureID) {
2452
+ case CultureIDs.De_DE: return "Dateipfad für den Export (EUR1)";
2453
+ case CultureIDs.En_US: return "File Path for Export (EUR1)";
2454
+ case CultureIDs.Es_ES: return "Ruta de archivo para exportación (EUR1)";
2455
+ case CultureIDs.Fr_FR: return "Chemin du fichier à exporter (EUR1)";
2456
+ case CultureIDs.Pt_PT: return "Caminho do arquivo para exportação (EUR1)";
2457
+ default: return "Percorso del File per Export (EUR1)";
2458
+ }
2459
+ }
2430
2460
  static get ExportTo() {
2431
2461
  switch (this._cultureID) {
2432
2462
  case CultureIDs.De_DE: return "Exportieren nach...";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.20.0-dev1.61",
3
+ "version": "6.20.0-dev1.63",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",