Skip to content

Commit 9981a8a

Browse files
committed
Merge branch 'develop' of https://github.com/devtron-labs/devtron-fe-common-lib into fix/ai-fixes
2 parents b07ed17 + 19aed84 commit 9981a8a

24 files changed

Lines changed: 565 additions & 291 deletions

.eslintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ src/Common/DebouncedSearch/__tests__/DebouncedSearch.test.tsx
2323
src/Common/DevtronProgressing/DevtronProgressing.tsx
2424
src/Common/Dialogs/DialogForm.tsx
2525
src/Common/DraggableWrapper/DraggableButton.tsx
26-
src/Common/DraggableWrapper/DraggableWrapper.tsx
2726
src/Common/Drawer/Drawer.tsx
2827
src/Common/Grid/Grid.tsx
2928
src/Common/Helper.tsx

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "1.22.8-beta-5",
3+
"version": "1.22.8-beta-10",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Assets/IconV2/ic-ses.svg

Lines changed: 6 additions & 0 deletions
Loading

src/Assets/IconV2/ic-slack.svg

Lines changed: 10 additions & 0 deletions
Loading

src/Assets/IconV2/ic-smtp.svg

Lines changed: 7 additions & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Loading

src/Common/DraggableWrapper/DraggableWrapper.tsx

Lines changed: 49 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,37 @@
1515
*/
1616

1717
import { useEffect, useRef, useState } from 'react'
18-
import Draggable, { ControlPosition, DraggableData } from 'react-draggable'
19-
import { DraggableWrapperProps, DraggablePositionVariant } from './types'
20-
import { useWindowSize } from '../Hooks'
18+
import Draggable, { ControlPosition } from 'react-draggable'
19+
20+
import { DEVTRON_BASE_MAIN_ID } from '@Shared/constants'
21+
2122
import { MAX_Z_INDEX } from '../Constants'
23+
import { useWindowSize } from '../Hooks'
24+
import { DraggablePositionVariant, DraggableWrapperProps } from './types'
2225

