@sap-ux/control-property-editor 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.eslintrc.js +16 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +201 -0
- package/README.md +16 -0
- package/dist/app.css +2 -0
- package/dist/app.css.map +7 -0
- package/dist/app.js +347 -0
- package/dist/app.js.map +7 -0
- package/esbuild.js +25 -0
- package/jest.config.js +20 -0
- package/package.json +68 -0
- package/src/App.scss +57 -0
- package/src/App.tsx +136 -0
- package/src/Workarounds.scss +79 -0
- package/src/actions.ts +3 -0
- package/src/components/AppLogo.module.scss +8 -0
- package/src/components/AppLogo.tsx +75 -0
- package/src/components/ChangeIndicator.tsx +80 -0
- package/src/components/Separator.tsx +32 -0
- package/src/components/ThemeSelectorCallout.scss +48 -0
- package/src/components/ThemeSelectorCallout.tsx +125 -0
- package/src/components/ToolBar.scss +39 -0
- package/src/components/ToolBar.tsx +26 -0
- package/src/components/index.ts +4 -0
- package/src/devices.ts +18 -0
- package/src/global.d.ts +4 -0
- package/src/i18n/i18n.json +68 -0
- package/src/i18n.ts +25 -0
- package/src/icons.tsx +198 -0
- package/src/index.css +1288 -0
- package/src/index.tsx +47 -0
- package/src/middleware.ts +54 -0
- package/src/panels/LeftPanel.scss +17 -0
- package/src/panels/LeftPanel.tsx +48 -0
- package/src/panels/changes/ChangeStack.module.scss +3 -0
- package/src/panels/changes/ChangeStack.tsx +219 -0
- package/src/panels/changes/ChangeStackHeader.tsx +43 -0
- package/src/panels/changes/ChangesPanel.module.scss +18 -0
- package/src/panels/changes/ChangesPanel.tsx +90 -0
- package/src/panels/changes/ControlGroup.module.scss +17 -0
- package/src/panels/changes/ControlGroup.tsx +61 -0
- package/src/panels/changes/PropertyChange.module.scss +24 -0
- package/src/panels/changes/PropertyChange.tsx +159 -0
- package/src/panels/changes/UnknownChange.module.scss +46 -0
- package/src/panels/changes/UnknownChange.tsx +96 -0
- package/src/panels/changes/index.tsx +3 -0
- package/src/panels/changes/utils.ts +36 -0
- package/src/panels/index.ts +2 -0
- package/src/panels/outline/Funnel.tsx +64 -0
- package/src/panels/outline/NoControlFound.tsx +45 -0
- package/src/panels/outline/OutlinePanel.scss +98 -0
- package/src/panels/outline/OutlinePanel.tsx +38 -0
- package/src/panels/outline/Tree.tsx +393 -0
- package/src/panels/outline/index.ts +1 -0
- package/src/panels/outline/utils.ts +154 -0
- package/src/panels/properties/Clipboard.tsx +44 -0
- package/src/panels/properties/DeviceSelector.tsx +40 -0
- package/src/panels/properties/DeviceToggle.tsx +39 -0
- package/src/panels/properties/DropdownEditor.tsx +80 -0
- package/src/panels/properties/Funnel.tsx +64 -0
- package/src/panels/properties/HeaderField.tsx +150 -0
- package/src/panels/properties/IconValueHelp.tsx +203 -0
- package/src/panels/properties/InputTypeSelector.tsx +20 -0
- package/src/panels/properties/InputTypeToggle.module.scss +4 -0
- package/src/panels/properties/InputTypeToggle.tsx +79 -0
- package/src/panels/properties/InputTypeWrapper.tsx +259 -0
- package/src/panels/properties/NoControlSelected.tsx +38 -0
- package/src/panels/properties/Properties.scss +102 -0
- package/src/panels/properties/PropertiesList.tsx +162 -0
- package/src/panels/properties/PropertiesPanel.tsx +30 -0
- package/src/panels/properties/PropertyDocumentation.module.scss +81 -0
- package/src/panels/properties/PropertyDocumentation.tsx +174 -0
- package/src/panels/properties/SapUiIcon.scss +109 -0
- package/src/panels/properties/StringEditor.tsx +122 -0
- package/src/panels/properties/ViewChanger.module.scss +5 -0
- package/src/panels/properties/ViewChanger.tsx +143 -0
- package/src/panels/properties/constants.ts +2 -0
- package/src/panels/properties/index.tsx +1 -0
- package/src/panels/properties/propertyValuesCache.ts +39 -0
- package/src/panels/properties/types.ts +49 -0
- package/src/slice.ts +216 -0
- package/src/store.ts +19 -0
- package/src/use-local-storage.ts +40 -0
- package/src/use-window-size.ts +39 -0
- package/src/variables.scss +2 -0
- package/test/unit/App.test.tsx +207 -0
- package/test/unit/appIndex.test.ts +23 -0
- package/test/unit/components/ChangeIndicator.test.tsx +120 -0
- package/test/unit/components/ThemeSelector.test.tsx +41 -0
- package/test/unit/middleware.test.ts +116 -0
- package/test/unit/panels/changes/ChangesPanel.test.tsx +261 -0
- package/test/unit/panels/changes/utils.test.ts +40 -0
- package/test/unit/panels/outline/OutlinePanel.test.tsx +353 -0
- package/test/unit/panels/outline/__snapshots__/utils.test.ts.snap +36 -0
- package/test/unit/panels/outline/utils.test.ts +83 -0
- package/test/unit/panels/properties/Clipboard.test.tsx +18 -0
- package/test/unit/panels/properties/DropdownEditor.test.tsx +62 -0
- package/test/unit/panels/properties/Funnel.test.tsx +34 -0
- package/test/unit/panels/properties/HeaderField.test.tsx +36 -0
- package/test/unit/panels/properties/IconValueHelp.test.tsx +60 -0
- package/test/unit/panels/properties/InputTypeToggle.test.tsx +126 -0
- package/test/unit/panels/properties/InputTypeWrapper.test.tsx +430 -0
- package/test/unit/panels/properties/PropertyDocumentation.test.tsx +131 -0
- package/test/unit/panels/properties/StringEditor.test.tsx +107 -0
- package/test/unit/panels/properties/ViewChanger.test.tsx +190 -0
- package/test/unit/panels/properties/propertyValuesCache.test.ts +23 -0
- package/test/unit/slice.test.ts +268 -0
- package/test/unit/utils.tsx +67 -0
- package/test/utils/utils.tsx +25 -0
- package/tsconfig.eslint.json +4 -0
- package/tsconfig.json +39 -0
package/esbuild.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { esbuildOptionsBrowser, build } = require('../../esbuildConfig');
|
|
2
|
+
const NodeModulesPolyfills = require('@esbuild-plugins/node-modules-polyfill');
|
|
3
|
+
const alias = require('esbuild-plugin-alias');
|
|
4
|
+
|
|
5
|
+
// Set esbuild options for this build
|
|
6
|
+
esbuildOptionsBrowser.plugins = esbuildOptionsBrowser.plugins.concat(
|
|
7
|
+
alias({
|
|
8
|
+
'react': require.resolve('react'),
|
|
9
|
+
'react-dom': require.resolve('react-dom')
|
|
10
|
+
})
|
|
11
|
+
);
|
|
12
|
+
const esbuildOptions = { ...esbuildOptionsBrowser };
|
|
13
|
+
|
|
14
|
+
esbuildOptions.external = esbuildOptions.external.concat([]);
|
|
15
|
+
esbuildOptions.entryPoints = {
|
|
16
|
+
app: './src/index.tsx'
|
|
17
|
+
};
|
|
18
|
+
esbuildOptions.format = 'esm';
|
|
19
|
+
esbuildOptions.plugins = esbuildOptions.plugins.concat([NodeModulesPolyfills.NodeModulesPolyfillPlugin()]);
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
esbuildOptions
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
build(esbuildOptions, process.argv.slice(2));
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const config = require('../../jest.base');
|
|
2
|
+
config.testEnvironment = 'jsdom';
|
|
3
|
+
config.collectCoverageFrom = ['src/**/*.{ts,tsx}'];
|
|
4
|
+
config.transform = {
|
|
5
|
+
'^.+\\.test.tsx?$': 'ts-jest',
|
|
6
|
+
'.+\\.(css|sass|scss)$': 'jest-scss-transform'
|
|
7
|
+
};
|
|
8
|
+
config.globals = {
|
|
9
|
+
'ts-jest': {
|
|
10
|
+
jsx: 'react',
|
|
11
|
+
diagnostics: {
|
|
12
|
+
warnOnly: true,
|
|
13
|
+
exclude: /\.(spec|test)\.ts$/
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
config.preset = 'ts-jest';
|
|
18
|
+
config.transformIgnorePatterns = ['<rootDir>/node_modules/'];
|
|
19
|
+
config.testMatch = ['**/test/unit/**/*.(test).ts(x)?'];
|
|
20
|
+
module.exports = config;
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sap-ux/control-property-editor",
|
|
3
|
+
"displayName": "Control Property Editor",
|
|
4
|
+
"description": "Control Property Editor",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"version": "0.2.0",
|
|
7
|
+
"main": "dist/app.js",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
11
|
+
"directory": "packages/control-property-editor"
|
|
12
|
+
},
|
|
13
|
+
"private": false,
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@fluentui/react": "8.100.0",
|
|
16
|
+
"@fluentui/react-hooks": "8.6.14",
|
|
17
|
+
"@reduxjs/toolkit": "1.6.1",
|
|
18
|
+
"@testing-library/jest-dom": "5.16.5",
|
|
19
|
+
"@testing-library/react": "12.1.4",
|
|
20
|
+
"@testing-library/dom": "9.3.1",
|
|
21
|
+
"@types/react-dom": "16.8.5",
|
|
22
|
+
"@types/react-redux": "7.1.1",
|
|
23
|
+
"@types/redux-logger": "3.0.7",
|
|
24
|
+
"@types/remote-redux-devtools": "0.5.4",
|
|
25
|
+
"@types/source-map-support": "0.5.0",
|
|
26
|
+
"@types/react": "16.14.45",
|
|
27
|
+
"body-parser": "1.20.1",
|
|
28
|
+
"eslint-plugin-react": "7.32.2",
|
|
29
|
+
"http-proxy-middleware": "1.3.1",
|
|
30
|
+
"i18next": "19.0.2",
|
|
31
|
+
"npm-run-all": "4.1.5",
|
|
32
|
+
"react": "16.14.0",
|
|
33
|
+
"react-dom": "16.14.0",
|
|
34
|
+
"react-i18next": "11.10.0",
|
|
35
|
+
"react-redux": "7.2.1",
|
|
36
|
+
"redux": "4.0.4",
|
|
37
|
+
"redux-logger": "3.0.6",
|
|
38
|
+
"rimraf": "3.0.0",
|
|
39
|
+
"source-map-support": "0.5.16",
|
|
40
|
+
"stream-browserify": "3.0.0",
|
|
41
|
+
"ts-import-plugin": "1.6.3",
|
|
42
|
+
"ts-jest": "29.1.1",
|
|
43
|
+
"postcss-modules": "6.0.0",
|
|
44
|
+
"copyfiles": "2.4.1",
|
|
45
|
+
"express": "4.18.2",
|
|
46
|
+
"ejs": "3.1.7",
|
|
47
|
+
"@ui5/fs": "3.0.4",
|
|
48
|
+
"esbuild-plugin-alias": "0.2.1",
|
|
49
|
+
"@esbuild-plugins/node-modules-polyfill": "0.1.4",
|
|
50
|
+
"autoprefixer": "10.4.7",
|
|
51
|
+
"postcss": "8.4.14",
|
|
52
|
+
"yargs-parser": "21.1.1",
|
|
53
|
+
"@sap-ux/ui-components": "1.11.14",
|
|
54
|
+
"@sap-ux-private/control-property-editor-common": "0.1.0"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"clean": "rimraf ./dist ./coverage *.tsbuildinfo",
|
|
58
|
+
"build": "npm-run-all -l -s clean -p build:compile build:webapp",
|
|
59
|
+
"build:compile": "tsc --build ./tsconfig.json --pretty --dry",
|
|
60
|
+
"build:webapp": "node esbuild.js",
|
|
61
|
+
"watch": "npm-run-all -p watch:*",
|
|
62
|
+
"watch:webapp": "node esbuild.js --watch --minify=false",
|
|
63
|
+
"test": "jest --maxWorkers=1 --ci --forceExit --detectOpenHandles --config='jest.config.js'",
|
|
64
|
+
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand --config='jest.config.js' --colors",
|
|
65
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
66
|
+
"lint:fix": "eslint . --ext .ts,.tsx --fix"
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/App.scss
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
*:not([data-icon-name='CheckMark']):not(.sapUiIcon) {
|
|
2
|
+
font-family: var(--vscode-font-family) !important;
|
|
3
|
+
}
|
|
4
|
+
html {
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
}
|
|
7
|
+
.app {
|
|
8
|
+
display: flex;
|
|
9
|
+
height: 100%;
|
|
10
|
+
background-color: var(--vscode-editor-background);
|
|
11
|
+
min-width: 0;
|
|
12
|
+
min-height: 0;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
justify-content: space-between;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.app-preview {
|
|
18
|
+
height: 100%;
|
|
19
|
+
border-width: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.app-content {
|
|
23
|
+
flex-grow: 1;
|
|
24
|
+
display: flex;
|
|
25
|
+
overflow-x: auto;
|
|
26
|
+
overflow-y: hidden;
|
|
27
|
+
background-color: inherit;
|
|
28
|
+
padding: 19px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.app-canvas {
|
|
32
|
+
flex-shrink: 1;
|
|
33
|
+
margin: 0 auto;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.app-panel {
|
|
37
|
+
height: 100%;
|
|
38
|
+
width: 300px;
|
|
39
|
+
background: var(--vscode-sideBar-background);
|
|
40
|
+
color: var(--vscode-foreground);
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.app-panel-scroller {
|
|
47
|
+
overflow-y: auto;
|
|
48
|
+
overflow-x: hidden;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.app-panel-left {
|
|
52
|
+
border-right: 1px solid var(--vscode-contrastBorder);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.app-panel-right {
|
|
56
|
+
border-left: 1px solid var(--vscode-contrastBorder);
|
|
57
|
+
}
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { UIDialog, UILink, UIToggle } from '@sap-ux/ui-components';
|
|
6
|
+
|
|
7
|
+
import { PropertiesPanel, LeftPanel } from './panels';
|
|
8
|
+
import { useLocalStorage } from './use-local-storage';
|
|
9
|
+
import type { RootState } from './store';
|
|
10
|
+
import { useAppDispatch } from './store';
|
|
11
|
+
import { changePreviewScale } from './slice';
|
|
12
|
+
import { useWindowSize } from './use-window-size';
|
|
13
|
+
import { DEFAULT_DEVICE_WIDTH, DEVICE_WIDTH_MAP } from './devices';
|
|
14
|
+
|
|
15
|
+
import './App.scss';
|
|
16
|
+
import './Workarounds.scss';
|
|
17
|
+
|
|
18
|
+
export interface AppProps {
|
|
19
|
+
previewUrl: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* React element for App.
|
|
24
|
+
*
|
|
25
|
+
* @param appProps - AppProps
|
|
26
|
+
* @returns ReactElement
|
|
27
|
+
*/
|
|
28
|
+
export default function App(appProps: AppProps): ReactElement {
|
|
29
|
+
const { previewUrl } = appProps;
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const sheet = window.document.styleSheets[0];
|
|
32
|
+
sheet.insertRule(
|
|
33
|
+
'@font-face {font-family: "SAP-icons"; src: url("/resources/sap/ui/core/themes/base/fonts/SAP-icons.woff2") format("woff2"),' +
|
|
34
|
+
'local("SAP-icons"); font-weight: normal; font-style: normal}',
|
|
35
|
+
sheet.cssRules.length
|
|
36
|
+
);
|
|
37
|
+
}, []);
|
|
38
|
+
const { t } = useTranslation();
|
|
39
|
+
const dispatch = useAppDispatch();
|
|
40
|
+
const [hideWarningDialog, setHideWarningDialog] = useLocalStorage('hide-warning-dialog', false);
|
|
41
|
+
const [isWarningDialogVisible, setWarningDialogVisibility] = useState(() => hideWarningDialog !== true);
|
|
42
|
+
|
|
43
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
44
|
+
|
|
45
|
+
const previewWidth = useSelector<RootState, string>(
|
|
46
|
+
(state) => `${DEVICE_WIDTH_MAP.get(state.deviceType) ?? DEFAULT_DEVICE_WIDTH}px`
|
|
47
|
+
);
|
|
48
|
+
const previewScale = useSelector<RootState, number>((state) => state.scale);
|
|
49
|
+
const fitPreview = useSelector<RootState, boolean>((state) => state.fitPreview ?? false);
|
|
50
|
+
const windowSize = useWindowSize();
|
|
51
|
+
|
|
52
|
+
const containerRef = useCallback(
|
|
53
|
+
(node) => {
|
|
54
|
+
if (node === null) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
if (isInitialized && !fitPreview) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const paddingWidth = 40;
|
|
62
|
+
const width = node.clientWidth;
|
|
63
|
+
const availableWidth = width - paddingWidth;
|
|
64
|
+
const requiredWidth = parseInt(previewWidth, 10);
|
|
65
|
+
if (availableWidth < requiredWidth) {
|
|
66
|
+
const scale = availableWidth / requiredWidth;
|
|
67
|
+
dispatch(changePreviewScale(scale));
|
|
68
|
+
const startPosition = (node.scrollWidth - width) / 2;
|
|
69
|
+
if (typeof node.scrollTo === 'function') {
|
|
70
|
+
node.scrollTo(startPosition, 0);
|
|
71
|
+
}
|
|
72
|
+
} else if (previewScale < 1 && availableWidth >= requiredWidth) {
|
|
73
|
+
dispatch(changePreviewScale(1));
|
|
74
|
+
}
|
|
75
|
+
if (!isInitialized) {
|
|
76
|
+
setIsInitialized(true);
|
|
77
|
+
}
|
|
78
|
+
}, 0);
|
|
79
|
+
},
|
|
80
|
+
[windowSize, fitPreview]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
function closeWarningDialog(): void {
|
|
84
|
+
setWarningDialogVisibility(false);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className="app">
|
|
89
|
+
<section className="app-panel app-panel-left">
|
|
90
|
+
<LeftPanel />
|
|
91
|
+
</section>
|
|
92
|
+
<section ref={containerRef} className="app-content">
|
|
93
|
+
<div className="app-canvas">
|
|
94
|
+
<iframe
|
|
95
|
+
className="app-preview"
|
|
96
|
+
id="preview"
|
|
97
|
+
style={{
|
|
98
|
+
width: previewWidth,
|
|
99
|
+
transform: `scale(${previewScale})`
|
|
100
|
+
}}
|
|
101
|
+
src={previewUrl}
|
|
102
|
+
title={t('APPLICATION_PREVIEW_TITLE')}
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
</section>
|
|
106
|
+
<section className="app-panel app-panel-right">
|
|
107
|
+
<PropertiesPanel />
|
|
108
|
+
</section>
|
|
109
|
+
|
|
110
|
+
<UIDialog
|
|
111
|
+
hidden={!isWarningDialogVisible}
|
|
112
|
+
closeButtonAriaLabel={t('CLOSE')}
|
|
113
|
+
dialogContentProps={{
|
|
114
|
+
title: t('TOOL_DISCLAIMER_TITLE'),
|
|
115
|
+
subText: t('TOOL_DISCLAIMER_TEXT')
|
|
116
|
+
}}
|
|
117
|
+
acceptButtonText={t('OK')}
|
|
118
|
+
onAccept={closeWarningDialog}>
|
|
119
|
+
<UILink href="https://ui5.sap.com/#/topic/03265b0408e2432c9571d6b3feb6b1fd">
|
|
120
|
+
{t('FE_DOCUMENTATION_LINK_TEXT')}
|
|
121
|
+
</UILink>
|
|
122
|
+
<UIToggle
|
|
123
|
+
className="space space-toggle"
|
|
124
|
+
label={t('DONT_SHOW_WARNING_ON_START')}
|
|
125
|
+
inlineLabel
|
|
126
|
+
inlineLabelLeft
|
|
127
|
+
labelFlexGrow
|
|
128
|
+
checked={hideWarningDialog}
|
|
129
|
+
onChange={(_event, checked = false): void => {
|
|
130
|
+
setHideWarningDialog(checked);
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
</UIDialog>
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// UITextField
|
|
2
|
+
.ms-TextField {
|
|
3
|
+
.ms-TextField-field {
|
|
4
|
+
font-family: var(--vscode-font-family);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.ms-Label {
|
|
8
|
+
margin-top: 0;
|
|
9
|
+
margin-bottom: 4px;
|
|
10
|
+
padding: 0;
|
|
11
|
+
font-weight: normal;
|
|
12
|
+
height: 18px;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// UIDialog
|
|
17
|
+
.ms-Dialog {
|
|
18
|
+
.ms-Dialog-title {
|
|
19
|
+
color: var(--vscode-foreground);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.ms-Dialog-subText {
|
|
23
|
+
color: var(--vscode-foreground);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// UIList
|
|
28
|
+
|
|
29
|
+
.ms-GroupHeader.app-panel-selected-bg {
|
|
30
|
+
.ms-GroupHeader-title {
|
|
31
|
+
color: var(--vscode-list-activeSelectionForeground);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.ms-GroupHeader-expand svg path {
|
|
35
|
+
fill: var(--vscode-list-activeSelectionForeground);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.uiList-group-entry:hover {
|
|
40
|
+
outline: 1px dashed var(--vscode-contrastActiveBorder);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// UIIconButton
|
|
44
|
+
.ms-Button.ms-Button--icon.is-checked {
|
|
45
|
+
background-color: var(--vscode-button-hoverBackground);
|
|
46
|
+
outline: 1px solid var(--vscode-contrastActiveBorder);
|
|
47
|
+
svg {
|
|
48
|
+
path,
|
|
49
|
+
rect {
|
|
50
|
+
fill: var(--vscode-button-foreground);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Tree
|
|
56
|
+
.app-panel-selected-bg {
|
|
57
|
+
.ms-GroupHeader-expand:hover {
|
|
58
|
+
color: var(--vscode-list-activeSelectionForeground);
|
|
59
|
+
background-color: var(--vscode-list-activeSelectionBackground);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.app-panel-hc-selected-bg {
|
|
64
|
+
outline: 1px solid var(--vscode-contrastActiveBorder);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ms-GroupHeader.ms-GroupHeader--compact {
|
|
68
|
+
&:hover {
|
|
69
|
+
outline: 1px dashed var(--vscode-contrastActiveBorder);
|
|
70
|
+
}
|
|
71
|
+
.ms-GroupHeader-title {
|
|
72
|
+
height: 18px;
|
|
73
|
+
padding: 5px 0;
|
|
74
|
+
font-family: var(--vscode-font-family);
|
|
75
|
+
}
|
|
76
|
+
> div {
|
|
77
|
+
height: 28px;
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/actions.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Text } from '@fluentui/react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import styles from './AppLogo.module.scss';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* React element for app logo.
|
|
10
|
+
*
|
|
11
|
+
* @returns ReactElement
|
|
12
|
+
*/
|
|
13
|
+
export function AppLogo(): ReactElement {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
<AppIcon />
|
|
18
|
+
<Text className={styles.flexEditorText}>{t('APP_TITLE')}</Text>
|
|
19
|
+
</>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* React element for app icon.
|
|
25
|
+
*
|
|
26
|
+
* @returns ReactElement
|
|
27
|
+
*/
|
|
28
|
+
function AppIcon(): ReactElement {
|
|
29
|
+
return (
|
|
30
|
+
<span data-testid="Control-Property-Editor-Icon">
|
|
31
|
+
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
32
|
+
<path
|
|
33
|
+
d="M18.1988 19.7416L18.3835 22.6424L15.1241 24.2613L12.3644 21.4256L9.68087 24.6741L6.37801 23.5551L6.53012 19.4591L2.47759 19.9806L1.07605 16.7755L4.05297 13.8095L1 11.3106L2.32549 7.89908L4.80263 7.83389L6.37801 7.8013"
|
|
34
|
+
stroke="var(--vscode-icon-foreground)"
|
|
35
|
+
strokeWidth="1.5"
|
|
36
|
+
strokeMiterlimit="10"
|
|
37
|
+
strokeLinecap="round"
|
|
38
|
+
strokeLinejoin="round"
|
|
39
|
+
/>
|
|
40
|
+
<path
|
|
41
|
+
d="M14.092 17.5578C13.2228 18.0249 12.1798 18.2205 11.0825 18.0141C9.22461 17.6555 7.76875 16.0802 7.54059 14.2114C7.44281 13.4726 7.54059 12.7556 7.76874 12.1146"
|
|
42
|
+
stroke="var(--vscode-icon-foreground)"
|
|
43
|
+
strokeWidth="1.5"
|
|
44
|
+
strokeMiterlimit="10"
|
|
45
|
+
strokeLinecap="round"
|
|
46
|
+
strokeLinejoin="round"
|
|
47
|
+
/>
|
|
48
|
+
<path
|
|
49
|
+
d="M12.5708 5.28068C12.473 5.57402 12.2557 6.32369 12.2014 7.27978C12.1253 8.63786 12.4404 9.75692 12.6794 10.4197C12.3643 10.2458 11.8754 10.0285 11.2344 9.94162C10.7455 9.87643 10.3326 9.89816 10.0284 9.94162C9.53951 8.89861 8.88763 7.13854 8.82245 4.86782C8.77899 3.27072 9.03974 1.94523 9.30049 1C12.9728 1.30421 15.7432 3.85741 16.0583 6.79087C16.3517 9.49617 14.4503 11.5279 14.1244 11.8647"
|
|
50
|
+
stroke="var(--vscode-icon-foreground)"
|
|
51
|
+
strokeWidth="1.5"
|
|
52
|
+
strokeMiterlimit="10"
|
|
53
|
+
strokeLinecap="round"
|
|
54
|
+
strokeLinejoin="round"
|
|
55
|
+
/>
|
|
56
|
+
<path
|
|
57
|
+
d="M13.9724 2.95565C14.4287 2.46674 15.1132 1.89091 16.0584 1.48892C17.1666 1.02174 18.1553 0.989147 18.7203 1.01088C18.905 1.48892 19.0897 2.05388 19.1983 2.70576C19.5025 4.44411 19.22 5.91084 18.9593 6.81261C19.7633 6.64964 20.8389 6.5084 22.0992 6.57359C23.2617 6.62791 24.2504 6.83434 25.0001 7.05163C24.9892 7.50795 24.8914 9.93077 22.9792 11.7778C22.9358 11.8212 22.8814 11.8647 22.8271 11.919C22.3599 12.3319 21.0127 13.4618 18.9593 13.5813C18.3074 13.6139 17.2861 13.5813 16.0584 13.1033C15.5478 13.1033 15.3848 13.2336 15.3305 13.3423C15.2001 13.603 15.5587 13.9181 15.8085 14.5483C15.9389 14.8633 16.0476 15.2653 16.0476 15.7542C16.9167 16.1888 18.4269 16.8081 20.3934 16.9602C22.2839 17.1123 23.8158 16.7646 24.7393 16.4822C24.8154 16.1345 24.9023 15.5152 24.7393 14.7873C24.6198 14.2549 24.4242 13.8529 24.2613 13.5813"
|
|
58
|
+
stroke="var(--vscode-icon-foreground)"
|
|
59
|
+
strokeWidth="1.5"
|
|
60
|
+
strokeMiterlimit="10"
|
|
61
|
+
strokeLinecap="round"
|
|
62
|
+
strokeLinejoin="round"
|
|
63
|
+
/>
|
|
64
|
+
<path
|
|
65
|
+
d="M18.7205 9.91989C18.8182 9.93076 19.4701 9.97421 20.1655 10.1806C21.5235 10.5718 22.5448 11.3975 22.9685 11.7669"
|
|
66
|
+
stroke="var(--vscode-icon-foreground)"
|
|
67
|
+
strokeWidth="1.5"
|
|
68
|
+
strokeMiterlimit="10"
|
|
69
|
+
strokeLinecap="round"
|
|
70
|
+
strokeLinejoin="round"
|
|
71
|
+
/>
|
|
72
|
+
</svg>
|
|
73
|
+
</span>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
|
|
5
|
+
interface ChangeIndicatorProps {
|
|
6
|
+
saved: number;
|
|
7
|
+
pending: number;
|
|
8
|
+
id?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* React element for change indicator.
|
|
13
|
+
*
|
|
14
|
+
* @param props - ChangeIndicatorProps
|
|
15
|
+
* @returns ReactElement
|
|
16
|
+
*/
|
|
17
|
+
export function ChangeIndicator(props: ChangeIndicatorProps): ReactElement {
|
|
18
|
+
const { saved, pending, id } = props;
|
|
19
|
+
const rest = { id };
|
|
20
|
+
const color = 'var(--vscode-terminal-ansiGreen)';
|
|
21
|
+
|
|
22
|
+
if (saved > 0 && pending === 0) {
|
|
23
|
+
return (
|
|
24
|
+
<svg
|
|
25
|
+
role="img"
|
|
26
|
+
width="8"
|
|
27
|
+
height="8"
|
|
28
|
+
viewBox="0 0 8 8"
|
|
29
|
+
fill="none"
|
|
30
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
31
|
+
{...rest}>
|
|
32
|
+
<ChangeIndicatorTooltip {...props} />
|
|
33
|
+
<circle cx="4" cy="4" r="4" fill={color} />
|
|
34
|
+
</svg>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (pending > 0 && saved === 0) {
|
|
39
|
+
return (
|
|
40
|
+
<svg
|
|
41
|
+
role="img"
|
|
42
|
+
width="8"
|
|
43
|
+
height="8"
|
|
44
|
+
viewBox="0 0 8 8"
|
|
45
|
+
fill="none"
|
|
46
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
47
|
+
{...rest}>
|
|
48
|
+
<ChangeIndicatorTooltip {...props} />
|
|
49
|
+
<circle cx="4" cy="4" r="3.5" stroke={color} />
|
|
50
|
+
</svg>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<svg role="img" width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg" {...rest}>
|
|
56
|
+
<ChangeIndicatorTooltip {...props} />
|
|
57
|
+
<circle cx="4" cy="4" r="3.5" stroke={color} />
|
|
58
|
+
<path d="M4 8a4 4 0 1 0 0-8v8Z" fill={color} />
|
|
59
|
+
</svg>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* React element for change indicator tooltip.
|
|
65
|
+
*
|
|
66
|
+
* @param changeIndicatorProps - ChangeIndicatorProps
|
|
67
|
+
* @returns ReactElement
|
|
68
|
+
*/
|
|
69
|
+
function ChangeIndicatorTooltip(changeIndicatorProps: ChangeIndicatorProps): ReactElement {
|
|
70
|
+
const { saved, pending } = changeIndicatorProps;
|
|
71
|
+
const { t } = useTranslation();
|
|
72
|
+
if (saved > 0 && pending === 0) {
|
|
73
|
+
return <title>{t('SAVED_CHANGES')}</title>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (pending > 0 && saved === 0) {
|
|
77
|
+
return <title>{t('UNSAVED_CHANGES')}</title>;
|
|
78
|
+
}
|
|
79
|
+
return <title>{t('SAVED_AND_UNSAVED_CHANGES')}</title>;
|
|
80
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CSSProperties, DetailedHTMLProps, HTMLAttributes, ReactElement } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
interface SeparatorProps {
|
|
5
|
+
direction?: 'horizontal' | 'vertical';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* React element for seperator.
|
|
10
|
+
*
|
|
11
|
+
* @param separatorProps SeparatorProps & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
|
12
|
+
* @returns ReactElement
|
|
13
|
+
*/
|
|
14
|
+
export function Separator(
|
|
15
|
+
separatorProps: SeparatorProps & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
|
16
|
+
): ReactElement {
|
|
17
|
+
const { direction, style, ...rest } = separatorProps;
|
|
18
|
+
const isVertical = direction === 'vertical';
|
|
19
|
+
const borderProp = isVertical ? 'borderLeft' : 'borderBottom';
|
|
20
|
+
const inlineStyles: CSSProperties = {
|
|
21
|
+
...{
|
|
22
|
+
[borderProp]: '1px solid var(--vscode-contrastBorder, var(--vscode-editorIndentGuide-background))'
|
|
23
|
+
},
|
|
24
|
+
...style
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (isVertical) {
|
|
28
|
+
inlineStyles.height = '100%';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <div style={inlineStyles} {...rest} />;
|
|
32
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#theme-light {
|
|
2
|
+
border-radius: 50%;
|
|
3
|
+
width: 14px;
|
|
4
|
+
height: 14px;
|
|
5
|
+
background: #ffffff;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
#theme-dark {
|
|
9
|
+
border-radius: 50%;
|
|
10
|
+
width: 14px;
|
|
11
|
+
height: 14px;
|
|
12
|
+
background-color: #3c3c3c;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#theme-high-contrast {
|
|
16
|
+
border-radius: 50%;
|
|
17
|
+
width: 14px;
|
|
18
|
+
height: 14px;
|
|
19
|
+
background: #f38518;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.theme-child {
|
|
23
|
+
display: flex;
|
|
24
|
+
float: left;
|
|
25
|
+
width: 20px;
|
|
26
|
+
height: 20px;
|
|
27
|
+
margin: 10px 0 10px 10px;
|
|
28
|
+
border-radius: 1px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.selected {
|
|
32
|
+
border-radius: 1px;
|
|
33
|
+
background-color: var(--vscode-progressBar-background);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
div#theme-light {
|
|
37
|
+
margin-left: 3px;
|
|
38
|
+
margin-bottom: 3px;
|
|
39
|
+
margin-top: 3px;
|
|
40
|
+
}
|
|
41
|
+
div#theme-dark {
|
|
42
|
+
margin-left: 3px;
|
|
43
|
+
margin-top: 3px;
|
|
44
|
+
}
|
|
45
|
+
div#theme-high-contrast {
|
|
46
|
+
margin-left: 3px;
|
|
47
|
+
margin-top: 3px;
|
|
48
|
+
}
|