Skip to content

Commit 4534fa0

Browse files
committed
fix(ui-source-code-editor): apply current theme to v2 search panel
INSTUI-5081
1 parent 7b9f53f commit 4534fa0

3 files changed

Lines changed: 83 additions & 11 deletions

File tree

packages/ui-source-code-editor/src/SourceCodeEditor/v2/SearchPanel.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,25 @@ import {
3939
IconArrowOpenUpLine,
4040
IconSearchLine
4141
} from '@instructure/ui-icons'
42-
import { createRoot } from 'react-dom/client'
4342

4443
export type SearchConfig = {
4544
placeholder: string
4645
nextResultLabel: string
4746
prevResultLabel: string
4847
}
4948

50-
function SearchPanel({
49+
50+
export type SearchPanelHandlers = {
51+
onMount: (dom: HTMLElement, view: EditorView) => void
52+
onDestroy: (dom: HTMLElement) => void
53+
}
54+
55+
/**
56+
* ---
57+
* private: true
58+
* ---
59+
*/
60+
export function SearchPanel({
5161
view,
5262
searchConfig
5363
}: {
@@ -135,15 +145,24 @@ function SearchPanel({
135145
)
136146
}
137147

138-
export default function customSearch(searchConfig: SearchConfig | undefined) {
148+
export default function customSearch(
149+
searchConfig: SearchConfig | undefined,
150+
handlers: SearchPanelHandlers
151+
) {
139152
return searchConfig
140153
? search({
141154
createPanel: (view) => {
142155
const dom = document.createElement('div')
143156
dom.style.padding = '8px'
144-
const root = createRoot(dom)
145-
root.render(<SearchPanel view={view} searchConfig={searchConfig} />)
146-
return { dom }
157+
return {
158+
dom,
159+
mount() {
160+
handlers.onMount(dom, view)
161+
},
162+
destroy() {
163+
handlers.onDestroy(dom)
164+
}
165+
}
147166
}
148167
})
149168
: []

packages/ui-source-code-editor/src/SourceCodeEditor/v2/index.tsx

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
import { Component } from 'react'
26+
import { createPortal } from 'react-dom'
2627
import { deepEqual as isEqual } from '@instructure/ui-utils'
2728

2829
import { EditorSelection, EditorState, StateEffect } from '@codemirror/state'
@@ -89,7 +90,7 @@ import { textDirectionContextConsumer } from '@instructure/ui-i18n'
8990

9091
import { withStyleNew } from '@instructure/emotion'
9192

92-
import customSearch from './SearchPanel.js'
93+
import customSearch, { SearchPanel } from './SearchPanel.js'
9394

9495
import generateStyle from './styles.js'
9596

@@ -98,6 +99,16 @@ import { rtlHorizontalArrowKeymap } from './customKeybinding.js'
9899
import { allowedProps } from './props.js'
99100
import 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
---
103114
category: 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
}

packages/ui-source-code-editor/src/SourceCodeEditor/v2/styles.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ const generateStyle = (
160160
'.cm-placeholder': {
161161
// for better contrast
162162
color: componentTheme.placeholderBackgroundColor
163+
},
164+
'.cm-panels': {
165+
backgroundColor: componentTheme.background,
166+
color: componentTheme.color
163167
}
164168
},
165169

0 commit comments

Comments
 (0)