2326
/**
2427
* TODO: import it as lazy, after it is supported in common
2528
* 1. If using react select please use menuPlacement='auto'
2629
* 2. dragSelector will be used to identify the grabbable button that will grab the div to drag
27-
* 3. parentRef is the reference point from which we will derive the base top:0 ,left: 0 position
30+
* 3. The wrapper is positioned at the viewport's top-left (top: 0, left: 0) using fixed positioning; parentRef is an optional
31+
* reference that may be used for position calculations but is not the base origin for the coordinate system.
2832
*/
29-
export default function DraggableWrapper({
33+
const DraggableWrapper = ({
3034
children,
3135
zIndex = MAX_Z_INDEX,
3236
positionVariant,
3337
dragSelector,
3438
parentRef,
35-
boundaryGap = 16,
39+
boundaryGap = { x: 16, y: 16 },
3640
childDivProps = {},
37-
layoutFixDelta = 0,
38-
}: DraggableWrapperProps) {
41+
}: DraggableWrapperProps) => {
3942
const windowSize = useWindowSize()
4043
const nodeRef = useRef<HTMLDivElement>(null)
4144

42-
const [position, setPosition] = useState<ControlPosition>({
43-
x: 0,
44-
y: 0,
45-
})
45+
// letting the dom render the element without displaying it so that we know it's dimensions
46+
const [initialRenderDone, setInitialRenderDone] = useState(false)
4647

47-
const getDefaultPosition = (positionVariant: DraggablePositionVariant): ControlPosition => {
48+
const getDefaultPosition = (): ControlPosition => {
4849
// if this return x: 0, y: 0 then it will be top left corner of parentDiv
4950
const parentRect =
5051
parentRef?.current?.getBoundingClientRect() ??
@@ -60,73 +61,62 @@ export default function DraggableWrapper({
6061

6162
switch (positionVariant) {
6263
case DraggablePositionVariant.PARENT_BOTTOM_CENTER: {
63-
// currently at parentRect.x and need to start to the center of its width and half of node should lie on left of center and other half on right
64-
const x = (parentRect.width - nodeRefWidth) / 2
65-
// TODO (v3): Temp fix. Revisit
66-
const parentRectTop = parentRect.top > 0 ? parentRect.top : layoutFixDelta
67-
// currently at parentRect.y now parent height can be greater than windowSize.height so taking min
68-
// subtracting parentRect.top since window height already contains that
69-
const baseY =
70-
parentRect.height > windowSize.height ? windowSize.height - parentRectTop : parentRect.height
71-
const y = baseY - nodeRefHeight - boundaryGap
64+
// center div to middle of the parent rect and then add the left offset of the parent rect
65+
const x = (parentRect.width - nodeRefWidth) / 2 + parentRect.left
66+
if (parentRect.height > windowSize.height) {
67+
// since the parent itself overflows, we use windowSize for calculations
68+
return { x, y: windowSize.height - boundaryGap.y - nodeRefHeight }
69+
}
70+
// y = parentRect.bottom will place the widget at the extreme bottom of the parent,
71+
// therefore need to offset it to the top by boundary and its own height
72+
const y = parentRect.bottom - nodeRefHeight - boundaryGap.y
7273
return { x, y }
7374
}
7475
case DraggablePositionVariant.SCREEN_BOTTOM_RIGHT: {
75-
const x = windowSize.width - parentRect.left - nodeRefWidth - boundaryGap
76-
const y = windowSize.height - parentRect.top - nodeRefHeight - boundaryGap
76+
// x = windowSize.width will place the widget at the extreme right,
77+
// therefore need to offset it to the left by boundary and its own width
78+
const x = windowSize.width - nodeRefWidth - boundaryGap.x
79+
// y = windowSize.height will place the widget at the extreme bottom,
80+
// therefore need to offset it to the top by boundary and its own height
81+
const y = windowSize.height - nodeRefHeight - boundaryGap.y
7782

7883
return { x, y }
7984
}
8085
// Add more cases for other variants if needed
8186
default: {
82-
// Since need node to be in center of screen so subtracting width/2 by left of parentRect it will start the node from center but want node's midpoint at center so subtracting node's width from it.
83-
const x = windowSize.width / 2 - parentRect.left - nodeRefWidth / 2
84-
// subtracting top since windowSize already contains that
85-
const y = windowSize.height - parentRect.top - nodeRefHeight - boundaryGap
87+
// we need to first place the start of the widget at (windowSize.width / 2)
88+
// followed by moving it half of its own width to the left such that center of widget
89+
// aligns with the central axis of the screen
90+
const x = (windowSize.width - nodeRefWidth) / 2
91+
// y = windowSize.height will place the widget at the extreme bottom,
92+
// therefore need to offset it to the top by boundary and its own height
93+
const y = windowSize.height - nodeRefHeight - boundaryGap.y
8694

8795
return { x, y }
8896
}
8997
}
9098
}
9199

92-
// On change of windowSize we will reset the position to default
93100
useEffect(() => {
94-
const defaultPosition = getDefaultPosition(positionVariant)
95-
setPosition(defaultPosition)
96-
}, [nodeRef, positionVariant, windowSize])
97-
98-
// Would be called on drag and will not update the state if the new position is out of window screen
99-
function handlePositionChange(e, data: DraggableData) {
100-
const offsetX = parentRef?.current?.getBoundingClientRect().left ?? 0
101-
const offsetY = parentRef?.current?.getBoundingClientRect().top ?? 0
102-
103-
const nodeRefHeight = nodeRef.current?.getBoundingClientRect().height ?? 0
104-
const nodeRefWidth = nodeRef.current?.getBoundingClientRect().width ?? 0
105-
106-
if (
107-
offsetX + data.x + nodeRefWidth + boundaryGap > windowSize.width ||
108-
offsetY + data.y + nodeRefHeight + boundaryGap > windowSize.height ||
109-
offsetX + data.x < 0 ||
110-
offsetY + data.y < 0
111-
) {
112-
return
113-
}
114-
115-
setPosition({
116-
x: data.x,
117-
y: data.y,
118-
})
119-
}
101+
// make the element visible after the initial render
102+
setInitialRenderDone(true)
103+
}, [])
120104

121105
return (
122106
// Since we are using position fixed so we need to disable click on the div so that it does not interfere with the click of other elements
123107
<div
124-
className="dc__position-fixed dc__disable-click"
108+
className={`dc__position-fixed dc__disable-click dc__top-0 dc__left-0 ${initialRenderDone ? '' : 'dc__visibility-hidden'}`}
125109
style={{
126110
zIndex,
127111
}}
128112
>
129-
<Draggable handle={dragSelector} nodeRef={nodeRef} position={position} onDrag={handlePositionChange}>
113+
<Draggable
114+
key={`${windowSize.height}-${windowSize.width}-${initialRenderDone}`}
115+
handle={dragSelector}
116+
defaultPosition={getDefaultPosition()}
117+
bounds={`#${DEVTRON_BASE_MAIN_ID}`}
118+
nodeRef={nodeRef}
119+
>
130120
<div
131121
ref={nodeRef}
132122
{...childDivProps}
@@ -141,3 +131,5 @@ export default function DraggableWrapper({
141131
</div>
142132
)
143133
}
134+
135+
export default DraggableWrapper

src/Common/DraggableWrapper/types.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { HTMLAttributes, ReactNode, RefObject } from 'react'
1818

1919
export enum DraggablePositionVariant {
2020
PARENT_BOTTOM_CENTER = 'PARENT_BOTTOM_CENTER',
21+
PARENT_BOTTOM_RIGHT = 'PARENT_BOTTOM_RIGHT',
2122
SCREEN_BOTTOM_CENTER = 'SCREEN_BOTTOM_CENTER',
2223
SCREEN_BOTTOM_RIGHT = 'SCREEN_BOTTOM_RIGHT',
2324
// Can add more based on requirement
@@ -35,13 +36,8 @@ export interface DraggableWrapperProps {
3536
*/
3637
dragSelector: string
3738
parentRef?: RefObject<HTMLDivElement>
38-
boundaryGap?: number
39+
boundaryGap?: Record<'x' | 'y', number>
3940
childDivProps?: HTMLAttributes<HTMLDivElement>
40-
/**
41-
* Delta for fixing the scrollable layout positioning
42-
* @deprecated
43-
*/
44-
layoutFixDelta?: number
4541
}
4642

4743
/**

0 commit comments

Comments
 (0)