@topconsultnpm/sdkui-react 6.20.0-dev1.67 → 6.20.0-dev1.69

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.
@@ -59,6 +59,8 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
59
59
  const touchEvent = e;
60
60
  const element = e.currentTarget;
61
61
  const touch = touchEvent.touches[0];
62
+ // Prevent text selection during long press
63
+ e.preventDefault();
62
64
  let state = touchStateMap.get(element);
63
65
  if (!state) {
64
66
  state = { timeout: null, startX: 0, startY: 0, longPressTriggered: false };
@@ -119,17 +121,25 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
119
121
  state.longPressTriggered = false;
120
122
  }
121
123
  };
124
+ // Prevent default iOS context menu
125
+ const handleContextMenu = (e) => {
126
+ e.preventDefault();
127
+ e.stopPropagation();
128
+ return false;
129
+ };
122
130
  // Attach listeners to all matching elements
123
131
  elements.forEach(element => {
124
132
  const el = element;
125
- // Prevent iOS native callout
133
+ // Prevent iOS native callout and text selection
126
134
  const style = el.style;
127
135
  style.webkitTouchCallout = 'none';
128
136
  style.webkitUserSelect = 'none';
137
+ style.userSelect = 'none';
129
138
  el.addEventListener('touchstart', handleTouchStart, { passive: true });
130
139
  el.addEventListener('touchmove', handleTouchMove, { passive: true });
131
140
  el.addEventListener('touchend', handleTouchEnd);
132
141
  el.addEventListener('touchcancel', handleTouchEnd);
142
+ el.addEventListener('contextmenu', handleContextMenu);
133
143
  el.addEventListener('click', handleClick, { capture: true });
134
144
  });
135
145
  return () => {
@@ -138,10 +148,12 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
138
148
  const style = el.style;
139
149
  style.webkitTouchCallout = '';
140
150
  style.webkitUserSelect = '';
151
+ style.userSelect = '';
141
152
  el.removeEventListener('touchstart', handleTouchStart);
142
153
  el.removeEventListener('touchmove', handleTouchMove);
143
154
  el.removeEventListener('touchend', handleTouchEnd);
144
155
  el.removeEventListener('touchcancel', handleTouchEnd);
156
+ el.removeEventListener('contextmenu', handleContextMenu);
145
157
  el.removeEventListener('click', handleClick, { capture: true });
146
158
  });
147
159
  };
@@ -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, IconSeparator, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
7
+ import { IconAdd, IconCloseOutline, IconMenuVertical, IconPin, IconSave, IconSeparator, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
8
+ import { ButtonNames, TMMessageBoxManager } from '../../base/TMPopUp';
8
9
  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" }) }));
9
10
  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" }) }));
10
11
  const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 100, }) => {
@@ -603,6 +604,45 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
603
604
  const snapshotIds = stateSnapshot.current.items.map(i => i.id).join(',');
604
605
  return currentIds !== snapshotIds;
605
606
  };
607
+ const handleClose = () => {
608
+ // If all items removed, exit without asking and restore last items
609
+ if (state.items.length === 0 && stateSnapshot.current) {
610
+ setState(s => ({
611
+ ...s,
612
+ items: [...stateSnapshot.current.items],
613
+ orientation: stateSnapshot.current.orientation,
614
+ position: { ...stateSnapshot.current.position },
615
+ isConfigMode: false,
616
+ }));
617
+ stateSnapshot.current = null;
618
+ return;
619
+ }
620
+ // If no changes, simply exit config mode
621
+ if (!hasChanges()) {
622
+ stateSnapshot.current = null;
623
+ const cleanedItems = removeTrailingSeparators(state.items);
624
+ setState(s => ({ ...s, isConfigMode: false, items: cleanedItems }));
625
+ return;
626
+ }
627
+ // If there are changes, ask for confirmation
628
+ TMMessageBoxManager.show({
629
+ message: 'Perderai le tue modifiche, sei sicuro?',
630
+ buttons: [ButtonNames.YES, ButtonNames.NO],
631
+ onButtonClick: (buttonName) => {
632
+ if (buttonName === ButtonNames.YES && stateSnapshot.current) {
633
+ // Restore snapshot and exit config mode
634
+ setState(s => ({
635
+ ...s,
636
+ items: [...stateSnapshot.current.items],
637
+ orientation: stateSnapshot.current.orientation,
638
+ position: { ...stateSnapshot.current.position },
639
+ isConfigMode: false,
640
+ }));
641
+ stateSnapshot.current = null;
642
+ }
643
+ },
644
+ });
645
+ };
606
646
  const toggleOrientation = () => {
607
647
  const newOrientation = state.orientation === 'horizontal' ? 'vertical' : 'horizontal';
608
648
  if (state.orientation === 'horizontal' && newOrientation === 'vertical') {
@@ -740,6 +780,8 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
740
780
  currentOnClick();
741
781
  }
742
782
  }, disabled: state.isConfigMode ? isDisabled && !state.isConfigMode : isDisabled, children: item.icon }) }), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
