diff --git a/package-lock.json b/package-lock.json index c15737e4a..7d308c280 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "@redhat-developer/vscode-extension-proposals": "0.0.23", "@redhat-developer/vscode-redhat-telemetry": "0.10.2", "@vscode/codicons": "^0.0.32", - "@vscode/webview-ui-toolkit": "1.2.2", "chokidar": "^3.5.3", "expand-home-dir": "^0.0.3", "fmtr": "^1.1.2", @@ -274,47 +273,6 @@ "node": ">=8" } }, - "node_modules/@microsoft/fast-element": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.11.0.tgz", - "integrity": "sha512-VKJYMkS5zgzHHb66sY7AFpYv6IfFhXrjQcAyNgi2ivD65My1XOhtjfKez5ELcLFRJfgZNAxvI8kE69apXERTkw==" - }, - "node_modules/@microsoft/fast-foundation": { - "version": "2.47.0", - "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.47.0.tgz", - "integrity": "sha512-EyFuioaZQ9ngjUNRQi8R3dIPPsaNQdUOS+tP0G7b1MJRhXmQWIitBM6IeveQA6ZvXG6H21dqgrfEWlsYrUZ2sw==", - "dependencies": { - "@microsoft/fast-element": "^1.11.0", - "@microsoft/fast-web-utilities": "^5.4.1", - "tabbable": "^5.2.0", - "tslib": "^1.13.0" - } - }, - "node_modules/@microsoft/fast-foundation/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@microsoft/fast-react-wrapper": { - "version": "0.1.48", - "resolved": "https://registry.npmjs.org/@microsoft/fast-react-wrapper/-/fast-react-wrapper-0.1.48.tgz", - "integrity": "sha512-9NvEjru9Kn5ZKjomAMX6v+eF0DR+eDkxKDwDfi+Wb73kTbrNzcnmlwd4diN15ygH97kldgj2+lpvI4CKLQQWLg==", - "dependencies": { - "@microsoft/fast-element": "^1.9.0", - "@microsoft/fast-foundation": "^2.41.1" - }, - "peerDependencies": { - "react": ">=16.9.0" - } - }, - "node_modules/@microsoft/fast-web-utilities": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", - "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", - "dependencies": { - "exenv-es6": "^1.1.1" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -968,19 +926,6 @@ "node": ">=16" } }, - "node_modules/@vscode/webview-ui-toolkit": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@vscode/webview-ui-toolkit/-/webview-ui-toolkit-1.2.2.tgz", - "integrity": "sha512-xIQoF4FC3Xh6d7KNKIoIezSiFWYFuf6gQMdDyKueKBFGeKwaHWEn+dY2g3makvvEsNMEDji/woEwvg9QSbuUsw==", - "dependencies": { - "@microsoft/fast-element": "^1.6.2", - "@microsoft/fast-foundation": "^2.38.0", - "@microsoft/fast-react-wrapper": "^0.1.18" - }, - "peerDependencies": { - "react": ">=16.9.0" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -2371,11 +2316,6 @@ "node": ">=8" } }, - "node_modules/exenv-es6": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", - "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==" - }, "node_modules/expand-home-dir": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/expand-home-dir/-/expand-home-dir-0.0.3.tgz", @@ -5210,11 +5150,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tabbable": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", - "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==" - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", diff --git a/package.json b/package.json index 0b750e53b..163decb80 100644 --- a/package.json +++ b/package.json @@ -2132,7 +2132,6 @@ "@redhat-developer/vscode-extension-proposals": "0.0.23", "@redhat-developer/vscode-redhat-telemetry": "0.10.2", "@vscode/codicons": "^0.0.32", - "@vscode/webview-ui-toolkit": "1.2.2", "chokidar": "^3.5.3", "expand-home-dir": "^0.0.3", "fmtr": "^1.1.2", diff --git a/src/refactoring/changeSignaturePanel.ts b/src/refactoring/changeSignaturePanel.ts index 5935d9f72..f5f7728a0 100644 --- a/src/refactoring/changeSignaturePanel.ts +++ b/src/refactoring/changeSignaturePanel.ts @@ -116,8 +116,8 @@ export class ChangeSignaturePanel { - - + + Change Signature diff --git a/src/webview/changeSignature/App.css b/src/webview/changeSignature/App.css index 2feef25ea..102e8222f 100644 --- a/src/webview/changeSignature/App.css +++ b/src/webview/changeSignature/App.css @@ -4,6 +4,9 @@ main { max-width: 600px; margin-left: auto; margin-right: auto; + color: var(--vscode-foreground); + font-family: var(--vscode-font-family); + font-size: var(--vscode-font-size); } .section { @@ -13,18 +16,18 @@ main { .section-columns { display: flex; width: 100%; - padding-left: calc(var(--design-unit) * 1px); + padding-left: 4px; } .text-title { margin: 0; - height: calc(var(--input-height) * 0.8px); + height: 21px; } .text-title-content { - padding: 0 0 0 calc(var(--design-unit) * 1px); + padding: 0 0 0 4px; margin: 0.5rem 0 0 0; - height: calc(var(--input-height) * 0.8px); + height: 21px; } .header-left { @@ -51,6 +54,91 @@ main { box-sizing: border-box; } +/* Form controls -------------------------------------------------------- */ + +.vsc-textfield, +.vsc-dropdown { + box-sizing: border-box; + width: 100%; + height: 26px; + padding: 2px 6px; + color: var(--vscode-input-foreground); + background-color: var(--vscode-input-background); + border: 1px solid var(--vscode-dropdown-border, var(--vscode-input-border, transparent)); + border-radius: 2px; + font-family: inherit; + font-size: inherit; + outline: none; +} + +.vsc-textfield:focus, +.vsc-dropdown:focus { + border-color: var(--vscode-focusBorder); +} + +.vsc-dropdown { + cursor: pointer; +} + +/* Buttons -------------------------------------------------------------- */ + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + height: 26px; + padding: 0 11px; + border: 1px solid var(--vscode-button-border, transparent); + border-radius: 2px; + font-family: inherit; + font-size: inherit; + cursor: pointer; + outline: none; +} + +.btn:focus-visible { + outline: 1px solid var(--vscode-focusBorder); + outline-offset: 2px; +} + +.btn:disabled { + opacity: 0.4; + cursor: default; +} + +.btn-primary { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); +} + +.btn-primary:hover:not(:disabled) { + background-color: var(--vscode-button-hoverBackground); +} + +.btn-secondary { + color: var(--vscode-button-secondaryForeground); + background-color: var(--vscode-button-secondaryBackground); +} + +.btn-secondary:hover:not(:disabled) { + background-color: var(--vscode-button-secondaryHoverBackground); +} + +.btn-icon { + height: 22px; + width: 22px; + padding: 0; + color: var(--vscode-icon-foreground); + background-color: transparent; + border: none; + border-radius: 4px; +} + +.btn-icon:hover:not(:disabled) { + background-color: var(--vscode-toolbar-hoverBackground); +} + .vsc-button-left { float: left; margin: 0 0.5rem 0.5rem 0; @@ -66,80 +154,150 @@ main { } .bottom-buttons { - padding: 0 0 0 calc(var(--design-unit) * 1px); + padding: 0 0 0 4px; margin: 0.5rem 0 0 0; + overflow: hidden; } .preview { - padding: 0 0 0 calc(var(--design-unit) * 1px); + box-sizing: border-box; margin: 0 0 0.5rem 0; width: 99%; + color: var(--vscode-input-foreground); + background-color: var(--vscode-input-background); + border: 1px solid var(--vscode-input-border, transparent); + border-radius: 2px; + padding: 4px 6px; + font-family: var(--vscode-editor-font-family, monospace); + font-size: inherit; + resize: vertical; + outline: none; +} + +.preview:focus { + border-color: var(--vscode-focusBorder); } +/* Tabs ----------------------------------------------------------------- */ + .parameters-panel { margin: 0; width: calc(99% + 4px); } +.tabs { + display: flex; + border-bottom: 1px solid var(--vscode-panel-border, var(--vscode-editorGroup-border)); +} + +.tab { + padding: 6px 10px; + background-color: transparent; + border: none; + border-bottom: 1px solid transparent; + color: var(--vscode-panelTitle-inactiveForeground, var(--vscode-foreground)); + font-family: inherit; + font-size: inherit; + cursor: pointer; + outline: none; +} + +.tab:hover { + color: var(--vscode-panelTitle-activeForeground, var(--vscode-foreground)); +} + +.tab-active { + color: var(--vscode-panelTitle-activeForeground, var(--vscode-foreground)); + border-bottom-color: var(--vscode-panelTitle-activeBorder, var(--vscode-focusBorder)); +} + +.tab:focus-visible { + outline: 1px solid var(--vscode-focusBorder); + outline-offset: -1px; +} + .parameters-view { - padding: 0 0 0 calc(var(--design-unit) * 1px); + padding: 0 0 0 4px; + display: flex; flex-direction: column; } -.parameter-cell { - padding-left: 0; - pointer-events: none; +.parameters-view[hidden] { + display: none; } -.parameter-cell-title { - padding-left: 0; +/* Table ---------------------------------------------------------------- */ + +.parameter-table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; } -.parameter-cell-title:focus { - border-color: var(--vscode-keybindingTable-headerBackground); - background-color: inherit; - color: inherit; +.parameter-table th, +.parameter-table td { + text-align: left; + vertical-align: middle; + padding: 2px 4px; + height: 26px; + box-sizing: border-box; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.parameter-cell-title { + padding-left: 4px; + font-weight: 600; } .parameter-cell-header { background-color: var(--vscode-keybindingTable-headerBackground); } +.parameter-cell { + padding-left: 4px; +} + .parameter-cell-edit { - padding-left: 0; + padding: 0 4px; background-color: var(--vscode-input-background); } -.parameter-cell-edit-button { +.parameter-input { + box-sizing: border-box; + width: 100%; + height: 100%; padding: 0; border: 0; - display: flex; - justify-content: right; - background-color: var(--vscode-input-background); + outline: none; + background-color: transparent; + color: var(--vscode-input-foreground); + font-family: inherit; + font-size: inherit; } +.parameter-cell-edit-button, .parameter-cell-button { padding: 0; border: 0; - display: flex; - justify-content: right; -} - -.parameter-cell-button:focus { - background-color: inherit; + text-align: right; + width: 1%; + white-space: nowrap; } -.parameter-cell-button:active { - background-color: inherit; +.parameter-cell-edit-button { + background-color: var(--vscode-input-background); } .table-buttons { display: inline-flex; + justify-content: flex-end; } .table-buttons-edit { display: inline-flex; - background-color: var(--vscode-editor-background); + justify-content: flex-end; } .table-buttons-edit-ok { @@ -151,7 +309,18 @@ main { margin: 0; } +/* Checkbox ------------------------------------------------------------- */ + .delegate { - padding: 0 0 0 calc(var(--design-unit) * 1px); + display: flex; + align-items: center; + gap: 6px; + padding: 0 0 0 4px; margin: 0.5rem 0 0.5rem 0; + cursor: pointer; +} + +.delegate input[type="checkbox"] { + accent-color: var(--vscode-checkbox-background); + cursor: pointer; } diff --git a/src/webview/changeSignature/App.tsx b/src/webview/changeSignature/App.tsx index 1531efeda..4e33a3e16 100644 --- a/src/webview/changeSignature/App.tsx +++ b/src/webview/changeSignature/App.tsx @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/prefer-for-of */ -import { VSCodeButton, VSCodeTextField, VSCodeDropdown, VSCodeOption, VSCodeCheckbox, VSCodePanels, VSCodePanelTab, VSCodePanelView, VSCodeDataGrid, VSCodeDataGridCell, VSCodeDataGridRow, VSCodeTextArea } from "@vscode/webview-ui-toolkit/react"; import "./App.css"; import React from "react"; import { vscode } from "../vscodeApiWrapper"; @@ -8,10 +7,13 @@ import cloneDeep from "lodash/cloneDeep"; type State = UIState & Metadata; +type ActiveTab = "parameters" | "exceptions"; + interface UIState { focusRow: number; editParameterRow: number; editExceptionRow: number; + activeTab: ActiveTab; } interface Metadata { @@ -50,6 +52,7 @@ export class App extends React.Component<{}, State> { focusRow: -1, editParameterRow: -1, editExceptionRow: -1, + activeTab: "parameters", methodIdentifier: undefined, isDelegate: false, methodName: undefined, @@ -91,6 +94,10 @@ export class App extends React.Component<{}, State> { this.setState({ methodName: event.target.value }); + } else if (id === "delegate") { + this.setState({ + isDelegate: event.target.checked + }); } return; }; @@ -121,7 +128,11 @@ export class App extends React.Component<{}, State> { if (!id) { return; } - if (id === "refactor") { + if (id === "tab-parameters") { + this.setState({ activeTab: "parameters", focusRow: -1 }); + } else if (id === "tab-exceptions") { + this.setState({ activeTab: "exceptions", focusRow: -1 }); + } else if (id === "refactor") { this.doRefactor(false); } else if (id === "preview") { this.doRefactor(true); @@ -175,11 +186,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 +202,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) { @@ -244,29 +259,25 @@ export class App extends React.Component<{}, State> { return i !== selectedRowNumber; }) }); - } else if (id === "delegate") { - this.setState({ - isDelegate: event.target.checked - }); } else if (id.startsWith("confirmParameter")) { const selectedRowNumber: number | undefined = this.getSelectedRowNumber(id); 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 +291,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 +301,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 +320,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, @@ -361,7 +354,9 @@ export class App extends React.Component<{}, State> { }; onMouseEnter = (event: any) => { - const id = event.target.id as string; + const currentTarget = event.currentTarget as HTMLElement | null; + const target = event.target as HTMLElement | null; + const id = currentTarget?.id || target?.id || currentTarget?.closest("tr")?.id || target?.closest("tr")?.id || ""; if (id.includes("Header")) { this.setState({ focusRow: -1 @@ -383,7 +378,6 @@ export class App extends React.Component<{}, State> { }; componentDidMount(): void { - this.setTextAreaCursorStyle(); window.addEventListener("message", this.handleMessage); vscode.postMessage({ command: "webviewReady" @@ -410,19 +404,6 @@ export class App extends React.Component<{}, State> { : o1 === o2; }; - /** - * Set the cursor style of the text area to text. Since the text area is - * inside a shadow DOM, we need to add a style element to the shadow DOM. - */ - setTextAreaCursorStyle(): void { - const host = document.getElementById("textArea"); - if (host?.shadowRoot) { - const style = document.createElement('style'); - style.innerHTML = '.control { cursor: text !important; }'; - host.shadowRoot.appendChild(style); - } - } - isDefaultValueEditable = (row: number) => { return this.state.parameters[row].originalIndex === -1; }; @@ -431,54 +412,69 @@ export class App extends React.Component<{}, State> { return this.isDefaultValueEditable(row) ? this.state.parameters[row].defaultValue : "-"; }; + /** + * Render a table cell whose value can be edited. When editing, a real + * control is rendered so that the typed text is visibly rendered + * and read back reliably via its value (see redhat-developer/vscode-java#4417). + */ + renderEditableCell = (id: string, value: string, editing: boolean, editable: boolean) => { + return + {editable + ? + : {value}} + ; + }; + generateParameterDataGridRow = (row: number) => { - return - {this.state.parameters[row].type} - {this.state.parameters[row].name} - {this.getDefaultValue(row)} - - {row === this.state.editParameterRow ? + const editing = row === this.state.editParameterRow; + return + {this.renderEditableCell(`parameterType-${row}`, this.state.parameters[row].type, editing, editing)} + {this.renderEditableCell(`parameterName-${row}`, this.state.parameters[row].name, editing, editing)} + {this.renderEditableCell(`parameterDefault-${row}`, this.getDefaultValue(row), editing, editing && this.isDefaultValueEditable(row))} + + {editing ?
- OK - Cancel + +
: row === this.state.focusRow ?
- {row === 0 ? <> : - - } - {row === this.state.parameters.length - 1 ? <> : - - } - - - - - - + {row === 0 ? <> : } + {row === this.state.parameters.length - 1 ? <> : } + +
:
} -
-
; + + ; }; generateExceptionDataGridRow = (row: number) => { - return - {this.state.exceptions[row].type} - - {row === this.state.editExceptionRow ? + const editing = row === this.state.editExceptionRow; + return + {this.renderEditableCell(`exceptionType-${row}`, this.state.exceptions[row].type, editing, editing)} + + {editing ?
- OK - Cancel + +
: row === this.state.focusRow ?
- - - - - - + +
:
} -
-
; + + ; }; render = () => { @@ -489,76 +485,89 @@ export class App extends React.Component<{}, State> {
Access modifier:
- - public - protected - package-private - private - +
Return type:
- +
Method name:
- +
- - Parameters - Exceptions - - - - Type - Name - Default value - - - { - (() => { - const options: JSX.Element[] = []; - for (let row = 0; row < this.state.parameters.length; row++) { - options.push(this.generateParameterDataGridRow(row)); - } - return options; - })() - } - +
+
+ + +
+ + +
Method signature:
- - Keep original method as delegate to changed method + +
- Refactor - Preview - Reset + + +
);