diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css index c88e369e63..cdf2d866cf 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.m.css @@ -1,2 +1,66 @@ .checkbox { + composes: theme-checkbox from global; + box-sizing: content-box !important; +} +.checkboxInput { + composes: theme-checkbox_native-control from global; +} +.checkboxBackground { + composes: theme-checkbox__background from global; + box-sizing: border-box !important; +} +.checkboxCheckmark { + composes: theme-checkbox__checkmark from global; +} +.checkboxCheckmarkPath { + composes: theme-checkbox__checkmark-path from global; +} +.checkboxMixedmark { + composes: theme-checkbox__mixedmark from global; +} +.checkboxRipple { + composes: theme-checkbox__ripple from global; +} +.checkboxContainer { + display: flex; + align-items: center; + height: 32px; +} +.checkboxLabel { + composes: theme-typography--body2 from global; + cursor: pointer; +} +.checkboxCaption { + composes: theme-text-text-hint-on-light theme-typography--caption from global; +} + +.primary { + composes: theme-checkbox_primary from global; +} +.surface { + composes: theme-checkbox_surface from global; +} +.small { + composes: theme-checkbox_small from global; +} + +.small { + &.checkboxContainer { + & .checkbox { + width: 14px; + height: 14px; + } + & .checkboxBackground { + width: 14px; + height: 14px; + } + } +} + +.disabled { + composes: theme-checkbox--disabled from global; +} + +.checked { + composes: theme-checkbox--checked from global; } diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx index a2adc04def..f135d1de72 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/CheckboxMarkup.tsx @@ -6,103 +6,19 @@ * you may not use this file except in compliance with the License. */ import { useLayoutEffect, useRef } from 'react'; -import styled, { css } from 'reshadow'; - -import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { s } from '../../s'; import { useS } from '../../useS'; -import { useStyles } from '../../useStyles'; import CheckboxMarkupStyles from './CheckboxMarkup.m.css'; export type CheckboxMod = 'primary' | 'surface' | 'small'; -const checkboxStyles = css` - checkbox { - composes: theme-checkbox from global; - box-sizing: content-box !important; - } - checkbox-input { - composes: theme-checkbox_native-control from global; - } - checkbox-background { - composes: theme-checkbox__background from global; - box-sizing: border-box !important; - } - checkbox-checkmark { - composes: theme-checkbox__checkmark from global; - } - checkbox-checkmark-path { - composes: theme-checkbox__checkmark-path from global; - } - checkbox-mixedmark { - composes: theme-checkbox__mixedmark from global; - } - checkbox-ripple { - composes: theme-checkbox__ripple from global; - } - checkbox-container { - display: flex; - align-items: center; - height: 32px; - } - checkbox-label { - composes: theme-typography--body2 from global; - cursor: pointer; - } - checkbox-caption { - composes: theme-text-text-hint-on-light theme-typography--caption from global; - } -`; - -const checkboxMod: Record = { - primary: css` - checkbox { - composes: theme-checkbox_primary from global; - } - `, - surface: css` - checkbox { - composes: theme-checkbox_surface from global; - } - `, - small: css` - checkbox { - composes: theme-checkbox_small from global; - } - checkbox-container { - & checkbox { - width: 14px; - height: 14px; - } - & checkbox-background { - width: 14px; - height: 14px; - } - } - `, -}; - -const checkboxState = { - disabled: css` - checkbox { - composes: theme-checkbox--disabled from global; - } - `, - checked: css` - checkbox { - composes: theme-checkbox--checked from global; - } - `, -}; - interface ICheckboxMarkupProps extends Omit, 'style'> { label?: string; caption?: string; indeterminate?: boolean; ripple?: boolean; mod?: CheckboxMod[]; - style?: ComponentStyle; } export { CheckboxMarkupStyles }; @@ -115,7 +31,6 @@ export const CheckboxMarkup: React.FC = function CheckboxM title, mod = ['primary'], ripple = true, - style, readOnly, caption, ...rest @@ -129,32 +44,40 @@ export const CheckboxMarkup: React.FC = function CheckboxM } }); - return styled( - useStyles( - checkboxStyles, - ...(mod || []).map(mod => checkboxMod[mod]), - rest.disabled && checkboxState.disabled, - rest.checked && checkboxState.checked, - style, - ), - )( - - - - - - - - - - {ripple && } - + return ( +
+
+ +
+ + + +
+
+ {ripple &&
} +
{label && (id || rest.name) && ( - + + {caption &&
{caption}
} + )} - , +
); }; diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx index db90e7c33a..6bf183b379 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/FieldCheckbox.tsx @@ -5,36 +5,39 @@ * 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 { filterLayoutFakeProps, getLayoutProps } from '../../Containers/filterLayoutFakeProps'; import elementsSizeStyles from '../../Containers/shared/ElementsSize.m.css'; import { s } from '../../s'; import { useS } from '../../useS'; -import formControlStyles from '../FormControl.m.css'; +import { Field } from '../Field'; +import { FieldLabel } from '../FieldLabel'; import { isControlPresented } from '../isControlPresented'; import { Checkbox, CheckboxBaseProps, CheckboxType, ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox'; import fieldCheckboxStyles from './FieldCheckbox.m.css'; -export const FieldCheckbox: CheckboxType = function FieldCheckbox({ +export const FieldCheckbox: CheckboxType = observer(function FieldCheckbox({ children, className, ...rest }: CheckboxBaseProps & (ICheckboxControlledProps | ICheckboxObjectProps)) { const layoutProps = getLayoutProps(rest); const checkboxProps = filterLayoutFakeProps(rest); - const styles = useS(elementsSizeStyles, formControlStyles, fieldCheckboxStyles); + const styles = useS(fieldCheckboxStyles); if (checkboxProps.autoHide && !isControlPresented(checkboxProps.name, checkboxProps.state)) { return null; } return ( -
- + + {children && ( - + )} -
+ ); -}; +}); diff --git a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx index 661cbae450..53eff392f7 100644 --- a/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Checkboxes/Switch.tsx @@ -8,10 +8,11 @@ import { observer } from 'mobx-react-lite'; import { filterLayoutFakeProps } from '../../Containers/filterLayoutFakeProps'; -import elementsSizeStyles from '../../Containers/shared/ElementsSize.m.css'; import { s } from '../../s'; import { useS } from '../../useS'; -import formControlStyles from '../FormControl.m.css'; +import { Field } from '../Field'; +import { FieldDescription } from '../FieldDescription'; +import { FieldLabel } from '../FieldLabel'; import { isControlPresented } from '../isControlPresented'; import type { ICheckboxControlledProps, ICheckboxObjectProps } from './Checkbox'; import switchStyles from './Switch.m.css'; @@ -64,14 +65,14 @@ export const Switch: SwitchType = observer(function Switch({ onChange, }); rest = filterLayoutFakeProps(rest); - const styles = useS(elementsSizeStyles, formControlStyles, switchStyles, ...mod.map(mod => switchMod[mod])); + const styles = useS(switchStyles, ...mod.map(mod => switchMod[mod])); if (autoHide && !isControlPresented(name, state)) { return null; } return ( -
+
@@ -91,15 +92,11 @@ export const Switch: SwitchType = observer(function Switch({ />
- +
- {description && ( -
- {description} -
- )} -
+ {description && {description}} + ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.m.css b/webapp/packages/core-blocks/src/FormControls/Combobox.m.css index 939d725a5b..78b26e7bd3 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.m.css +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.m.css @@ -23,6 +23,15 @@ padding-right: 24px !important; } +.input { + font-size: 12px; + + &.select { + cursor: pointer; + user-select: none; + } +} + .menuButton { position: absolute; right: 0; diff --git a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx index a47c0ad08e..da3dfedde8 100644 --- a/webapp/packages/core-blocks/src/FormControls/Combobox.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Combobox.tsx @@ -11,7 +11,6 @@ import { Menu, MenuButton, MenuItem, useMenuState } from 'reakit/Menu'; import { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; -import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; import { getComputed } from '../getComputed'; import { Icon } from '../Icon'; import { IconOrImage } from '../IconOrImage'; @@ -20,8 +19,10 @@ import { useTranslate } from '../localization/useTranslate'; import { s } from '../s'; import { useS } from '../useS'; import comboboxStyles from './Combobox.m.css'; +import { Field } from './Field'; +import { FieldDescription } from './FieldDescription'; +import { FieldLabel } from './FieldLabel'; import { FormContext } from './FormContext'; -import formControlStyles from './FormControl.m.css'; type BaseProps = Omit, 'onChange' | 'onSelect' | 'name' | 'value' | 'defaultValue'> & ILayoutSizeProps & { @@ -93,7 +94,7 @@ export const Combobox: ComboboxType = observer(function Combobox({ const context = useContext(FormContext); const menuRef = useRef(null); const [inputRef, setInputRef] = useState(null); - const styles = useS(elementsSizeStyles, formControlStyles, comboboxStyles); + const styles = useS(comboboxStyles); const menu = useMenuState({ placement: 'bottom-end', @@ -255,17 +256,22 @@ export const Combobox: ComboboxType = observer(function Combobox({ } return ( -
+ {children && ( -
+ {children} - {rest.required && ' *'} -
+ )} -
+
{(icon || loading) && ( -
- {loading ? : typeof icon === 'string' ? : icon} +
+ {loading ? ( + + ) : typeof icon === 'string' ? ( + + ) : ( + icon + )}
)} {!filteredItems.length ? ( - + {translate('combobox_no_results_placeholder')} ) : ( @@ -314,28 +318,22 @@ export const Combobox: ComboboxType = observer(function Combobox({ title={title} {...menu} disabled={disabled} - className={styles.menuItem} + className={s(styles, { menuItem: true })} onClick={event => handleSelect(event.currentTarget.id)} > {iconSelector && ( -
- {icon && typeof icon === 'string' ? : icon} +
+ {icon && typeof icon === 'string' ? : icon}
)} -
- {valueSelector(item)} -
+
{valueSelector(item)}
); }) )}
- {description && ( -
- {description} -
- )} -
+ {description && {description}} + ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/Field.m.css b/webapp/packages/core-blocks/src/FormControls/Field.m.css new file mode 100644 index 0000000000..e35f38c294 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/Field.m.css @@ -0,0 +1,10 @@ +.field { + box-sizing: border-box; + max-width: 100%; + + /* nested */ + & .field { + height: 32px; + padding: 0; + } +} diff --git a/webapp/packages/core-blocks/src/FormControls/Field.tsx b/webapp/packages/core-blocks/src/FormControls/Field.tsx new file mode 100644 index 0000000000..f6ba8ca247 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/Field.tsx @@ -0,0 +1,25 @@ +import { observer } from 'mobx-react-lite'; +import type { HTMLAttributes, PropsWithChildren } from 'react'; + +import { getLayoutProps } from '../Containers/filterLayoutFakeProps'; +import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; +import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; +import { s } from '../s'; +import { useS } from '../useS'; +import fieldStyles from './Field.m.css'; + +type Props = ILayoutSizeProps & + HTMLAttributes & { + className?: string; + }; +export const Field: React.FC> = observer(function Field({ children, className, ...rest }) { + const styles = useS(fieldStyles, elementsSizeStyles); + + const layoutProps = getLayoutProps(rest); + + return ( +
+ {children} +
+ ); +}); diff --git a/webapp/packages/core-blocks/src/FormControls/FieldDescription.m.css b/webapp/packages/core-blocks/src/FormControls/FieldDescription.m.css new file mode 100644 index 0000000000..4a050fef44 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/FieldDescription.m.css @@ -0,0 +1,15 @@ +.fieldDescription { + composes: theme-typography--caption from global; + /*color: var(--theme-text-hint-on-background);*/ + box-sizing: border-box; + padding-top: 4px; + min-height: 24px; + + &.invalid { + color: var(--theme-negative); + } + + &:empty { + display: none; + } +} diff --git a/webapp/packages/core-blocks/src/FormControls/FieldDescription.tsx b/webapp/packages/core-blocks/src/FormControls/FieldDescription.tsx new file mode 100644 index 0000000000..8ad2c2534d --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/FieldDescription.tsx @@ -0,0 +1,16 @@ +import { observer } from 'mobx-react-lite'; +import type { PropsWithChildren } from 'react'; + +import { s } from '../s'; +import { useS } from '../useS'; +import fieldDescriptionStyles from './FieldDescription.m.css'; + +interface Props { + className?: string; + invalid?: boolean; +} +export const FieldDescription: React.FC> = observer(function FieldDescription({ children, className, invalid }) { + const styles = useS(fieldDescriptionStyles); + + return
{children}
; +}); diff --git a/webapp/packages/core-blocks/src/FormControls/FieldLabel.m.css b/webapp/packages/core-blocks/src/FormControls/FieldLabel.m.css new file mode 100644 index 0000000000..3cf2127a3b --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/FieldLabel.m.css @@ -0,0 +1,7 @@ +.fieldLabel { + composes: theme-typography--body1 from global; + box-sizing: border-box; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} diff --git a/webapp/packages/core-blocks/src/FormControls/FieldLabel.tsx b/webapp/packages/core-blocks/src/FormControls/FieldLabel.tsx new file mode 100644 index 0000000000..0c9d123c79 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/FieldLabel.tsx @@ -0,0 +1,22 @@ +import { observer } from 'mobx-react-lite'; +import type { LabelHTMLAttributes, PropsWithChildren } from 'react'; + +import { s } from '../s'; +import { useS } from '../useS'; +import fieldLabelStyles from './FieldLabel.m.css'; + +type Props = LabelHTMLAttributes & { + className?: string; + title?: string; + required?: boolean; +}; +export const FieldLabel: React.FC> = observer(function FieldLabel({ children, className, required, ...rest }) { + const styles = useS(fieldLabelStyles); + + return ( + + ); +}); diff --git a/webapp/packages/core-blocks/src/FormControls/Filter.m.css b/webapp/packages/core-blocks/src/FormControls/Filter.m.css new file mode 100644 index 0000000000..7a3483d9cf --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/Filter.m.css @@ -0,0 +1,46 @@ +.filterContainer { + position: relative; + min-width: 24px; + min-height: 24px; +} +.inputField { + display: none; + width: 300px; + &.max { + width: 100%; + } + &.toggled { + display: block; + } + + & .input { + padding-right: 40px !important; + } + +} +.iconButton { + position: absolute; + right: 0; + top: 0; + margin: 0; + width: 24px; + height: 24px; + border-radius: 2px; + cursor: auto; + + &.toggled { + right: 4px; + top: 4px; + } + &.cross { + width: 16px; + height: 16px; + top: 8px; + right: 8px; + } +} + +.toggleMode { + composes: theme-background-primary theme-text-on-primary from global; + cursor: pointer; +} diff --git a/webapp/packages/core-blocks/src/FormControls/Filter.tsx b/webapp/packages/core-blocks/src/FormControls/Filter.tsx index e3907563f4..5a1f4fa809 100644 --- a/webapp/packages/core-blocks/src/FormControls/Filter.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Filter.tsx @@ -7,74 +7,20 @@ */ import { observer } from 'mobx-react-lite'; import { useCallback, useEffect, useState } from 'react'; -import styled, { css, use } from 'reshadow'; - -import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { IconButton } from '../IconButton'; +import { s } from '../s'; import { useFocus } from '../useFocus'; -import { useStyles } from '../useStyles'; +import { useS } from '../useS'; +import filterStyle from './Filter.m.css'; import { InputField } from './InputField'; -const filterStyles = css` - filter-container { - position: relative; - min-width: 24px; - min-height: 24px; - } - InputField { - display: none; - width: 300px; - &[|max] { - width: 100%; - } - &[|toggled] { - display: block; - } - } - IconButton { - position: absolute; - right: 0; - top: 0; - margin: 0; - width: 24px; - height: 24px; - border-radius: 2px; - cursor: auto; - - &[|toggled] { - right: 4px; - top: 4px; - } - &[name='cross'] { - width: 16px; - height: 16px; - top: 8px; - right: 8px; - } - } -`; - -const toggleModeButtonStyle = css` - IconButton { - composes: theme-background-primary theme-text-on-primary from global; - cursor: pointer; - } -`; - -const innerInputStyle = css` - input { - padding-right: 40px !important; - } -`; - interface BaseProps { toggleMode?: boolean; placeholder?: string; disabled?: boolean; max?: boolean; className?: string; - style?: ComponentStyle; onToggle?: (status: boolean) => void; onKeyDown?: (event: React.KeyboardEvent) => void; onClick?: (event: React.MouseEvent) => void; @@ -103,13 +49,12 @@ export const Filter = observer>(functio disabled, max, className, - style, onFilter, onToggle, onKeyDown, onClick, }) { - const styles = useStyles(filterStyles, style, toggleMode && toggleModeButtonStyle); + const styles = useS(filterStyle); const [inputRef, ref] = useFocus({}); const [toggled, setToggled] = useState(!toggleMode); @@ -156,24 +101,28 @@ export const Filter = observer>(functio value = state[name]; } - return styled(styles)( - + return ( +
{String(value) ? ( - filter('', name)} /> + filter('', name)} + /> ) : ( - + )} - , +
); }); diff --git a/webapp/packages/core-blocks/src/FormControls/FormBox.tsx b/webapp/packages/core-blocks/src/FormControls/FormBox.tsx deleted file mode 100644 index 4fd120e961..0000000000 --- a/webapp/packages/core-blocks/src/FormControls/FormBox.tsx +++ /dev/null @@ -1,24 +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 styled, { css } from 'reshadow'; - -const styles = css` - box { - flex: 1; - display: flex; - flex-wrap: wrap; - } -`; - -interface Props { - className?: string; -} - -export const FormBox: React.FC> = function FormBox({ children, className }) { - return styled(styles)({children}); -}; diff --git a/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx b/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx deleted file mode 100644 index 2f3582111b..0000000000 --- a/webapp/packages/core-blocks/src/FormControls/FormBoxElement.tsx +++ /dev/null @@ -1,32 +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 styled, { css, use } from 'reshadow'; - -const styles = css` - box-element { - flex-basis: 550px; - flex-grow: 1; - - &[|max] { - width: 100%; - } - } -`; - -interface Props { - className?: string; - max?: boolean; -} - -export const FormBoxElement: React.FC> = function FormBoxElement({ children, className, max }) { - return styled(styles)( - - {children} - , - ); -}; diff --git a/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.m.css b/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.m.css new file mode 100644 index 0000000000..2021d937ca --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.m.css @@ -0,0 +1,16 @@ +.fieldLabel { + composes: theme-typography--body1 from global; + font-weight: 500; + margin-bottom: 10px; + box-sizing: border-box; + overflow: hidden; + white-space: initial; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.fieldDescription { + padding: 0; +} diff --git a/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx b/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx index b5a085d426..38d6ecfc3c 100644 --- a/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx +++ b/webapp/packages/core-blocks/src/FormControls/FormFieldDescription.tsx @@ -5,33 +5,14 @@ * 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 { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; -import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; import { s } from '../s'; import { useS } from '../useS'; -import { useStyles } from '../useStyles'; -import { baseFormControlStyles, baseValidFormControlStyles } from './baseFormControlStyles'; - -const style = css` - field-label { - composes: theme-typography--body1 from global; - font-weight: 500; - margin-bottom: 10px; - box-sizing: border-box; - overflow: hidden; - white-space: initial; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - } - field-description { - padding: 0; - } -`; +import { Field } from './Field'; +import { FieldDescription } from './FieldDescription'; +import { FieldLabel } from './FieldLabel'; +import style from './FormFieldDescription.m.css'; interface Props extends ILayoutSizeProps { label?: string; @@ -48,13 +29,12 @@ export const FormFieldDescription: React.FC> = fu }) { const layoutProps = getLayoutProps(rest); rest = filterLayoutFakeProps(rest); - const styles = useStyles(baseFormControlStyles, baseValidFormControlStyles, style); - const sizeStyles = useS(elementsSizeStyles); + const styles = useS(style); - return styled(styles)( - - {label && {label}} - {children} - , + return ( + + {label && {label}} + {children} + ); }; diff --git a/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx b/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx deleted file mode 100644 index 0859fff033..0000000000 --- a/webapp/packages/core-blocks/src/FormControls/FormGroup.tsx +++ /dev/null @@ -1,23 +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 styled, { css } from 'reshadow'; - -const styles = css` - group { - box-sizing: border-box; - display: flex; - } -`; - -interface Props { - className?: string; -} - -export const FormGroup: React.FC> = function FormGroup({ children, className }) { - return styled(styles)({children}); -}; diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.m.css b/webapp/packages/core-blocks/src/FormControls/InputField.m.css index 3531611b5b..4baf35784c 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.m.css +++ b/webapp/packages/core-blocks/src/FormControls/InputField.m.css @@ -45,3 +45,7 @@ .input:not(:only-child) { padding-right: 32px !important; } +.input { + font-size: 12px; +} + diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.tsx b/webapp/packages/core-blocks/src/FormControls/InputField.tsx index af0112c3af..d539a096b8 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputField.tsx @@ -7,14 +7,11 @@ */ import { observer } from 'mobx-react-lite'; import React, { forwardRef, useCallback, useContext, useLayoutEffect, useRef, useState } from 'react'; -import styled, { use } from 'reshadow'; -import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { isNotNullDefined } from '@cloudbeaver/core-utils'; import { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; -import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; import { Icon } from '../Icon'; import { Loader } from '../Loader/Loader'; import { useTranslate } from '../localization/useTranslate'; @@ -23,9 +20,10 @@ import { useCombinedHandler } from '../useCombinedHandler'; import { useCombinedRef } from '../useCombinedRef'; import { useS } from '../useS'; import { useStateDelay } from '../useStateDelay'; -import { useStyles } from '../useStyles'; +import { Field } from './Field'; +import { FieldDescription } from './FieldDescription'; +import { FieldLabel } from './FieldLabel'; import { FormContext } from './FormContext'; -import formControlStyles from './FormControl.m.css'; import inputFieldStyle from './InputField.m.css'; import { isControlPresented } from './isControlPresented'; import { useCapsLockTracker } from './useCapsLockTracker'; @@ -36,9 +34,7 @@ type BaseProps = Omit, 'onChange' | loading?: boolean; description?: string; labelTooltip?: string; - mod?: 'surface'; ref?: React.ForwardedRef; - style?: ComponentStyle; canShowPassword?: boolean; onCustomCopy?: () => void; icon?: React.ReactElement; @@ -73,7 +69,6 @@ export const InputField: InputFieldType = observer -
+ return ( + + {children} - {required && ' *'} -
-
+ +
{loading && ( -
+
)} {passwordType && canShowPassword && ( -
+
)} {onCustomCopy && ( -
+
)} {icon && ( -
+
{icon}
)}
- {(description || passwordType) && ( -
- {description} -
- )} -
, + {(description || passwordType) && {description}} + ); }), ) as InputFieldType; diff --git a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.m.css b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.m.css new file mode 100644 index 0000000000..99bd8dee98 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.m.css @@ -0,0 +1,22 @@ +.fieldLabel { + display: block; + composes: theme-typography--body1 from global; + font-weight: 500; +} +.fieldLabel:not(:empty) { + padding-bottom: 10px; +} +.fieldDescription { + display: flex; + align-items: center; + gap: 2px; +} +.iconButton { + width: 12px; + height: 12px; + flex-shrink: 0; + cursor: pointer; + &:hover { + opacity: 0.5; + } +} diff --git a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx index 1fc5202f6c..258436c234 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx @@ -7,51 +7,25 @@ */ import { observer } from 'mobx-react-lite'; import { ReactNode, useContext, useState } from 'react'; -import styled, { css } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { blobToData, bytesToSize } from '@cloudbeaver/core-utils'; import { Button } from '../Button'; -import { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; -import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; import { IconButton } from '../IconButton'; import { useTranslate } from '../localization/useTranslate'; import { s } from '../s'; import { UploadArea } from '../UploadArea'; import { useS } from '../useS'; -import { useStyles } from '../useStyles'; -import { baseFormControlStyles, baseInvalidFormControlStyles, baseValidFormControlStyles } from './baseFormControlStyles'; +import { Field } from './Field'; +import { FieldDescription } from './FieldDescription'; +import { FieldLabel } from './FieldLabel'; import { FormContext } from './FormContext'; +import inputFileTextContentStyles from './InputFileTextContent.m.css'; const DEFAULT_MAX_FILE_SIZE = 2048; -const INPUT_FILE_FIELD_STYLES = css` - field-label { - display: block; - composes: theme-typography--body1 from global; - font-weight: 500; - } - field-label:not(:empty) { - padding-bottom: 10px; - } - field-description { - display: flex; - align-items: center; - gap: 2px; - } - IconButton { - width: 12px; - height: 12px; - flex-shrink: 0; - cursor: pointer; - &:hover { - opacity: 0.5; - } - } -`; - interface Props extends ILayoutSizeProps { name: keyof TState; state: TState; @@ -80,14 +54,12 @@ export const InputFileTextContent: InputFileTextContentType = observer(function tooltip, required, fileName, - style, maxFileSize = DEFAULT_MAX_FILE_SIZE, disabled, className, children, onChange, mapValue, - ...rest }: Props>) { const translate = useTranslate(); const context = useContext(FormContext); @@ -95,10 +67,7 @@ export const InputFileTextContent: InputFileTextContentType = observer(function const [selected, setSelected] = useState(null); const [error, setError] = useState(null); - const layoutProps = getLayoutProps(rest); - rest = filterLayoutFakeProps(rest); - const styles = useStyles(INPUT_FILE_FIELD_STYLES, baseFormControlStyles, style, error ? baseInvalidFormControlStyles : baseValidFormControlStyles); - const sizeStyles = useS(elementsSizeStyles); + const styles = useS(inputFileTextContentStyles); const savedExternally = !!fileName && state[name] !== ''; const saved = savedExternally || !!state[name]; @@ -166,21 +135,20 @@ export const InputFileTextContent: InputFileTextContentType = observer(function } } - return styled(styles)( - - + return ( + + {children} - {required && ' *'} - + - + {description} - {(selected || saved) && } - - , + {(selected || saved) && } + + ); }); diff --git a/webapp/packages/core-blocks/src/FormControls/InputFiles.m.css b/webapp/packages/core-blocks/src/FormControls/InputFiles.m.css new file mode 100644 index 0000000000..e1e4cde4f4 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/InputFiles.m.css @@ -0,0 +1,18 @@ +.fieldLabel { + display: block; + composes: theme-typography--body1 from global; + font-weight: 500; +} +.fieldLabel:not(:empty) { + padding-bottom: 10px; +} +.inputContainer { + position: relative; +} +.tags { + padding-top: 8px; + + &:empty { + display: none; + } +} diff --git a/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx b/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx index 2bd1d6d252..9161835e21 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx @@ -7,14 +7,12 @@ */ import { observer } from 'mobx-react-lite'; import { forwardRef, useContext, useEffect, useState } from 'react'; -import styled, { css, use } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; import { Button } from '../Button'; import { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; -import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; import { useTranslate } from '../localization/useTranslate'; import { s } from '../s'; import { Tag } from '../Tags/Tag'; @@ -24,32 +22,13 @@ import { useCombinedHandler } from '../useCombinedHandler'; import { useRefInherit } from '../useRefInherit'; import { useS } from '../useS'; import { useStateDelay } from '../useStateDelay'; -import { useStyles } from '../useStyles'; -import { baseFormControlStyles, baseInvalidFormControlStyles, baseValidFormControlStyles } from './baseFormControlStyles'; +import { Field } from './Field'; +import { FieldDescription } from './FieldDescription'; +import { FieldLabel } from './FieldLabel'; import { FormContext } from './FormContext'; +import InputFilesStyles from './InputFiles.m.css'; import { isControlPresented } from './isControlPresented'; -const INPUT_FIELD_STYLES = css` - field-label { - display: block; - composes: theme-typography--body1 from global; - font-weight: 500; - } - field-label:not(:empty) { - padding-bottom: 10px; - } - input-container { - position: relative; - } - Tags { - padding-top: 8px; - - &:empty { - display: none; - } - } -`; - type BaseProps = Omit, 'onChange' | 'name' | 'value' | 'style'> & ILayoutSizeProps & { error?: boolean; @@ -57,9 +36,7 @@ type BaseProps = Omit, 'onChange' | description?: string; labelTooltip?: string; hideTags?: boolean; - mod?: 'surface'; ref?: React.Ref; - style?: ComponentStyle; aggregate?: boolean; onDuplicate?: (files: File[]) => void; }; @@ -89,7 +66,6 @@ export const InputFiles: InputFilesType = observer( forwardRef(function InputFiles( { name, - style, value: valueControlled, required, state, @@ -100,7 +76,6 @@ export const InputFiles: InputFilesType = observer( description, labelTooltip, hideTags, - mod, autoHide, aggregate, onChange, @@ -114,8 +89,7 @@ export const InputFiles: InputFilesType = observer( const ref = useRefInherit(refInherit); const [innerState, setInnerState] = useState(null); const translate = useTranslate(); - const styles = useStyles(baseFormControlStyles, error ? baseInvalidFormControlStyles : baseValidFormControlStyles, INPUT_FIELD_STYLES, style); - const sizeStyles = useS(elementsSizeStyles); + const styles = useS(InputFilesStyles); const context = useContext(FormContext); loading = useStateDelay(loading ?? false, 300); @@ -195,28 +169,27 @@ export const InputFiles: InputFilesType = observer( const files = Array.from(value ?? []); - return styled(styles)( - - + return ( + + {children} - {required && ' *'} - - - + +
+ {!hideTags && ( - + {files.map((file, i) => ( ))} )} - - {description && {description}} - , +
+ {description && {description}} +
); }), ) as InputFilesType; diff --git a/webapp/packages/core-blocks/src/FormControls/Radio.m.css b/webapp/packages/core-blocks/src/FormControls/Radio.m.css new file mode 100644 index 0000000000..18e3481717 --- /dev/null +++ b/webapp/packages/core-blocks/src/FormControls/Radio.m.css @@ -0,0 +1,66 @@ +.radio { + composes: theme-radio from global; +} + +.radioNoRipple { + composes: theme-radio_no-ripple from global; +} + +.radioBackground { + composes: theme-radio_background from global; +} +.input { + composes: theme-radio_native-control from global; +} +.radioOuterCircle { + composes: theme-radio_outer-circle from global; +} +.radioInnerCircle { + composes: theme-radio_inner-circle from global; +} +.radioRipple { + composes: theme-radio_ripple from global; +} +.field { + display: inline-flex; + align-items: center; + vertical-align: middle; +} +.label { + cursor: pointer; + .disabled { + cursor: auto; + } +} + +.primary { + composes: theme-radio_primary from global; +} + +.small { + composes: theme-radio_small from global; +} + +.field.menu { + padding: 0; + + & .radio { + width: 14px; + height: 14px; + } + & .radioBackground { + width: 14px; + height: 14px; + } + & .radioInnerCircle { + border-width: 7px; + } +} + +.disabledRadio { + composes: theme-radio_disabled from global; +} + +.disabledInput { + opacity: 0 !important; +} diff --git a/webapp/packages/core-blocks/src/FormControls/Radio.tsx b/webapp/packages/core-blocks/src/FormControls/Radio.tsx index 9d57f36495..6e4ca83afd 100644 --- a/webapp/packages/core-blocks/src/FormControls/Radio.tsx +++ b/webapp/packages/core-blocks/src/FormControls/Radio.tsx @@ -7,105 +7,19 @@ */ import { observer } from 'mobx-react-lite'; import { useCallback, useContext } from 'react'; -import styled, { css, use } from 'reshadow'; import { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps'; -import elementsSizeStyles from '../Containers/shared/ElementsSize.m.css'; import { s } from '../s'; import { useS } from '../useS'; -import { useStyles } from '../useStyles'; -import { baseFormControlStyles } from './baseFormControlStyles'; +import { Field } from './Field'; import { FormContext } from './FormContext'; +import style from './Radio.m.css'; import { RadioGroupContext } from './RadioGroupContext'; -const radioStyles = css` - radio { - composes: theme-radio from global; - } - radio-background { - composes: theme-radio_background from global; - } - input { - composes: theme-radio_native-control from global; - } - radio-outer-circle { - composes: theme-radio_outer-circle from global; - } - radio-inner-circle { - composes: theme-radio_inner-circle from global; - } - radio-ripple { - composes: theme-radio_ripple from global; - } - field { - display: inline-flex; - align-items: center; - font-weight: 500; - padding: 7px 12px; - vertical-align: middle; - } - label { - cursor: pointer; - &[|disabled] { - cursor: auto; - } - } -`; - -const radioMod = { - primary: css` - radio { - composes: theme-radio_primary from global; - } - `, - small: css` - radio { - composes: theme-radio_small from global; - } - `, - menu: css` - radio { - composes: theme-radio_small from global; - } - field { - padding: 0; - - & radio { - width: 14px; - height: 14px; - } - & radio-background { - width: 14px; - height: 14px; - } - & radio-inner-circle { - border-width: 7px; - } - } - `, -}; - -const noRippleStyles = css` - radio { - composes: theme-radio_no-ripple from global; - } -`; - -const radioState = { - disabled: css` - radio { - composes: theme-radio--disabled from global; - } - input { - opacity: 0 !important; - } - `, -}; - type BaseProps = Omit, 'onChange' | 'value' | 'checked'> & ILayoutSizeProps & { - mod?: Array; + mod?: Array<'primary' | 'small' | 'menu'>; ripple?: boolean; }; @@ -142,9 +56,10 @@ export const Radio: RadioType = observer(function Radio({ children, ...rest }: ControlledProps | ObjectProps) { + const styles = useS(style); + const layoutProps = getLayoutProps(rest); rest = filterLayoutFakeProps(rest); - const sizeStyles = useS(elementsSizeStyles); const formContext = useContext(FormContext); const context = useContext(RadioGroupContext); @@ -184,27 +99,36 @@ export const Radio: RadioType = observer(function Radio({ checked = state[name] === value; } - return styled( - useStyles( - baseFormControlStyles, - radioStyles, - ...(mod || []).map(mod => radioMod[mod]), - !ripple && noRippleStyles, - rest.disabled && radioState.disabled, - ), - )( - - - - - - - - {ripple && } - -