743
- }), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: true, children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) })), state.isConfigMode && state.items.length < maxItems && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getPinContextMenuItems(), trigger: "left", keepOpenOnClick: true, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Add, children: _jsx(S.AddButton, { children: _jsx(IconAdd, {}) }) }) })), state.isConfigMode && (_jsxs(_Fragment, { children: [_jsx(S.Separator, { "$orientation": state.orientation }), _jsxs(S.ButtonGroup, { "$orientation": state.orientation, children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Undo, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.UndoButton, { onClick: handleUndo, disabled: !hasChanges(), children: _jsx(IconUndo, { fontSize: 18 }) }) }), _jsx(TMTooltip, { content: state.items.length === 0 ? 'Devi aggiungere almeno un item' : SDKUI_Localizator.ApplyAndClose, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.ApplyButton, { onClick: toggleConfigMode, disabled: state.items.length === 0, children: _jsx(IconApply, { fontSize: 20 }) }) })] })] }))] })] }));
783
+ }), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: true, children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) })), state.isConfigMode && state.items.length < maxItems && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getPinContextMenuItems(), trigger: "left", keepOpenOnClick: true, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Add, children: _jsx(S.AddButton, { children: _jsx(IconAdd, {}) }) }) })), state.isConfigMode && (_jsxs(_Fragment, { children: [_jsx(S.Separator, { "$orientation": state.orientation }), _jsxs(S.ButtonGroup, { "$orientation": state.orientation, children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Undo, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.UndoButton, { onClick: handleUndo, disabled: !hasChanges(), children: _jsx(IconUndo, { fontSize: 18 }) }) }), _jsx(TMTooltip, { content: state.items.length === 0
784
+ ? 'Devi aggiungere almeno un item'
785
+ : SDKUI_Localizator.Save, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.ApplyButton, { onClick: toggleConfigMode, disabled: state.items.length === 0 || !hasChanges(), children: _jsx(IconSave, { fontSize: 20 }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Close, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.CloseButton, { onClick: handleClose, children: _jsx(IconCloseOutline, { fontSize: 20 }) }) })] })] }))] })] }));
744
786
  };
745
787
  export default TMFloatingMenuBar;
@@ -33,6 +33,7 @@ export declare const MenuButton: import("styled-components/dist/types").IStyledC
33
33
  }>> & string;
34
34
  export declare const ConfigButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
35
35
  export declare const ApplyButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
36
+ export declare const CloseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
36
37
  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"> & {
37
38
  $isActive?: boolean;
