diff --git a/webapp/packages/core-blocks/src/ActionIconButton.m.css b/webapp/packages/core-blocks/src/ActionIconButton.m.css new file mode 100644 index 0000000000..62d354bcc9 --- /dev/null +++ b/webapp/packages/core-blocks/src/ActionIconButton.m.css @@ -0,0 +1,10 @@ +.actionIconButton { + composes: theme-form-element-radius theme-ripple from global; + + padding: 4px !important; + margin: 2px !important; + width: 24px !important; + height: 24px !important; + overflow: hidden; + flex-shrink: 0; +} diff --git a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.m.css b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.m.css new file mode 100644 index 0000000000..8f1533dd3a --- /dev/null +++ b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.m.css @@ -0,0 +1,16 @@ +.status { + composes: theme-background-positive from global; + position: absolute; + opacity: 0; + transition: opacity 0.3s ease; + bottom: 0; + right: 0; + box-sizing: border-box; + width: 8px; + height: 8px; + border-radius: 50%; + + &.connected { + opacity: 1; + } +} diff --git a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx index 1f9ebb35a8..22d0a349ee 100644 --- a/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx +++ b/webapp/packages/core-blocks/src/ConnectionImageWithMask/ConnectionMark.tsx @@ -5,32 +5,18 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import styled, { css, use } from 'reshadow'; +import { observer } from 'mobx-react-lite'; -const styles = css` - status { - composes: theme-background-positive from global; - position: absolute; - opacity: 0; - transition: opacity 0.3s ease; - bottom: 0; - right: 0; - box-sizing: border-box; - width: 8px; - height: 8px; - border-radius: 50%; - - &[|connected] { - opacity: 1; - } - } -`; +import { s } from '../s'; +import { useS } from '../useS'; +import style from './ConnectionMark.m.css'; interface Props { connected: boolean; className?: string; } -export const ConnectionMark: React.FC = function ConnectionMark({ connected, className }) { - return styled(styles)(); -}; +export const ConnectionMark: React.FC = observer(function ConnectionMark({ connected, className }) { + const styles = useS(style); + return
; +}); diff --git a/webapp/packages/core-blocks/src/IconButton.m.css b/webapp/packages/core-blocks/src/IconButton.m.css index 61fd320c09..aab16ad798 100644 --- a/webapp/packages/core-blocks/src/IconButton.m.css +++ b/webapp/packages/core-blocks/src/IconButton.m.css @@ -14,4 +14,4 @@ width: 100%; height: 100%; } -} \ No newline at end of file +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.m.css new file mode 100644 index 0000000000..8949559b9a --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.m.css @@ -0,0 +1,5 @@ +.node { + box-sizing: border-box; + width: inherit; + min-width: 100%; +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.tsx index 256c38d27f..cc16d0f789 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNode.tsx @@ -8,14 +8,14 @@ import { computed, observable } from 'mobx'; import { observer } from 'mobx-react-lite'; import { forwardRef } from 'react'; -import styled, { use } from 'reshadow'; -import { getComputed } from '../../getComputed'; +import { s } from '../../s'; import { useObjectRef } from '../../useObjectRef'; import { useObservableRef } from '../../useObservableRef'; +import { useS } from '../../useS'; import type { ITreeNodeState } from './ITreeNodeState'; +import style from './TreeNode.m.css'; import { ITreeNodeContext, TreeNodeContext } from './TreeNodeContext'; -import { TREE_NODE_STYLES } from './TreeNodeStyles'; interface Props extends ITreeNodeState { className?: string; @@ -48,6 +48,7 @@ export const TreeNode = observer( }, ref, ) { + const styles = useS(style); const handlersRef = useObjectRef(handlers); async function processAction(action: () => Promise) { @@ -113,12 +114,10 @@ export const TreeNode = observer( }, ); - const elementExpanded = getComputed(() => nodeContext.externalExpanded ?? nodeContext.expanded); - - return styled(TREE_NODE_STYLES)( - + return ( +
{children} - , +
); }), ); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.m.css new file mode 100644 index 0000000000..9147a3540b --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.m.css @@ -0,0 +1,24 @@ +.treeNodeControl { + composes: theme-ripple theme-ripple-selectable from global; + box-sizing: border-box; + height: 22px; + display: flex; + align-items: center; + padding: 2px 0 2px 0; + user-select: none; + white-space: nowrap; + position: initial !important; + outline: none; + + &::before { + left: 0 !important; + top: auto !important; + height: inherit !important; + width: 100% !important; + } + + & > * { + margin-right: 0; + margin-left: 4px; + } +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.tsx index cfd07665b3..f0a6f97052 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeControl.tsx @@ -10,11 +10,14 @@ import React, { forwardRef, useContext } from 'react'; import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events'; +import { s } from '../../s'; +import { useS } from '../../useS'; import { EventTreeNodeClickFlag } from './EventTreeNodeClickFlag'; import { EventTreeNodeExpandFlag } from './EventTreeNodeExpandFlag'; import { EventTreeNodeSelectFlag } from './EventTreeNodeSelectFlag'; import type { ITreeNodeState } from './ITreeNodeState'; import { TreeNodeContext } from './TreeNodeContext'; +import style from './TreeNodeControl.m.css'; const KEY = { ENTER: 'Enter', @@ -25,15 +28,15 @@ interface Props extends ITreeNodeState { onClick?: (event: React.MouseEvent) => void; onMouseDown?: (event: React.MouseEvent) => void; className?: string; - big?: boolean; children?: React.ReactNode; } export const TreeNodeControl = observer, HTMLDivElement>( forwardRef(function TreeNodeControl( - { title, group, disabled, loading, selected, expanded, externalExpanded, leaf, onClick, onMouseDown, className, children, big, ...rest }, + { title, group, disabled, loading, selected, expanded, externalExpanded, leaf, onClick, onMouseDown, className, children, ...rest }, ref, ) { + const styles = useS(style); const context = useContext(TreeNodeContext); if (!context) { @@ -112,7 +115,7 @@ export const TreeNodeControl = observer(function TreeNodeExpand({ leaf, big, filterActive, disabled, className }) { + const styles = useS(style); const context = useContext(TreeNodeContext); if (!context) { @@ -90,10 +85,14 @@ export const TreeNodeExpand = observer(function TreeNodeExpand({ leaf, bi } } - return styled(styles)( - + return ( +
{loading && } - {expandable && } - , + {expandable && } +
); }); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.m.css new file mode 100644 index 0000000000..20eb274d11 --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.m.css @@ -0,0 +1,12 @@ +.treeNodeIcon { + position: relative; + box-sizing: border-box; + flex-shrink: 0; + width: 16px; + height: 16px; +} + +.staticImage { + position: relative; + height: 100%; +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.tsx index a7841dc780..ea596bd1c5 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeIcon.tsx @@ -5,30 +5,25 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import styled, { css } from 'reshadow'; - -import type { ComponentStyle } from '@cloudbeaver/core-theming'; +import { observer } from 'mobx-react-lite'; +import { s } from '../../s'; import { StaticImage } from '../../StaticImage'; -import { useStyles } from '../../useStyles'; - -const styles = css` - StaticImage { - height: 100%; - } -`; +import { useS } from '../../useS'; +import style from './TreeNodeIcon.m.css'; interface Props { icon?: string; - style?: ComponentStyle; className?: string; } -export const TreeNodeIcon: React.FC> = function TreeNodeIcon({ icon, style, className, children }) { - return styled(useStyles(styles, style))( - - {icon && } +export const TreeNodeIcon: React.FC> = observer(function TreeNodeIcon({ icon, className, children }) { + const styles = useS(style); + + return ( +
+ {icon && } {children} - , +
); -}; +}); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.m.css new file mode 100644 index 0000000000..cb76e298e2 --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.m.css @@ -0,0 +1,8 @@ +.treeNodeName { + position: relative; + box-sizing: border-box; + padding-right: 0; + display: flex; + align-items: center; + margin-right: 4px; +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.tsx index 891ef816e0..597bfe10f5 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeName.tsx @@ -5,15 +5,22 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { observer } from 'mobx-react-lite'; + +import { s } from '../../s'; +import { useS } from '../../useS'; +import style from './TreeNodeName.m.css'; interface Props extends React.HTMLAttributes { className?: string; } -export const TreeNodeName: React.FC = function TreeNodeName({ className, children, ...rest }) { +export const TreeNodeName: React.FC = observer(function TreeNodeName({ className, children, ...rest }) { + const styles = useS(style); + return ( -
+
{children}
); -}; +}); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.m.css new file mode 100644 index 0000000000..cbb45c7cba --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.m.css @@ -0,0 +1,10 @@ +.treeNodeNested { + box-sizing: border-box; + padding-left: 8px; + display: none; + + &.root { + padding: 0; + display: block; + } +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.tsx index 8c15519db5..b8281fbe8c 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNested.tsx @@ -5,18 +5,27 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { observer } from 'mobx-react-lite'; import { forwardRef } from 'react'; +import { s } from '../../s'; +import { useS } from '../../useS'; +import style from './TreeNodeNested.m.css'; + interface Props extends React.PropsWithChildren { expanded?: boolean; root?: boolean; className?: string; } -export const TreeNodeNested = forwardRef(function TreeNodeNested({ className, children }, ref) { - return ( -
- {children} -
- ); -}); +export const TreeNodeNested = observer( + forwardRef(function TreeNodeNested({ root, className, children }, ref) { + const styles = useS(style); + + return ( +
+ {children} +
+ ); + }), +); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.m.css new file mode 100644 index 0000000000..d1e5ec397d --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.m.css @@ -0,0 +1,4 @@ +.treeNodeNestedMessage { + composes: theme-typography--caption from global; + padding: 4px 12px; +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.tsx index 63bfe78446..bc7a8bb4b7 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeNestedMessage.tsx @@ -5,12 +5,17 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { observer } from 'mobx-react-lite'; + +import { s } from '../../s'; +import { useS } from '../../useS'; +import style from './TreeNodeNestedMessage.m.css'; interface Props { - big?: boolean; className?: string; } -export const TreeNodeNestedMessage: React.FC> = function TreeNodeNestedMessage({ className, children }) { - return
{children}
; -}; +export const TreeNodeNestedMessage: React.FC> = observer(function TreeNodeNestedMessage({ className, children }) { + const styles = useS(style); + return
{children}
; +}); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.m.css b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.m.css new file mode 100644 index 0000000000..88cba18609 --- /dev/null +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.m.css @@ -0,0 +1,4 @@ +.loader { + width: 40px; + height: 40px; +} diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.tsx b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.tsx index 93f0b39737..e84b5ad014 100644 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.tsx +++ b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeSelect.tsx @@ -7,21 +7,16 @@ */ import { observer } from 'mobx-react-lite'; import { useContext } from 'react'; -import styled, { css } from 'reshadow'; import { EventContext } from '@cloudbeaver/core-events'; import { Checkbox } from '../../FormControls/Checkboxes/Checkbox'; import { Loader } from '../../Loader/Loader'; +import { s } from '../../s'; +import { useS } from '../../useS'; import { EventTreeNodeSelectFlag } from './EventTreeNodeSelectFlag'; import { TreeNodeContext } from './TreeNodeContext'; - -const styles = css` - Loader { - width: 40px; - height: 40px; - } -`; +import style from './TreeNodeSelect.m.css'; interface Props { group?: boolean; @@ -42,6 +37,7 @@ export const TreeNodeSelect = observer(function TreeNodeSelect({ loadIndicator, className, }) { + const styles = useS(style); const context = useContext(TreeNodeContext); if (!context) { @@ -67,9 +63,13 @@ export const TreeNodeSelect = observer(function TreeNodeSelect({ EventContext.set(event, EventTreeNodeSelectFlag); } - return styled(styles)( + return (
- {loading ? : } -
, + {loading ? ( + + ) : ( + + )} +
); }); diff --git a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts b/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts deleted file mode 100644 index 3dc933e13c..0000000000 --- a/webapp/packages/core-blocks/src/Tree/TreeNode/TreeNodeStyles.ts +++ /dev/null @@ -1,188 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { css } from 'reshadow'; - -export const TREE_NODE_STYLES = css` - TreeNodeControl { - composes: theme-ripple theme-ripple-selectable from global; - } - TreeNodeNestedMessage { - composes: theme-text-text-hint-on-light from global; - } - node { - box-sizing: border-box; - width: inherit; - min-width: 100%; - - &[use|expanded] { - & > TreeNodeNested { - display: block; - } - - & > TreeNodeControl > TreeNodeExpand { - transform: rotate(0deg); - } - } - - & TreeNodeControl { - box-sizing: border-box; - height: 22px; - display: flex; - align-items: center; - padding: 2px 0 2px 0; - user-select: none; - white-space: nowrap; - position: initial; - outline: none; - - &::before { - left: 0; - top: auto; - height: inherit; - width: 100%; - } - - &[|dragging] { - opacity: 0.6; - } - - &[|editing]::before { - display: none; - } - - & > * { - margin-right: 0; - margin-left: 4px; - } - - & TreeNodeName { - margin-right: 4px; - } - } - } - - TreeNodeExpand { - display: flex; - box-sizing: border-box; - flex-shrink: 0; - opacity: 0.5; - width: 16px; - height: 16px; - transform: rotate(-90deg); - & [|size='small'] { - display: block; - } - - & [|size='big'] { - display: none; - } - } - - NavigationNode[dragging] { - opacity: 0.5 !important; - } - - TreeNodeIcon { - box-sizing: border-box; - flex-shrink: 0; - width: 16px; - height: 16px; - } - - TreeNodeName { - box-sizing: border-box; - padding-right: 0; - display: flex; - align-items: center; - margin-right: 4px; - } - - TreeNodeFilter { - position: relative; - min-width: 24px; - min-height: 24px; - display: flex; - align-items: center; - } - - TreeNodeIcon, - TreeNodeExpand, - TreeNodeName { - position: relative; - } - - TreeNodeNested { - box-sizing: border-box; - padding-left: 8px; - display: none; - - &[root] { - padding: 0; - display: block; - } - - &[expanded] { - display: block; - } - } - - TreeNodeNestedMessage { - composes: theme-typography--caption from global; - padding: 4px 12px; - - &[big] { - padding: 4px 24px; - } - } - - tree-box[|big] { - & TreeNodeNestedMessage { - padding: 4px 24px; - } - } - - node TreeNodeControl[big] { - height: 46px; - padding: 0px 16px; - - & TreeNodeName { - margin: 0; - padding-right: 8px; - padding-left: 8px; - } - & TreeNodeIcon { - width: 24px; - height: 24px; - } - & TreeNodeExpand { - width: 16px; - height: 16px; - } - - & TreeNodeExpand [|size='small'] { - display: none; - } - - & TreeNodeExpand [|size='big'] { - display: block; - } - - & > * { - margin-right: 8px; - margin-left: 8px; - } - - & TreeNodeSelect { - margin: 0; - } - } - - node TreeNodeControl[big] + TreeNodeNested { - padding-left: 24px; - } -`; diff --git a/webapp/packages/core-blocks/src/index.ts b/webapp/packages/core-blocks/src/index.ts index a9d36511d4..d0fcbea067 100644 --- a/webapp/packages/core-blocks/src/index.ts +++ b/webapp/packages/core-blocks/src/index.ts @@ -25,6 +25,7 @@ export * from './ConnectionImageWithMask/ConnectionImageWithMask'; export { default as ConnectionImageWithMaskSvgStyles } from './ConnectionImageWithMask/ConnectionImageWithMaskSvg.m.css'; export * from './Menu/ACTION_ICON_BUTTON_STYLES'; +export { default as ActionIconButtonStyles } from './ActionIconButton.m.css'; export * from './Menu/Menu'; export { default as MenuStyles } from './Menu/Menu.m.css'; export * from './Menu/MenuBarSmallItem'; @@ -106,12 +107,13 @@ export * from './Tree/TreeNode/TreeNodeName'; export * from './Tree/TreeNode/TreeNodeNested'; export * from './Tree/TreeNode/TreeNodeNestedMessage'; export * from './Tree/TreeNode/TreeNodeSelect'; -export * from './Tree/TreeNode/TreeNodeStyles'; export * from './Button'; export * from './ToolsPanel/ToolsAction'; export * from './ToolsPanel/ToolsPanel'; export { default as ToolsPanelStyles } from './ToolsPanel/ToolsPanel.m.css'; export { default as ToolsActionStyles } from './ToolsPanel/ToolsAction.m.css'; +export { default as TreeNodeNestedMessageStyles } from './Tree/TreeNode/TreeNodeNestedMessage.m.css'; +export { default as TreeNodeStyles } from './Tree/TreeNode/TreeNode.m.css'; export * from './FormControls/Checkboxes/Checkbox'; export * from './FormControls/Checkboxes/FieldCheckbox'; export * from './FormControls/Checkboxes/CheckboxMarkup'; diff --git a/webapp/packages/core-cli/configs/webpack.config.js b/webapp/packages/core-cli/configs/webpack.config.js index d43cd1c56a..8976486b15 100644 --- a/webapp/packages/core-cli/configs/webpack.config.js +++ b/webapp/packages/core-cli/configs/webpack.config.js @@ -242,6 +242,7 @@ module.exports = (env, argv) => { plugins: [ new ForkTsCheckerWebpackPlugin({ typescript: { + typescriptPath: require.resolve('typescript'), configFile: resolve('tsconfig.json'), configOverwrite: { include: ['**/src/**/*.ts', '**/src/**/*.tsx'], diff --git a/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/ErrorDetailsDialog.tsx b/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/ErrorDetailsDialog.tsx index e1ac728334..35bd0e3044 100644 --- a/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/ErrorDetailsDialog.tsx +++ b/webapp/packages/core-notifications/src/NotificationsItem/ErrorDetailsDialog/ErrorDetailsDialog.tsx @@ -19,13 +19,13 @@ function DisplayErrorInfo({ error }: { error: IErrorInfo }) { return ( <> - - {error.isHtml ?