@topconsultnpm/sdkui-react-beta 6.6.1 → 6.6.3

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.
@@ -1,26 +1,25 @@
1
- import React from 'react';
2
- export declare const useContextMenu: () => {
3
- clicked: boolean;
4
- setClicked: React.Dispatch<React.SetStateAction<boolean>>;
5
- points: {
1
+ import React, { ReactNode } from 'react';
2
+ export interface ITMContextMenuItemProps {
3
+ icon?: ReactNode;
4
+ text?: any;
5
+ items?: ITMContextMenuItemProps[];
6
+ disabled?: boolean;
7
+ isSelected?: boolean;
8
+ id?: string;
9
+ onItemClick?: () => void;
10
+ onItemMouseOver?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
11
+ }
12
+ export interface ITMContextMenuProps {
13
+ items?: ITMContextMenuItemProps[];
14
+ coords?: {
6
15
  x: number;
7
16
  y: number;
8
17
  };
9
- setPoints: React.Dispatch<React.SetStateAction<{
10
- x: number;
11
- y: number;
12
- }>>;
13
- };
14
- export declare const Container: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
15
- $top: number;
16
- $left: number;
17
- }>> & string;
18
- export declare const MenuOption: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
19
- interface ITMContextMenu {
20
- menuData: any[];
21
- onMenuItemClick?: (item: string) => void;
22
- top: number;
23
- left: number;
18
+ subMenuDir?: 'left' | 'right';
24
19
  }
25
- declare const TMContextMenu: React.FunctionComponent<ITMContextMenu>;
20
+ declare const TMContextMenu: ({ items, coords, subMenuDir, }: ITMContextMenuProps) => import("react/jsx-runtime").JSX.Element;
21
+ export declare const useTMContextMenu: (ref: React.RefObject<HTMLElement>) => (boolean | {
22
+ x: number;
23
+ y: number;
24
+ })[];
26
25
  export default TMContextMenu;
@@ -1,56 +1,109 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
3
  import styled from 'styled-components';
4
- import { Colors, FontSize } from '../../utils/theme';
5
- // #region Hook useContextMenu
6
- export const useContextMenu = () => {
7
- // boolean value to determine if the user has right clicked
8
- const [clicked, setClicked] = useState(false);
9
- // allows us to track the x,y coordinates of the users right click
10
- const [points, setPoints] = useState({ x: 0, y: 0 });
4
+ import { IconRight } from '../../helper/TMIcons';
5
+ const StyledContextMenuContainer = styled.div `
6
+ display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; z-index: 300; position: fixed; top: ${props => `${props.$top}px`}; left: ${props => `${props.$left}px`}; right: ${props => `${props.$right}px`}; bottom: ${props => `${props.$bottom}px`}; width: max-content; height: max-content; background-color: white; box-shadow: 1px 1px 2px #00000040;
7
+ `;
8
+ const StyledContextMenuItem = styled.div `
9
+ cursor: ${props => !props.$disabled ? 'pointer' : 'default'}; display: flex; align-items: center; gap: 5px; transition: ease 100ms; padding: 5px; background-color: ${props => props.$isSelected && '#e9e9e9'}; width: 100%; height: 100%; color: ${props => props.$disabled && '#d0d0d0'}; &:hover { background-color: ${props => !props.$disabled && '#e9e9e9'} ; }
10
+ `;
11
+ const TMContextMenu = ({ items = [], coords = { x: 0, y: 0 }, subMenuDir = 'right', }) => {
12
+ // Coordinates for sub-menus
13
+ const [subMenuCoords, setSubMenuCoords] = useState({ x: 0, y: 0 });
14
+ // Track which item is currently hovered
15
+ const [hoveredItem, setHoveredItem] = useState(null);
16
+ // Size of the menu
17
+ const [menuSize, setMenuSize] = useState({ x: 0, y: 0 });
18
+ // Current direction for submenus
19
+ const [currentSubMenuDir, setCurrentSubMenuDir] = useState(subMenuDir);
20
+ // Reference to the context menu DOM element
21
+ const contextMenuRef = useRef(null);
22
+ // Uupdate submenu direction based on incoming props
23
+ useEffect(() => setCurrentSubMenuDir(subMenuDir), [subMenuDir]);
24
+ // Calculate the size of the context menu and adjust submenu direction
25
+ // Run this effect only once when the component mounts
26
+ useEffect(() => {
27
+ if (contextMenuRef.current) {
28
+ setMenuSize({
29
+ x: contextMenuRef.current.getBoundingClientRect().width || 0,
30
+ y: contextMenuRef.current.getBoundingClientRect().height || 0,
31
+ });
32
+ }
33
+ }, []);
11
34
  useEffect(() => {
12
- // reset clicked to false on user click
13
- const handleClick = () => {
14
- setClicked(false);
35
+ // This effect checks the width on resize
36
+ const handleResize = () => {
37
+ if (window.innerWidth <= coords.x + menuSize.x) {
38
+ // Change direction to left if menu goes beyond right edge
39
+ setCurrentSubMenuDir('left');
40
+ }
41
+ else {
42
+ // Default to right if there's space
43
+ setCurrentSubMenuDir('right');
44
+ }
15
45
  };
16
- // add listener for user click
17
- document.addEventListener("click", handleClick);
18
- // clean up listener function to avoid memory leaks
46
+ // Attach event listener
47
+ window.addEventListener('resize', handleResize);
48
+ handleResize(); // Call it initially to set the direction
49
+ // Clean up the event listener on unmount
19
50
  return () => {
20
- document.removeEventListener("click", handleClick);
51
+ window.removeEventListener('resize', handleResize);
21
52
  };
22
- }, []);
23
- return { clicked, setClicked, points, setPoints };
53
+ }, [coords, menuSize.x]); // Only watch coords and the width of menuSize
54
+ // Handle mouse over event on items to potentially show submenus
55
+ const onItemMouseOver = (item, index) => {
56
+ if (!item.disabled && item.items && item.items.length > 0) {
57
+ setHoveredItem(index);
58
+ const boundingRect = contextMenuRef.current?.getBoundingClientRect();
59
+ if (boundingRect) {
60
+ // Calculate the sub-menu position based on the current item position
61
+ const subMenuX = currentSubMenuDir === 'right' ? boundingRect.right : boundingRect.left - menuSize.x;
62
+ const subMenuY = boundingRect.top + index * 30; // Adjust Y coordinate to match item
63
+ setSubMenuCoords({ x: subMenuX, y: subMenuY });
64
+ }
65
+ }
66
+ else {
67
+ // Clear hover state if the item has no sub-menu
68
+ setHoveredItem(null); // If no submenu, clear hover state
69
+ }
70
+ };
71
+ return (_jsx(StyledContextMenuContainer, { ref: contextMenuRef, "$left": currentSubMenuDir === 'right' ? coords.x : 'none', "$top": window.innerHeight > coords.y + menuSize.y ? coords.y : 'none', "$right": currentSubMenuDir === 'left' ? window.innerWidth - coords.x : 'none', "$bottom": window.innerHeight <= coords.y + menuSize.y ? window.innerHeight - coords.y : 'none', children: items.map((item, index) => (_jsxs("div", { style: { width: '100%' }, children: [_jsxs(StyledContextMenuItem, { id: item.id, onMouseOver: () => onItemMouseOver(item, index), onMouseEnter: () => onItemMouseOver(item, index), "$isSelected": item.isSelected, "$disabled": item.disabled, onClick: () => !item.disabled && item.onItemClick && item.onItemClick(), children: [_jsx("div", { style: { transform: 'translateY(3px)' }, children: item.icon }), _jsx("div", { style: { width: '100%' }, children: item.items && item.items.length > 0 ? (_jsxs("div", { style: {
72
+ width: '100%',
73
+ display: 'flex',
74
+ alignItems: 'center',
75
+ gap: 5,
76
+ justifyContent: 'space-between',
77
+ }, children: [item.text, " ", _jsx(IconRight, { style: { transform: 'translateY(1px)' }, fontSize: 10 })] })) : (_jsx("div", { style: { width: '100%' }, children: item.text })) })] }), item.items && item.items.length > 0 && hoveredItem === index && (_jsx(TMContextMenu, { subMenuDir: currentSubMenuDir, coords: subMenuCoords, items: item.items }))] }, index))) }));
24
78
  };
25
- // #endregion
26
- export const Container = styled.div `
27
- position: absolute;
28
- padding: 5px 5px;
29
- background-color: white;
30
- width: max-content;
31
- height: max-content;
32
- border-radius: 2px;
33
- display: flex;
34
- flex-direction: column;
35
- justify-content: flex-start;
36
- align-items: center;
37
- box-shadow: 2px 2px 10px #00000030;
38
- z-index: 2;
39
- top: ${(props) => props.$top || 0}px;
40
- left: ${(props) => props.$left || 0}px;
41
- `;
42
- export const MenuOption = styled.div `
43
- width: 100%;
44
- height: 20px;
45
- padding: 3px;
46
- cursor: pointer;
47
- font-size: ${FontSize.defaultFontSize};
48
-
49
- &:hover {
50
- color: ${Colors.primary};
51
- }
52
- `;
53
- const TMContextMenu = ({ menuData, top, left, onMenuItemClick }) => {
54
- return (_jsx(_Fragment, { children: _jsx(Container, { "$top": top, "$left": left, children: menuData.map((item, index) => (_jsx(MenuOption, { onClick: (e) => onMenuItemClick?.(e.target.innerText), children: item.text }, index))) }) }));
79
+ export const useTMContextMenu = (ref) => {
80
+ // Coordinates for the context menu
81
+ const [coords, setCoords] = useState({ x: 0, y: 0 });
82
+ // State to control visibility of the context menu
83
+ const [showContextMenu, setShowContexMenu] = useState(false);
84
+ // Effect to hide context menu when clicking outside of the referenced element
85
+ useEffect(() => {
86
+ const menu = ref.current;
87
+ const deSelectAll = (e) => { if (menu && !menu.contains(e.target)) {
88
+ setShowContexMenu(false);
89
+ } };
90
+ window.addEventListener('contextmenu', deSelectAll);
91
+ return () => { window.removeEventListener('contextmenu', deSelectAll); };
92
+ }, []);
93
+ // Effect to hide context menu on left-click anywhere
94
+ useEffect(() => {
95
+ const handleClick = () => { setShowContexMenu(false); };
96
+ window.addEventListener("click", handleClick);
97
+ return () => { window.removeEventListener("click", handleClick); };
98
+ }, []);
99
+ // Effect to show context menu on right-click and prevent default context menu
100
+ useEffect(() => {
101
+ let menu = ref.current;
102
+ if (menu) {
103
+ menu?.addEventListener('contextmenu', (e) => { e.preventDefault(); setShowContexMenu(true); setCoords({ x: e.pageX, y: e.pageY }); });
104
+ }
105
+ return () => menu?.removeEventListener('contextmenu', (e) => { setCoords({ x: e.pageX, y: e.pageY }); });
106
+ }, [ref]);
107
+ return [coords, showContextMenu];
55
108
  };
56
109
  export default TMContextMenu;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ export declare const useContextMenu: () => {
3
+ clicked: boolean;
4
+ setClicked: React.Dispatch<React.SetStateAction<boolean>>;
5
+ points: {
6
+ x: number;
7
+ y: number;
8
+ };
9
+ setPoints: React.Dispatch<React.SetStateAction<{
10
+ x: number;
11
+ y: number;
12
+ }>>;
13
+ };
14
+ export declare const Container: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
15
+ $top: number;
16
+ $left: number;
17
+ }>> & string;
18
+ export declare const MenuOption: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
19
+ interface ITMContextMenu {
20
+ menuData: any[];
21
+ onMenuItemClick?: (item: string) => void;
22
+ top: number;
23
+ left: number;
24
+ }
25
+ declare const TMContextMenuOLD: React.FunctionComponent<ITMContextMenu>;
26
+ export default TMContextMenuOLD;
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import styled from 'styled-components';
4
+ import { Colors, FontSize } from '../../utils/theme';
5
+ // #region Hook useContextMenu
6
+ export const useContextMenu = () => {
7
+ // boolean value to determine if the user has right clicked
8
+ const [clicked, setClicked] = useState(false);
9
+ // allows us to track the x,y coordinates of the users right click
10
+ const [points, setPoints] = useState({ x: 0, y: 0 });
11
+ useEffect(() => {
12
+ // reset clicked to false on user click
13
+ const handleClick = () => {
14
+ setClicked(false);
15
+ };
16
+ // add listener for user click
17
+ document.addEventListener("click", handleClick);
18
+ // clean up listener function to avoid memory leaks
19
+ return () => {
20
+ document.removeEventListener("click", handleClick);
21
+ };
22
+ }, []);
23
+ return { clicked, setClicked, points, setPoints };
24
+ };
25
+ // #endregion
26
+ export const Container = styled.div `
27
+ position: absolute;
28
+ padding: 5px 5px;
29
+ background-color: white;
30
+ width: max-content;
31
+ height: max-content;
32
+ border-radius: 2px;
33
+ display: flex;
34
+ flex-direction: column;
35
+ justify-content: flex-start;
36
+ align-items: center;
37
+ box-shadow: 2px 2px 10px #00000030;
38
+ z-index: 2;
39
+ top: ${(props) => props.$top || 0}px;
40
+ left: ${(props) => props.$left || 0}px;
41
+ `;
42
+ export const MenuOption = styled.div `
43
+ width: 100%;
44
+ height: 20px;
45
+ padding: 3px;
46
+ cursor: pointer;
47
+ font-size: ${FontSize.defaultFontSize};
48
+
49
+ &:hover {
50
+ color: ${Colors.primary};
51
+ }
52
+ `;
53
+ const TMContextMenuOLD = ({ menuData, top, left, onMenuItemClick }) => {
54
+ return (_jsx(_Fragment, { children: _jsx(Container, { "$top": top, "$left": left, children: menuData.map((item, index) => (_jsx(MenuOption, { onClick: (e) => onMenuItemClick?.(e.target.innerText), children: item.text }, index))) }) }));
55
+ };
56
+ export default TMContextMenuOLD;
@@ -1,24 +1,25 @@
1
- import React from 'react';
2
- import { ITMEditorBase, Colors as C } from '../base/TMEditorBase';
3
- type SelectedValueType = {
4
- fieldName: string;
5
- fieldValues: any[];
6
- };
7
- interface ITMListView extends ITMEditorBase {
8
- dataSource?: any[];
9
- multipleSelect?: boolean;
1
+ interface ListProps<T> {
2
+ dataSource?: T[];
3
+ selectedItem?: T;
4
+ exprKey?: string;
5
+ searchKeys?: string[];
6
+ customColor?: string;
10
7
  searchable?: boolean;
11
- header?: boolean;
12
- footer?: boolean;
13
- selectedListItems?: (e: any[]) => void;
14
- displayField?: string;
15
- customListViewItem?: JSX.Element;
16
- customItemDetails?: JSX.Element;
17
- hasItemDetails?: boolean;
18
- detailsFields?: string[];
19
- color?: C;
20
- selectedValues?: any[] | SelectedValueType;
21
- maxHeight?: string;
8
+ id?: string;
9
+ scroll?: {
10
+ x: number;
11
+ y: number;
12
+ };
13
+ orderBy?: string;
14
+ grouping?: string;
15
+ onScrollChange?: (e: {
16
+ x: number;
17
+ y: number;
18
+ }) => void;
19
+ onSelectionChanged?: (item: T) => void;
20
+ onItemClick?: (item: T) => void;
21
+ onItemDblClick?: (item: T) => void;
22
+ itemTemplate?: (item: T) => JSX.Element;
22
23
  }
23
- declare const TMListView: React.FC<ITMListView>;
24
+ declare const TMListView: <T>({ grouping, orderBy, id, onScrollChange, scroll, searchKeys, searchable, itemTemplate, customColor, dataSource, exprKey, onSelectionChanged, onItemClick, onItemDblClick, selectedItem }: ListProps<T>) => import("react/jsx-runtime").JSX.Element;
24
25
  export default TMListView;