diff --git a/src/webview/changeSignature/App.css b/src/webview/changeSignature/App.css index 2feef25ea..867f579c6 100644 --- a/src/webview/changeSignature/App.css +++ b/src/webview/changeSignature/App.css @@ -110,6 +110,19 @@ main { background-color: var(--vscode-input-background); } +.parameter-input { + box-sizing: border-box; + width: 100%; + height: 100%; + padding: 0; + border: 0; + outline: none; + background-color: transparent; + color: var(--vscode-input-foreground); + font-family: inherit; + font-size: inherit; +} + .parameter-cell-edit-button { padding: 0; border: 0; diff --git a/src/webview/changeSignature/App.tsx b/src/webview/changeSignature/App.tsx index 1531efeda..b2010a8d3 100644 --- a/src/webview/changeSignature/App.tsx +++ b/src/webview/changeSignature/App.tsx @@ -175,11 +175,13 @@ export class App extends React.Component<{}, State> { editParameterRow: selectedRowNumber, editExceptionRow: -1, focusRow: -1, + }, () => { + const elementToSelect = document.getElementById(`parameterType-${selectedRowNumber}`) as HTMLInputElement | null; + if (elementToSelect) { + elementToSelect.focus(); + elementToSelect.select(); + } }); - const elementToSelect = document.getElementById(`parameterType-${selectedRowNumber}`); - if (elementToSelect) { - elementToSelect.focus(); - } } else if (id.startsWith("editException")) { const selectedRowNumber: number | undefined = this.getSelectedRowNumber(id); if (selectedRowNumber === undefined) { @@ -189,11 +191,13 @@ export class App extends React.Component<{}, State> { editParameterRow: -1, editExceptionRow: selectedRowNumber, focusRow: -1, + }, () => { + const elementToSelect = document.getElementById(`exceptionType-${selectedRowNumber}`) as HTMLInputElement | null; + if (elementToSelect) { + elementToSelect.focus(); + elementToSelect.select(); + } }); - const elementToSelect = document.getElementById(`exceptionType-${selectedRowNumber}`); - if (elementToSelect) { - elementToSelect.focus(); - } } else if (id.startsWith("upParameter")) { const selectedRowNumber: number | undefined = this.getSelectedRowNumber(id); if (selectedRowNumber === undefined) { @@ -253,20 +257,20 @@ export class App extends React.Component<{}, State> { if (selectedRowNumber === undefined) { return; } - const parameterType = document.getElementById(`parameterType-${selectedRowNumber}`); - const parameterName = document.getElementById(`parameterName-${selectedRowNumber}`); - const parameterDefault = this.isDefaultValueEditable(selectedRowNumber) ? document.getElementById(`parameterDefault-${selectedRowNumber}`) : undefined; + const parameterType = document.getElementById(`parameterType-${selectedRowNumber}`) as HTMLInputElement | null; + const parameterName = document.getElementById(`parameterName-${selectedRowNumber}`) as HTMLInputElement | null; + const parameterDefault = this.isDefaultValueEditable(selectedRowNumber) ? document.getElementById(`parameterDefault-${selectedRowNumber}`) as HTMLInputElement | null : undefined; this.setState({ parameters: this.state.parameters.map((e, i) => { if (i === selectedRowNumber) { - if (parameterType?.outerText) { - e.type = parameterType.outerText; + if (parameterType?.value) { + e.type = parameterType.value; } - if (parameterName?.outerText) { - e.name = parameterName.outerText; + if (parameterName?.value) { + e.name = parameterName.value; } - if (parameterDefault?.outerText) { - e.defaultValue = parameterDefault.outerText; + if (parameterDefault?.value) { + e.defaultValue = parameterDefault.value; } } return e; @@ -280,20 +284,6 @@ export class App extends React.Component<{}, State> { if (selectedRowNumber === undefined) { return; } - const parameterType = document.getElementById(`parameterType-${selectedRowNumber}`); - if (parameterType) { - parameterType.textContent = this.state.parameters[selectedRowNumber].type; - } - const parameterName = document.getElementById(`parameterName-${selectedRowNumber}`); - if (parameterName) { - parameterName.textContent = this.state.parameters[selectedRowNumber].name; - } - if (this.isDefaultValueEditable(selectedRowNumber)) { - const parameterDefault = document.getElementById(`parameterDefault-${selectedRowNumber}`); - if (parameterDefault) { - parameterDefault.textContent = this.state.parameters[selectedRowNumber].defaultValue; - } - } this.setState({ editParameterRow: -1, editExceptionRow: -1, @@ -304,12 +294,12 @@ export class App extends React.Component<{}, State> { if (selectedRowNumber === undefined) { return; } - const exceptionType = document.getElementById(`exceptionType-${selectedRowNumber}`); + const exceptionType = document.getElementById(`exceptionType-${selectedRowNumber}`) as HTMLInputElement | null; this.setState({ exceptions: this.state.exceptions.map((e, i) => { if (i === selectedRowNumber) { - if (exceptionType?.outerText) { - e.type = exceptionType.outerText; + if (exceptionType?.value) { + e.type = exceptionType.value; } } return e; @@ -323,10 +313,6 @@ export class App extends React.Component<{}, State> { if (selectedRowNumber === undefined) { return; } - const exceptionType = document.getElementById(`exceptionType-${selectedRowNumber}`); - if (exceptionType) { - exceptionType.textContent = this.state.exceptions[selectedRowNumber].type; - } this.setState({ editParameterRow: -1, editExceptionRow: -1, @@ -431,11 +417,28 @@ export class App extends React.Component<{}, State> { return this.isDefaultValueEditable(row) ? this.state.parameters[row].defaultValue : "-"; }; + /** + * Render a data grid cell whose value can be edited. When editing, a real + * control is rendered as slotted content of the cell so that the + * typed text is visibly rendered and read back reliably. This avoids relying + * on `contentEditable` directly on the (deprecated) webview-ui-toolkit + * `vscode-data-grid-cell`, whose shadow-DOM slot does not render text nodes + * placed on the host (see redhat-developer/vscode-java#4417). + */ + renderEditableCell = (id: string, value: string, editing: boolean, editable: boolean, gridColumn: string) => { + return + {editable + ? + : {value}} + ; + }; + generateParameterDataGridRow = (row: number) => { + const editing = row === this.state.editParameterRow; return - {this.state.parameters[row].type} - {this.state.parameters[row].name} - {this.getDefaultValue(row)} + {this.renderEditableCell(`parameterType-${row}`, this.state.parameters[row].type, editing, editing, "1")} + {this.renderEditableCell(`parameterName-${row}`, this.state.parameters[row].name, editing, editing, "2")} + {this.renderEditableCell(`parameterDefault-${row}`, this.getDefaultValue(row), editing, editing && this.isDefaultValueEditable(row), "3")} {row === this.state.editParameterRow ?
@@ -461,8 +464,9 @@ export class App extends React.Component<{}, State> { }; generateExceptionDataGridRow = (row: number) => { + const editing = row === this.state.editExceptionRow; return - {this.state.exceptions[row].type} + {this.renderEditableCell(`exceptionType-${row}`, this.state.exceptions[row].type, editing, editing, "1")} {row === this.state.editExceptionRow ?