11'use client' ;
2- import { Fragment , Ref , useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
2+ import { Fragment , Ref , useEffect , useMemo , useRef , useState } from 'react' ;
33import { Combobox , ComboboxItem , ComboboxList , ComboboxProvider } from '@ariakit/react' ;
44import { CaretRightIcon , CaretSortIcon , MagnifyingGlassIcon } from '@radix-ui/react-icons' ;
55import * as RadixSelect from '@radix-ui/react-select' ;
@@ -63,47 +63,42 @@ export function PlatformSelector({
6363 const currentPlatformKey = currentPlatform ?. key ;
6464 const [ open , setOpen ] = useState ( false ) ;
6565 const [ searchValue , setSearchValue ] = useState ( '' ) ;
66- const debounceRef = useRef < NodeJS . Timeout > ( ) ;
67-
68- // Debounced search handler to prevent rapid re-renders
69- const debouncedSetSearchValue = useCallback ( ( value : string ) => {
70- if ( debounceRef . current ) {
71- clearTimeout ( debounceRef . current ) ;
72- }
73- debounceRef . current = setTimeout ( ( ) => setSearchValue ( value ) , 100 ) ;
74- } , [ ] ) ;
7566
7667 const matches = useMemo ( ( ) => {
7768 if ( ! searchValue ) {
7869 return platformsAndGuides ;
7970 }
80-
81- // Find currently selected platform first to ensure it's never filtered out
82- const selectedPlatform = platformsAndGuides . find (
83- lang => lang . key === currentPlatformKey
84- ) ;
85-
86- // Filter out the selected platform from search, then add it back at the end
87- const otherPlatforms = platformsAndGuides . filter (
88- lang => lang . key !== currentPlatformKey
89- ) ;
90-
9171 // any of these fields can be used to match the search value
9272 const keys = [ 'title' , 'name' , 'aliases' , 'sdk' , 'keywords' ] ;
93- const matches_ = matchSorter ( otherPlatforms , searchValue , {
73+ const matches_ = matchSorter ( platformsAndGuides , searchValue , {
9474 keys,
9575 threshold : matchSorter . rankings . ACRONYM ,
9676 } ) ;
97-
98- // Always include the selected platform at the beginning
99- return selectedPlatform ? [ selectedPlatform , ...matches_ ] : matches_ ;
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+ ) ;
82+ if ( selectedPlatform && ! matches_ . includes ( selectedPlatform ) ) {
83+ matches_ . push ( selectedPlatform ) ;
84+ }
85+ return matches_ ;
10086 } , [ searchValue , currentPlatformKey , platformsAndGuides ] ) ;
10187
10288 const router = useRouter ( ) ;
10389 const onPlatformChange = ( platformKey : string ) => {
10490 const cleanKey = platformKey . replace ( '-redirect' , '' ) ;
105- const targetPlatform = platformsAndGuides . find ( platform => platform . key === cleanKey ) ;
106-
91+ let targetPlatform = platformsAndGuides . find ( platform => platform . key === cleanKey ) ;
92+
93+ // Special handling for JavaScript: when platform "javascript" is selected,
94+ // redirect to the real browser guide "javascript.browser" instead
95+ if ( cleanKey === 'javascript' && targetPlatform ?. type === 'platform' ) {
96+ const browserGuide = platformsAndGuides . find ( p => p . key === 'javascript.browser' ) ;
97+ if ( browserGuide ) {
98+ targetPlatform = browserGuide ;
99+ }
100+ }
101+
107102 if ( targetPlatform ) {
108103 localStorage . setItem ( 'active-platform' , targetPlatform . key ) ;
109104 router . push ( targetPlatform . url ) ;
@@ -120,9 +115,17 @@ export function PlatformSelector({
120115 } , [ open ] ) ;
121116
122117 const [ storedPlatformKey , setStoredPlatformKey ] = useState < string | null > ( null ) ;
123- const storedPlatform = platformsAndGuides . find (
118+ let storedPlatform = platformsAndGuides . find (
124119 platform => platform . key === storedPlatformKey
125120 ) ;
121+
122+ // Handle stored JavaScript platform: redirect to browser guide
123+ if ( storedPlatformKey === 'javascript' && storedPlatform ?. type === 'platform' ) {
124+ const browserGuide = platformsAndGuides . find ( p => p . key === 'javascript.browser' ) ;
125+ if ( browserGuide ) {
126+ storedPlatform = browserGuide ;
127+ }
128+ }
126129
127130 useEffect ( ( ) => {
128131 if ( currentPlatformKey ) {
@@ -132,15 +135,6 @@ export function PlatformSelector({
132135 }
133136 } , [ currentPlatformKey ] ) ;
134137
135- // Cleanup debounce timer on unmount
136- useEffect ( ( ) => {
137- return ( ) => {
138- if ( debounceRef . current ) {
139- clearTimeout ( debounceRef . current ) ;
140- }
141- } ;
142- } , [ ] ) ;
143-
144138 const path = usePathname ( ) ;
145139 const isPlatformPage = Boolean (
146140 path ?. startsWith ( '/platforms/' ) &&
@@ -158,7 +152,7 @@ export function PlatformSelector({
158152 < div >
159153 < RadixSelect . Root
160154 defaultValue = { currentPlatformKey }
161- value = { showStoredPlatform ? storedPlatformKey : undefined }
155+ value = { showStoredPlatform ? storedPlatform ?. key : undefined }
162156 onValueChange = { onPlatformChange }
163157 open = { open }
164158 onOpenChange = { setOpen }
@@ -167,7 +161,7 @@ export function PlatformSelector({
167161 open = { open }
168162 setOpen = { setOpen }
169163 includesBaseElement = { false }
170- setValue = { debouncedSetSearchValue }
164+ setValue = { setSearchValue }
171165 >
172166 < RadixSelect . Trigger aria-label = "Platform" className = { styles . select } >
173167 < RadixSelect . Value placeholder = "Choose your SDK" />
0 commit comments