#806 resolve double tab to select timezone-issue

This commit is contained in:
lethemanh
2026-04-18 10:45:31 +07:00
parent d42fe1ce9f
commit d8c35c5c48
5 changed files with 44 additions and 19 deletions
+11
View File
@@ -41,6 +41,7 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router-dom": "^6.23.1", "react-router-dom": "^6.23.1",
"react-virtuoso": "^4.18.5",
"redux-first-history": "^5.2.0", "redux-first-history": "^5.2.0",
"twake-i18n": "^0.3.0", "twake-i18n": "^0.3.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
@@ -12616,6 +12617,16 @@
"react-dom": ">=16.6.0" "react-dom": ">=16.6.0"
} }
}, },
"node_modules/react-virtuoso": {
"version": "4.18.5",
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.18.5.tgz",
"integrity": "sha512-QDyNjyNEuurZG67SOmzYyxEkQYSyGmAMixOI6M15L/Q4CF39EgG+88y6DgZRo0q7rmy0HPx3Fj90I8/tPdnRCQ==",
"license": "MIT",
"peerDependencies": {
"react": ">=16 || >=17 || >= 18 || >= 19",
"react-dom": ">=16 || >=17 || >= 18 || >=19"
}
},
"node_modules/read-cache": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+1
View File
@@ -36,6 +36,7 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-redux": "^9.2.0", "react-redux": "^9.2.0",
"react-router-dom": "^6.23.1", "react-router-dom": "^6.23.1",
"react-virtuoso": "^4.18.5",
"redux-first-history": "^5.2.0", "redux-first-history": "^5.2.0",
"twake-i18n": "^0.3.0", "twake-i18n": "^0.3.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
@@ -9,6 +9,7 @@ import {
} from '@linagora/twake-mui' } from '@linagora/twake-mui'
import { Search as SearchIcon } from '@mui/icons-material' import { Search as SearchIcon } from '@mui/icons-material'
import React, { useState, useMemo, useEffect, useRef } from 'react' import React, { useState, useMemo, useEffect, useRef } from 'react'
import { Virtuoso } from 'react-virtuoso'
import { useTimeZoneList } from './hooks/useTimeZoneList' import { useTimeZoneList } from './hooks/useTimeZoneList'
import { TimezoneSelectProps } from './TimezoneSelector' import { TimezoneSelectProps } from './TimezoneSelector'
import { useI18n } from 'twake-i18n' import { useI18n } from 'twake-i18n'
@@ -31,6 +32,14 @@ const filterTimezones = (
}) })
} }
const VirtuosoList = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>((props, ref) => (
<List component="div" {...props} ref={ref} sx={{ pt: 0, pb: 0 }} />
))
VirtuosoList.displayName = 'VirtuosoList'
export const SmallTimezoneSelector: React.FC< export const SmallTimezoneSelector: React.FC<
TimezoneSelectProps & { TimezoneSelectProps & {
onClose: () => void onClose: () => void
@@ -57,7 +66,6 @@ export const SmallTimezoneSelector: React.FC<
onClose() onClose()
} }
const selectedRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLInputElement>(null) const inputRef = useRef<HTMLInputElement>(null)
const paperRef = useRef<HTMLDivElement>(null) const paperRef = useRef<HTMLDivElement>(null)
@@ -96,7 +104,6 @@ export const SmallTimezoneSelector: React.FC<
} }
inputRef.current?.focus() inputRef.current?.focus()
selectedRef.current?.scrollIntoView({ behavior: 'auto', block: 'start' })
return (): void => { return (): void => {
if (viewport) { if (viewport) {
@@ -158,18 +165,27 @@ export const SmallTimezoneSelector: React.FC<
}} }}
/> />
</Box> </Box>
<List sx={{ overflow: 'auto', flex: 1, pt: 0 }}> <Box sx={{ flex: 1, minHeight: 0 }}>
{filteredTimeZones.map(tz => ( <Virtuoso
<TimezoneListItem data={filteredTimeZones}
key={tz} initialTopMostItemIndex={Math.max(
tz={tz} 0,
referenceDate={referenceDate} filteredTimeZones.findIndex(tz => tz === effectiveTimezone)
isSelected={effectiveTimezone === tz} )}
onSelect={handleSelect} components={{
selectedRef={selectedRef} List: VirtuosoList
/> }}
))} itemContent={(_index, tz) => (
</List> <TimezoneListItem
key={tz}
tz={tz}
referenceDate={referenceDate}
isSelected={effectiveTimezone === tz}
onSelect={handleSelect}
/>
)}
/>
</Box>
</StyledSwipeableDrawer> </StyledSwipeableDrawer>
) )
} }
@@ -42,7 +42,7 @@ export function TimezoneAutocomplete({
disableClearable = false, disableClearable = false,
hideBorder = false, hideBorder = false,
openOnFocus = false openOnFocus = false
}: TimezoneAutocompleteProps) { }: TimezoneAutocompleteProps): React.ReactElement {
const options = useMemo<TimezoneOption[]>(() => { const options = useMemo<TimezoneOption[]>(() => {
return zones.map(tz => ({ return zones.map(tz => ({
value: tz, value: tz,
+1 -4
View File
@@ -15,15 +15,13 @@ interface TimezoneListItemProps {
referenceDate: Date referenceDate: Date
isSelected: boolean isSelected: boolean
onSelect: (tz: string) => void onSelect: (tz: string) => void
selectedRef: React.RefObject<HTMLDivElement> | null
} }
export const TimezoneListItem: React.FC<TimezoneListItemProps> = ({ export const TimezoneListItem: React.FC<TimezoneListItemProps> = ({
tz, tz,
referenceDate, referenceDate,
isSelected, isSelected,
onSelect, onSelect
selectedRef
}) => { }) => {
const theme = useTheme() const theme = useTheme()
const offset = getTimezoneOffset(tz, referenceDate) const offset = getTimezoneOffset(tz, referenceDate)
@@ -34,7 +32,6 @@ export const TimezoneListItem: React.FC<TimezoneListItemProps> = ({
<ListItemButton <ListItemButton
selected={isSelected} selected={isSelected}
aria-selected={isSelected} aria-selected={isSelected}
ref={isSelected ? selectedRef : null}
onClick={() => onSelect(tz)} onClick={() => onSelect(tz)}
sx={{ py: 1 }} sx={{ py: 1 }}
> >