@@ -1851,7 +1851,7 @@ describe('MentionsInput', () => {
18511851 const suggestions = document . createElement ( 'div' )
18521852 const container = document . createElement ( 'div' )
18531853 highlighter . style . fontSize = '18px'
1854- suggestions . style . marginLeft = '5px '
1854+ suggestions . style . marginLeft = '0px '
18551855 suggestions . style . marginTop = '7px'
18561856 Object . defineProperty ( highlighter , 'getBoundingClientRect' , {
18571857 value : ( ) => ( {
@@ -1871,6 +1871,10 @@ describe('MentionsInput', () => {
18711871 instance . highlighterElement = highlighter
18721872 instance . suggestionsElement = suggestions
18731873 instance . containerElement = container
1874+ highlighter . scrollLeft = 5
1875+ highlighter . scrollTop = 3
1876+ Object . defineProperty ( highlighter , 'offsetWidth' , { value : 200 , configurable : true } )
1877+ Object . defineProperty ( container , 'offsetWidth' , { value : 320 , configurable : true } )
18741878
18751879 const setStateMock = jest . spyOn ( instance , 'setState' ) . mockImplementation ( ( update , cb ) => {
18761880 const nextState =
@@ -1887,9 +1891,92 @@ describe('MentionsInput', () => {
18871891 } )
18881892
18891893 expect ( instance . state . suggestionsPosition . position ) . toBe ( 'fixed' )
1890- expect ( typeof instance . state . suggestionsPosition . left ) . toBe ( 'number' )
1894+ expect ( instance . state . suggestionsPosition . left ) . toBe ( 9 )
18911895 expect ( typeof instance . state . suggestionsPosition . top ) . toBe ( 'number' )
18921896
1897+ act ( ( ) => {
1898+ instance . state . suggestionsPosition = { }
1899+ } )
1900+ Object . assign ( instance . props , { anchorMode : 'left' } )
1901+
1902+ act ( ( ) => {
1903+ instance . updateSuggestionsPosition ( )
1904+ } )
1905+
1906+ expect ( instance . state . suggestionsPosition . position ) . toBe ( 'fixed' )
1907+ expect ( instance . state . suggestionsPosition . left ) . toBe ( 4 )
1908+
1909+ highlighter . remove ( )
1910+ suggestions . remove ( )
1911+ container . remove ( )
1912+ setStateMock . mockRestore ( )
1913+ unmount ( )
1914+ } )
1915+
1916+ it ( 'anchors suggestions to the control edge when using anchorMode="left" outside portals.' , async ( ) => {
1917+ const ref = React . createRef < MentionsInput > ( )
1918+ const { unmount } = render (
1919+ < MentionsInput ref = { ref } value = "" anchorMode = "left" >
1920+ < Mention trigger = "@" data = { data } />
1921+ </ MentionsInput >
1922+ )
1923+
1924+ await waitFor ( ( ) => {
1925+ expect ( ref . current ) . not . toBeNull ( )
1926+ } )
1927+
1928+ const instance = ref . current as unknown as any
1929+ Object . defineProperty ( instance , 'resolvePortalHost' , {
1930+ value : ( ) => null ,
1931+ configurable : true ,
1932+ writable : true ,
1933+ } )
1934+
1935+ const highlighter = document . createElement ( 'div' )
1936+ const suggestions = document . createElement ( 'div' )
1937+ const container = document . createElement ( 'div' )
1938+ highlighter . style . fontSize = '16px'
1939+ Object . defineProperty ( highlighter , 'getBoundingClientRect' , {
1940+ value : ( ) => ( {
1941+ left : 2 ,
1942+ top : 8 ,
1943+ right : 0 ,
1944+ bottom : 0 ,
1945+ width : 0 ,
1946+ height : 0 ,
1947+ } ) ,
1948+ } )
1949+ Object . defineProperty ( highlighter , 'offsetWidth' , { value : 180 , configurable : true } )
1950+ Object . defineProperty ( container , 'offsetWidth' , { value : 220 , configurable : true } )
1951+ Object . defineProperty ( suggestions , 'offsetHeight' , { value : 40 , configurable : true } )
1952+ document . body . append ( highlighter )
1953+ document . body . append ( suggestions )
1954+ document . body . append ( container )
1955+
1956+ highlighter . scrollLeft = 14
1957+ highlighter . scrollTop = 5
1958+
1959+ instance . highlighterElement = highlighter
1960+ instance . suggestionsElement = suggestions
1961+ instance . containerElement = container
1962+ instance . state . caretPosition = { left : 32 , top : 18 }
1963+ instance . state . suggestionsPosition = { }
1964+
1965+ const setStateMock = jest . spyOn ( instance , 'setState' ) . mockImplementation ( ( update , cb ) => {
1966+ const nextState =
1967+ typeof update === 'function' ? update ( instance . state , instance . props ) : update
1968+ Object . assign ( instance . state , nextState )
1969+ cb ?.( )
1970+ } )
1971+
1972+ act ( ( ) => {
1973+ instance . updateSuggestionsPosition ( )
1974+ } )
1975+
1976+ expect ( instance . state . suggestionsPosition . position ) . toBeUndefined ( )
1977+ expect ( instance . state . suggestionsPosition . left ) . toBe ( 0 )
1978+ expect ( instance . state . suggestionsPosition . right ) . toBeUndefined ( )
1979+
18931980 highlighter . remove ( )
18941981 suggestions . remove ( )
18951982 container . remove ( )
@@ -1941,6 +2028,21 @@ describe('MentionsInput', () => {
19412028 }
19422029 ; ( globalThis as any ) . ResizeObserver = MockResizeObserver
19432030
2031+ const originalAdd = window . addEventListener
2032+ const originalRemove = window . removeEventListener
2033+ const handlers : Partial < Record < string , EventListener > > = { }
2034+ const addListener = jest
2035+ . spyOn ( window , 'addEventListener' )
2036+ . mockImplementation ( ( type : string , listener : EventListenerOrEventListenerObject , options ?: boolean | AddEventListenerOptions ) => {
2037+ handlers [ type ] = listener as EventListener
2038+ return originalAdd . call ( window , type , listener , options )
2039+ } )
2040+ const removeListener = jest
2041+ . spyOn ( window , 'removeEventListener' )
2042+ . mockImplementation ( ( type : string , listener : EventListenerOrEventListenerObject , options ?: boolean | EventListenerOptions ) => {
2043+ return originalRemove . call ( window , type , listener , options )
2044+ } )
2045+
19442046 const bridgeElement = instance . renderMeasurementBridge ( ) as React . ReactElement
19452047 const { unmount : unmountBridge } = render ( bridgeElement )
19462048
@@ -1957,10 +2059,32 @@ describe('MentionsInput', () => {
19572059 expect ( syncScroll . mock . calls . length ) . toBe ( syncCalls + 1 )
19582060 expect ( updatePosition . mock . calls . length ) . toBe ( positionCalls + 1 )
19592061
2062+ act ( ( ) => {
2063+ window . dispatchEvent ( new Event ( 'resize' ) )
2064+ } )
2065+
2066+ expect ( syncScroll . mock . calls . length ) . toBeGreaterThan ( syncCalls + 1 )
2067+ expect ( updatePosition . mock . calls . length ) . toBeGreaterThan ( positionCalls + 1 )
2068+
2069+ act ( ( ) => {
2070+ window . dispatchEvent ( new Event ( 'orientationchange' ) )
2071+ } )
2072+
2073+ expect ( syncScroll . mock . calls . length ) . toBeGreaterThan ( syncCalls + 2 )
2074+ expect ( updatePosition . mock . calls . length ) . toBeGreaterThan ( positionCalls + 2 )
2075+
19602076 unmountBridge ( )
19612077 for ( const observer of observers ) {
19622078 expect ( observer . disconnect ) . toHaveBeenCalled ( )
19632079 }
2080+ expect ( handlers . resize ) . toBeDefined ( )
2081+ expect ( handlers . orientationchange ) . toBeDefined ( )
2082+ expect ( addListener ) . toHaveBeenCalledWith ( 'resize' , handlers . resize )
2083+ expect ( addListener ) . toHaveBeenCalledWith ( 'orientationchange' , handlers . orientationchange )
2084+ expect ( removeListener ) . toHaveBeenCalledWith ( 'resize' , handlers . resize )
2085+ expect ( removeListener ) . toHaveBeenCalledWith ( 'orientationchange' , handlers . orientationchange )
2086+ addListener . mockRestore ( )
2087+ removeListener . mockRestore ( )
19642088 ; ( globalThis as any ) . ResizeObserver = originalResizeObserver
19652089 unmount ( )
19662090 } )
0 commit comments