diff --git a/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.m.css b/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.m.css new file mode 100644 index 0000000000..c141d48ce2 --- /dev/null +++ b/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.m.css @@ -0,0 +1,108 @@ +.container, +.button { + composes: theme-ripple from global; +} + +.container { + box-sizing: border-box; + display: inline-flex; + padding: 0px 1px; +} + +.name, +.value { + composes: theme-typography--caption from global; + position: relative; + display: flex; + align-items: center; + box-sizing: border-box; + flex: 1; + padding: 4px 0; + + & .shadowInput { + height: 24px; + padding: 0 36px 0 12px; + } +} + +.value, +.name { + margin-left: 24px; +} + +.name { + flex: 0 0 auto; + width: 276px; +} + +.remove { + position: relative; + flex: 0 0 auto; + align-items: center; + display: flex; + opacity: 0; +} + +.select { + flex: 0 0 auto; + align-items: center; + display: flex; +} + +.container:hover .remove { + opacity: 1; +} + +.shadowInput { + composes: theme-background-surface from global; +} + +.name .shadowInput, +.value .shadowInput { + box-sizing: border-box; + font: inherit; + color: inherit; + width: 100%; + outline: none; + + &.edited { + font-weight: 600; + } + + &:global([readonly]), + &:not(:focus):not([data-focus='true']) { + background: transparent !important; + border: solid 2px transparent !important; + } +} + +.icon, +.iconOrImage { + height: 16px; + display: block; +} + +.select .icon, +.select .iconOrImage { + &.focus { + transform: rotate(180deg); + } +} + +.button { + background: transparent; + outline: none; + padding: 4px; + cursor: pointer; +} + +.button, +.propertyValueSelector { + composes: theme-form-element-radius from global; + margin: 2px; + overflow: hidden; +} + +.error { + composes: theme-text-error from global; +} diff --git a/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx b/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx index 26253898a7..2ca3dffa11 100644 --- a/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx +++ b/webapp/packages/core-blocks/src/PropertiesTable/PropertyItem.tsx @@ -7,111 +7,17 @@ */ import { observer } from 'mobx-react-lite'; import { useCallback, useLayoutEffect, useRef, useState } from 'react'; -import styled, { css, use } from 'reshadow'; import { ShadowInput } from '../FormControls/ShadowInput'; import { Icon } from '../Icon'; import { IconOrImage } from '../IconOrImage'; import { useTranslate } from '../localization/useTranslate'; +import { s } from '../s'; +import { useS } from '../useS'; import type { IProperty } from './IProperty'; +import classes from './PropertyItem.m.css'; import { PropertyValueSelector } from './PropertyValueSelector'; -const styles = css` - [|error] { - composes: theme-text-error from global; - } - property-item, - button { - composes: theme-ripple from global; - } - property-item { - box-sizing: border-box; - display: inline-flex; - padding: 0px 1px; - } - property-name, - property-value { - composes: theme-typography--caption from global; - position: relative; - display: flex; - align-items: center; - box-sizing: border-box; - flex: 1; - padding: 4px 0; - - & ShadowInput { - height: 24px; - padding: 0 36px 0 12px; - } - } - property-value, - property-name { - margin-left: 24px; - } - property-name { - flex: 0 0 auto; - width: 276px; - } - property-remove { - position: relative; - flex: 0 0 auto; - align-items: center; - display: flex; - opacity: 0; - } - property-select { - flex: 0 0 auto; - align-items: center; - display: flex; - } - property-item:hover property-remove { - opacity: 1; - } - ShadowInput { - composes: theme-background-surface from global; - } - property-name ShadowInput, - property-value ShadowInput { - box-sizing: border-box; - font: inherit; - color: inherit; - width: 100%; - outline: none; - - &[|edited] { - font-weight: 600; - } - &:global([readonly]), - &:not(:focus):not([|focus]) { - background: transparent !important; - border: solid 2px transparent !important; - } - } - Icon, - IconOrImage { - height: 16px; - display: block; - } - property-select Icon, - property-select IconOrImage { - &[|focus] { - transform: rotate(180deg); - } - } - button { - background: transparent; - outline: none; - padding: 4px; - cursor: pointer; - } - button, - PropertyValueSelector { - composes: theme-form-element-radius from global; - margin: 2px; - overflow: hidden; - } -`; - interface Props { property: IProperty; value?: string; @@ -123,6 +29,7 @@ interface Props { } export const PropertyItem = observer(function PropertyItem({ property, value, onNameChange, onValueChange, onRemove, error, readOnly }) { + const styles = useS(classes); const translate = useTranslate(); const isDeletable = !readOnly && !property.displayName; const edited = value !== undefined && value !== property.defaultValue; @@ -148,11 +55,12 @@ export const PropertyItem = observer(function PropertyItem({ property, va const keyPlaceholder = String(property.keyPlaceholder); const valuePlaceholder = String(property.valuePlaceholder); - return styled(styles)( - - + return ( +
+
(function PropertyItem({ property, va > {property.displayName || property.key} - - +
+
(function PropertyItem({ property, va readOnly={readOnly} data-focus={focus} onChange={handleValueChange} - {...use({ focus, edited })} > {propertyValue} {edited && !isDeletable && ( - - - +
)} {isDeletable && ( - - - +
)} {!readOnly && property.validValues && property.validValues.length > 0 && ( - +
- + - +
)} - -
, + + ); }); diff --git a/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.m.css b/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.m.css new file mode 100644 index 0000000000..da9d7d57a5 --- /dev/null +++ b/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.m.css @@ -0,0 +1,7 @@ +.menuButton { + composes: theme-ripple from global; + background: transparent; + outline: none; + padding: 4px; + cursor: pointer; +} diff --git a/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.tsx b/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.tsx index fa16b1b9a6..643bd510d7 100644 --- a/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.tsx +++ b/webapp/packages/core-blocks/src/PropertiesTable/PropertyValueSelector.tsx @@ -8,19 +8,12 @@ import { observer } from 'mobx-react-lite'; import { useCallback, useEffect, useRef } from 'react'; import { Menu, MenuButton, MenuItem, useMenuState } from 'reakit/Menu'; -import styled, { css } from 'reshadow'; +import styled from 'reshadow'; import { BASE_DROPDOWN_STYLES } from '../FormControls/BASE_DROPDOWN_STYLES'; - -const styles = css` - MenuButton { - composes: theme-ripple from global; - background: transparent; - outline: none; - padding: 4px; - cursor: pointer; - } -`; +import { s } from '../s'; +import { useS } from '../useS'; +import classes from './PropertyValueSelector.m.css'; interface Props { propertyName?: string; @@ -40,6 +33,7 @@ export const PropertyValueSelector = observer>(fu onSelect, onSwitch, }) { + const styles = useS(classes); const menuRef = useRef(null); const menu = useMenuState({ placement: 'bottom-end', @@ -76,12 +70,9 @@ export const PropertyValueSelector = observer>(fu const visible = menu.visible; - return styled( - BASE_DROPDOWN_STYLES, - styles, - )( + return styled(BASE_DROPDOWN_STYLES)( <> - + {children} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.m.css b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.m.css new file mode 100644 index 0000000000..8225a1d152 --- /dev/null +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.m.css @@ -0,0 +1,7 @@ +.wrapper { + composes: theme-background-surface from global; + display: flex; + width: 100%; + flex: 1 1 auto; + padding-top: 16px; +} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.tsx b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.tsx index d5881537f4..77105a41bc 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertiesPagePanel.tsx @@ -6,25 +6,19 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; -import styled, { css } from 'reshadow'; + +import { s, useS } from '@cloudbeaver/core-blocks'; import type { ObjectPagePanelComponent } from '../ObjectPage/ObjectPage'; import { ObjectFolders } from './ObjectFolders'; - -const viewerStyles = css` - wrapper { - composes: theme-background-surface from global; - display: flex; - width: 100%; - flex: 1 1 auto; - padding-top: 16px; - } -`; +import classes from './ObjectPropertiesPagePanel.m.css'; export const ObjectPropertiesPagePanel: ObjectPagePanelComponent = observer(function ObjectPropertiesPagePanel({ tab }) { - return styled(viewerStyles)( - + const styles = useS(classes); + + return ( +
- , +
); }); diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.m.css b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.m.css new file mode 100644 index 0000000000..723b6e76cb --- /dev/null +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.m.css @@ -0,0 +1,23 @@ +.container { + cursor: pointer; + width: 100%; +} + +.container:not(.empty) .value { + padding-right: 8px; +} + +.box { + display: flex; + height: 100%; + align-items: center; + + & .icon { + width: 16px; + } +} + +.value { + flex-grow: 1; + flex-shrink: 1; +} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.tsx b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.tsx index f64c80a0e9..e3eff1fd6a 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/CellFormatter.tsx @@ -7,9 +7,8 @@ */ import { observer } from 'mobx-react-lite'; import { useContext, useState } from 'react'; -import styled, { css, use } from 'reshadow'; -import { getComputed, Icon, useMouse, useStateDelay } from '@cloudbeaver/core-blocks'; +import { getComputed, Icon, s, useMouse, useS, useStateDelay } from '@cloudbeaver/core-blocks'; import { ConnectionInfoResource, DATA_CONTEXT_CONNECTION } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import { DATA_CONTEXT_NAV_NODE, type DBObject, type NavNode, NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; @@ -19,37 +18,16 @@ import { MENU_NAV_TREE, useNode } from '@cloudbeaver/plugin-navigation-tree'; import type { RenderCellProps } from '@cloudbeaver/plugin-react-data-grid'; import { getValue } from '../../helpers'; +import classes from './CellFormatter.m.css'; import { TableContext } from './TableContext'; -const menuStyles = css` - menu-container { - cursor: pointer; - width: 100%; - } - menu-container:not([|menuEmpty]) value { - padding-right: 8px; - } - menu-box { - display: flex; - height: 100%; - align-items: center; - - & Icon { - width: 16px; - } - } - value { - flex-grow: 1; - flex-shrink: 1; - } -`; - interface Props { value: string; node: NavNode; } export const Menu = observer(function Menu({ value, node }) { + const styles = useS(classes); const navNodeManagerService = useService(NavNodeManagerService); const connectionsInfoResource = useService(ConnectionInfoResource); const menu = useMenu({ menu: MENU_NAV_TREE }); @@ -80,21 +58,21 @@ export const Menu = observer(function Menu({ value, node }) { return !menu.available; }); - return styled(menuStyles)( - - - + return ( +
+
+
{value} - +
{!menuEmpty && ( - - - +
+ +
)} - - , +
+
); }); diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.m.css b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.m.css new file mode 100644 index 0000000000..391a2f7a0e --- /dev/null +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.m.css @@ -0,0 +1,21 @@ +.container { + composes: theme-typography--body2 from global; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.dataGrid { + width: 100%; + height: 100%; +} + +.info { + padding: 4px 12px; +} + +.objectPropertyTableFooter { + composes: theme-background-secondary theme-text-on-secondary theme-border-color-background from global; + border-top: 1px solid; +} diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.tsx b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.tsx index 1d2954b204..f667a24fae 100644 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.tsx +++ b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/ObjectPropertyTable/Table/Table.tsx @@ -7,9 +7,9 @@ */ import { observer } from 'mobx-react-lite'; import { useCallback, useState } from 'react'; -import styled, { css } from 'reshadow'; +import styled from 'reshadow'; -import { IScrollState, Link, useControlledScroll, useStyles, useTable, useTranslate } from '@cloudbeaver/core-blocks'; +import { IScrollState, Link, s, useControlledScroll, useS, useStyles, useTable, useTranslate } from '@cloudbeaver/core-blocks'; import type { DBObject } from '@cloudbeaver/core-navigation-tree'; import type { ObjectPropertyInfo } from '@cloudbeaver/core-sdk'; import { useTabLocalState } from '@cloudbeaver/core-ui'; @@ -26,30 +26,10 @@ import { ColumnSelect } from './Columns/ColumnSelect/ColumnSelect'; import { HeaderRenderer } from './HeaderRenderer'; import baseStyles from './styles/base.scss'; import { tableStyles } from './styles/styles'; +import classes from './Table.m.css'; import { TableContext } from './TableContext'; import { useTableData } from './useTableData'; -const style = css` - wrapper { - composes: theme-typography--body2 from global; - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - } - DataGrid { - width: 100%; - height: 100%; - } - data-info { - padding: 4px 12px; - } - ObjectPropertyTableFooter { - composes: theme-background-secondary theme-text-on-secondary theme-border-color-background from global; - border-top: 1px solid; - } -`; - const CELL_FONT = '400 12px Roboto'; const COLUMN_FONT = '700 12px Roboto'; const CELL_PADDING = 16; @@ -95,9 +75,11 @@ function getMeasuredCells(columns: ObjectPropertyInfo[], rows: DBObject[]) { const CUSTOM_COLUMNS = [ColumnSelect, ColumnIcon]; export const Table = observer(function Table({ objects, hasNextPage, loadMore }) { + const styles = useS(classes); + const [tableContainer, setTableContainerRef] = useState(null); const translate = useTranslate(); - const styles = useStyles(style, baseStyles, tableStyles); + const deprecatedStyles = useStyles(baseStyles, tableStyles); const tableState = useTable(); const tabLocalState = useTabLocalState(() => ({ scrollTop: 0, scrollLeft: 0 })); @@ -137,11 +119,11 @@ export const Table = observer(function Table({ objects, hasNextPage, return null; } - return styled(styles)( + return styled(deprecatedStyles)( - +
row.id} columns={tableData.columns} @@ -149,14 +131,14 @@ export const Table = observer(function Table({ objects, hasNextPage, onScroll={handleScroll} /> {hasNextPage && ( - +
{translate('ui_load_more')} - +
)} - - + +
, ); });