@@ -3,7 +3,6 @@ import { useRef, useState } from 'react'
3
3
import { classNames } from '../../utils/class-names'
4
4
5
5
import { Button } from '../../components/button'
6
- import { flushSync } from 'react-dom'
7
6
8
7
type Option = {
9
8
name : string
@@ -13,32 +12,32 @@ type Option = {
13
12
14
13
export default function Home ( ) {
15
14
let [ list , setList ] = useState < Option [ ] > ( ( ) => [
16
- { name : 'Alice' , disabled : false } ,
17
- { name : 'Bob' , disabled : false } ,
18
- { name : 'Charlie' , disabled : false } ,
19
- { name : 'David' , disabled : false } ,
20
- { name : 'Eve' , disabled : false } ,
21
- { name : 'Fred' , disabled : false } ,
22
- { name : 'George' , disabled : false } ,
23
- { name : 'Helen' , disabled : false } ,
24
- { name : 'Iris' , disabled : false } ,
25
- { name : 'John' , disabled : false } ,
26
- { name : 'Kate' , disabled : false } ,
27
- { name : 'Linda' , disabled : false } ,
28
- { name : 'Michael' , disabled : false } ,
29
- { name : 'Nancy' , disabled : false } ,
30
- { name : 'Oscar' , disabled : true } ,
31
- { name : 'Peter' , disabled : false } ,
32
- { name : 'Quentin' , disabled : false } ,
33
- { name : 'Robert' , disabled : false } ,
34
- { name : 'Sarah' , disabled : false } ,
35
- { name : 'Thomas' , disabled : false } ,
36
- { name : 'Ursula' , disabled : false } ,
37
- { name : 'Victor' , disabled : false } ,
38
- { name : 'Wendy' , disabled : false } ,
39
- { name : 'Xavier' , disabled : false } ,
40
- { name : 'Yvonne' , disabled : false } ,
41
- { name : 'Zachary' , disabled : false } ,
15
+ { name : 'Alice' , disabled : false } ,
16
+ { name : 'Bob' , disabled : false } ,
17
+ { name : 'Charlie' , disabled : false } ,
18
+ { name : 'David' , disabled : false } ,
19
+ { name : 'Eve' , disabled : false } ,
20
+ { name : 'Fred' , disabled : false } ,
21
+ { name : 'George' , disabled : false } ,
22
+ { name : 'Helen' , disabled : false } ,
23
+ { name : 'Iris' , disabled : false } ,
24
+ { name : 'John' , disabled : false } ,
25
+ { name : 'Kate' , disabled : false } ,
26
+ { name : 'Linda' , disabled : false } ,
27
+ { name : 'Michael' , disabled : false } ,
28
+ { name : 'Nancy' , disabled : false } ,
29
+ { name : 'Oscar' , disabled : true } ,
30
+ { name : 'Peter' , disabled : false } ,
31
+ { name : 'Quentin' , disabled : false } ,
32
+ { name : 'Robert' , disabled : false } ,
33
+ { name : 'Sarah' , disabled : false } ,
34
+ { name : 'Thomas' , disabled : false } ,
35
+ { name : 'Ursula' , disabled : false } ,
36
+ { name : 'Victor' , disabled : false } ,
37
+ { name : 'Wendy' , disabled : false } ,
38
+ { name : 'Xavier' , disabled : false } ,
39
+ { name : 'Yvonne' , disabled : false } ,
40
+ { name : 'Zachary' , disabled : false } ,
42
41
] )
43
42
44
43
let emptyOption = useRef ( { name : 'No results' , disabled : true , empty : true } )
@@ -52,10 +51,9 @@ export default function Home() {
52
51
? list
53
52
: list . filter ( ( item ) => item . name . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) )
54
53
55
-
56
54
return (
57
55
< div className = "mx-auto max-w-fit" >
58
- < div className = "py-8 font-mono text-xs" > Selected person: { selectedPerson ?. name ?? " N/A" } </ div >
56
+ < div className = "py-8 font-mono text-xs" > Selected person: { selectedPerson ?. name ?? ' N/A' } </ div >
59
57
< Combobox
60
58
virtual = { {
61
59
options : filtered . length > 0 ? filtered : [ emptyOption . current ] ,
@@ -68,12 +66,11 @@ export default function Home() {
68
66
setQuery ( '' )
69
67
} }
70
68
as = "div"
71
-
72
69
// Don't do this lol — it's not supported
73
70
// It's just so we can tab to the "Add" button for the demo
74
71
// The combobox doesn't actually support this behavior
75
72
onKeyDownCapture = { ( event : KeyboardEvent ) => {
76
- let addButton = document . querySelector ( '#add_person' )
73
+ let addButton = document . querySelector ( '#add_person' ) as HTMLElement | null
77
74
if ( event . key === 'Tab' && addButton && filtered . length === 0 ) {
78
75
event . preventDefault ( )
79
76
setTimeout ( ( ) => addButton . focus ( ) , 0 )
@@ -116,69 +113,76 @@ export default function Home() {
116
113
// It comes with some caveats:
117
114
// like the option callback being called with a null option (which is probably a bug)
118
115
static = { filtered . length === 0 }
119
-
120
116
ref = { optionsRef }
121
117
className = { classNames (
122
- " shadow-xs max-h-60 rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5" ,
118
+ ' shadow-xs max-h-60 rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5' ,
123
119
filtered . length === 0 ? 'overflow-hidden' : 'overflow-auto'
124
120
) }
125
121
>
126
- {
127
- ( { option } : { option : Option } ) => {
128
- if ( ! option || option . empty ) {
129
- return (
130
- < Combobox . Option
131
- // TODO: `disabled` being required is a bug
132
- disabled
133
- // Note: Do NOT use `null` for the `value`
134
- value = { option ?? emptyOption . current }
135
- className = "relative w-full cursor-default select-none py-2 px-3 focus:outline-none text-center"
136
- >
137
- < div className = "grid grid-cols-1 grid-rows-1 h-full relative" >
138
- < div className = "absolute inset-0" >
139
- < svg fill = "none" viewBox = "0 0 24 24" strokeWidth = { 0.5 } stroke = "currentColor" className = "text-gray-500/5 -translate-y-1/4" >
140
- < path strokeLinecap = "round" strokeLinejoin = "round" d = "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z" />
141
- </ svg >
142
- </ div >
143
- < div className = "z-20 col-start-1 row-start-1 col-span-full row-span-full p-8 flex flex-col justify-center items-center" >
144
- < h3 className = "mx-2 text-xl mb-4 text-gray-400 font-semibold" > No people found</ h3 >
145
- < button
146
- id = "add_person"
147
- type = "button"
148
- className = "bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded font-semibold focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:outline-none"
149
- onClick = { ( ) => {
150
- let person = { name : query , disabled : false }
151
- setList ( list => [ ...list , person ] )
152
- setSelectedPerson ( person )
153
- } }
154
- >
155
- Add "{ query } "
156
- </ button >
157
- </ div >
158
- </ div >
159
- </ Combobox . Option >
160
- )
161
- }
162
-
122
+ { ( { option } : { option : Option } ) => {
123
+ if ( ! option || option . empty ) {
163
124
return (
164
125
< Combobox . Option
165
126
// TODO: `disabled` being required is a bug
166
- disabled = { option . disabled }
167
- value = { option }
168
- className = { ( { active } ) => {
169
- return classNames (
170
- 'relative w-full cursor-default select-none py-2 pl-3 pr-9 focus:outline-none' ,
171
- active ? 'bg-indigo-600 text-white' : 'text-gray-900'
172
- )
173
- } }
127
+ disabled
128
+ // Note: Do NOT use `null` for the `value`
129
+ value = { option ?? emptyOption . current }
130
+ className = "relative w-full cursor-default select-none px-3 py-2 text-center focus:outline-none"
174
131
>
175
- < span className = 'block truncate' >
176
- { option . name }
177
- </ span >
132
+ < div className = "relative grid h-full grid-cols-1 grid-rows-1" >
133
+ < div className = "absolute inset-0" >
134
+ < svg
135
+ fill = "none"
136
+ viewBox = "0 0 24 24"
137
+ strokeWidth = { 0.5 }
138
+ stroke = "currentColor"
139
+ className = "-translate-y-1/4 text-gray-500/5"
140
+ >
141
+ < path
142
+ strokeLinecap = "round"
143
+ strokeLinejoin = "round"
144
+ d = "M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z"
145
+ />
146
+ </ svg >
147
+ </ div >
148
+ < div className = "z-20 col-span-full col-start-1 row-span-full row-start-1 flex flex-col items-center justify-center p-8" >
149
+ < h3 className = "mx-2 mb-4 text-xl font-semibold text-gray-400" >
150
+ No people found
151
+ </ h3 >
152
+ < button
153
+ id = "add_person"
154
+ type = "button"
155
+ className = "rounded bg-blue-500 px-4 py-2 font-semibold text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
156
+ onClick = { ( ) => {
157
+ let person = { name : query , disabled : false }
158
+ setList ( ( list ) => [ ...list , person ] )
159
+ setSelectedPerson ( person )
160
+ } }
161
+ >
162
+ Add "{ query } "
163
+ </ button >
164
+ </ div >
165
+ </ div >
178
166
</ Combobox . Option >
179
167
)
180
168
}
181
- }
169
+
170
+ return (
171
+ < Combobox . Option
172
+ // TODO: `disabled` being required is a bug
173
+ disabled = { option . disabled }
174
+ value = { option }
175
+ className = { ( { active } ) => {
176
+ return classNames (
177
+ 'relative w-full cursor-default select-none py-2 pl-3 pr-9 focus:outline-none' ,
178
+ active ? 'bg-indigo-600 text-white' : 'text-gray-900'
179
+ )
180
+ } }
181
+ >
182
+ < span className = "block truncate" > { option . name } </ span >
183
+ </ Combobox . Option >
184
+ )
185
+ } }
182
186
</ Combobox . Options >
183
187
</ div >
184
188
</ div >
0 commit comments