Skip to content

Commit f405945

Browse files
author
Amrit Kashyap Borah
committed
refactor: use DraggableWrapper in FloatingVariableSuggestions
1 parent 30ee20c commit f405945

4 files changed

Lines changed: 70 additions & 178 deletions

File tree

src/Common/DraggableWrapper/DraggableWrapper.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const DraggableWrapper = ({
3636
positionVariant,
3737
dragSelector,
3838
parentRef,
39-
boundaryGap = 16,
39+
boundaryGap = { x: 16, y: 16 },
4040
childDivProps = {},
4141
}: DraggableWrapperProps) => {
4242
const windowSize = useWindowSize()
@@ -64,21 +64,21 @@ const DraggableWrapper = ({
6464
// center div to middle of the parent rect and then add the left offset of the parent rect
6565
const x = (parentRect.width - nodeRefWidth) / 2 + parentRect.left
6666
if (parentRect.height > windowSize.height) {
67-
return { x, y: windowSize.height - boundaryGap - nodeRefHeight }
67+
return { x, y: windowSize.height - boundaryGap.y - nodeRefHeight }
6868
}
69-
const y = parentRect.bottom - nodeRefHeight - boundaryGap
69+
const y = parentRect.bottom - nodeRefHeight - boundaryGap.y
7070
return { x, y }
7171
}
7272
case DraggablePositionVariant.SCREEN_BOTTOM_RIGHT: {
73-
const x = windowSize.width - nodeRefWidth - boundaryGap
74-
const y = windowSize.height - nodeRefHeight - boundaryGap
73+
const x = windowSize.width - nodeRefWidth - boundaryGap.x
74+
const y = windowSize.height - nodeRefHeight - boundaryGap.y
7575

7676
return { x, y }
7777
}
7878
// Add more cases for other variants if needed
7979
default: {
8080
const x = (windowSize.width - nodeRefWidth) / 2
81-
const y = windowSize.height - nodeRefHeight - boundaryGap
81+
const y = windowSize.height - nodeRefHeight - boundaryGap.y
8282

8383
return { x, y }
8484
}

src/Common/DraggableWrapper/types.ts

Lines changed: 2 additions & 1 deletion
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,7 +36,7 @@ export interface DraggableWrapperProps {
3536
*/
3637
dragSelector: string
3738
parentRef?: RefObject<HTMLDivElement>
38-
boundaryGap?: number
39+
boundaryGap?: Record<'x' | 'y', number>
3940
childDivProps?: HTMLAttributes<HTMLDivElement>
4041
}
4142

src/Shared/Components/FloatingVariablesSuggestions/FloatingVariablesSuggestions.tsx

Lines changed: 62 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,15 @@
1414
* limitations under the License.
1515
*/
1616

17-
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
18-
import Draggable from 'react-draggable'
17+
import React, { memo, useCallback, useState } from 'react'
1918
import Tippy from '@tippyjs/react'
2019

2120
import { ReactComponent as ICDrag } from '@Icons/ic-drag.svg'
21+
import { DraggablePositionVariant, DraggableWrapper } from '@Common/DraggableWrapper'
2222
import { useAsync } from '@Common/Helper'
23-
import { useWindowSize } from '@Common/Hooks'
2423
import { ALLOW_ACTION_OUTSIDE_FOCUS_TRAP } from '@Shared/constants'
2524

2625
import { Icon } from '../Icon'
27-
import { SUGGESTIONS_SIZE } from './constants'
2826
import { getScopedVariables } from './service'
2927
import Suggestions from './Suggestions'
3028
import { FloatingVariablesSuggestionsProps } from './types'
@@ -35,7 +33,6 @@ import { FloatingVariablesSuggestionsProps } from './types'
3533
* @param appId - To fetch the scoped variables
3634
* @param envId - (Optional)
3735
* @param clusterId - (Optional)
38-
* @param bounds - (Optional) To set the bounds of the suggestions
3936
* @param hideObjectVariables - (Optional) To hide the object/array variables, default is true
4037
* @returns
4138
*/
@@ -44,89 +41,18 @@ const FloatingVariablesSuggestions = ({
4441
appId,
4542
envId,
4643
clusterId,
47-
bounds,
4844
hideObjectVariables = true,
4945
showValueOnHover = true,
5046
isTemplateView,
5147
}: FloatingVariablesSuggestionsProps) => {
5248
const [isActive, setIsActive] = useState<boolean>(false)
53-
const [collapsedPosition, setCollapsedPosition] = useState<{ x: number; y: number }>({ x: 0, y: 0 })
54-
const [expandedPosition, setExpandedPosition] = useState<{ x: number; y: number }>({ x: 0, y: 0 })
5549

5650
const [loadingScopedVariables, variablesData, error, reloadScopedVariables] = useAsync(
5751
() => getScopedVariables(appId, envId, clusterId, { hideObjectVariables, isTemplateView }),
5852
[appId, envId, clusterId],
5953
)
6054

61-
const windowSize = useWindowSize()
62-
// In case of StrictMode, we get error findDOMNode is deprecated in StrictMode
63-
// So we use useRef to get the DOM node
64-
const nodeRef = useRef(null)
65-
66-
// nodeRef.current is dependency even though its a ref as initially its null and we need to get the
67-
// first value that it gets and after that is not going to trigger again
68-
const initialPosition = useMemo(() => {
69-
const initialPositionData = nodeRef.current?.getBoundingClientRect() || {
70-
x: 0,
71-
y: 0,
72-
}
73-
return { x: initialPositionData.x, y: initialPositionData.y }
74-
}, [nodeRef.current])
75-
76-
// The size of the active state can expand say in case user expands SuggestionsInfo and the widget is at bottom of screen
77-
useEffect(() => {
78-
const resizeObserver = new ResizeObserver((entries) => {
79-
if (entries?.length > 0 && isActive) {
80-
const { height } = entries[0].contentRect
81-
if (initialPosition.y + expandedPosition.y + height > windowSize.height) {
82-
setExpandedPosition({
83-
x: expandedPosition.x,
84-
y: windowSize.height - height - initialPosition.y,
85-
})
86-
}
87-
}
88-
})
89-
resizeObserver.observe(nodeRef.current)
90-
return () => {
91-
resizeObserver.disconnect()
92-
}
93-
}, [isActive, expandedPosition, windowSize, initialPosition])
94-
9555
const handleActivation = () => {
96-
const currentPosInScreen = {
97-
x: initialPosition.x + collapsedPosition.x,
98-
y: initialPosition.y + collapsedPosition.y,
99-
}
100-
101-
setExpandedPosition({
102-
x: collapsedPosition.x,
103-
y: collapsedPosition.y,
104-
})
105-
106-
if (currentPosInScreen.y > windowSize.height - SUGGESTIONS_SIZE.height) {
107-
setExpandedPosition({
108-
x: collapsedPosition.x,
109-
y: windowSize.height - SUGGESTIONS_SIZE.height - initialPosition.y,
110-
})
111-
}
112-
113-
if (currentPosInScreen.x > windowSize.width - SUGGESTIONS_SIZE.width) {
114-
setExpandedPosition({
115-
x: windowSize.width - SUGGESTIONS_SIZE.width - initialPosition.x,
116-
y: collapsedPosition.y,
117-
})
118-
}
119-
120-
if (
121-
currentPosInScreen.x > windowSize.width - SUGGESTIONS_SIZE.width &&
122-
currentPosInScreen.y > windowSize.height - SUGGESTIONS_SIZE.height
123-
) {
124-
setExpandedPosition({
125-
x: windowSize.width - SUGGESTIONS_SIZE.width - initialPosition.x,
126-
y: windowSize.height - SUGGESTIONS_SIZE.height - initialPosition.y,
127-
})
128-
}
129-
13056
setIsActive(true)
13157
}
13258

@@ -136,103 +62,71 @@ const FloatingVariablesSuggestions = ({
13662
setIsActive(false)
13763
}, [])
13864

139-
// e will be unused, but we need to pass it as a parameter since Draggable expects it
140-
const handleCollapsedDrag = (e, data: { x: number; y: number }) => {
141-
const currentPosInScreen = {
142-
x: initialPosition.x + data.x,
143-
y: initialPosition.y + data.y,
144-
}
145-
if (
146-
currentPosInScreen.y < 0 ||
147-
currentPosInScreen.x < 0 ||
148-
currentPosInScreen.x + (nodeRef.current?.getBoundingClientRect().width || 0) > windowSize.width ||
149-
currentPosInScreen.y + (nodeRef.current?.getBoundingClientRect().height || 0) > windowSize.height
150-
) {
151-
return
152-
}
153-
154-
setCollapsedPosition(data)
155-
}
65+
const boundaryGap = { x: 32, y: 90 }
15666

157-
const handleExpandedDrag = (e, data: { x: number; y: number }) => {
158-
const currentPosInScreen = {
159-
x: initialPosition.x + data.x,
160-
y: initialPosition.y + data.y,
161-
}
162-
if (
163-
currentPosInScreen.y < 0 ||
164-
currentPosInScreen.x < 0 ||
165-
currentPosInScreen.x + (nodeRef.current?.getBoundingClientRect().width || 0) > windowSize.width ||
166-
currentPosInScreen.y + (nodeRef.current?.getBoundingClientRect().height || 0) > windowSize.height
167-
) {
168-
return
169-
}
170-
setExpandedPosition(data)
171-
// Only Need to retain the collapsed position if the user has not dragged the suggestions, so need to update
172-
setCollapsedPosition(data)
173-
}
174-
175-
if (!isActive) {
176-
return (
177-
<Draggable
178-
bounds={bounds}
179-
handle=".handle-drag"
180-
nodeRef={nodeRef}
181-
position={collapsedPosition}
182-
onDrag={handleCollapsedDrag}
183-
>
184-
<div
185-
className="bcn-7 dc__outline-none-imp dc__border-n0 br-48 flex h-40 pt-8 pb-8 pl-12 pr-12 dc__gap-8 dc__no-shrink dc__position-abs"
186-
style={{ zIndex, boxShadow: '0px 4px 8px 0px rgba(0, 0, 0, 0.20)' }}
187-
ref={nodeRef}
188-
data-testid="collapsed-state"
67+
return (
68+
<>
69+
<div className={`${isActive ? 'dc__visibility-hidden dc__disable-click' : ''} `}>
70+
<DraggableWrapper
71+
key="collapsed"
72+
zIndex={zIndex}
73+
positionVariant={DraggablePositionVariant.SCREEN_BOTTOM_RIGHT}
74+
dragSelector=".handle-drag"
75+
boundaryGap={boundaryGap}
76+
parentRef={null}
18977
>
190-
<button type="button" className="dc__outline-none-imp dc__no-border p-0 bcn-7 h-24">
191-
<ICDrag className="handle-drag dc__grabbable icon-dim-24 fcn-2" />
192-
</button>
193-
194-
<Tippy content="Scoped variables" placement="top" className="default-tt" arrow={false}>
195-
<button
196-
className={`dc__outline-none-imp dc__no-border p-0 bcn-7 h-20 ${ALLOW_ACTION_OUTSIDE_FOCUS_TRAP}`}
197-
type="button"
198-
onClick={handleActivation}
199-
data-testid="activate-suggestions"
200-
aria-label="Activate suggestions"
201-
>
202-
<Icon name="ic-view-variable-toggle" color="N0" size={20} />
78+
<div
79+
className="bcn-7 dc__outline-none-imp dc__border-n0 br-48 flex h-40 pt-8 pb-8 pl-12 pr-12 dc__gap-8 dc__no-shrink"
80+
style={{ zIndex, boxShadow: '0px 4px 8px 0px rgba(0, 0, 0, 0.20)' }}
81+
data-testid="collapsed-state"
82+
>
83+
<button type="button" className="dc__outline-none-imp dc__no-border p-0 bcn-7 h-24">
84+
<ICDrag className="handle-drag dc__grabbable icon-dim-24 fcn-2" />
20385
</button>
204-
</Tippy>
205-
</div>
206-
</Draggable>
207-
)
208-
}
20986

210-
return (
211-
<Draggable
212-
bounds={bounds}
213-
handle=".handle-drag"
214-
nodeRef={nodeRef}
215-
position={expandedPosition}
216-
onDrag={handleExpandedDrag}
217-
>
218-
<div
219-
className={`flex column dc__no-shrink w-356 dc__content-space dc__border-radius-8-imp dc__border dc__overflow-hidden dc__position-abs mxh-504 bg__overlay--primary ${ALLOW_ACTION_OUTSIDE_FOCUS_TRAP}`}
220-
style={{
221-
zIndex,
222-
boxShadow: '0px 4px 8px 0px rgba(0, 0, 0, 0.25)',
223-
}}
224-
ref={nodeRef}
225-
>
226-
<Suggestions
227-
handleDeActivation={handleDeActivation}
228-
loading={loadingScopedVariables}
229-
variables={variablesData ?? []}
230-
reloadVariables={reloadScopedVariables}
231-
error={error}
232-
showValueOnHover={showValueOnHover}
233-
/>
87+
<Tippy content="Scoped variables" placement="top" className="default-tt" arrow={false}>
88+
<button
89+
className={`dc__outline-none-imp dc__no-border p-0 bcn-7 h-20 ${ALLOW_ACTION_OUTSIDE_FOCUS_TRAP}`}
90+
type="button"
91+
onClick={handleActivation}
92+
data-testid="activate-suggestions"
93+
aria-label="Activate suggestions"
94+
>
95+
<Icon name="ic-view-variable-toggle" color="N0" size={20} />
96+
</button>
97+
</Tippy>
98+
</div>
99+
</DraggableWrapper>
100+
</div>
101+
102+
<div className={`${!isActive ? 'dc__visibility-hidden dc__disable-click' : ''}`}>
103+
<DraggableWrapper
104+
key={`expanded-${loadingScopedVariables}`}
105+
zIndex={zIndex}
106+
positionVariant={DraggablePositionVariant.SCREEN_BOTTOM_RIGHT}
107+
dragSelector=".handle-drag"
108+
boundaryGap={boundaryGap}
109+
parentRef={null}
110+
>
111+
<div
112+
className={`flex column dc__no-shrink w-356 dc__content-space dc__border-radius-8-imp dc__border dc__overflow-hidden mxh-504 bg__overlay--primary ${ALLOW_ACTION_OUTSIDE_FOCUS_TRAP}`}
113+
style={{
114+
zIndex,
115+
boxShadow: '0px 4px 8px 0px rgba(0, 0, 0, 0.25)',
116+
}}
117+
>
118+
<Suggestions
119+
handleDeActivation={handleDeActivation}
120+
loading={loadingScopedVariables}
121+
variables={variablesData ?? []}
122+
reloadVariables={reloadScopedVariables}
123+
error={error}
124+
showValueOnHover={showValueOnHover}
125+
/>
126+
</div>
127+
</DraggableWrapper>
234128
</div>
235-
</Draggable>
129+
</>
236130
)
237131
}
238132

src/Shared/Components/FloatingVariablesSuggestions/types.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { DraggableBounds } from 'react-draggable'
18-
1917
import { AppConfigProps } from '@Pages/index'
2018

2119
export interface ScopedVariableType {
@@ -32,7 +30,6 @@ export interface FloatingVariablesSuggestionsProps extends Required<Pick<AppConf
3230
appId?: string
3331
envId?: string
3432
clusterId?: string
35-
bounds?: DraggableBounds | string | false
3633
/**
3734
* This will hide the variables with object/array values if set to true
3835
* @default true

0 commit comments

Comments
 (0)