@@ -5,14 +5,15 @@ import type {
5
5
} from "@tiptap/suggestion" ;
6
6
import { forwardRef , useEffect , useImperativeHandle , useState } from "react" ;
7
7
import { Tag } from "../../Tag/Tag" ;
8
+ import type { PlainTag } from "../../../../interfaces/Tag" ;
8
9
9
10
export const NEW_TAG_PREFIX = 'New tag "' ;
10
11
export const getNewTagPhrase = ( tag : string ) =>
11
12
`${ NEW_TAG_PREFIX } ${ tag . toLowerCase ( ) } "` ;
12
13
13
14
export let isUserSelectingTag = false ;
14
15
15
- type Props = SuggestionProps < { name : string ; hue : number } , MentionNodeAttrs > ;
16
+ type Props = SuggestionProps < PlainTag , MentionNodeAttrs > ;
16
17
17
18
export type TagListRef = {
18
19
onKeyDown : ( data : SuggestionKeyDownProps ) => boolean ;
@@ -49,12 +50,25 @@ export const TagList = forwardRef<TagListRef, Props>((props, ref) => {
49
50
}
50
51
} ;
51
52
53
+ const scrollIntoView = ( index : number ) => {
54
+ const itemElement = document . querySelector (
55
+ `[data-selector=tags-dropdown]>:nth-child(${ index + 1 } )` ,
56
+ ) ;
57
+ itemElement ?. scrollIntoView ( {
58
+ block : "nearest" ,
59
+ } ) ;
60
+ } ;
61
+
52
62
const upHandler = ( ) => {
53
- setSelectedIndex ( ( selectedIndex + items . length - 1 ) % items . length ) ;
63
+ const nextIndex = ( selectedIndex + items . length - 1 ) % items . length ;
64
+ setSelectedIndex ( nextIndex ) ;
65
+ scrollIntoView ( nextIndex ) ;
54
66
} ;
55
67
56
68
const downHandler = ( ) => {
57
- setSelectedIndex ( ( selectedIndex + 1 ) % items . length ) ;
69
+ const nextIndex = ( selectedIndex + 1 ) % items . length ;
70
+ setSelectedIndex ( nextIndex ) ;
71
+ scrollIntoView ( nextIndex ) ;
58
72
} ;
59
73
60
74
const enterHandler = ( ) => {
@@ -93,12 +107,15 @@ export const TagList = forwardRef<TagListRef, Props>((props, ref) => {
93
107
} ) ) ;
94
108
95
109
return (
96
- < div className = "bg-white border border-stone-400 rounded-md shadow flex flex-col gap-1 scroll-auto px-3 py-2 relative" >
110
+ < div
111
+ data-selector = "tags-dropdown"
112
+ className = "bg-white border border-stone-400 rounded-md shadow flex flex-col gap-1 scroll-auto px-3 py-2 relative overflow-y-auto max-h-64"
113
+ >
97
114
{ items . length ? (
98
115
items . map ( ( item , index ) => (
99
116
< button
100
117
type = "button"
101
- className = { `flex gap-1 text-left py-1 px-3 rounded-md ${ index === selectedIndex ? "bg-stone-300" : "hover:bg-stone-200" } ` }
118
+ className = { `flex flex-col gap-1 text-left py-1 px-3 rounded-md ${ index === selectedIndex ? "bg-stone-300" : "hover:bg-stone-200" } ` }
102
119
key = { item . name }
103
120
title = { item . name }
104
121
onClick = { ( ) => selectItem ( index ) }
@@ -107,6 +124,13 @@ export const TagList = forwardRef<TagListRef, Props>((props, ref) => {
107
124
name = { item . name }
108
125
hue = { item . hue }
109
126
/>
127
+ < div
128
+ className = "text-sm text-stone-500 px-2 max-h-10 overflow-hidden text-clip"
129
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: it's html entered by the user in the TextInput, they get what they deserve
130
+ dangerouslySetInnerHTML = { {
131
+ __html : item . description ?? "" ,
132
+ } }
133
+ />
110
134
</ button >
111
135
) )
112
136
) : (
0 commit comments