38
39
  }, "ref"> & {
@@ -74,7 +74,7 @@ export const GripHandle = styled.div `
74
74
  display: flex;
75
75
  align-items: center;
76
76
  justify-content: center;
77
- padding: ${props => props.$orientation === 'horizontal' ? '10px 6px' : '6px 10px'};
77
+ padding: ${props => props.$orientation === 'horizontal' ? '6px 4px' : '4px 6px'};
78
78
  cursor: grab;
79
79
  color: rgba(255, 255, 255, 0.7);
80
80
  transition: all 0.2s ease;
@@ -98,7 +98,7 @@ export const GripHandle = styled.div `
98
98
  export const Separator = styled.div `
99
99
  background: rgba(255, 255, 255, 0.25);
100
100
  width: ${props => props.$orientation === 'horizontal' ? '1px' : '100%'};
101
- height: ${props => props.$orientation === 'horizontal' ? '24px' : '1px'};
101
+ height: ${props => props.$orientation === 'horizontal' ? '20px' : '1px'};
102
102
  margin: ${props => props.$orientation === 'horizontal' ? '0 4px' : '4px 0'};
103
103
  flex-shrink: 0;
104
104
  `;
@@ -111,8 +111,8 @@ export const ItemSeparator = styled.div `
111
111
  display: flex;
112
112
  align-items: center;
113
113
  justify-content: center;
114
- width: 34px;
115
- height: 34px;
114
+ width: 30px;
115
+ height: 30px;
116
116
  background: transparent;
117
117
  border-radius: 8px;
118
118
  cursor: grab;
@@ -122,7 +122,7 @@ export const ItemSeparator = styled.div `
122
122
  content: '';
123
123
  background: rgba(255, 255, 255, 0.25);
124
124
  width: ${props.$orientation === 'horizontal' ? '2px' : '100%'};
125
- height: ${props.$orientation === 'horizontal' ? '20px' : '2px'};
125
+ height: ${props.$orientation === 'horizontal' ? '18px' : '2px'};
126
126
  border-radius: 1px;
127
127
  }
128
128
 
@@ -137,7 +137,7 @@ export const ItemSeparator = styled.div `
137
137
  /* Normal mode: simple line with tight spacing */
138
138
  background: rgba(255, 255, 255, 0.25);
139
139
  width: ${props.$orientation === 'horizontal' ? '1px' : '100%'};
140
- height: ${props.$orientation === 'horizontal' ? '24px' : '1px'};
140
+ height: ${props.$orientation === 'horizontal' ? '20px' : '1px'};
141
141
  margin: ${props.$orientation === 'horizontal' ? '0 2px' : '2px 0'};
142
142
  `}
143
143
  `;
@@ -145,8 +145,8 @@ export const MenuButton = styled.button `
145
145
  display: flex;
146
146
  align-items: center;
147
147
  justify-content: center;
148
- width: 34px;
149
- height: 34px;
148
+ width: 30px;
149
+ height: 30px;
150
150
  background: transparent;
151
151
  border: none;
152
152
  border-radius: 8px;
@@ -243,6 +243,40 @@ export const ApplyButton = styled.button `
243
243
  height: 20px;
244
244
  }
245
245
  `;
246
+ export const CloseButton = styled.button `
247
+ display: flex;
248
+ align-items: center;
249
+ justify-content: center;
250
+ width: 24px;
251
+ height: 24px;
252
+ background: transparent;
253
+ border: none;
254
+ border-radius: 4px;
255
+ color: rgba(239, 68, 68, 1);
256
+ font-size: 10px;
257
+ cursor: pointer;
258
+ transition: all 0.2s ease;
259
+ padding: 3px;
260
+
261
+ &:hover:not(:disabled) {
262
+ background: rgba(255, 255, 255, 0.1);
263
+ color: rgba(239, 68, 68, 1);
264
+ }
265
+
266
+ &:active:not(:disabled) {
267
+ transform: scale(0.9);
268
+ }
269
+
270
+ &:disabled {
271
+ opacity: 0.3;
272
+ cursor: default;
273
+ }
274
+
275
+ svg {
276
+ width: 20px;
277
+ height: 20px;
278
+ }
279
+ `;
246
280
  export const ContextMenuButton = styled(MenuButton) `
247
281
  svg {
248
282
  transform: translateY(0);
@@ -252,13 +286,13 @@ export const AddButton = styled.button `
252
286
  display: flex;
253
287
  align-items: center;
254
288
  justify-content: center;
255
- width: 28px;
256
- height: 28px;
289
+ width: 26px;
290
+ height: 26px;
257
291
  background: rgba(255, 255, 255, 0.15);
258
292
  border: 1px dashed rgba(255, 255, 255, 0.4);
259
293
  border-radius: 8px;
260
294
  color: white;
261
- font-size: 20px;
295
+ font-size: 18px;
262
296
  font-weight: bold;
263
297
  line-height: 0;
264
298
  cursor: pointer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.20.0-dev1.67",
3
+ "version": "6.20.0-dev1.69",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",