@dktunited-techoff/techoff-suite-ui 1.13.3 → 1.13.5

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.
@@ -7,6 +7,7 @@
7
7
  padding: 12px;
8
8
  box-shadow: 0px 8px 9px 0px #1010101a;
9
9
  background: #ffffff;
10
+ z-index: 10;
10
11
  }
11
12
  .ts-menu-button-menu--bottom-end {
12
13
  right: 0;
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
- import { useState } from 'react';
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
3
4
  import { TsIcon } from '../TsIcon/TsIcon';
4
5
  import { useClickOutside } from '../../hooks/use-click-outside';
5
6
  import './TsMenuButton.css';
@@ -18,17 +19,34 @@ export const TsMenuItem = ({ icon, label, onClick }) => {
18
19
  };
19
20
  export const TsMenuButton = ({ menuAlignment = 'bottom-start', mainButton, items }) => {
20
21
  const [showMenu, setShowMenu] = useState(false);
21
- const dropdownRef = useClickOutside(() => setShowMenu(false));
22
+ const buttonRef = useClickOutside(() => setShowMenu(false));
23
+ const menuRef = useRef(null);
24
+ const [menuStyle, setMenuStyle] = useState({});
22
25
  // ########
23
26
  // Hanlders
24
27
  const handleShowMenu = (e) => {
25
28
  e.stopPropagation();
26
29
  setShowMenu(true);
27
30
  };
31
+ // ########
32
+ // Watchers
33
+ useEffect(() => {
34
+ if (showMenu && buttonRef.current && menuRef.current) {
35
+ const buttonRect = buttonRef.current.getBoundingClientRect();
36
+ const viewportHeight = window.innerHeight;
37
+ const menuHeight = menuRef.current.getBoundingClientRect().height;
38
+ const spaceBelow = viewportHeight - buttonRect.bottom;
39
+ setMenuStyle({
40
+ top: spaceBelow >= menuHeight ? `${buttonRect.bottom + 4}px` : `${buttonRect.top - menuHeight - 4}px`,
41
+ left: `${buttonRect.left}px`,
42
+ });
43
+ }
44
+ }, [showMenu]);
45
+ const menu = showMenu && (React.createElement("div", { className: `ts-menu-button-menu ts-menu-button-menu--${menuAlignment}`, style: menuStyle, ref: menuRef }, items));
28
46
  // #########
29
47
  // Rendering
30
- return (React.createElement("div", { className: "ts-menu-button", ref: dropdownRef },
31
- React.cloneElement(mainButton, { onClick: handleShowMenu }),
32
- showMenu && React.createElement("div", { className: `ts-menu-button-menu ts-menu-button-menu--${menuAlignment}` }, items)));
48
+ return (React.createElement("div", { className: "ts-menu-button" },
49
+ React.createElement("div", { ref: buttonRef }, React.cloneElement(mainButton, { onClick: handleShowMenu })),
50
+ createPortal(menu, document.body)));
33
51
  };
34
52
  //# sourceMappingURL=TsMenuButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TsMenuButton.js","sourceRoot":"","sources":["../../../src/components/TsMenuButton/TsMenuButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAc,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,oBAAoB,CAAC;AAE5B,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE;IAChC,YAAY;IACZ,YAAY;IACZ,OAAO,6BAAK,SAAS,EAAC,iBAAiB,GAAG,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAmB,EAAE,EAAE;IACtE,YAAY;IACZ,YAAY;IACZ,OAAO,CACL,gCAAQ,SAAS,EAAC,cAAc,EAAC,OAAO,EAAE,OAAO;QAC9C,IAAI,IAAI,CACP,6BAAK,SAAS,EAAC,mBAAmB;YAChC,oBAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAC,IAAI,GAAG,CAC5B,CACP;QAED,6BAAK,SAAS,EAAC,oBAAoB,IAAE,KAAK,CAAO,CAC1C,CACV,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAAE,aAAa,GAAG,cAAc,EAAE,UAAU,EAAE,KAAK,EAAqB,EAAE,EAAE;IACvG,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAE9D,WAAW;IACX,WAAW;IACX,MAAM,cAAc,GAAG,CAAC,CAAgC,EAAE,EAAE;QAC1D,CAAC,CAAC,eAAe,EAAE,CAAC;QACpB,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,YAAY;IACZ,YAAY;IACZ,OAAO,CACL,6BAAK,SAAS,EAAC,gBAAgB,EAAC,GAAG,EAAE,WAAW;QAC7C,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;QAC3D,QAAQ,IAAI,6BAAK,SAAS,EAAE,4CAA4C,aAAa,EAAE,IAAG,KAAK,CAAO,CACnG,CACP,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"TsMenuButton.js","sourceRoot":"","sources":["../../../src/components/TsMenuButton/TsMenuButton.tsx"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@
7
7
  padding: 12px;
8
8
  box-shadow: 0px 8px 9px 0px #1010101a;
9
9
  background: #ffffff;
10
+ z-index: 10;
10
11
  }
