@@ -47,9 +47,40 @@ export function WhereClauseEditor({
4747 const [ isDismissed , setIsDismissed ] = React . useState ( false )
4848 const [ activeIndex , setActiveIndex ] = React . useState ( 0 )
4949
50- React . useEffect ( ( ) => {
51- setCursor ( ( current ) => Math . min ( current , value . length ) )
52- } , [ value ] )
50+ const lastAttrKeyRef = React . useRef < string | null > ( null )
51+ const lastResourceKeyRef = React . useRef < string | null > ( null )
52+
53+ const notifyActiveKeys = React . useCallback (
54+ ( expression : string , cursorPos : number ) => {
55+ const ac = getWhereClauseAutocomplete ( {
56+ expression,
57+ cursor : cursorPos ,
58+ dataSource,
59+ values,
60+ scope : autocompleteScope ,
61+ maxSuggestions,
62+ } )
63+
64+ const nextAttrKey =
65+ ac . context === "value" && ac . key ?. startsWith ( "attr." )
66+ ? ac . key . slice ( 5 )
67+ : null
68+ if ( nextAttrKey !== lastAttrKeyRef . current ) {
69+ lastAttrKeyRef . current = nextAttrKey
70+ onActiveAttributeKey ?.( nextAttrKey )
71+ }
72+
73+ const nextResourceKey =
74+ ac . context === "value" && ac . key ?. startsWith ( "resource." )
75+ ? ac . key . slice ( 9 )
76+ : null
77+ if ( nextResourceKey !== lastResourceKeyRef . current ) {
78+ lastResourceKeyRef . current = nextResourceKey
79+ onActiveResourceAttributeKey ?.( nextResourceKey )
80+ }
81+ } ,
82+ [ autocompleteScope , dataSource , maxSuggestions , onActiveAttributeKey , onActiveResourceAttributeKey , values ] ,
83+ )
5384
5485 const autocomplete = React . useMemo (
5586 ( ) =>
@@ -64,37 +95,19 @@ export function WhereClauseEditor({
6495 [ autocompleteScope , cursor , dataSource , maxSuggestions , value , values ] ,
6596 )
6697
67- // Notify parent when user is editing a value for an attr.* key
68- React . useEffect ( ( ) => {
69- if ( ! onActiveAttributeKey ) return
70- if ( autocomplete . context === "value" && autocomplete . key ?. startsWith ( "attr." ) ) {
71- onActiveAttributeKey ( autocomplete . key . slice ( 5 ) )
72- } else {
73- onActiveAttributeKey ( null )
74- }
75- } , [ autocomplete . context , autocomplete . key , onActiveAttributeKey ] )
76-
77- // Notify parent when user is editing a value for a resource.* key
78- React . useEffect ( ( ) => {
79- if ( ! onActiveResourceAttributeKey ) return
80- if ( autocomplete . context === "value" && autocomplete . key ?. startsWith ( "resource." ) ) {
81- onActiveResourceAttributeKey ( autocomplete . key . slice ( 9 ) )
82- } else {
83- onActiveResourceAttributeKey ( null )
84- }
85- } , [ autocomplete . context , autocomplete . key , onActiveResourceAttributeKey ] )
86-
8798 const suggestions = autocomplete . suggestions
8899 const isOpen = isFocused && ! isDismissed && suggestions . length > 0
89100
90- React . useEffect ( ( ) => {
91- setActiveIndex ( 0 )
92- } , [ autocomplete . context , autocomplete . query , suggestions . length ] )
93-
94- const syncCursor = React . useCallback ( ( target : HTMLTextAreaElement ) => {
95- setCursor ( target . selectionStart ?? target . value . length )
96- setIsDismissed ( false )
97- } , [ ] )
101+ const syncCursor = React . useCallback (
102+ ( target : HTMLTextAreaElement ) => {
103+ const pos = target . selectionStart ?? target . value . length
104+ setCursor ( pos )
105+ setIsDismissed ( false )
106+ setActiveIndex ( 0 )
107+ notifyActiveKeys ( target . value , pos )
108+ } ,
109+ [ notifyActiveKeys ] ,
110+ )
98111
99112 const applySuggestion = React . useCallback (
100113 ( index : number ) => {
@@ -114,6 +127,7 @@ export function WhereClauseEditor({
114127 onChange ( applied . expression )
115128 setCursor ( applied . cursor )
116129 setIsDismissed ( false )
130+ notifyActiveKeys ( applied . expression , applied . cursor )
117131
118132 const schedule = ( callback : ( ) => void ) => {
119133 if ( typeof window !== "undefined" && window . requestAnimationFrame ) {
@@ -134,7 +148,7 @@ export function WhereClauseEditor({
134148 textarea . setSelectionRange ( applied . cursor , applied . cursor )
135149 } )
136150 } ,
137- [ autocomplete . context , autocomplete . replaceEnd , autocomplete . replaceStart , onChange , suggestions , value ] ,
151+ [ autocomplete . context , autocomplete . replaceEnd , autocomplete . replaceStart , notifyActiveKeys , onChange , suggestions , value ] ,
138152 )
139153
140154 return (
@@ -155,8 +169,12 @@ export function WhereClauseEditor({
155169 setIsFocused ( false )
156170 } }
157171 onChange = { ( event ) => {
158- syncCursor ( event . currentTarget )
172+ const pos = event . currentTarget . selectionStart ?? event . currentTarget . value . length
173+ setCursor ( pos )
174+ setIsDismissed ( false )
175+ setActiveIndex ( 0 )
159176 onChange ( event . target . value )
177+ notifyActiveKeys ( event . target . value , pos )
160178 } }
161179 onClick = { ( event ) => syncCursor ( event . currentTarget ) }
162180 onSelect = { ( event ) => syncCursor ( event . currentTarget ) }
0 commit comments