2323 */
2424
2525import { Component } from 'react'
26+ import { createPortal } from 'react-dom'
2627import { deepEqual as isEqual } from '@instructure/ui-utils'
2728
2829import { EditorSelection , EditorState , StateEffect } from '@codemirror/state'
@@ -89,7 +90,7 @@ import { textDirectionContextConsumer } from '@instructure/ui-i18n'
8990
9091import { withStyleNew } from '@instructure/emotion'
9192
92- import customSearch from './SearchPanel.js'
93+ import customSearch , { SearchPanel } from './SearchPanel.js'
9394
9495import generateStyle from './styles.js'
9596
@@ -98,6 +99,16 @@ import { rtlHorizontalArrowKeymap } from './customKeybinding.js'
9899import { allowedProps } from './props.js'
99100import type { SourceCodeEditorProps } from './props'
100101
102+ type SearchPanelInstance = {
103+ id : number
104+ dom : HTMLElement
105+ view : EditorView
106+ }
107+
108+ type SourceCodeEditorState = {
109+ searchPanels : SearchPanelInstance [ ]
110+ }
111+
101112/**
102113---
103114category: components
@@ -106,7 +117,10 @@ category: components
106117@withDeterministicId ( )
107118@withStyleNew ( generateStyle )
108119@textDirectionContextConsumer ( )
109- class SourceCodeEditor extends Component < SourceCodeEditorProps > {
120+ class SourceCodeEditor extends Component <
121+ SourceCodeEditorProps ,
122+ SourceCodeEditorState
123+ > {
110124 static displayName = 'SourceCodeEditor'
111125 static readonly componentId = 'SourceCodeEditor'
112126
@@ -133,13 +147,35 @@ class SourceCodeEditor extends Component<SourceCodeEditorProps> {
133147
134148 ref : HTMLDivElement | null = null
135149
150+ state : SourceCodeEditorState = { searchPanels : [ ] }
151+
136152 private _containerRef ?: HTMLDivElement
137153 private _editorView ?: EditorView
138154
139155 private _raf : RequestAnimationFrameType [ ] = [ ]
140156
157+ private _searchPanelId = 0
158+ private _isUnmounting = false
159+
141160 private _newSelectionAfterValueChange ?: EditorSelection
142161
162+ handleSearchPanelMount = ( dom : HTMLElement , view : EditorView ) => {
163+ this . setState ( ( state ) => ( {
164+ searchPanels : [
165+ ...state . searchPanels ,
166+ { id : ++ this . _searchPanelId , dom, view }
167+ ]
168+ } ) )
169+ }
170+
171+ handleSearchPanelDestroy = ( dom : HTMLElement ) => {
172+ if ( this . _isUnmounting ) return
173+
174+ this . setState ( ( state ) => ( {
175+ searchPanels : state . searchPanels . filter ( ( panel ) => panel . dom !== dom )
176+ } ) )
177+ }
178+
143179 handleRef = ( el : HTMLDivElement | null ) => {
144180 const { elementRef } = this . props
145181
@@ -310,6 +346,7 @@ class SourceCodeEditor extends Component<SourceCodeEditorProps> {
310346 }
311347
312348 componentWillUnmount ( ) {
349+ this . _isUnmounting = true
313350 this . _editorView ?. destroy ( )
314351
315352 this . cancelAnimationFrames ( )
@@ -349,7 +386,8 @@ class SourceCodeEditor extends Component<SourceCodeEditorProps> {
349386 'indentWithTab' ,
350387 'indentUnit' ,
351388 'highlightActiveLine' ,
352- 'attachment'
389+ 'attachment' ,
390+ 'searchConfig'
353391 ]
354392
355393 for ( const prop of propsToObserve ) {
@@ -438,7 +476,10 @@ class SourceCodeEditor extends Component<SourceCodeEditorProps> {
438476 crosshairCursor ( ) ,
439477 highlightSelectionMatches ( ) ,
440478 indentOnInput ( ) ,
441- customSearch ( this . props . searchConfig ) ,
479+ customSearch ( this . props . searchConfig , {
480+ onMount : this . handleSearchPanelMount ,
481+ onDestroy : this . handleSearchPanelDestroy
482+ } ) ,
442483 keymap . of ( this . keymaps )
443484 ]
444485 }
@@ -669,7 +710,7 @@ class SourceCodeEditor extends Component<SourceCodeEditorProps> {
669710 }
670711
671712 render ( ) {
672- const { label, styles, ...restProps } = this . props
713+ const { label, styles, searchConfig , ...restProps } = this . props
673714
674715 return (
675716 < div
@@ -687,6 +728,14 @@ class SourceCodeEditor extends Component<SourceCodeEditorProps> {
687728 css = { styles ?. codeEditorContainer }
688729 />
689730 </ label >
731+ { searchConfig &&
732+ this . state . searchPanels . map ( ( { id, dom, view } ) =>
733+ createPortal (
734+ < SearchPanel view = { view } searchConfig = { searchConfig } /> ,
735+ dom ,
736+ String ( id )
737+ )
738+ ) }
690739 </ div >
691740 )
692741 }
0 commit comments