|
1 | 1 | 'use client'; |
2 | | -import {Fragment, Ref, useEffect, useMemo, useRef, useState} from 'react'; |
| 2 | +import {Fragment, Ref, startTransition, useCallback, useEffect, useMemo, useRef, useState} from 'react'; |
3 | 3 | import {Combobox, ComboboxItem, ComboboxList, ComboboxProvider} from '@ariakit/react'; |
4 | 4 | import {CaretRightIcon, CaretSortIcon, MagnifyingGlassIcon} from '@radix-ui/react-icons'; |
5 | 5 | import * as RadixSelect from '@radix-ui/react-select'; |
@@ -63,25 +63,40 @@ export function PlatformSelector({ |
63 | 63 | const currentPlatformKey = currentPlatform?.key; |
64 | 64 | const [open, setOpen] = useState(false); |
65 | 65 | const [searchValue, setSearchValue] = useState(''); |
| 66 | + |
| 67 | + // Controlled search handler for virtual guide stability |
| 68 | + const handleSearchValueChange = useCallback((value: string) => { |
| 69 | + // Use startTransition for virtual guides to prevent focus issues |
| 70 | + if (currentPlatformKey === 'javascript-platform') { |
| 71 | + startTransition(() => setSearchValue(value)); |
| 72 | + } else { |
| 73 | + setSearchValue(value); |
| 74 | + } |
| 75 | + }, [currentPlatformKey]); |
66 | 76 |
|
67 | 77 | const matches = useMemo(() => { |
68 | 78 | if (!searchValue) { |
69 | 79 | return platformsAndGuides; |
70 | 80 | } |
| 81 | + |
| 82 | + // Find the currently selected platform/guide first |
| 83 | + const selectedPlatform = platformsAndGuides.find( |
| 84 | + lang => lang.key === currentPlatformKey |
| 85 | + ); |
| 86 | + |
71 | 87 | // any of these fields can be used to match the search value |
72 | 88 | const keys = ['title', 'name', 'aliases', 'sdk', 'keywords']; |
73 | | - const matches_ = matchSorter(platformsAndGuides, searchValue, { |
| 89 | + let matches_ = matchSorter(platformsAndGuides, searchValue, { |
74 | 90 | keys, |
75 | 91 | threshold: matchSorter.rankings.ACRONYM, |
76 | 92 | }); |
77 | | - // Radix Select does not work if we don't render the selected item, so we |
78 | | - // make sure to include it in the list of matches. |
79 | | - const selectedPlatform = platformsAndGuides.find( |
80 | | - lang => lang.key === currentPlatformKey |
81 | | - ); |
| 93 | + |
| 94 | + // For virtual guides (like javascript-platform), ensure they're always included |
| 95 | + // when they're the current selection, to prevent focus/display issues |
82 | 96 | if (selectedPlatform && !matches_.includes(selectedPlatform)) { |
83 | | - matches_.push(selectedPlatform); |
| 97 | + matches_ = [selectedPlatform, ...matches_]; |
84 | 98 | } |
| 99 | + |
85 | 100 | return matches_; |
86 | 101 | }, [searchValue, currentPlatformKey, platformsAndGuides]); |
87 | 102 |
|
@@ -161,7 +176,7 @@ export function PlatformSelector({ |
161 | 176 | open={open} |
162 | 177 | setOpen={setOpen} |
163 | 178 | includesBaseElement={false} |
164 | | - setValue={setSearchValue} |
| 179 | + setValue={handleSearchValueChange} |
165 | 180 | > |
166 | 181 | <RadixSelect.Trigger aria-label="Platform" className={styles.select}> |
167 | 182 | <RadixSelect.Value placeholder="Choose your SDK" /> |
|
0 commit comments