mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
feat(core-blocks): CB-667 naming fixes
This commit is contained in:
@@ -32,14 +32,14 @@ const styles = css`
|
||||
}
|
||||
`;
|
||||
|
||||
export interface INodeState {
|
||||
export interface ITreeNodeState {
|
||||
filter: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
root?: string;
|
||||
selectionTree?: boolean;
|
||||
localState?: MetadataMap<string, INodeState>;
|
||||
localState?: MetadataMap<string, ITreeNodeState>;
|
||||
control?: React.FC<{
|
||||
node: NavNode;
|
||||
}>;
|
||||
@@ -65,24 +65,26 @@ export const ElementsTree: React.FC<Props> = observer(function ElementsTree({
|
||||
}) {
|
||||
const nodeChildren = useChildren(root);
|
||||
const Placeholder = emptyPlaceholder;
|
||||
const [state] = useState(() => new MetadataMap<string, INodeState>(() => ({ filter: '' })));
|
||||
const [localTreeNodesState] = useState(() => new MetadataMap<string, ITreeNodeState>(() => ({ filter: '' })));
|
||||
|
||||
const elementsTreeState = localState || state;
|
||||
const treeNodesState = localState || localTreeNodesState;
|
||||
|
||||
const getMetadata = useCallback((node: NavNode) => elementsTreeState.get(node.id), [elementsTreeState]);
|
||||
const getTreeNodeState = useCallback((node: NavNode) =>
|
||||
treeNodesState.get(node.id), [treeNodesState]);
|
||||
|
||||
const onFilterHandler = useCallback((node: NavNode, value: string) => {
|
||||
elementsTreeState.get(node.id).filter = value;
|
||||
const treeNodeState = treeNodesState.get(node.id);
|
||||
treeNodeState.filter = value;
|
||||
|
||||
if (onFilter) {
|
||||
onFilter(node, value);
|
||||
}
|
||||
}, [elementsTreeState, onFilter]);
|
||||
}, [treeNodesState, onFilter]);
|
||||
|
||||
const context = useMemo<ITreeContext>(
|
||||
() => ({
|
||||
state: elementsTreeState,
|
||||
getMetadata,
|
||||
treeNodesState,
|
||||
getTreeNodeState,
|
||||
selectionTree,
|
||||
control,
|
||||
onOpen,
|
||||
@@ -90,7 +92,7 @@ export const ElementsTree: React.FC<Props> = observer(function ElementsTree({
|
||||
isSelected,
|
||||
onFilter: onFilterHandler,
|
||||
}),
|
||||
[control, selectionTree, onOpen, onSelect, isSelected, onFilterHandler, elementsTreeState, getMetadata]
|
||||
[control, selectionTree, onOpen, onSelect, isSelected, onFilterHandler, treeNodesState, getTreeNodeState]
|
||||
);
|
||||
|
||||
if (!nodeChildren.children || nodeChildren.children.length === 0) {
|
||||
|
||||
@@ -111,7 +111,7 @@ export function useNavigationNode(node: NavNode): INavigationNode {
|
||||
// TODO: seems like selection & expand should be specific for separate tree definitions
|
||||
navigationTreeService.expandNode(node.id, false);
|
||||
|
||||
context?.state?.delete(node.id);
|
||||
context?.treeNodesState?.delete(node.id);
|
||||
}, [node.id]);
|
||||
|
||||
return {
|
||||
@@ -124,7 +124,7 @@ export function useNavigationNode(node: NavNode): INavigationNode {
|
||||
handleOpen,
|
||||
handleSelect,
|
||||
handleFilter,
|
||||
filterValue: context?.state?.get(node.id).filter || '',
|
||||
filterValue: context?.treeNodesState?.get(node.id).filter || '',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ import { createContext } from 'react';
|
||||
import type { MetadataMap } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { NavNode } from '../shared/NodesManager/EntityTypes';
|
||||
import type { INodeState } from './ElementsTree';
|
||||
import type { ITreeNodeState } from './ElementsTree';
|
||||
|
||||
export interface ITreeContext {
|
||||
state?: MetadataMap<string, INodeState>;
|
||||
getMetadata?: (node: NavNode) => INodeState;
|
||||
treeNodesState?: MetadataMap<string, ITreeNodeState>;
|
||||
getTreeNodeState?: (node: NavNode) => ITreeNodeState;
|
||||
selectionTree: boolean;
|
||||
control?: React.FC<{
|
||||
node: NavNode;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
|
||||
import { useCallback, useContext } from 'react';
|
||||
import styled, { use, css } from 'reshadow';
|
||||
|
||||
import { useStyles } from '@cloudbeaver/core-theming';
|
||||
import { ComponentStyle, useStyles } from '@cloudbeaver/core-theming';
|
||||
|
||||
import type { IFlexItemsLayoutProps, IGridItemsLayoutProps, ILayoutSizeProps } from '../Containers/LayoutProps';
|
||||
import { baseFormControlStylesNew } from './baseFormControlStylesNew';
|
||||
@@ -20,16 +20,19 @@ import { isControlPresented } from './isControlPresented';
|
||||
const INPUT_FIELD_STYLES = css`
|
||||
field-label {
|
||||
display: block;
|
||||
padding-bottom: 10px;
|
||||
composes: theme-typography--body1 from global;
|
||||
font-weight: 500;
|
||||
}
|
||||
field-label:not(:empty) {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
`;
|
||||
|
||||
type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'name' | 'value'> & ILayoutSizeProps & IGridItemsLayoutProps & IFlexItemsLayoutProps & {
|
||||
description?: string;
|
||||
mod?: 'surface';
|
||||
ref?: React.Ref<HTMLInputElement>;
|
||||
style?: ComponentStyle;
|
||||
};
|
||||
|
||||
type ControlledProps = BaseProps & {
|
||||
@@ -55,6 +58,7 @@ interface InputFieldType {
|
||||
|
||||
export const InputFieldNew: InputFieldType = observer(function InputFieldNew({
|
||||
name,
|
||||
style,
|
||||
value: valueControlled,
|
||||
required,
|
||||
state,
|
||||
@@ -69,7 +73,7 @@ export const InputFieldNew: InputFieldType = observer(function InputFieldNew({
|
||||
onChange,
|
||||
...rest
|
||||
}: ControlledProps | ObjectProps<any, any>, ref: React.Ref<HTMLInputElement>) {
|
||||
const styles = useStyles(baseFormControlStylesNew, INPUT_FIELD_STYLES);
|
||||
const styles = useStyles(baseFormControlStylesNew, INPUT_FIELD_STYLES, style);
|
||||
const context = useContext(FormContext);
|
||||
|
||||
const handleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -92,7 +96,7 @@ export const InputFieldNew: InputFieldType = observer(function InputFieldNew({
|
||||
|
||||
return styled(styles)(
|
||||
<field as="div" className={className} {...use({ small, medium, large })}>
|
||||
<field-label as='label'>{children} {required && '*'}</field-label>
|
||||
<field-label as='label'>{children}{required && ' *'}</field-label>
|
||||
<input
|
||||
ref={ref}
|
||||
role='new'
|
||||
|
||||
@@ -16,54 +16,44 @@ import { IconButton } from '../../IconButton';
|
||||
import { useFocus } from '../../useFocus';
|
||||
import { TreeNodeContext } from './TreeNodeContext';
|
||||
|
||||
const styles = css`
|
||||
const styles = composes(
|
||||
css`
|
||||
IconButton {
|
||||
composes: theme-background-primary theme-text-on-primary from global;
|
||||
}
|
||||
`,
|
||||
css`
|
||||
filter-container {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
}
|
||||
InputFieldNew {
|
||||
display: none;
|
||||
width: 300px;
|
||||
max-width: 300px;
|
||||
&[|filterMode] {
|
||||
&[|filterEnabled] {
|
||||
display: block;
|
||||
& > :global(input) {
|
||||
height: 28px;
|
||||
padding-right: 24px !important;
|
||||
}
|
||||
& > :global(label) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 2px;
|
||||
margin: 0;
|
||||
background: #cccccc;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
&[|filterMode] {
|
||||
/* 24px icon width + 2px input border */
|
||||
left: calc(100% - 26px);
|
||||
border-radius: 2px;
|
||||
&[|filterEnabled] {
|
||||
border-radius: unset;
|
||||
}
|
||||
}
|
||||
`;
|
||||
`);
|
||||
|
||||
const filterButtonMode = {
|
||||
filter: composes(
|
||||
css`
|
||||
IconButton {
|
||||
composes: theme-background-primary theme-text-on-primary from global;
|
||||
}
|
||||
`),
|
||||
passive:
|
||||
css`
|
||||
IconButton {
|
||||
color: #398fca;
|
||||
background-color: #cccccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
`,
|
||||
};
|
||||
const innerInputStyle = css`
|
||||
input {
|
||||
height: 28px;
|
||||
padding-right: 24px !important;
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
disabled?: boolean;
|
||||
@@ -74,9 +64,9 @@ export const TreeNodeFilter: React.FC<Props> = function TreeNodeFilter({
|
||||
disabled,
|
||||
className,
|
||||
}) {
|
||||
const [focusedRef] = useFocus<HTMLInputElement>({});
|
||||
const [inputRef] = useFocus<HTMLInputElement>({});
|
||||
const context = useContext(TreeNodeContext);
|
||||
const [filterMode, setFilterMode] = useState(!!context?.filterValue);
|
||||
const [filterEnabled, setFilterEnabled] = useState(!!context?.filterValue);
|
||||
|
||||
if (!context) {
|
||||
throw new Error('Context not provided');
|
||||
@@ -92,21 +82,22 @@ export const TreeNodeFilter: React.FC<Props> = function TreeNodeFilter({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (filterMode) {
|
||||
focusedRef.current?.focus();
|
||||
if (filterEnabled) {
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
}, [filterMode]);
|
||||
}, [filterEnabled]);
|
||||
|
||||
return styled(useStyles(styles, filterMode ? filterButtonMode.filter : filterButtonMode.passive))(
|
||||
return styled(useStyles(styles))(
|
||||
<filter-container as='div' className={className} onClick={handleClick} onDoubleClick={preventPropagation}>
|
||||
<InputFieldNew
|
||||
ref={focusedRef}
|
||||
ref={inputRef}
|
||||
style={innerInputStyle}
|
||||
disabled={disabled}
|
||||
value={context.filterValue}
|
||||
{...use({ filterMode })}
|
||||
{...use({ filterEnabled })}
|
||||
onChange={value => context.filter(value.trim())}
|
||||
/>
|
||||
<IconButton name='search' disabled={disabled} onClick={() => setFilterMode(!filterMode)} {...use({ filterMode })} />
|
||||
<IconButton name='search' disabled={disabled} onClick={() => setFilterEnabled(!filterEnabled)} {...use({ filterEnabled })} />
|
||||
</filter-container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@ $input-background: $mdc-theme-secondary;
|
||||
$input-background-disabled: $input-background;
|
||||
$input-background-readonly: $input-background;
|
||||
|
||||
$button-background-disabled: #cccccc;
|
||||
|
||||
$mdc-theme-text-colors: (
|
||||
dark: (
|
||||
primary: white,
|
||||
@@ -44,19 +46,19 @@ $mdc-theme-text-colors: (
|
||||
);
|
||||
|
||||
$mdc-ripple-dark-ink-opacities: (
|
||||
hover: .04,
|
||||
focus: .12,
|
||||
press: .12,
|
||||
selected: .08,
|
||||
activated: .12
|
||||
hover: 0.04,
|
||||
focus: 0.12,
|
||||
press: 0.12,
|
||||
selected: 0.08,
|
||||
activated: 0.12,
|
||||
) !default;
|
||||
|
||||
$mdc-ripple-light-ink-opacities: (
|
||||
hover: .04,
|
||||
focus: .12,
|
||||
press: .12,
|
||||
selected: .08,
|
||||
activated: .12
|
||||
hover: 0.04,
|
||||
focus: 0.12,
|
||||
press: 0.12,
|
||||
selected: 0.08,
|
||||
activated: 0.12,
|
||||
) !default;
|
||||
|
||||
$theme-name: "dark";
|
||||
|
||||
@@ -25,6 +25,8 @@ $input-background: $mdc-theme-surface;
|
||||
$input-background-disabled: $mdc-theme-secondary;
|
||||
$input-background-readonly: $mdc-theme-secondary;
|
||||
|
||||
$button-background-disabled: #cccccc;
|
||||
|
||||
$theme-name: "light";
|
||||
|
||||
@import "mixins";
|
||||
|
||||
@@ -16,6 +16,7 @@ $mdc-theme-extra-property-values: (
|
||||
input-background: $input-background,
|
||||
input-background-disabled: $input-background-disabled,
|
||||
input-background-readonly: $input-background-readonly,
|
||||
button-background-disabled: $button-background-disabled,
|
||||
);
|
||||
|
||||
$mdc-theme-property-values: map-merge($mdc-theme-property-values, $mdc-theme-extra-property-values);
|
||||
|
||||
Reference in New Issue
Block a user