CB-3585 migrate itemList to css-modules (#1832)

Co-authored-by: Alexey <wrouds@gmail.com>
This commit is contained in:
Dmitriy Osipov
2023-07-24 16:37:19 +03:00
committed by GitHub
co-authored by Alexey
parent 90cd350267
commit e5ed5c8682
14 changed files with 142 additions and 167 deletions
@@ -1,86 +1,73 @@
/*
* 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 { createContext } from 'react';
import { css } from 'reshadow';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
export const ITEM_LIST_STYLES = css`
item-list {
.itemList {
composes: theme-background-surface from global;
box-sizing: border-box;
border-collapse: collapse;
z-index: 0;
overflow: auto;
}
item-list-overflow,
item-list-overflow-top {
}
.itemListOverflow,
.itemListOverflowTop {
position: sticky;
flex-shrink: 0;
width: 100%;
height: 8px;
pointer-events: none;
}
item-list-overflow {
}
.itemListOverflow {
composes: branding-overflow from global;
bottom: 0;
}
item-list-overflow-top {
}
.itemListOverflowTop {
composes: branding-overflow-inverse from global;
top: 0;
z-index: 1;
}
list-search {
}
.listSearch {
composes: theme-background-surface theme-text-on-surface theme-typography--body1 from global;
position: sticky;
top: 0;
padding: 16px 24px;
z-index: 1;
& input-box {
position: relative;
}
& input {
padding: 4px 32px 4px 8px;
}
& action-button {
position: absolute;
display: flex;
align-items: center;
height: 100%;
top: 50%;
right: 4px;
transform: translateY(-50%);
& IconButton {
& .inputBox {
position: relative;
box-sizing: border-box;
overflow: hidden;
border-radius: 2px;
height: 24px;
width: 24px;
margin: 0;
&[name='cross'] {
padding: 4px;
}
}
}
}
IconButton {
& .input {
padding: 4px 32px 4px 8px;
}
& .actionButton {
position: absolute;
display: flex;
align-items: center;
height: 100%;
top: 50%;
right: 4px;
transform: translateY(-50%);
& .iconButton {
position: relative;
box-sizing: border-box;
overflow: hidden;
border-radius: 2px;
height: 24px;
width: 24px;
margin: 0;
}
& .crossIcon {
padding: 4px;
}
}
}
.iconButton {
composes: theme-ripple theme-background-primary theme-text-on-primary from global;
}
list-item:not(:nth-last-child(2)) {
}
.listItem:not(:nth-last-child(2)) {
border-bottom: 1px solid;
}
list-item {
}
.listItem {
composes: theme-ripple theme-background-surface theme-border-color-secondary from global;
position: relative;
cursor: pointer;
@@ -88,19 +75,19 @@ export const ITEM_LIST_STYLES = css`
box-sizing: border-box;
align-items: center;
padding: 0 16px;
}
list-item-icon {
}
.listItemIcon {
display: flex;
align-items: center;
box-sizing: border-box;
padding: 8px;
& StaticImage {
box-sizing: border-box;
width: 24px;
& .staticImage {
box-sizing: border-box;
width: 24px;
}
}
list-item-name {
}
.listItemName {
composes: theme-border-color-secondary theme-typography--body1 from global;
box-sizing: border-box;
font-weight: 500;
@@ -111,8 +98,8 @@ export const ITEM_LIST_STYLES = css`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
list-item-description {
}
.listItemDescription {
composes: theme-typography--body2 from global;
box-sizing: border-box;
max-width: 460px;
@@ -121,7 +108,4 @@ export const ITEM_LIST_STYLES = css`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`;
export const Styles = createContext<ComponentStyle>(ITEM_LIST_STYLES);
}
@@ -5,24 +5,25 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import styled from 'reshadow';
import type { ComponentStyle } from '@cloudbeaver/core-theming';
import { useStyles } from '../useStyles';
import { ITEM_LIST_STYLES, Styles } from './styles';
import { s } from '../s';
import { useS } from '../useS';
import style from './ItemList.m.css';
interface Props {
className?: string;
styles?: ComponentStyle;
}
export const ItemList: React.FC<React.PropsWithChildren<Props>> = function ItemList({ children, className, styles }) {
return styled(useStyles(styles || ITEM_LIST_STYLES))(
<item-list className={className}>
<item-list-overflow-top />
<Styles.Provider value={styles || ITEM_LIST_STYLES}>{children}</Styles.Provider>
<item-list-overflow />
</item-list>,
export const ItemList: React.FC<React.PropsWithChildren<Props>> = function ItemList({ children, className }) {
const styles = useS(style);
return (
<div className={s(styles, { itemList: true }, className)}>
<div className={s(styles, { itemListOverflowTop: true }, className)} />
{children}
<div className={s(styles, { itemListOverflow: true }, className)} />
</div>
);
};
@@ -5,13 +5,14 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useCallback, useContext, useRef, useState } from 'react';
import styled, { use } from 'reshadow';
import { useCallback, useRef, useState } from 'react';
import { use } from 'reshadow';
import { IconButton } from '../IconButton';
import { useTranslate } from '../localization/useTranslate';
import { useStyles } from '../useStyles';
import { Styles } from './styles';
import { s } from '../s';
import { useS } from '../useS';
import style from './ItemList.m.css';
interface IProps {
value?: string;
@@ -24,7 +25,7 @@ interface IProps {
export const ItemListSearch: React.FC<IProps> = function ItemListSearch({ value, placeholder, disabled, onChange, onSearch, className }) {
const inputRef = useRef<HTMLInputElement>(null);
const styles = useContext(Styles);
const styles = useS(style);
const [search, setSearch] = useState(value ?? '');
const translate = useTranslate();
const changeHandler = useCallback(
@@ -54,12 +55,13 @@ export const ItemListSearch: React.FC<IProps> = function ItemListSearch({ value,
const inputValue = value ?? search;
return styled(useStyles(styles || []))(
<list-search className={className}>
<input-box>
return (
<div className={s(styles, { listSearch: true })}>
<div className={s(styles, { inputBox: true })}>
<input
ref={inputRef}
name="search"
className={s(styles, { input: true }, className)}
placeholder={translate(placeholder || 'ui_search')}
value={inputValue}
autoComplete="off"
@@ -67,14 +69,14 @@ export const ItemListSearch: React.FC<IProps> = function ItemListSearch({ value,
onChange={event => changeHandler(event.target.value)}
{...use({ mod: 'surface' })}
/>
<action-button as="div">
<div className={s(styles, { actionButton: true })}>
{!onSearch && inputValue ? (
<IconButton name="cross" onClick={() => changeHandler('')} />
<IconButton className={s(styles, { iconButton: true, crossIcon: true })} name="cross" onClick={() => changeHandler('')} />
) : (
<IconButton name="search" onClick={searchHandler} />
<IconButton className={s(styles, { iconButton: true })} name="search" onClick={searchHandler} />
)}
</action-button>
</input-box>
</list-search>,
</div>
</div>
</div>
);
};
@@ -5,11 +5,9 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useContext } from 'react';
import styled from 'reshadow';
import { useStyles } from '../useStyles';
import { Styles } from './styles';
import { s } from '../s';
import { useS } from '../useS';
import style from './ItemList.m.css';
interface Props {
onClick: () => void;
@@ -17,11 +15,11 @@ interface Props {
}
export const ListItem: React.FC<React.PropsWithChildren<Props>> = function ListItem({ children, onClick, className }) {
const styles = useContext(Styles);
const styles = useS(style);
return styled(useStyles(styles))(
<list-item as="div" className={className} onClick={onClick}>
return (
<div className={s(styles, { listItem: true }, className)} onClick={onClick}>
{children}
</list-item>,
</div>
);
};
@@ -5,11 +5,10 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useContext } from 'react';
import styled from 'reshadow';
import { s } from '../s';
import { useS } from '../useS';
import style from './ItemList.m.css';
import { useStyles } from '../useStyles';
import { Styles } from './styles';
interface Props {
title?: string;
@@ -17,11 +16,11 @@ interface Props {
}
export const ListItemDescription: React.FC<React.PropsWithChildren<Props>> = function ListItemDescription({ title, children, className }) {
const styles = useContext(Styles);
const styles = useS(style);
return styled(useStyles(styles))(
<list-item-description title={title} className={className}>
return (
<div title={title} className={s(styles, { listItemDescription: true }, className)}>
{children}
</list-item-description>,
</div>
);
};
};
@@ -5,18 +5,16 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useContext } from 'react';
import styled from 'reshadow';
import { useStyles } from '../useStyles';
import { Styles } from './styles';
import { s } from '../s';
import { useS } from '../useS';
import style from './ItemList.m.css';
interface Props {
className?: string;
}
export const ListItemIcon: React.FC<React.PropsWithChildren<Props>> = function ListItemIcon({ children, className }) {
const styles = useContext(Styles);
const styles = useS(style);
return styled(useStyles(styles))(<list-item-icon className={className}>{children}</list-item-icon>);
return <div className={s(styles, { listItemIcon: true }, className)}>{children}</div>;
};
@@ -5,18 +5,16 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { useContext } from 'react';
import styled from 'reshadow';
import { useStyles } from '../useStyles';
import { Styles } from './styles';
import { s } from '../s';
import { useS } from '../useS';
import style from './ItemList.m.css';
interface Props {
className?: string;
}
export const ListItemName: React.FC<React.PropsWithChildren<Props>> = function ListItemName({ children, className }) {
const styles = useContext(Styles);
const styles = useS(style);
return styled(useStyles(styles))(<list-item-name className={className}>{children}</list-item-name>);
return <div className={s(styles, { listItemName: true }, className)}>{children}</div>;
};
-1
View File
@@ -10,7 +10,6 @@ export * from './ItemList/ListItem';
export * from './ItemList/ListItemDescription';
export * from './ItemList/ListItemIcon';
export * from './ItemList/ListItemName';
export { ITEM_LIST_STYLES } from './ItemList/styles';
export * from './layout/AppLogo';
export * from './layout/BASE_LAYOUT_GRID_STYLES';
@@ -0,0 +1,5 @@
.staticImage {
box-sizing: border-box;
width: 24px;
max-height: 24px;
};
@@ -7,9 +7,10 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import styled, { css } from 'reshadow';
import { ListItem, ListItemDescription, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks';
import { ListItem, ListItemDescription, ListItemIcon, ListItemName, s, StaticImage, useS } from '@cloudbeaver/core-blocks';
import style from './Driver.m.css';
export interface IDriver {
id: string;
@@ -18,14 +19,6 @@ export interface IDriver {
description?: string;
}
const styles = css`
StaticImage {
box-sizing: border-box;
width: 24px;
max-height: 24px;
}
`;
interface Props {
driver: IDriver;
onSelect: (driverId: string) => void;
@@ -33,14 +26,15 @@ interface Props {
export const Driver = observer<Props>(function Driver({ driver, onSelect }) {
const select = useCallback(() => onSelect(driver.id), [driver]);
const styles = useS(style);
return styled(styles)(
return (
<ListItem onClick={select}>
<ListItemIcon>
<StaticImage icon={driver.icon} />
<StaticImage icon={driver.icon} className={s(styles, { staticImage: true })} />
</ListItemIcon>
<ListItemName>{driver.name}</ListItemName>
<ListItemDescription title={driver.description}>{driver.description}</ListItemDescription>
</ListItem>,
</ListItem>
);
});
@@ -0,0 +1,5 @@
.wrapper {
display: flex;
flex-direction: column;
overflow: auto;
}
@@ -7,11 +7,11 @@
*/
import { observer } from 'mobx-react-lite';
import { useMemo, useState } from 'react';
import styled, { css } from 'reshadow';
import { ItemList, ItemListSearch, useFocus, useTranslate } from '@cloudbeaver/core-blocks';
import { ItemList, ItemListSearch, s, useFocus, useS, useTranslate } from '@cloudbeaver/core-blocks';
import { Driver, IDriver } from './Driver';
import style from './DriverSelector.m.css';
interface Props {
drivers: IDriver[];
@@ -19,15 +19,8 @@ interface Props {
onSelect: (driverId: string) => void;
}
const style = css`
div {
display: flex;
flex-direction: column;
overflow: auto;
}
`;
export const DriverSelector = observer<Props>(function DriverSelector({ drivers, className, onSelect }) {
const styles = useS(style);
const translate = useTranslate();
const [focusedRef] = useFocus<HTMLDivElement>({ focusFirstChild: true });
const [search, setSearch] = useState('');
@@ -38,14 +31,14 @@ export const DriverSelector = observer<Props>(function DriverSelector({ drivers,
return drivers.filter(driver => driver.name?.toUpperCase().includes(search.toUpperCase()));
}, [search, drivers]);
return styled(style)(
<div ref={focusedRef}>
return (
<div ref={focusedRef} className={s(styles, { wrapper: true })}>
<ItemListSearch placeholder={translate('connections_driver_search_placeholder')} onChange={setSearch} />
<ItemList className={className}>
{filteredDrivers.map(driver => (
<Driver key={driver.id} driver={driver} onSelect={onSelect} />
))}
</ItemList>
</div>,
</div>
);
});
@@ -0,0 +1,5 @@
.staticImage {
box-sizing: border-box;
width: 24px;
max-height: 24px;
};
@@ -7,18 +7,11 @@
*/
import { observer } from 'mobx-react-lite';
import { useCallback } from 'react';
import styled, { css } from 'reshadow';
import { ListItem, ListItemDescription, ListItemIcon, ListItemName, StaticImage } from '@cloudbeaver/core-blocks';
import { ListItem, ListItemDescription, ListItemIcon, ListItemName, s, StaticImage, useS } from '@cloudbeaver/core-blocks';
import type { DBDriver } from '@cloudbeaver/core-connections';
const styles = css`
StaticImage {
box-sizing: border-box;
width: 24px;
max-height: 24px;
}
`;
import style from './Driver.m.css';
interface Props {
driver: DBDriver;
@@ -27,14 +20,15 @@ interface Props {
export const Driver = observer<Props>(function Driver({ driver, onSelect }) {
const select = useCallback(() => onSelect(driver.id), [driver]);
const styles = useS(style);
return styled(styles)(
return (
<ListItem onClick={select}>
<ListItemIcon>
<StaticImage icon={driver.icon} />
<StaticImage icon={driver.icon} className={s(styles, { staticImage: true })} />
</ListItemIcon>
<ListItemName>{driver.name}</ListItemName>
<ListItemDescription title={driver.description}>{driver.description}</ListItemDescription>
</ListItem>,
</ListItem>
);
});