Skip to content

Commit e22cbd0

Browse files
committed
fix(popup): handle auto scroll and remove useless deps effect
Signed-off-by: aphilibeaux <[email protected]>
1 parent 868225e commit e22cbd0

File tree

4 files changed

+89
-51
lines changed

4 files changed

+89
-51
lines changed

packages/ui/src/components/DateInput/components/Popup.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import type { Dispatch, ReactNode, RefObject, SetStateAction } from 'react'
4-
import { useEffect, useRef } from 'react'
4+
import { useLayoutEffect, useRef } from 'react'
55
import { Popup } from '../../Popup'
66
import { POPUP_WIDTH } from '../constants'
77
import { dateinputPopup } from './styles.css'
@@ -38,7 +38,7 @@ export const CalendarPopup = ({
3838
}: PopupProps) => {
3939
const ref = useRef<HTMLDivElement>(null)
4040

41-
useEffect(() => {
41+
useLayoutEffect(() => {
4242
document.addEventListener('mousedown', event =>
4343
handleClickOutside(event, ref, setVisible, refInput),
4444
)

packages/ui/src/components/SelectInput/components/Dropdown.tsx

Lines changed: 85 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22

33
import { useTheme } from '@ultraviolet/themes'
44
import type {
5+
ChangeEvent,
56
ComponentProps,
67
Dispatch,
78
KeyboardEvent,
9+
MouseEvent,
810
ReactNode,
911
RefObject,
1012
SetStateAction,
1113
} from 'react'
1214
import {
15+
use,
1316
useCallback,
14-
useContext,
1517
useEffect,
18+
useLayoutEffect,
1619
useMemo,
1720
useRef,
1821
useState,
@@ -219,13 +222,26 @@ const CreateDropdown = ({
219222
)
220223
}
221224

222-
const handleClick = (clickedOption: OptionType, group?: string) => {
225+
const handleClick = ({
226+
clickedOption,
227+
group,
228+
event,
229+
}: {
230+
clickedOption: OptionType
231+
group?: string
232+
event:
233+
| MouseEvent<HTMLDivElement>
234+
| KeyboardEvent<HTMLDivElement>
235+
| ChangeEvent<HTMLDivElement>
236+
}) => {
237+
event.stopPropagation()
238+
223239
setSelectedData({ clickedOption, group, type: 'selectOption' })
224240
if (multiselect) {
225241
if (selectedData.selectedValues.includes(clickedOption.value)) {
226242
onChange?.(
227243
selectedData.selectedValues.filter(
228-
val => val !== clickedOption.value,
244+
value => value !== clickedOption.value,
229245
),
230246
)
231247
} else {
@@ -420,16 +436,25 @@ const CreateDropdown = ({
420436
data-testid={`option-${option.value}`}
421437
id={`option-${indexOption}`}
422438
key={option.value}
423-
onClick={() => {
439+
onClick={event => {
424440
if (!option.disabled) {
425-
handleClick(option, group)
441+
handleClick({
442+
clickedOption: option,
443+
event,
444+
group,
445+
})
446+
}
447+
}}
448+
onKeyDown={event => {
449+
const shouldClick = [' ', 'Enter'].includes(event.key)
450+
if (shouldClick) {
451+
handleClick({
452+
clickedOption: option,
453+
event,
454+
group,
455+
})
426456
}
427457
}}
428-
onKeyDown={event =>
429-
[' ', 'Enter'].includes(event.key)
430-
? handleClick(option, group)
431-
: null
432-
}
433458
ref={
434459
option.value === defaultSearchValue ||
435460
option.searchText === defaultSearchValue
@@ -447,9 +472,13 @@ const CreateDropdown = ({
447472
}
448473
className={dropdownCheckbox}
449474
disabled={option.disabled}
450-
onChange={() => {
475+
onChange={event => {
451476
if (!option.disabled) {
452-
handleClick(option, group)
477+
handleClick({
478+
clickedOption: option,
479+
event,
480+
group,
481+
})
453482
}
454483
}}
455484
tabIndex={-1}
@@ -548,14 +577,23 @@ const CreateDropdown = ({
548577
data-testid={`option-${option.value}`}
549578
id={`option-${index}`}
550579
key={option.value}
551-
onClick={() => {
580+
onClick={event => {
552581
if (!option.disabled) {
553-
handleClick(option)
582+
handleClick({
583+
clickedOption: option,
584+
event,
585+
})
586+
}
587+
}}
588+
onKeyDown={event => {
589+
const shouldClick = [' ', 'Enter'].includes(event.key)
590+
if (shouldClick) {
591+
handleClick({
592+
clickedOption: option,
593+
event,
594+
})
554595
}
555596
}}
556-
onKeyDown={event =>
557-
[' ', 'Enter'].includes(event.key) ? handleClick(option) : null
558-
}
559597
ref={
560598
option.value === defaultSearchValue ||
561599
option.searchText === defaultSearchValue
@@ -573,9 +611,12 @@ const CreateDropdown = ({
573611
}
574612
className={dropdownCheckbox}
575613
disabled={option.disabled}
576-
onChange={() => {
614+
onChange={event => {
577615
if (!option.disabled) {
578-
handleClick(option)
616+
handleClick({
617+
clickedOption: option,
618+
event,
619+
})
579620
}
580621
}}
581622
tabIndex={-1}
@@ -637,35 +678,41 @@ export const Dropdown = ({
637678
const [maxWidth, setWidth] = useState<string | number>(
638679
refSelect.current?.offsetWidth ?? '100%',
639680
)
640-
const modalContext = useContext(ModalContext)
681+
const modalContext = use(ModalContext)
641682

642-
useEffect(() => {
683+
useLayoutEffect(() => {
643684
if (refSelect.current && isDropdownVisible) {
644685
const position =
645686
refSelect.current.getBoundingClientRect().bottom +
646687
DROPDOWN_MAX_HEIGHT +
647688
Number(theme.sizing[INPUT_SIZE_HEIGHT[size]].replace('rem', '')) * 16 +
648689
Number.parseInt(theme.space['5'], 10)
649690
const overflow = position - window.innerHeight + 32
691+
650692
if (overflow > 0 && modalContext) {
651693
const currentModal = modalContext.openedModals[0]
652694
const modalElement = currentModal?.ref.current
653695

654696
if (modalElement) {
655-
const parentElement = modalElement.parentNode as HTMLElement
656-
if (parentElement) {
697+
const parentElement = modalElement.parentNode
698+
699+
if (parentElement instanceof HTMLElement) {
657700
parentElement.scrollBy({
658701
behavior: 'smooth',
659702
top: overflow,
660703
})
704+
} else {
705+
modalElement.scrollBy({
706+
behavior: 'smooth',
707+
top: overflow,
708+
})
661709
}
662710
} else {
663711
window.scrollBy({ behavior: 'smooth', top: overflow })
664712
}
665713
}
666714
}
667-
// oxlint-disable react/exhaustive-deps
668-
}, [isDropdownVisible, refSelect, size, ref.current])
715+
}, [isDropdownVisible, refSelect, size, modalContext, theme])
669716

670717
const resizeDropdown = useCallback(() => {
671718
if (
@@ -696,33 +743,24 @@ export const Dropdown = ({
696743
setSearch('')
697744
}
698745

699-
if (!searchable) {
700-
document.addEventListener('keydown', event =>
701-
handleKeyDown(
702-
event,
703-
ref,
704-
options,
705-
searchBarActive,
706-
setSearch,
707-
setDefaultSearch,
708-
search,
709-
),
746+
const eventKeydown = (event: globalThis.KeyboardEvent) =>
747+
handleKeyDown(
748+
event,
749+
ref,
750+
options,
751+
searchBarActive,
752+
setSearch,
753+
setDefaultSearch,
754+
search,
710755
)
756+
757+
if (!searchable) {
758+
document.addEventListener('keydown', eventKeydown)
711759
}
712760

713761
return () => {
714762
if (!searchable) {
715-
document.removeEventListener('keydown', event =>
716-
handleKeyDown(
717-
event,
718-
ref,
719-
options,
720-
searchBarActive,
721-
setSearch,
722-
setDefaultSearch,
723-
search,
724-
),
725-
)
763+
document.removeEventListener('keydown', eventKeydown)
726764
}
727765
}
728766
}, [

packages/ui/src/components/TagList/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ export const TagList = ({
223223
const visibleTagsCopy = visibleTags.filter(
224224
(_, index) => index < visibleTags.length - 1,
225225
)
226-
const tagToMove = visibleTags[visibleTags.length - 1] ?? ''
226+
const tagToMove = visibleTags.at(-1) ?? ''
227227

228228
setVisibleTags(visibleTagsCopy)
229229
setHiddenTags([tagToMove, ...hiddenTags])

packages/ui/src/components/VerificationCode/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ export const VerificationCode = ({
133133
const prevIndex = index - 1
134134
const nextIndex = index + 1
135135
const first = inputRefs[0]
136-
const last = inputRefs[inputRefs.length - 1]
136+
const last = inputRefs.at(-1)
137137
const prev = inputRefs[prevIndex]
138138
const next = inputRefs[nextIndex]
139139
const vals = [...values]

0 commit comments

Comments
 (0)