|
1 | 1 | import { Element } from '@core/element' |
2 | | -import { html, css } from 'lit' |
3 | | -import { customElement } from 'lit/decorators.js' |
| 2 | +import { html, css, type PropertyValues } from 'lit' |
| 3 | +import { customElement, state } from 'lit/decorators.js' |
4 | 4 | import { consume } from '@lit/context' |
5 | 5 |
|
6 | 6 | import { EditorView, basicSetup } from 'codemirror' |
@@ -28,45 +28,75 @@ export class DevtoolsSource extends Element { |
28 | 28 | width: 100%; |
29 | 29 | height: 100%; |
30 | 30 | padding: 10px 0px; |
| 31 | + flex: 1; |
| 32 | + min-height: 0; |
31 | 33 | } |
32 | 34 | .cm-content { |
33 | 35 | padding: 0 !important; |
34 | 36 | } |
35 | 37 |
|
36 | 38 | .source-container { |
| 39 | + display: flex; |
| 40 | + flex-direction: column; |
37 | 41 | width: 100%; |
38 | 42 | height: 100%; |
| 43 | + overflow: hidden; |
39 | 44 | } |
40 | 45 | ` |
41 | 46 | ] |
42 | 47 |
|
43 | 48 | @consume({ context: sourceContext, subscribe: true }) |
| 49 | + @state() |
44 | 50 | sources: Record<string, string> = {} |
45 | 51 |
|
46 | 52 | #editorView?: EditorView |
47 | 53 | #activeFile?: string |
| 54 | + #tabObserver?: MutationObserver |
48 | 55 |
|
49 | 56 | connectedCallback(): void { |
50 | 57 | super.connectedCallback() |
51 | 58 | window.addEventListener( |
52 | 59 | 'app-source-highlight', |
53 | 60 | this.#highlightCallSource.bind(this) |
54 | 61 | ) |
| 62 | + // Observe when the containing tab becomes active so CodeMirror can remeasure |
| 63 | + // after having been initialized while the tab was hidden (display:none). |
| 64 | + requestAnimationFrame(() => { |
| 65 | + const tab = this.closest('wdio-devtools-tab') |
| 66 | + if (tab) { |
| 67 | + this.#tabObserver = new MutationObserver(() => { |
| 68 | + if (tab.hasAttribute('active') && this.#editorView) { |
| 69 | + // Force CodeMirror to remeasure and re-render after becoming visible |
| 70 | + requestAnimationFrame(() => { |
| 71 | + this.#editorView?.requestMeasure() |
| 72 | + this.#editorView?.dom.dispatchEvent(new Event('resize')) |
| 73 | + }) |
| 74 | + } |
| 75 | + }) |
| 76 | + this.#tabObserver.observe(tab, { attributes: true, attributeFilter: ['active'] }) |
| 77 | + } |
| 78 | + }) |
55 | 79 | } |
56 | 80 |
|
57 | 81 | disconnectedCallback(): void { |
58 | 82 | super.disconnectedCallback() |
59 | 83 | this.#editorView?.destroy() |
60 | 84 | this.#editorView = undefined |
| 85 | + this.#tabObserver?.disconnect() |
| 86 | + this.#tabObserver = undefined |
61 | 87 | } |
62 | 88 |
|
63 | | - updated() { |
| 89 | + updated(_changedProperties: PropertyValues<this>) { |
64 | 90 | const sourceFileNames = Object.keys(this.sources || {}) |
65 | 91 | if (sourceFileNames.length === 0) { |
66 | 92 | return |
67 | 93 | } |
68 | | - // Mount or refresh the editor for the first source file |
69 | | - this.#mountEditor(sourceFileNames[0]) |
| 94 | + // Respect an explicitly highlighted file; otherwise show the first available |
| 95 | + const targetFile = |
| 96 | + this.#activeFile && this.sources?.[this.#activeFile] |
| 97 | + ? this.#activeFile |
| 98 | + : sourceFileNames[0] |
| 99 | + this.#mountEditor(targetFile) |
70 | 100 | } |
71 | 101 |
|
72 | 102 | #mountEditor(filePath: string, highlightLine?: number) { |
@@ -101,6 +131,11 @@ export class DevtoolsSource extends Element { |
101 | 131 | this.#editorView = new EditorView(opts) |
102 | 132 | this.#activeFile = filePath |
103 | 133 |
|
| 134 | + // Force a measure on the next frame so CodeMirror can calculate heights |
| 135 | + // correctly — needed when the editor was created while the panel was hidden |
| 136 | + // or before layout was complete. |
| 137 | + requestAnimationFrame(() => this.#editorView?.requestMeasure()) |
| 138 | + |
104 | 139 | if (highlightLine && highlightLine > 0) { |
105 | 140 | this.#scrollToLine(this.#editorView, highlightLine) |
106 | 141 | } |
|
0 commit comments