@linzjs/step-ag-grid 1.4.4 → 1.4.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.
- package/dist/index.js +1602 -3043
- package/dist/index.js.map +1 -1
- package/dist/src/components/GridLoadableCell.d.ts +2 -0
- package/dist/src/components/gridForm/GridFormDropDown.d.ts +1 -1
- package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +1 -1
- package/dist/src/components/gridPopoverEdit/GridPopoverMenu.d.ts +1 -1
- package/dist/src/react-menu3/components/ControlledMenu.d.ts +2 -0
- package/dist/src/react-menu3/components/FocusableItem.d.ts +1 -0
- package/dist/src/react-menu3/components/Menu.d.ts +2 -0
- package/dist/src/react-menu3/components/MenuButton.d.ts +1 -0
- package/dist/src/react-menu3/components/MenuDivider.d.ts +2 -0
- package/dist/src/react-menu3/components/MenuGroup.d.ts +2 -0
- package/dist/src/react-menu3/components/MenuHeader.d.ts +2 -0
- package/dist/src/react-menu3/components/MenuItem.d.ts +1 -0
- package/dist/src/react-menu3/components/MenuList.d.ts +30 -0
- package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +2 -0
- package/dist/src/react-menu3/components/SubMenu.d.ts +1 -0
- package/dist/src/react-menu3/hooks/index.d.ts +9 -0
- package/dist/src/react-menu3/hooks/useBEM.d.ts +9 -0
- package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +2 -0
- package/dist/src/react-menu3/hooks/useIsomorphicLayoutEffect.d.ts +3 -0
- package/dist/src/react-menu3/hooks/useItemEffect.d.ts +2 -0
- package/dist/src/react-menu3/hooks/useItemState.d.ts +6 -0
- package/dist/src/react-menu3/hooks/useItems.d.ts +5 -0
- package/dist/src/react-menu3/hooks/useMenuChange.d.ts +1 -0
- package/dist/src/react-menu3/hooks/useMenuState.d.ts +11 -0
- package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +10 -0
- package/dist/src/react-menu3/index.d.ts +11 -0
- package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +10 -0
- package/dist/src/react-menu3/positionUtils/index.d.ts +3 -0
- package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +7 -0
- package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +7 -0
- package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +21 -0
- package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +21 -0
- package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +8 -0
- package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +21 -0
- package/dist/src/react-menu3/style-utils/index.d.ts +11 -0
- package/dist/src/react-menu3/utils/constants.d.ts +50 -0
- package/dist/src/react-menu3/utils/index.d.ts +4 -0
- package/dist/src/react-menu3/utils/propTypes.d.ts +55 -0
- package/dist/src/react-menu3/utils/utils.d.ts +27 -0
- package/dist/src/react-menu3/utils/withHovering.d.ts +1 -0
- package/dist/step-ag-grid.esm.js +1513 -2953
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +18 -9
- package/src/components/GridLoadableCell.scss +4 -0
- package/src/components/GridLoadableCell.tsx +5 -1
- package/src/components/GridPopoverHook.tsx +4 -50
- package/src/components/gridForm/GridFormDropDown.tsx +2 -2
- package/src/components/gridForm/GridFormMultiSelect.tsx +4 -4
- package/src/components/gridForm/GridFormPopoutMenu.tsx +1 -1
- package/src/components/gridPopoverEdit/GridPopoverMenu.scss +6 -2
- package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +1 -1
- package/src/components/gridRender/GridRenderPopoutMenuCell.tsx +7 -9
- package/src/react-menu3/components/ControlledMenu.tsx +260 -0
- package/src/react-menu3/components/FocusableItem.tsx +70 -0
- package/src/react-menu3/components/Menu.tsx +96 -0
- package/src/react-menu3/components/MenuButton.tsx +33 -0
- package/src/react-menu3/components/MenuDivider.tsx +21 -0
- package/src/react-menu3/components/MenuGroup.tsx +38 -0
- package/src/react-menu3/components/MenuHeader.tsx +21 -0
- package/src/react-menu3/components/MenuItem.tsx +130 -0
- package/src/react-menu3/components/MenuList.tsx +434 -0
- package/src/react-menu3/components/MenuRadioGroup.tsx +33 -0
- package/src/react-menu3/components/SubMenu.tsx +243 -0
- package/src/react-menu3/hooks/index.ts +9 -0
- package/src/react-menu3/hooks/useBEM.ts +32 -0
- package/src/react-menu3/hooks/useCombinedRef.ts +30 -0
- package/src/react-menu3/hooks/useIsomorphicLayoutEffect.ts +15 -0
- package/src/react-menu3/hooks/useItemEffect.ts +22 -0
- package/src/react-menu3/hooks/useItemState.ts +63 -0
- package/src/react-menu3/hooks/useItems.ts +110 -0
- package/src/react-menu3/hooks/useMenuChange.ts +12 -0
- package/src/react-menu3/hooks/useMenuState.ts +24 -0
- package/src/react-menu3/hooks/useMenuStateAndFocus.ts +15 -0
- package/src/react-menu3/index.d.ts +682 -0
- package/src/react-menu3/index.ts +11 -0
- package/src/react-menu3/positionUtils/getPositionHelpers.ts +76 -0
- package/src/react-menu3/positionUtils/index.ts +3 -0
- package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +8 -0
- package/src/react-menu3/positionUtils/placeArrowVertical.ts +8 -0
- package/src/react-menu3/positionUtils/placeLeftorRight.ts +76 -0
- package/src/react-menu3/positionUtils/placeToporBottom.ts +77 -0
- package/src/react-menu3/positionUtils/positionContextMenu.ts +49 -0
- package/src/react-menu3/positionUtils/positionMenu.ts +73 -0
- package/src/react-menu3/style-utils/index.ts +80 -0
- package/src/react-menu3/style-utils.d.ts +110 -0
- package/src/react-menu3/styles/_mixins.scss +11 -0
- package/src/react-menu3/styles/_var.scss +20 -0
- package/src/react-menu3/styles/core.scss +80 -0
- package/src/react-menu3/styles/index.scss +70 -0
- package/src/react-menu3/styles/theme-dark.scss +30 -0
- package/src/react-menu3/styles/transitions/slide.scss +47 -0
- package/src/react-menu3/utils/constants.ts +63 -0
- package/src/react-menu3/utils/index.ts +4 -0
- package/src/react-menu3/utils/propTypes.ts +61 -0
- package/src/react-menu3/utils/utils.ts +71 -0
- package/src/react-menu3/utils/withHovering.tsx +22 -0
- package/src/stories/components/GridPopoutEditDropDown.stories.tsx +1 -3
- package/src/utils/util.ts +2 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { parsePadding } from "../utils";
|
|
3
|
+
|
|
4
|
+
export const getPositionHelpers = (containerRef, menuRef, menuScroll, boundingBoxPadding) => {
|
|
5
|
+
const menuRect = menuRef.current.getBoundingClientRect();
|
|
6
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
7
|
+
const thisWindow = containerRef.current.ownerDocument.defaultView;
|
|
8
|
+
const boundingRect =
|
|
9
|
+
menuScroll === window || menuScroll === thisWindow
|
|
10
|
+
? {
|
|
11
|
+
left: 0,
|
|
12
|
+
top: 0,
|
|
13
|
+
right: thisWindow.document.documentElement.clientWidth,
|
|
14
|
+
bottom: thisWindow.innerHeight,
|
|
15
|
+
}
|
|
16
|
+
: menuScroll.getBoundingClientRect();
|
|
17
|
+
const padding = parsePadding(boundingBoxPadding);
|
|
18
|
+
|
|
19
|
+
// For left and top, overflows are negative value.
|
|
20
|
+
// For right and bottom, overflows are positive value.
|
|
21
|
+
const getLeftOverflow = (x) => x + containerRect.left - boundingRect.left - padding.left;
|
|
22
|
+
const getRightOverflow = (x) => x + containerRect.left + menuRect.width - boundingRect.right + padding.right;
|
|
23
|
+
const getTopOverflow = (y) => y + containerRect.top - boundingRect.top - padding.top;
|
|
24
|
+
const getBottomOverflow = (y) => y + containerRect.top + menuRect.height - boundingRect.bottom + padding.bottom;
|
|
25
|
+
|
|
26
|
+
const confineHorizontally = (x) => {
|
|
27
|
+
// If menu overflows to the left side, adjust x to have the menu contained within the viewport
|
|
28
|
+
// and there is no need to check the right side;
|
|
29
|
+
// if it doesn't overflow to the left, then check the right side
|
|
30
|
+
let leftOverflow = getLeftOverflow(x);
|
|
31
|
+
if (leftOverflow < 0) {
|
|
32
|
+
x -= leftOverflow;
|
|
33
|
+
} else {
|
|
34
|
+
const rightOverflow = getRightOverflow(x);
|
|
35
|
+
if (rightOverflow > 0) {
|
|
36
|
+
x -= rightOverflow;
|
|
37
|
+
// Check again to make sure menu doesn't overflow to the left
|
|
38
|
+
// because it may go off screen and cannot be scroll into view.
|
|
39
|
+
leftOverflow = getLeftOverflow(x);
|
|
40
|
+
if (leftOverflow < 0) x -= leftOverflow;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return x;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const confineVertically = (y) => {
|
|
48
|
+
// Similar logic to confineHorizontally above
|
|
49
|
+
let topOverflow = getTopOverflow(y);
|
|
50
|
+
if (topOverflow < 0) {
|
|
51
|
+
y -= topOverflow;
|
|
52
|
+
} else {
|
|
53
|
+
const bottomOverflow = getBottomOverflow(y);
|
|
54
|
+
if (bottomOverflow > 0) {
|
|
55
|
+
y -= bottomOverflow;
|
|
56
|
+
// Check again to make sure menu doesn't overflow to the bottom
|
|
57
|
+
// because it may go off screen and cannot be scroll into view.
|
|
58
|
+
topOverflow = getTopOverflow(y);
|
|
59
|
+
if (topOverflow < 0) y -= topOverflow;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return y;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
menuRect,
|
|
68
|
+
containerRect,
|
|
69
|
+
getLeftOverflow,
|
|
70
|
+
getRightOverflow,
|
|
71
|
+
getTopOverflow,
|
|
72
|
+
getBottomOverflow,
|
|
73
|
+
confineHorizontally,
|
|
74
|
+
confineVertically,
|
|
75
|
+
};
|
|
76
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export const placeArrowHorizontal = ({ arrowRef, menuX, anchorRect, containerRect, menuRect }) => {
|
|
3
|
+
let x = anchorRect.left - containerRect.left - menuX + anchorRect.width / 2;
|
|
4
|
+
const offset = arrowRef.current.offsetWidth * 1.25;
|
|
5
|
+
x = Math.max(offset, x);
|
|
6
|
+
x = Math.min(x, menuRect.width - offset);
|
|
7
|
+
return x;
|
|
8
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export const placeArrowVertical = ({ arrowRef, menuY, anchorRect, containerRect, menuRect }) => {
|
|
3
|
+
let y = anchorRect.top - containerRect.top - menuY + anchorRect.height / 2;
|
|
4
|
+
const offset = arrowRef.current.offsetHeight * 1.25;
|
|
5
|
+
y = Math.max(offset, y);
|
|
6
|
+
y = Math.min(y, menuRect.height - offset);
|
|
7
|
+
return y;
|
|
8
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { placeArrowVertical } from "./placeArrowVertical";
|
|
3
|
+
|
|
4
|
+
export const placeLeftorRight = ({
|
|
5
|
+
anchorRect,
|
|
6
|
+
containerRect,
|
|
7
|
+
menuRect,
|
|
8
|
+
placeLeftorRightY,
|
|
9
|
+
placeLeftX,
|
|
10
|
+
placeRightX,
|
|
11
|
+
getLeftOverflow,
|
|
12
|
+
getRightOverflow,
|
|
13
|
+
confineHorizontally,
|
|
14
|
+
confineVertically,
|
|
15
|
+
arrowRef,
|
|
16
|
+
arrow,
|
|
17
|
+
direction,
|
|
18
|
+
position,
|
|
19
|
+
}) => {
|
|
20
|
+
let computedDirection = direction;
|
|
21
|
+
let y = placeLeftorRightY;
|
|
22
|
+
if (position !== "initial") {
|
|
23
|
+
y = confineVertically(y);
|
|
24
|
+
if (position === "anchor") {
|
|
25
|
+
// restrict menu to the edge of anchor element
|
|
26
|
+
y = Math.min(y, anchorRect.bottom - containerRect.top);
|
|
27
|
+
y = Math.max(y, anchorRect.top - containerRect.top - menuRect.height);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let x, leftOverflow, rightOverflow;
|
|
32
|
+
if (computedDirection === "left") {
|
|
33
|
+
x = placeLeftX;
|
|
34
|
+
|
|
35
|
+
if (position !== "initial") {
|
|
36
|
+
// if menu overflows to the left,
|
|
37
|
+
// try to reposition it to the right of the anchor.
|
|
38
|
+
leftOverflow = getLeftOverflow(x);
|
|
39
|
+
if (leftOverflow < 0) {
|
|
40
|
+
// if menu overflows to the right after repositioning,
|
|
41
|
+
// choose a side which has less overflow
|
|
42
|
+
rightOverflow = getRightOverflow(placeRightX);
|
|
43
|
+
if (rightOverflow <= 0 || -leftOverflow > rightOverflow) {
|
|
44
|
+
x = placeRightX;
|
|
45
|
+
computedDirection = "right";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
// Opposite logic to the 'left' direction above
|
|
51
|
+
x = placeRightX;
|
|
52
|
+
|
|
53
|
+
if (position !== "initial") {
|
|
54
|
+
rightOverflow = getRightOverflow(x);
|
|
55
|
+
if (rightOverflow > 0) {
|
|
56
|
+
leftOverflow = getLeftOverflow(placeLeftX);
|
|
57
|
+
if (leftOverflow >= 0 || -leftOverflow < rightOverflow) {
|
|
58
|
+
x = placeLeftX;
|
|
59
|
+
computedDirection = "left";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (position === "auto") x = confineHorizontally(x);
|
|
66
|
+
const arrowY = arrow
|
|
67
|
+
? placeArrowVertical({
|
|
68
|
+
menuY: y,
|
|
69
|
+
arrowRef,
|
|
70
|
+
anchorRect,
|
|
71
|
+
containerRect,
|
|
72
|
+
menuRect,
|
|
73
|
+
})
|
|
74
|
+
: undefined;
|
|
75
|
+
return { arrowY, x, y, computedDirection };
|
|
76
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { placeArrowHorizontal } from "./placeArrowHorizontal";
|
|
3
|
+
|
|
4
|
+
export const placeToporBottom = ({
|
|
5
|
+
anchorRect,
|
|
6
|
+
containerRect,
|
|
7
|
+
menuRect,
|
|
8
|
+
placeToporBottomX,
|
|
9
|
+
placeTopY,
|
|
10
|
+
placeBottomY,
|
|
11
|
+
getTopOverflow,
|
|
12
|
+
getBottomOverflow,
|
|
13
|
+
confineHorizontally,
|
|
14
|
+
confineVertically,
|
|
15
|
+
arrowRef,
|
|
16
|
+
arrow,
|
|
17
|
+
direction,
|
|
18
|
+
position,
|
|
19
|
+
}) => {
|
|
20
|
+
// make sure invalid direction is treated as 'bottom'
|
|
21
|
+
let computedDirection = direction === "top" ? "top" : "bottom";
|
|
22
|
+
let x = placeToporBottomX;
|
|
23
|
+
if (position !== "initial") {
|
|
24
|
+
x = confineHorizontally(x);
|
|
25
|
+
if (position === "anchor") {
|
|
26
|
+
// restrict menu to the edge of anchor element
|
|
27
|
+
x = Math.min(x, anchorRect.right - containerRect.left);
|
|
28
|
+
x = Math.max(x, anchorRect.left - containerRect.left - menuRect.width);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let y, topOverflow, bottomOverflow;
|
|
33
|
+
if (computedDirection === "top") {
|
|
34
|
+
y = placeTopY;
|
|
35
|
+
|
|
36
|
+
if (position !== "initial") {
|
|
37
|
+
// if menu overflows to the top,
|
|
38
|
+
// try to reposition it to the bottom of the anchor.
|
|
39
|
+
topOverflow = getTopOverflow(y);
|
|
40
|
+
if (topOverflow < 0) {
|
|
41
|
+
// if menu overflows to the bottom after repositioning,
|
|
42
|
+
// choose a side which has less overflow
|
|
43
|
+
bottomOverflow = getBottomOverflow(placeBottomY);
|
|
44
|
+
if (bottomOverflow <= 0 || -topOverflow > bottomOverflow) {
|
|
45
|
+
y = placeBottomY;
|
|
46
|
+
computedDirection = "bottom";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
// Opposite logic to the 'top' direction above
|
|
52
|
+
y = placeBottomY;
|
|
53
|
+
|
|
54
|
+
if (position !== "initial") {
|
|
55
|
+
bottomOverflow = getBottomOverflow(y);
|
|
56
|
+
if (bottomOverflow > 0) {
|
|
57
|
+
topOverflow = getTopOverflow(placeTopY);
|
|
58
|
+
if (topOverflow >= 0 || -topOverflow < bottomOverflow) {
|
|
59
|
+
y = placeTopY;
|
|
60
|
+
computedDirection = "top";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (position === "auto") y = confineVertically(y);
|
|
67
|
+
const arrowX = arrow
|
|
68
|
+
? placeArrowHorizontal({
|
|
69
|
+
menuX: x,
|
|
70
|
+
arrowRef,
|
|
71
|
+
anchorRect,
|
|
72
|
+
containerRect,
|
|
73
|
+
menuRect,
|
|
74
|
+
})
|
|
75
|
+
: undefined;
|
|
76
|
+
return { arrowX, x, y, computedDirection };
|
|
77
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
export const positionContextMenu = ({ positionHelpers, anchorPoint }) => {
|
|
3
|
+
const {
|
|
4
|
+
menuRect,
|
|
5
|
+
containerRect,
|
|
6
|
+
getLeftOverflow,
|
|
7
|
+
getRightOverflow,
|
|
8
|
+
getTopOverflow,
|
|
9
|
+
getBottomOverflow,
|
|
10
|
+
confineHorizontally,
|
|
11
|
+
confineVertically,
|
|
12
|
+
} = positionHelpers;
|
|
13
|
+
|
|
14
|
+
let x, y;
|
|
15
|
+
|
|
16
|
+
// position the menu with cursor pointing to its top-left corner
|
|
17
|
+
x = anchorPoint.x - containerRect.left;
|
|
18
|
+
y = anchorPoint.y - containerRect.top;
|
|
19
|
+
|
|
20
|
+
// If menu overflows to the right of viewport,
|
|
21
|
+
// try to reposition it on the left side of cursor.
|
|
22
|
+
// If menu overflows to the left of viewport after repositioning,
|
|
23
|
+
// choose a side which has less overflow
|
|
24
|
+
// and adjust x to have it contained within the viewport.
|
|
25
|
+
const rightOverflow = getRightOverflow(x);
|
|
26
|
+
if (rightOverflow > 0) {
|
|
27
|
+
const adjustedX = x - menuRect.width;
|
|
28
|
+
const leftOverflow = getLeftOverflow(adjustedX);
|
|
29
|
+
if (leftOverflow >= 0 || -leftOverflow < rightOverflow) {
|
|
30
|
+
x = adjustedX;
|
|
31
|
+
}
|
|
32
|
+
x = confineHorizontally(x);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Similar logic to the left and right side above.
|
|
36
|
+
let computedDirection = "bottom";
|
|
37
|
+
const bottomOverflow = getBottomOverflow(y);
|
|
38
|
+
if (bottomOverflow > 0) {
|
|
39
|
+
const adjustedY = y - menuRect.height;
|
|
40
|
+
const topOverflow = getTopOverflow(adjustedY);
|
|
41
|
+
if (topOverflow >= 0 || -topOverflow < bottomOverflow) {
|
|
42
|
+
y = adjustedY;
|
|
43
|
+
computedDirection = "top";
|
|
44
|
+
}
|
|
45
|
+
y = confineVertically(y);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { x, y, computedDirection };
|
|
49
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { placeLeftorRight } from "./placeLeftorRight";
|
|
3
|
+
import { placeToporBottom } from "./placeToporBottom";
|
|
4
|
+
|
|
5
|
+
export const positionMenu = ({
|
|
6
|
+
arrow,
|
|
7
|
+
align,
|
|
8
|
+
direction,
|
|
9
|
+
offsetX,
|
|
10
|
+
offsetY,
|
|
11
|
+
position,
|
|
12
|
+
anchorRef,
|
|
13
|
+
arrowRef,
|
|
14
|
+
positionHelpers,
|
|
15
|
+
}) => {
|
|
16
|
+
const { menuRect, containerRect } = positionHelpers;
|
|
17
|
+
|
|
18
|
+
let horizontalOffset = offsetX;
|
|
19
|
+
let verticalOffset = offsetY;
|
|
20
|
+
if (arrow) {
|
|
21
|
+
if (direction === "left" || direction === "right") {
|
|
22
|
+
horizontalOffset += arrowRef.current.offsetWidth;
|
|
23
|
+
} else {
|
|
24
|
+
verticalOffset += arrowRef.current.offsetHeight;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const anchorRect = anchorRef.current.getBoundingClientRect();
|
|
29
|
+
const placeLeftX = anchorRect.left - containerRect.left - menuRect.width - horizontalOffset;
|
|
30
|
+
const placeRightX = anchorRect.right - containerRect.left + horizontalOffset;
|
|
31
|
+
const placeTopY = anchorRect.top - containerRect.top - menuRect.height - verticalOffset;
|
|
32
|
+
const placeBottomY = anchorRect.bottom - containerRect.top + verticalOffset;
|
|
33
|
+
|
|
34
|
+
let placeToporBottomX, placeLeftorRightY;
|
|
35
|
+
if (align === "end") {
|
|
36
|
+
placeToporBottomX = anchorRect.right - containerRect.left - menuRect.width;
|
|
37
|
+
placeLeftorRightY = anchorRect.bottom - containerRect.top - menuRect.height;
|
|
38
|
+
} else if (align === "center") {
|
|
39
|
+
placeToporBottomX = anchorRect.left - containerRect.left - (menuRect.width - anchorRect.width) / 2;
|
|
40
|
+
placeLeftorRightY = anchorRect.top - containerRect.top - (menuRect.height - anchorRect.height) / 2;
|
|
41
|
+
} else {
|
|
42
|
+
placeToporBottomX = anchorRect.left - containerRect.left;
|
|
43
|
+
placeLeftorRightY = anchorRect.top - containerRect.top;
|
|
44
|
+
}
|
|
45
|
+
placeToporBottomX += horizontalOffset;
|
|
46
|
+
placeLeftorRightY += verticalOffset;
|
|
47
|
+
|
|
48
|
+
const options = {
|
|
49
|
+
...positionHelpers,
|
|
50
|
+
anchorRect,
|
|
51
|
+
placeLeftX,
|
|
52
|
+
placeRightX,
|
|
53
|
+
placeLeftorRightY,
|
|
54
|
+
placeTopY,
|
|
55
|
+
placeBottomY,
|
|
56
|
+
placeToporBottomX,
|
|
57
|
+
arrowRef,
|
|
58
|
+
arrow,
|
|
59
|
+
direction,
|
|
60
|
+
position,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
switch (direction) {
|
|
64
|
+
case "left":
|
|
65
|
+
case "right":
|
|
66
|
+
return placeLeftorRight(options);
|
|
67
|
+
|
|
68
|
+
case "top":
|
|
69
|
+
case "bottom":
|
|
70
|
+
default:
|
|
71
|
+
return placeToporBottom(options);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
menuContainerClass,
|
|
3
|
+
menuButtonClass,
|
|
4
|
+
menuClass,
|
|
5
|
+
menuArrowClass,
|
|
6
|
+
menuItemClass,
|
|
7
|
+
menuDividerClass,
|
|
8
|
+
menuHeaderClass,
|
|
9
|
+
menuGroupClass,
|
|
10
|
+
radioGroupClass,
|
|
11
|
+
subMenuClass,
|
|
12
|
+
} from "../utils";
|
|
13
|
+
|
|
14
|
+
const bem = (block) => (element) => (modifier) => {
|
|
15
|
+
let selector = `.${block}`;
|
|
16
|
+
if (element) selector += `__${element}`;
|
|
17
|
+
if (modifier) selector += `--${modifier}`;
|
|
18
|
+
return selector;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const createSelector = (blockElement, modifiers = []) => {
|
|
22
|
+
const selectorObj = {};
|
|
23
|
+
Object.defineProperty(selectorObj, "name", {
|
|
24
|
+
value: blockElement(),
|
|
25
|
+
enumerable: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
modifiers.forEach((modifier) => {
|
|
29
|
+
const selector = modifier.split("-").reduce((prev, curr) => `${prev}${curr[0].toUpperCase()}${curr.slice(1)}`);
|
|
30
|
+
Object.defineProperty(selectorObj, selector, {
|
|
31
|
+
value: blockElement(modifier),
|
|
32
|
+
enumerable: true,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return selectorObj;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const directions = ["dir-left", "dir-right", "dir-top", "dir-bottom"];
|
|
40
|
+
const menuBlock = bem(menuClass);
|
|
41
|
+
const menuSelector = createSelector(menuBlock(), [
|
|
42
|
+
"state-opening",
|
|
43
|
+
"state-open",
|
|
44
|
+
"state-closing",
|
|
45
|
+
"state-closed",
|
|
46
|
+
...directions,
|
|
47
|
+
]);
|
|
48
|
+
const menuArrowSelector = createSelector(menuBlock(menuArrowClass), directions);
|
|
49
|
+
const menuItemSelector = createSelector(menuBlock(menuItemClass), [
|
|
50
|
+
"hover",
|
|
51
|
+
"disabled",
|
|
52
|
+
"anchor",
|
|
53
|
+
"checked",
|
|
54
|
+
"open",
|
|
55
|
+
"submenu",
|
|
56
|
+
"focusable",
|
|
57
|
+
"type-radio",
|
|
58
|
+
"type-checkbox",
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const menuDividerSelector = createSelector(menuBlock(menuDividerClass));
|
|
62
|
+
const menuHeaderSelector = createSelector(menuBlock(menuHeaderClass));
|
|
63
|
+
const menuGroupSelector = createSelector(menuBlock(menuGroupClass));
|
|
64
|
+
const radioGroupSelector = createSelector(menuBlock(radioGroupClass));
|
|
65
|
+
const submenuSelector = createSelector(menuBlock(subMenuClass));
|
|
66
|
+
const menuContainerSelector = createSelector(bem(menuContainerClass)(), ["itemTransition"]);
|
|
67
|
+
const menuButtonSelector = createSelector(bem(menuButtonClass)(), ["open"]);
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
menuContainerSelector,
|
|
71
|
+
menuButtonSelector,
|
|
72
|
+
menuSelector,
|
|
73
|
+
menuArrowSelector,
|
|
74
|
+
menuItemSelector,
|
|
75
|
+
menuDividerSelector,
|
|
76
|
+
menuHeaderSelector,
|
|
77
|
+
menuGroupSelector,
|
|
78
|
+
radioGroupSelector,
|
|
79
|
+
submenuSelector,
|
|
80
|
+
};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
interface Base {
|
|
2
|
+
/**
|
|
3
|
+
* CSS selector for the element itself
|
|
4
|
+
*/
|
|
5
|
+
name: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface Directions {
|
|
9
|
+
/**
|
|
10
|
+
* Menu opens to the left
|
|
11
|
+
*/
|
|
12
|
+
dirLeft: string;
|
|
13
|
+
/**
|
|
14
|
+
* Menu opens to the right
|
|
15
|
+
*/
|
|
16
|
+
dirRight: string;
|
|
17
|
+
/**
|
|
18
|
+
* Menu opens to the top
|
|
19
|
+
*/
|
|
20
|
+
dirTop: string;
|
|
21
|
+
/**
|
|
22
|
+
* Menu opens to the bottom
|
|
23
|
+
*/
|
|
24
|
+
dirBottom: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const menuSelector: Readonly<
|
|
28
|
+
Base &
|
|
29
|
+
Directions & {
|
|
30
|
+
/**
|
|
31
|
+
* Menu transitions from closed to open
|
|
32
|
+
*/
|
|
33
|
+
stateOpening: string;
|
|
34
|
+
/**
|
|
35
|
+
* Menu is open
|
|
36
|
+
*/
|
|
37
|
+
stateOpen: string;
|
|
38
|
+
/**
|
|
39
|
+
* Menu transitions from open to closed
|
|
40
|
+
*/
|
|
41
|
+
stateClosing: string;
|
|
42
|
+
/**
|
|
43
|
+
* Menu is closed
|
|
44
|
+
*/
|
|
45
|
+
stateClosed: string;
|
|
46
|
+
}
|
|
47
|
+
>;
|
|
48
|
+
|
|
49
|
+
export const menuArrowSelector: Readonly<Base & Directions>;
|
|
50
|
+
|
|
51
|
+
export const menuItemSelector: Readonly<
|
|
52
|
+
Base & {
|
|
53
|
+
/**
|
|
54
|
+
* Menu item is hovered and focused
|
|
55
|
+
*/
|
|
56
|
+
hover: string;
|
|
57
|
+
/**
|
|
58
|
+
* Menu item is disabled
|
|
59
|
+
*/
|
|
60
|
+
disabled: string;
|
|
61
|
+
/**
|
|
62
|
+
* Menu item is a URL link (when the `href` prop is set)
|
|
63
|
+
*/
|
|
64
|
+
anchor: string;
|
|
65
|
+
/**
|
|
66
|
+
* Menu item is checked (only for a radio or checkbox item)
|
|
67
|
+
*/
|
|
68
|
+
checked: string;
|
|
69
|
+
/**
|
|
70
|
+
* Present on a submenu item when it's submenu is open
|
|
71
|
+
*/
|
|
72
|
+
open: string;
|
|
73
|
+
/**
|
|
74
|
+
* Present on a submenu item, which is set by the `label` prop on `SubMenu` component
|
|
75
|
+
*/
|
|
76
|
+
submenu: string;
|
|
77
|
+
/**
|
|
78
|
+
* Present on a `FocusableItem`
|
|
79
|
+
*/
|
|
80
|
+
focusable: string;
|
|
81
|
+
/**
|
|
82
|
+
* Menu item is a radio item
|
|
83
|
+
*/
|
|
84
|
+
typeRadio: string;
|
|
85
|
+
/**
|
|
86
|
+
* Menu item is a checkbox item
|
|
87
|
+
*/
|
|
88
|
+
typeCheckbox: string;
|
|
89
|
+
}
|
|
90
|
+
>;
|
|
91
|
+
|
|
92
|
+
export const menuDividerSelector: Readonly<Base>;
|
|
93
|
+
export const menuHeaderSelector: Readonly<Base>;
|
|
94
|
+
export const menuGroupSelector: Readonly<Base>;
|
|
95
|
+
export const radioGroupSelector: Readonly<Base>;
|
|
96
|
+
export const submenuSelector: Readonly<Base>;
|
|
97
|
+
|
|
98
|
+
export const menuContainerSelector: Readonly<
|
|
99
|
+
Base & {
|
|
100
|
+
itemTransition: string;
|
|
101
|
+
}
|
|
102
|
+
>;
|
|
103
|
+
|
|
104
|
+
export const menuButtonSelector: Readonly<
|
|
105
|
+
Base & {
|
|
106
|
+
open: string;
|
|
107
|
+
}
|
|
108
|
+
>;
|
|
109
|
+
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@use 'sass:math';
|
|
2
|
+
|
|
3
|
+
$color: #212529;
|
|
4
|
+
$color-dark: #cad1d8;
|
|
5
|
+
$color-disabled: #aaa;
|
|
6
|
+
$color-disabled-dark: #666;
|
|
7
|
+
|
|
8
|
+
$header-color: #888;
|
|
9
|
+
$divider-color: rgba(0, 0, 0, 0.12);
|
|
10
|
+
$divider-color-dark: #3a3a3a;
|
|
11
|
+
$border-color: rgba(0, 0, 0, 0.1);
|
|
12
|
+
$border-color-dark: #333;
|
|
13
|
+
|
|
14
|
+
$background-color: #fff;
|
|
15
|
+
$background-color-dark: #22262c;
|
|
16
|
+
$background-color-hover: #ebebeb;
|
|
17
|
+
$background-color-hover-dark: #31363c;
|
|
18
|
+
|
|
19
|
+
$arrow-size: 0.75rem;
|
|
20
|
+
$arrow-pos: -(math.div($arrow-size, 2));
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
@use 'var';
|
|
2
|
+
@use 'mixins';
|
|
3
|
+
|
|
4
|
+
.szh-menu {
|
|
5
|
+
@include mixins.reset-list;
|
|
6
|
+
@include mixins.remove-focus;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
width: max-content;
|
|
9
|
+
z-index: 100;
|
|
10
|
+
border: 1px solid var.$border-color;
|
|
11
|
+
background-color: var.$background-color;
|
|
12
|
+
|
|
13
|
+
&__arrow {
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
width: var.$arrow-size;
|
|
16
|
+
height: var.$arrow-size;
|
|
17
|
+
background-color: var.$background-color;
|
|
18
|
+
border: 1px solid transparent;
|
|
19
|
+
border-left-color: var.$border-color;
|
|
20
|
+
border-top-color: var.$border-color;
|
|
21
|
+
z-index: -1;
|
|
22
|
+
|
|
23
|
+
&--dir-left {
|
|
24
|
+
right: var.$arrow-pos;
|
|
25
|
+
transform: translateY(-50%) rotate(135deg);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&--dir-right {
|
|
29
|
+
left: var.$arrow-pos;
|
|
30
|
+
transform: translateY(-50%) rotate(-45deg);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&--dir-top {
|
|
34
|
+
bottom: var.$arrow-pos;
|
|
35
|
+
transform: translateX(-50%) rotate(-135deg);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&--dir-bottom {
|
|
39
|
+
top: var.$arrow-pos;
|
|
40
|
+
transform: translateX(-50%) rotate(45deg);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&__item {
|
|
45
|
+
@include mixins.remove-focus;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
|
|
48
|
+
&--hover {
|
|
49
|
+
background-color: var.$background-color-hover;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&--focusable {
|
|
53
|
+
cursor: default;
|
|
54
|
+
background-color: inherit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&--disabled {
|
|
58
|
+
cursor: default;
|
|
59
|
+
color: var.$color-disabled;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&__group {
|
|
64
|
+
box-sizing: border-box;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&__radio-group {
|
|
68
|
+
@include mixins.reset-list;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&__divider {
|
|
72
|
+
height: 1px;
|
|
73
|
+
margin: 0.5rem 0;
|
|
74
|
+
background-color: var.$divider-color;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.szh-menu-button {
|
|
79
|
+
box-sizing: border-box;
|
|
80
|
+
}
|