11
12
  .ts-menu-button-menu--bottom-end {
12
13
  right: 0;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TsMenuButton = exports.TsMenuItem = exports.TsMenuDivider = void 0;
4
4
  const React = require("react");
5
5
  const react_1 = require("react");
6
+ const react_dom_1 = require("react-dom");
6
7
  const TsIcon_1 = require("../TsIcon/TsIcon");
7
8
  const use_click_outside_1 = require("../../hooks/use-click-outside");
8
9
  require("./TsMenuButton.css");
@@ -23,18 +24,35 @@ const TsMenuItem = ({ icon, label, onClick }) => {
23
24
  exports.TsMenuItem = TsMenuItem;
24
25
  const TsMenuButton = ({ menuAlignment = 'bottom-start', mainButton, items }) => {
25
26
  const [showMenu, setShowMenu] = (0, react_1.useState)(false);
26
- const dropdownRef = (0, use_click_outside_1.useClickOutside)(() => setShowMenu(false));
27
+ const buttonRef = (0, use_click_outside_1.useClickOutside)(() => setShowMenu(false));
28
+ const menuRef = (0, react_1.useRef)(null);
29
+ const [menuStyle, setMenuStyle] = (0, react_1.useState)({});
27
30
  // ########
28
31
  // Hanlders
29
32
  const handleShowMenu = (e) => {
30
33
  e.stopPropagation();
31
34
  setShowMenu(true);
32
35
  };
36
+ // ########
37
+ // Watchers
38
+ (0, react_1.useEffect)(() => {
39
+ if (showMenu && buttonRef.current && menuRef.current) {
40
+ const buttonRect = buttonRef.current.getBoundingClientRect();
41
+ const viewportHeight = window.innerHeight;
42
+ const menuHeight = menuRef.current.getBoundingClientRect().height;
43
+ const spaceBelow = viewportHeight - buttonRect.bottom;
44
+ setMenuStyle({
45
+ top: spaceBelow >= menuHeight ? `${buttonRect.bottom + 4}px` : `${buttonRect.top - menuHeight - 4}px`,
46
+ left: `${buttonRect.left}px`,
47
+ });
48
+ }
49
+ }, [showMenu]);
50
+ const menu = showMenu && (React.createElement("div", { className: `ts-menu-button-menu ts-menu-button-menu--${menuAlignment}`, style: menuStyle, ref: menuRef }, items));
33
51
  // #########
34
52
  // Rendering
35
- return (React.createElement("div", { className: "ts-menu-button", ref: dropdownRef },
36
- React.cloneElement(mainButton, { onClick: handleShowMenu }),
37
- showMenu && React.createElement("div", { className: `ts-menu-button-menu ts-menu-button-menu--${menuAlignment}` }, items)));
53
+ return (React.createElement("div", { className: "ts-menu-button" },
54
+ React.createElement("div", { ref: buttonRef }, React.cloneElement(mainButton, { onClick: handleShowMenu })),
55
+ (0, react_dom_1.createPortal)(menu, document.body)));
38
56
  };
39
57
  exports.TsMenuButton = TsMenuButton;
40
58
  //# sourceMappingURL=TsMenuButton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TsMenuButton.js","sourceRoot":"","sources":["../../../src/components/TsMenuButton/TsMenuButton.tsx"],"names":[],"mappings":";;;AAAA,+BAA+B;AAC/B,iCAA6C;AAE7C,6CAA0C;AAC1C,qEAAgE;AAChE,8BAA4B;AAErB,MAAM,aAAa,GAAG,GAAG,EAAE;IAChC,YAAY;IACZ,YAAY;IACZ,OAAO,6BAAK,SAAS,EAAC,iBAAiB,GAAG,CAAC;AAC7C,CAAC,CAAC;AAJW,QAAA,aAAa,iBAIxB;AAEK,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAmB,EAAE,EAAE;IACtE,YAAY;IACZ,YAAY;IACZ,OAAO,CACL,gCAAQ,SAAS,EAAC,cAAc,EAAC,OAAO,EAAE,OAAO;QAC9C,IAAI,IAAI,CACP,6BAAK,SAAS,EAAC,mBAAmB;YAChC,oBAAC,eAAM,IAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAC,IAAI,GAAG,CAC5B,CACP;QAED,6BAAK,SAAS,EAAC,oBAAoB,IAAE,KAAK,CAAO,CAC1C,CACV,CAAC;AACJ,CAAC,CAAC;AAdW,QAAA,UAAU,cAcrB;AAEK,MAAM,YAAY,GAAG,CAAC,EAAE,aAAa,GAAG,cAAc,EAAE,UAAU,EAAE,KAAK,EAAqB,EAAE,EAAE;IACvG,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,IAAA,gBAAQ,EAAU,KAAK,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,IAAA,mCAAe,EAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAE9D,WAAW;IACX,WAAW;IACX,MAAM,cAAc,GAAG,CAAC,CAAgC,EAAE,EAAE;QAC1D,CAAC,CAAC,eAAe,EAAE,CAAC;QACpB,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,YAAY;IACZ,YAAY;IACZ,OAAO,CACL,6BAAK,SAAS,EAAC,gBAAgB,EAAC,GAAG,EAAE,WAAW;QAC7C,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;QAC3D,QAAQ,IAAI,6BAAK,SAAS,EAAE,4CAA4C,aAAa,EAAE,IAAG,KAAK,CAAO,CACnG,CACP,CAAC;AACJ,CAAC,CAAC;AAnBW,QAAA,YAAY,gBAmBvB"}
1
+ {"version":3,"file":"TsMenuButton.js","sourceRoot":"","sources":["../../../src/components/TsMenuButton/TsMenuButton.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dktunited-techoff/techoff-suite-ui",
3
- "version": "1.13.3",
3
+ "version": "1.13.5",
4
4
  "main": "lib/index.js",
5
5
  "types": "./lib",
6
6
  "module": "esm/index.js",
@@ -7,6 +7,7 @@
7
7
  padding: 12px;
8
8
  box-shadow: 0px 8px 9px 0px #1010101a;
9
9
  background: #ffffff;
10
+ z-index: 10;
10
11
  }
11
12
  .ts-menu-button-menu--bottom-end {
12
13
  right: 0;
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
- import { MouseEvent, useState } from 'react';
2
+ import { CSSProperties, MouseEvent, useEffect, useRef, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
3
4
  import { TsMenuButtonProps, TsMenuItemProps } from './TsMenuButton.types';
4
5
  import { TsIcon } from '../TsIcon/TsIcon';
5
6
  import { useClickOutside } from '../../hooks/use-click-outside';
@@ -29,7 +30,9 @@ export const TsMenuItem = ({ icon, label, onClick }: TsMenuItemProps) => {
29
30
 
30
31
  export const TsMenuButton = ({ menuAlignment = 'bottom-start', mainButton, items }: TsMenuButtonProps) => {
31
32
  const [showMenu, setShowMenu] = useState<boolean>(false);
32
- const dropdownRef = useClickOutside(() => setShowMenu(false));
33
+ const buttonRef = useClickOutside(() => setShowMenu(false));
34
+ const menuRef = useRef<HTMLDivElement>(null);
35
+ const [menuStyle, setMenuStyle] = useState<CSSProperties>({});
33
36
 
34
37
  // ########
35
38
  // Hanlders
@@ -38,12 +41,34 @@ export const TsMenuButton = ({ menuAlignment = 'bottom-start', mainButton, items
38
41
  setShowMenu(true);
39
42
  };
40
43
 
44
+ // ########
45
+ // Watchers
46
+ useEffect(() => {
47
+ if (showMenu && buttonRef.current && menuRef.current) {
48
+ const buttonRect = buttonRef.current.getBoundingClientRect();
49
+ const viewportHeight = window.innerHeight;
50
+ const menuHeight = menuRef.current.getBoundingClientRect().height;
51
+ const spaceBelow = viewportHeight - buttonRect.bottom;
52
+
53
+ setMenuStyle({
54
+ top: spaceBelow >= menuHeight ? `${buttonRect.bottom + 4}px` : `${buttonRect.top - menuHeight - 4}px`,
55
+ left: `${buttonRect.left}px`,
56
+ });
57
+ }
58
+ }, [showMenu]);
59
+
60
+ const menu = showMenu && (
61
+ <div className={`ts-menu-button-menu ts-menu-button-menu--${menuAlignment}`} style={menuStyle} ref={menuRef}>
62
+ {items}
63
+ </div>
64
+ );
65
+
41
66
  // #########
42
67
  // Rendering
43
68
  return (
44
- <div className="ts-menu-button" ref={dropdownRef}>
45
- {React.cloneElement(mainButton, { onClick: handleShowMenu })}
46
- {showMenu && <div className={`ts-menu-button-menu ts-menu-button-menu--${menuAlignment}`}>{items}</div>}
69
+ <div className="ts-menu-button">
70
+ <div ref={buttonRef}>{React.cloneElement(mainButton, { onClick: handleShowMenu })}</div>
71
+ {createPortal(menu, document.body)}
47
72
  </div>
48
73
  );
49
74
  };