From fab9d1dd43353c93c5e73aa4e1535c57775f036a Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:18:35 +0100 Subject: [PATCH] dbeaver/pro#7806 remove MenuBarSmallItem (#4224) * dbeaver/pro#7806 remove MenuBarSmallItem * dbeaver/pro#7806 remove reakit * dbeaver/pro#7806 remove extra class * dbeaver/pro#7806 increase base padding and background color * dbeaver/pro#7806 use more safe style --------- Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com> --- .../@dbeaver/ui-kit/src/Button/Button.tsx | 6 +- .../@dbeaver/ui-kit/src/Button/_base.css | 2 +- .../ui-kit/src/Composite/Composite.tsx | 32 +++ .../@dbeaver/ui-kit/src/Menu/Menu.tsx | 4 + .../@dbeaver/ui-kit/src/Popover/Popover.tsx | 9 +- .../@dbeaver/ui-kit/src/Portal/Portal.tsx | 15 ++ .../common-react/@dbeaver/ui-kit/src/index.ts | 15 +- webapp/package.json | 1 - webapp/packages/core-blocks/package.json | 2 - webapp/packages/core-blocks/src/Button.css | 5 +- .../InputAutocompletionMenu.module.css | 11 - .../FormControls/InputAutocompletionMenu.tsx | 87 +++----- .../InputFileTextContent.module.css | 9 - .../src/FormControls/InputFileTextContent.tsx | 18 +- .../src/FormControls/InputFiles.tsx | 2 +- .../core-blocks/src/FormControls/Textarea.tsx | 2 +- .../src/FormControls/useInputAutocomplete.ts | 17 +- .../packages/core-blocks/src/IconButton.tsx | 16 +- .../core-blocks/src/Menu/Menu.module.css | 34 --- webapp/packages/core-blocks/src/Menu/Menu.tsx | 202 ------------------ .../src/Menu/MenuBarSmallItem.module.css | 35 --- .../core-blocks/src/Menu/MenuBarSmallItem.tsx | 38 ---- .../core-blocks/src/Menu/MenuEmptyItem.tsx | 24 --- .../core-blocks/src/Menu/MenuItem.module.css | 30 --- .../core-blocks/src/Menu/MenuItem.tsx | 55 ----- .../core-blocks/src/Menu/MenuPanel.module.css | 34 --- .../core-blocks/src/Menu/MenuPanel.tsx | 71 ------ .../core-blocks/src/Menu/MenuStateContext.ts | 13 -- .../src/Menu/ReakitProxyComponent.ts | 22 -- webapp/packages/core-blocks/src/index.ts | 9 - .../packages/core-notifications/package.json | 2 +- .../core-notifications/src/Notifications.tsx | 3 +- .../packages/core-notifications/tsconfig.json | 3 + webapp/packages/core-ui/package.json | 1 - .../core-ui/src/ContextMenu/ContextMenu.tsx | 2 +- .../src/ContextMenu/IContextMenuProps.ts | 5 +- .../package.json | 1 - .../src/ConnectionForm/SSH/SSHKeyUploader.tsx | 2 +- .../package.json | 1 + .../GroupingTableItem.tsx | 12 +- .../tsconfig.json | 3 + .../TableHeader/TableWhereFilter.tsx | 53 +++-- .../packages/plugin-log-viewer/package.json | 1 + .../LogViewer/LogViewerInfoPanel.module.css | 4 - .../src/LogViewer/LogViewerInfoPanel.tsx | 24 ++- .../src/LogViewer/LogViewerTable.module.css | 9 +- .../src/LogViewer/LogViewerTable.tsx | 16 +- .../packages/plugin-log-viewer/tsconfig.json | 3 + .../plugin-object-viewer/package.json | 1 - .../src/ObjectPropertiesPage/FolderContext.ts | 11 - .../SQLCodeEditorPanel/SQLCodeEditorPanel.tsx | 20 +- webapp/yarn.lock | 73 +------ 52 files changed, 244 insertions(+), 826 deletions(-) create mode 100644 webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx create mode 100644 webapp/common-react/@dbeaver/ui-kit/src/Portal/Portal.tsx delete mode 100644 webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.module.css delete mode 100644 webapp/packages/core-blocks/src/Menu/Menu.module.css delete mode 100644 webapp/packages/core-blocks/src/Menu/Menu.tsx delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.module.css delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.tsx delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuItem.module.css delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuItem.tsx delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuPanel.module.css delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuPanel.tsx delete mode 100644 webapp/packages/core-blocks/src/Menu/MenuStateContext.ts delete mode 100644 webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts delete mode 100644 webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/FolderContext.ts diff --git a/webapp/common-react/@dbeaver/ui-kit/src/Button/Button.tsx b/webapp/common-react/@dbeaver/ui-kit/src/Button/Button.tsx index fd94ee9e73..e942dc5c54 100644 --- a/webapp/common-react/@dbeaver/ui-kit/src/Button/Button.tsx +++ b/webapp/common-react/@dbeaver/ui-kit/src/Button/Button.tsx @@ -1,11 +1,12 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 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 clsx from 'clsx'; +import { Button as AriaButton, type ButtonProps as UnstyledButtonProps } from '@ariakit/react'; import type { ControlSize } from '../types/controls.js'; import { componentProviderWrapper } from '../componentProviderWrapper.js'; import { ButtonRoot, type ButtonRootProps } from './ButtonRoot.js'; @@ -37,3 +38,6 @@ export function ButtonBaseIcon({ className, children, placement }: ButtonIconPro export const Button = componentProviderWrapper('Button', ButtonBase); export const ButtonIcon = componentProviderWrapper('ButtonIcon', ButtonBaseIcon); + +export const UnstyledButton = AriaButton; +export { type UnstyledButtonProps }; \ No newline at end of file diff --git a/webapp/common-react/@dbeaver/ui-kit/src/Button/_base.css b/webapp/common-react/@dbeaver/ui-kit/src/Button/_base.css index 23a0f00b2f..831cb41fc1 100644 --- a/webapp/common-react/@dbeaver/ui-kit/src/Button/_base.css +++ b/webapp/common-react/@dbeaver/ui-kit/src/Button/_base.css @@ -1,7 +1,7 @@ @layer base { :root { --dbv-kit-btn-height: var(--dbv-kit-control-height-medium); - --dbv-kit-btn-padding-inline: calc(var(--tw-spacing) * 2.5); + --dbv-kit-btn-padding-inline: calc(var(--tw-spacing) * 3); --dbv-kit-btn-gap: calc(var(--dbv-kit-btn-padding-inline) / 2); --dbv-kit-btn-outline-offset: var(--dbv-kit-control-outline-offset); diff --git a/webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx b/webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx new file mode 100644 index 0000000000..d051a16d5b --- /dev/null +++ b/webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx @@ -0,0 +1,32 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2026 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 { + Composite as AriakitComposite, + CompositeItem as AriakitCompositeItem, + CompositeProvider as AriakitCompositeProvider, + useCompositeStore, + type CompositeProps, + type CompositeItemProps, + type CompositeProviderProps, + type CompositeStore, +} from '@ariakit/react'; + +export function CompositeProvider({ children, ...props }: CompositeProviderProps) { + return {children}; +} + +export function Composite({ children, ...props }: CompositeProps) { + return {children}; +} + +export function CompositeItem({ children, ...props }: CompositeItemProps) { + return {children}; +} + +export { useCompositeStore, type CompositeProps, type CompositeItemProps, type CompositeProviderProps, type CompositeStore }; \ No newline at end of file diff --git a/webapp/common-react/@dbeaver/ui-kit/src/Menu/Menu.tsx b/webapp/common-react/@dbeaver/ui-kit/src/Menu/Menu.tsx index ab1838aacd..aff7ab7292 100644 --- a/webapp/common-react/@dbeaver/ui-kit/src/Menu/Menu.tsx +++ b/webapp/common-react/@dbeaver/ui-kit/src/Menu/Menu.tsx @@ -45,6 +45,8 @@ import { type MenuListProps, type MenuBarProps, type MenuItemCheckProps, + type MenuStore, + type MenuStoreState } from '@ariakit/react'; import clsx from 'clsx'; @@ -175,6 +177,8 @@ export { type MenuStoreProps, type MenuArrowProps, type HovercardStoreState, + type MenuStore, + type MenuStoreState }; Menu.Provider = MenuProvider; diff --git a/webapp/common-react/@dbeaver/ui-kit/src/Popover/Popover.tsx b/webapp/common-react/@dbeaver/ui-kit/src/Popover/Popover.tsx index c5e70bb742..94248eaa6a 100644 --- a/webapp/common-react/@dbeaver/ui-kit/src/Popover/Popover.tsx +++ b/webapp/common-react/@dbeaver/ui-kit/src/Popover/Popover.tsx @@ -1,6 +1,6 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 DBeaver Corp and others * * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. @@ -11,6 +11,10 @@ import clsx from 'clsx'; import './Popover.css'; +export function PopoverAnchor({ children, ...props }: Ariakit.PopoverAnchorProps) { + return {children}; +} + export function Popover({ children, ...props }: Ariakit.PopoverProviderProps) { return {children}; } @@ -40,3 +44,6 @@ Popover.PopoverArrow = PopoverArrow; Popover.PopoverHeading = PopoverHeading; Popover.PopoverDescription = PopoverDescription; Popover.PopoverContent = PopoverContent; +Popover.Anchor = PopoverAnchor; + +export { usePopoverStore, type PopoverStore } from '@ariakit/react'; \ No newline at end of file diff --git a/webapp/common-react/@dbeaver/ui-kit/src/Portal/Portal.tsx b/webapp/common-react/@dbeaver/ui-kit/src/Portal/Portal.tsx new file mode 100644 index 0000000000..7da9521ae4 --- /dev/null +++ b/webapp/common-react/@dbeaver/ui-kit/src/Portal/Portal.tsx @@ -0,0 +1,15 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2026 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 { Portal as AriakitPortal, type PortalProps } from '@ariakit/react'; + +export function Portal({ children, ...props }: PortalProps) { + return {children}; +} + +export type { PortalProps }; \ No newline at end of file diff --git a/webapp/common-react/@dbeaver/ui-kit/src/index.ts b/webapp/common-react/@dbeaver/ui-kit/src/index.ts index 5596debaf8..8c6d0485d6 100644 --- a/webapp/common-react/@dbeaver/ui-kit/src/index.ts +++ b/webapp/common-react/@dbeaver/ui-kit/src/index.ts @@ -21,7 +21,7 @@ export { type FocusTrapRegionProps, } from '@ariakit/react'; -export { Button, ButtonBase, type ButtonProps, ButtonIcon, type ButtonIconProps } from './Button/Button.js'; +export { Button, ButtonBase, type ButtonProps, ButtonIcon, type ButtonIconProps, UnstyledButton, type UnstyledButtonProps } from './Button/Button.js'; export { IconButton, IconButtonBase, type IconButtonProps } from './IconButton/IconButton.js'; export { Checkbox, CheckboxBase, type CheckboxProps } from './Checkbox/Checkbox.js'; export { ColorPicker } from './ColorPicker/ColorPicker.js'; @@ -46,7 +46,7 @@ export { } from './Select/Select.js'; export * from './Combobox/Combobox.js'; export * from './Command/Command.js'; -export { Popover } from './Popover/Popover.js'; +export { Popover, usePopoverStore, type PopoverStore } from './Popover/Popover.js'; export { SelectField, type SelectFieldProps, type SelectItem } from './Select/SelectField.js'; export { Spinner, type SpinnerProps } from './Spinner/Spinner.js'; export { Radio, RadioGroup, useRadioContext, useRadioStore, type RadioProviderProps, type RadioProps, type RadioGroupProps } from './Radio/index.js'; @@ -57,3 +57,14 @@ export * from './Menu/Menu.js'; export * from './Disclosure/Disclosure.js'; export * from './Dialog/Dialog.js'; export * from './Tab/Tab.js'; +export { Portal, type PortalProps } from './Portal/Portal.js'; +export { + Composite, + CompositeItem, + CompositeProvider, + useCompositeStore, + type CompositeProps, + type CompositeItemProps, + type CompositeProviderProps, + type CompositeStore, +} from './Composite/Composite.js'; diff --git a/webapp/package.json b/webapp/package.json index 2b49086829..cd3c47d47e 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -59,7 +59,6 @@ "prettier": "^3.6.2", "react": "^19", "react-dom": "^19", - "reakit": "^1", "rimraf": "^6", "typescript": "^5.8.3", "typescript-plugin-css-modules": "^5", diff --git a/webapp/packages/core-blocks/package.json b/webapp/packages/core-blocks/package.json index a00aa4d2cb..4d8f460cd6 100644 --- a/webapp/packages/core-blocks/package.json +++ b/webapp/packages/core-blocks/package.json @@ -44,8 +44,6 @@ "react-dom": "^19", "react-hotkeys-hook": "5.1.0", "react-minisearch": "^7", - "reakit": "^1", - "reakit-utils": "^0", "subscript": "^9", "tslib": "^2" }, diff --git a/webapp/packages/core-blocks/src/Button.css b/webapp/packages/core-blocks/src/Button.css index d717a9d86b..803c66f177 100644 --- a/webapp/packages/core-blocks/src/Button.css +++ b/webapp/packages/core-blocks/src/Button.css @@ -7,7 +7,6 @@ */ @layer components { .dbv-kit-button { - --dbv-kit-btn-padding-inline: 15px; --dbv-kit-btn-outline-color: var(--theme-primary); --dbv-kit-control-disabled-foreground: #3535355e; --dbv-kit-control-disabled-background: #3535351f; @@ -22,7 +21,7 @@ --dbv-kit-btn-primary-border-color: var(--theme-primary); --dbv-kit-btn-secondary-background: transparent; - --dbv-kit-btn-secondary-background-hover: color-mix(in srgb, transparent, var(--theme-primary) 5%); + --dbv-kit-btn-secondary-background-hover: color-mix(in srgb, transparent, var(--theme-primary) 10%); --dbv-kit-btn-secondary-background-active: color-mix(in srgb, transparent, var(--theme-primary) 20%); --dbv-kit-btn-secondary-foreground: var(--theme-link-color); --dbv-kit-btn-secondary-foreground-hover: var(--theme-link-color); @@ -37,7 +36,7 @@ --dbv-kit-btn-ghost-foreground-hover: var(--theme-link-color); --dbv-kit-btn-ghost-foreground-active: var(--theme-link-color); --dbv-kit-btn-ghost-background: transparent; - --dbv-kit-btn-ghost-background-hover: color-mix(in srgb, transparent, var(--theme-primary) 5%); + --dbv-kit-btn-ghost-background-hover: color-mix(in srgb, transparent, var(--theme-primary) 10%); --dbv-kit-btn-ghost-background-active: color-mix(in srgb, transparent, var(--theme-primary) 20%); --dbv-kit-btn-ghost-border-color: transparent; diff --git a/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.module.css b/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.module.css deleted file mode 100644 index d06eb71803..0000000000 --- a/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.module.css +++ /dev/null @@ -1,11 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ - -.menu { - display: none !important; -} diff --git a/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.tsx b/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.tsx index d276efb887..4352e46c65 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputAutocompletionMenu.tsx @@ -1,82 +1,45 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 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 { observer } from 'mobx-react-lite'; -import type { RefObject } from 'react'; -import BaseDropdownStyles from '../FormControls/BaseDropdown.module.css'; -import { IconOrImage } from '../IconOrImage.js'; -import { Menu } from '../Menu/Menu.js'; -import { MenuItem } from '../Menu/MenuItem.js'; -import type { IMenuState } from '../Menu/MenuStateContext.js'; -import { s } from '../s.js'; -import { Text } from '../Text.js'; -import { useS } from '../useS.js'; -import style from './InputAutocompletionMenu.module.css'; +import { observer } from 'mobx-react-lite'; +import { Composite, CompositeItem, Popover } from '@dbeaver/ui-kit'; + import { type InputAutocompleteProposal } from './useInputAutocomplete.js'; +import { useS } from '../useS.js'; +import { BaseDropdownStyles, IconOrImage, s, Text } from '../index.js'; +import { forwardRef } from 'react'; interface AutocompletionProps { - position: { x: number; y: number }; proposals: InputAutocompleteProposal[]; - menuRef: RefObject; className?: string; onSelect?: (proposal: InputAutocompleteProposal) => void; } -export const InputAutocompletionMenu = observer(function InputAutocompletionMenu({ - position, - className, - menuRef, +export const InputAutocompletionMenu = observer(forwardRef(function InputAutocompletionMenu({ proposals, onSelect, -}: AutocompletionProps) { - const styles = useS(style, BaseDropdownStyles); - const contextMenuPosition = { - position, - open: () => {}, - close: () => {}, - }; +}, ref) { + const styles = useS(BaseDropdownStyles); - function handleSelect(proposal: InputAutocompleteProposal) { - menuRef.current?.hide(); - onSelect?.(proposal); - } - - if (!proposals.length) { - return; - } - - // TODO: migrate to new menu or popover return ( - 0} - panelAvailable={proposals.length > 0} - className={s(styles, { menu: true }, className)} - menuRef={menuRef} - label="Autocompletion" - items={proposals.map(proposal => ( - handleSelect(proposal)} - > - {proposal.icon && ( -
- -
- )} - {proposal.displayString} -
- ))} - modal - /> + + + {proposals.map(proposal => ( + onSelect?.(proposal)}> + {proposal.icon && ( +
+ +
+ )} + {proposal.displayString} +
+ ))} +
+
); -}); +})); diff --git a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.module.css b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.module.css index 2d866a5806..8cd1e7c66c 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.module.css +++ b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.module.css @@ -18,12 +18,3 @@ 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 d7108bcdc4..06cbc4a78a 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFileTextContent.tsx @@ -9,10 +9,10 @@ import { observer } from 'mobx-react-lite'; import { type ReactNode, useContext, useState } from 'react'; import { blobToBase64, bytesToSize } from '@cloudbeaver/core-utils'; +import { IconButton } from '@dbeaver/ui-kit'; import { Button } from '../Button.js'; import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps.js'; -import { IconButton } from '../IconButton.js'; import { useTranslate } from '../localization/useTranslate.js'; import { s } from '../s.js'; import { UploadArea } from '../UploadArea.js'; @@ -22,6 +22,7 @@ import { FieldDescription } from './FieldDescription.js'; import { FieldLabel } from './FieldLabel.js'; import { FormContext } from './FormContext.js'; import inputFileTextContentStyles from './InputFileTextContent.module.css'; +import { Icon } from '../Icon.js'; const DEFAULT_MAX_FILE_SIZE = 2048; @@ -139,13 +140,24 @@ export const InputFileTextContent: InputFileTextContentType = observer(function {children} - {description} - {(selected || saved) && } + {(selected || saved) && ( + + + + )} ); diff --git a/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx b/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx index 9940effe85..3342cafc53 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputFiles.tsx @@ -184,7 +184,7 @@ export const InputFiles: InputFilesType = observer( diff --git a/webapp/packages/core-blocks/src/FormControls/useInputAutocomplete.ts b/webapp/packages/core-blocks/src/FormControls/useInputAutocomplete.ts index 1bd33d93e1..7ca873b2ee 100644 --- a/webapp/packages/core-blocks/src/FormControls/useInputAutocomplete.ts +++ b/webapp/packages/core-blocks/src/FormControls/useInputAutocomplete.ts @@ -1,17 +1,17 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 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 { action, computed, observable } from 'mobx'; -import { type RefObject, useEffect, useLayoutEffect, useMemo, useRef } from 'react'; +import { type RefObject, useEffect, useLayoutEffect, useMemo } from 'react'; import { debounce } from '@cloudbeaver/core-utils'; import { isNotNullDefined } from '@dbeaver/js-helpers'; -import type { IMenuState } from '../Menu/MenuStateContext.js'; import type { IContextMenuPositionCoords } from '../Menu/useContextMenuPosition.js'; import { useObservableRef } from '../useObservableRef.js'; import { type SearchStrategy, useSearch } from '../useSearch.js'; @@ -23,6 +23,7 @@ interface InputAutocompleteOptions { separator?: string | RegExp; matchStrategy?: SearchStrategy; predicate?: (suggestion: InputAutocompleteProposal, lastWord?: string) => boolean; + onNavigate?: () => void; } export interface InputAutocompleteProposal { @@ -38,7 +39,6 @@ interface State { proposals: InputAutocompleteProposal[]; position: IContextMenuPositionCoords; inputValue: string; - menuRef: RefObject; } const DEFAULT_SEPARATOR = ' '; @@ -48,7 +48,7 @@ const CONTEXT_INPUT_OFFSET_Y = 3; export const useInputAutocomplete = ( inputRef: RefObject, - { sourceHints, separator = DEFAULT_SEPARATOR, matchStrategy = 'contains', predicate }: InputAutocompleteOptions, + { sourceHints, separator = DEFAULT_SEPARATOR, matchStrategy = 'contains', onNavigate, predicate }: InputAutocompleteOptions, ): Readonly => { const search = useSearch({ sourceHints, @@ -56,7 +56,7 @@ export const useInputAutocomplete = ( matchStrategy, predicate, }); - const menuRef = useRef(null); + const state = useObservableRef( () => ({ position: { x: 0, y: 0 } as IContextMenuPositionCoords, @@ -126,7 +126,7 @@ export const useInputAutocomplete = ( position: observable.ref, inputValue: observable.ref, }, - { inputRef, search, menuRef }, + { inputRef, search, onNavigate }, ); const handleInput = useMemo( @@ -145,12 +145,11 @@ export const useInputAutocomplete = ( function handleKeyDown(event: any) { switch (event.key) { case 'Escape': - state.menuRef.current?.hide(); state.resetState(); break; case 'ArrowDown': case 'ArrowUp': - state.menuRef.current?.first(); + state.onNavigate?.(); break; case 'Tab': state.resetState(); diff --git a/webapp/packages/core-blocks/src/IconButton.tsx b/webapp/packages/core-blocks/src/IconButton.tsx index 0028a8ae22..e5c70ccc68 100644 --- a/webapp/packages/core-blocks/src/IconButton.tsx +++ b/webapp/packages/core-blocks/src/IconButton.tsx @@ -1,13 +1,14 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 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 { observer } from 'mobx-react-lite'; import type React from 'react'; -import { type ButtonProps, Button as ReakitButton } from 'reakit'; +import { UnstyledButton, type UnstyledButtonProps } from '@dbeaver/ui-kit'; import { Icon } from './Icon.js'; import IconButtonStyles from './IconButton.module.css'; @@ -16,25 +17,22 @@ import { StaticImage } from './StaticImage.js'; import { useS } from './useS.js'; interface Props { - tag?: 'button' | 'a' | 'div'; name: string; img?: boolean; viewBox?: string; } -export type IconButtonProps = Props & ButtonProps; +export type IconButtonProps = Props & UnstyledButtonProps; -export const IconButton: React.FC = observer(function IconButton({ tag, name, img, viewBox, className, ...rest }) { +export const IconButton: React.FC = observer(function IconButton({ name, img, viewBox, className, ...rest }) { const styles = useS(IconButtonStyles); - const Button = tag ?? ReakitButton; - return ( - + ); }); diff --git a/webapp/packages/core-blocks/src/Menu/Menu.module.css b/webapp/packages/core-blocks/src/Menu/Menu.module.css deleted file mode 100644 index 63a2520c16..0000000000 --- a/webapp/packages/core-blocks/src/Menu/Menu.module.css +++ /dev/null @@ -1,34 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -.menuButton { - composes: theme-ripple from global; -} -.menuButton { - background: none; - border: none; - color: inherit; - cursor: pointer; - - & .box { - display: flex; - align-items: center; - flex: 1; - height: inherit; - } -} -.menuButtonLink { - position: absolute; - width: 0; - height: 0; - overflow: hidden; - box-sizing: border-box; - padding: 0; - margin: 0; - border: none; - background: transparent; -} diff --git a/webapp/packages/core-blocks/src/Menu/Menu.tsx b/webapp/packages/core-blocks/src/Menu/Menu.tsx deleted file mode 100644 index 3467f5d984..0000000000 --- a/webapp/packages/core-blocks/src/Menu/Menu.tsx +++ /dev/null @@ -1,202 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite'; -import React, { forwardRef, useLayoutEffect, useRef, useState } from 'react'; -import { MenuButton, type MenuInitialState, useMenuState } from 'reakit'; -import type { ExtractHTMLAttributes } from 'reakit-utils'; - -import { ErrorBoundary } from '../ErrorBoundary.js'; -import { s } from '../s.js'; -import { useCombinedRef } from '../useCombinedRef.js'; -import { useObjectRef } from '../useObjectRef.js'; -import { useS } from '../useS.js'; -import style from './Menu.module.css'; -import { MenuPanel } from './MenuPanel.js'; -import { type IMenuState, MenuStateContext } from './MenuStateContext.js'; -import type { IContextMenuPosition } from './useContextMenuPosition.js'; - -interface IMenuProps extends React.ButtonHTMLAttributes { - contextMenuPosition?: IContextMenuPosition; - label: string; - items: React.ReactNode | (() => React.ReactNode); - menuRef?: React.RefObject; - disclosure?: boolean; - placement?: MenuInitialState['placement']; - submenu?: boolean; - modal?: boolean; - visible?: boolean; - rtl?: boolean; - hasBindings?: boolean; - panelAvailable?: boolean; - getHasBindings?: () => boolean; - onVisibleSwitch?: (visible: boolean) => void; -} - -/** - * @deprecated use the @dbeaver/ui-kit package instead - */ -export const Menu = observer( - forwardRef(function Menu( - { - contextMenuPosition, - label, - items, - menuRef, - disclosure, - children, - placement, - visible, - hasBindings, - panelAvailable, - getHasBindings, - onVisibleSwitch, - modal, - submenu, - rtl, - className, - ...props - }, - ref, - ) { - const innerMenuButtonRef = useRef(null); - const combinedRef = useCombinedRef(ref, innerMenuButtonRef); - const [relativePosition, setRelativePosition] = useState<{ x: number; y: number } | null>(null); - const menuButtonLinkRef = useRef(null); - const menuPanelRef = useRef(null); - const propsRef = useObjectRef({ onVisibleSwitch, visible }); - const menu = useMenuState({ - modal, - placement, - visible, - rtl, - unstable_fixed: true, - }); - const styles = useS(style); - - if (menuRef) { - menuRef.current = menu; - } - - let menuVisible = menu.visible; - - if (panelAvailable === false) { - menuVisible = false; - } - - useLayoutEffect(() => { - if (!menuVisible) { - setRelativePosition(null); - } - - propsRef.onVisibleSwitch?.(menuVisible); - }, [menuVisible]); - - useLayoutEffect(() => { - if (!contextMenuPosition?.position) { - return; - } - - if (menuVisible) { - menu.hide(); - return; - } - - if (innerMenuButtonRef.current) { - menu.show(); - - const boxSize = innerMenuButtonRef.current.getBoundingClientRect(); - setRelativePosition({ - x: contextMenuPosition.position.x - boxSize.x, - y: contextMenuPosition.position.y - boxSize.y, - }); - - contextMenuPosition.position = null; - } - }, [contextMenuPosition?.position, menuVisible]); - - useLayoutEffect(() => { - if (relativePosition) { - if (menuButtonLinkRef.current) { - menuButtonLinkRef.current.style.left = `${relativePosition.x}px`; - menuButtonLinkRef.current.style.top = `${relativePosition.y}px`; - } - } - }); - - const MenuButtonLink = MenuButton; - - if (React.isValidElement(children) && disclosure) { - return ( - - - - {(disclosureProps: ExtractHTMLAttributes) => React.cloneElement(children, { ...disclosureProps, ...(children.props as any) })} - - - {items} - - {relativePosition && ( - - )} - - - ); - } - - return ( - - - -
{children}
-
- - {items} - - {relativePosition && ( - - )} -
-
- ); - }), -); diff --git a/webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.module.css b/webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.module.css deleted file mode 100644 index 983b66aec3..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.module.css +++ /dev/null @@ -1,35 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ - -.iconButton { - overflow: hidden; - padding: 0; - margin: 0; - flex-shrink: 0; -} - -.iconBox { - composes: theme-form-element-radius theme-text-primary theme-ripple from global; - box-sizing: border-box; - overflow: hidden; - padding: 4px !important; - margin: 2px !important; - flex-shrink: 0; - height: 24px !important; - display: flex; - cursor: pointer; - align-items: center; - gap: 2px; - user-select: none; - outline: none; - - & .iconLabel { - text-transform: uppercase; - font-weight: 500; - } -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.tsx b/webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.tsx deleted file mode 100644 index 44234d1fbe..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuBarSmallItem.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 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 type { ButtonProps } from 'reakit'; - -import { IconButton } from '../IconButton.js'; -import { s } from '../s.js'; -import { useS } from '../useS.js'; -import moduleStyles from './MenuBarSmallItem.module.css'; - -interface Props extends Omit { - icon?: string; - viewBox?: string; - onClick?: React.MouseEventHandler; -} - -export const MenuBarSmallItem: React.FC> = function MenuBarSmallItem({ - icon, - viewBox, - children, - className, - onClick, - ...rest -}) { - const style = useS(moduleStyles); - // TODO: replace IconButton with StaticImage / Icon - // TODO: use button for icon-box (maybe) - return ( -
- {icon && } - {children &&
{children}
} -
- ); -}; diff --git a/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx b/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx deleted file mode 100644 index 3d46af0a2a..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuEmptyItem.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 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 { observer } from 'mobx-react-lite'; - -import { useTranslate } from '../localization/useTranslate.js'; -import { MenuItem } from './MenuItem.js'; -import { MenuItemElement } from './MenuItemElement.js'; - -export const MenuEmptyItem = observer(function MenuEmptyItem() { - const translate = useTranslate(); - - const label = translate('core_ui_empty'); - - return ( - - - - ); -}); diff --git a/webapp/packages/core-blocks/src/Menu/MenuItem.module.css b/webapp/packages/core-blocks/src/Menu/MenuItem.module.css deleted file mode 100644 index d3f2ca38fd..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuItem.module.css +++ /dev/null @@ -1,30 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -.menuItem { - composes: theme-ripple from global; - composes: menuItem from './MenuItemElement.module.css'; - - display: flex; - align-items: center; - border: none; - padding: 0; - background: none; - text-align: left; - outline: none; - color: inherit; - cursor: pointer; - white-space: nowrap; - - &.hidden { - display: none; - } - - &:global([aria-selected='true']) { - opacity: 0.7; - } -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuItem.tsx b/webapp/packages/core-blocks/src/Menu/MenuItem.tsx deleted file mode 100644 index 7c6f8d6859..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuItem.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite'; -import React, { useContext } from 'react'; -import { MenuItem as ReakitMenuItem, type CompositeItemOptions } from 'reakit'; - -import { s } from '../s.js'; -import { useCombinedHandler } from '../useCombinedHandler.js'; -import { useS } from '../useS.js'; -import style from './MenuItem.module.css'; -import { MenuStateContext } from './MenuStateContext.js'; -import type { ReakitProxyComponent, ReakitProxyComponentOptions } from './ReakitProxyComponent.js'; - -export type MenuItemOptions = CompositeItemOptions & { - selected?: boolean; - close?: boolean; -}; - -/** - * @deprecated use the @dbeaver/ui-kit package instead - */ -export const MenuItem: ReakitProxyComponent<'button', MenuItemOptions> = observer>( - function MenuItem({ children, hidden, selected, close, onClick, className, ...rest }) { - const menu = useContext(MenuStateContext); - const styles = useS(style); - - const handleClick = useCombinedHandler<[React.MouseEvent]>(onClick, function handleClick() { - if (close) { - menu?.hide(); - } - }); - - const MenuItem = ReakitMenuItem; - - return ( - - ); - }, -) as ReakitProxyComponent<'button', MenuItemOptions>; diff --git a/webapp/packages/core-blocks/src/Menu/MenuPanel.module.css b/webapp/packages/core-blocks/src/Menu/MenuPanel.module.css deleted file mode 100644 index 1880d7f0ab..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuPanel.module.css +++ /dev/null @@ -1,34 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -.menu { - outline: none; - z-index: 999; -} -.menuBox { - composes: theme-background-surface theme-text-on-surface theme-group-element-radius theme-typography--body2 theme-elevation-z5 from global; - composes: menuBox from './MenuItemElement.module.css'; - - display: flex; - flex-direction: column; - min-width: 140px; - padding: 6px 0; - - & .menuBox { - margin-top: -6px; - } -} - -.menu.modal .menuBox { - overflow: auto; - max-height: 80vh; - overflow-x: hidden; -} - -.menu.submenu { - margin-top: -6px; -} diff --git a/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx b/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx deleted file mode 100644 index 404469be68..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuPanel.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite'; -import { Children, forwardRef } from 'react'; -import { Menu, type MenuStateReturn } from 'reakit'; - -import { ErrorBoundary } from '../ErrorBoundary.js'; -import { getComputed } from '../getComputed.js'; -import { useTranslate } from '../localization/useTranslate.js'; -import { s } from '../s.js'; -import { useS } from '../useS.js'; -import { MenuEmptyItem } from './MenuEmptyItem.js'; -import style from './MenuPanel.module.css'; -import styleMenuItemElement from './MenuItemElement.module.css'; - -export interface IMenuPanelProps { - label: string; - menu: MenuStateReturn; // from reakit useMenuState - panelAvailable?: boolean; - hasBindings?: boolean; - getHasBindings?: () => boolean; - children: React.ReactNode | (() => React.ReactNode); - rtl?: boolean; - submenu?: boolean; - className?: string; -} - -/** - * @deprecated use the @dbeaver/ui-kit package instead - */ -export const MenuPanel = observer( - forwardRef(function MenuPanel({ label, menu, submenu, panelAvailable = true, rtl, getHasBindings, hasBindings, children, className }, ref) { - const translate = useTranslate(); - const styles = useS(style, styleMenuItemElement); - const visible = menu.visible; - - if (!visible) { - return null; - } - - hasBindings = panelAvailable && (hasBindings || getComputed(() => getHasBindings?.())); - - let renderedChildren: React.ReactNode = <>; - - if (panelAvailable) { - renderedChildren = typeof children === 'function' ? children() : children; - } - - return ( - - -
- {Children.count(renderedChildren) === 0 && } - {renderedChildren} -
-
-
- ); - }), -); diff --git a/webapp/packages/core-blocks/src/Menu/MenuStateContext.ts b/webapp/packages/core-blocks/src/Menu/MenuStateContext.ts deleted file mode 100644 index 8b3280b6b3..0000000000 --- a/webapp/packages/core-blocks/src/Menu/MenuStateContext.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 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 type { MenuStateReturn } from 'reakit'; - -export type IMenuState = MenuStateReturn; - -export const MenuStateContext = createContext(null); diff --git a/webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts b/webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts deleted file mode 100644 index 9e58300060..0000000000 --- a/webapp/packages/core-blocks/src/Menu/ReakitProxyComponent.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 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 type { As, PropsWithAs } from 'reakit-utils/types'; - -export type ReakitProxyPropsWithAs = PropsWithAs; - -export type ReakitProxyComponentOptions = ReakitProxyPropsWithAs; - -export type ReakitProxyComponent = { - ( - props: ReakitProxyPropsWithAs & { - as: TT; - }, - context?: any, - ): React.ReactElement | null; - (props: ReakitProxyPropsWithAs, context?: any): React.ReactElement | null; -}; diff --git a/webapp/packages/core-blocks/src/index.ts b/webapp/packages/core-blocks/src/index.ts index a94c34875f..7fcad9c718 100644 --- a/webapp/packages/core-blocks/src/index.ts +++ b/webapp/packages/core-blocks/src/index.ts @@ -58,17 +58,8 @@ export * from './ConnectionImageWithMask/ConnectionImageWithMask.js'; export { default as ConnectionImageWithMaskSvgStyles } from './ConnectionImageWithMask/ConnectionImageWithMaskSvg.module.css'; export * from './Menu/AriaKit/MenuAriaKit.js'; -export * from './Menu/Menu.js'; -export { default as MenuStyles } from './Menu/Menu.module.css'; -export * from './Menu/MenuBarSmallItem.js'; -export * from './Menu/MenuEmptyItem.js'; -export * from './Menu/MenuItem.js'; -export { default as MenuItemStyles } from './Menu/MenuItem.module.css'; export * from './Menu/MenuItemElement.js'; export { default as MenuItemElementStyles } from './Menu/MenuItemElement.module.css'; -export * from './Menu/MenuPanel.js'; -export { default as MenuPanelStyles } from './Menu/MenuPanel.module.css'; -export * from './Menu/MenuStateContext.js'; export * from './Menu/useContextMenuPosition.js'; export * from './ObjectPropertyInfo/ObjectPropertyInfoForm/ObjectPropertyInfoFormLoader.js'; diff --git a/webapp/packages/core-notifications/package.json b/webapp/packages/core-notifications/package.json index 37c9e02212..0f20a7aa88 100644 --- a/webapp/packages/core-notifications/package.json +++ b/webapp/packages/core-notifications/package.json @@ -25,11 +25,11 @@ "@cloudbeaver/core-blocks": "workspace:*", "@cloudbeaver/core-di": "workspace:*", "@cloudbeaver/core-events": "workspace:*", + "@dbeaver/ui-kit": "workspace:^", "mobx": "^6", "mobx-react-lite": "^4", "react": "^19", "react-dom": "^19", - "reakit": "^1", "tslib": "^2" }, "devDependencies": { diff --git a/webapp/packages/core-notifications/src/Notifications.tsx b/webapp/packages/core-notifications/src/Notifications.tsx index 0730b37924..8a36bc2f98 100644 --- a/webapp/packages/core-notifications/src/Notifications.tsx +++ b/webapp/packages/core-notifications/src/Notifications.tsx @@ -5,12 +5,13 @@ * 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 { Portal } from 'reakit'; import { s, useS } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; +import { Portal } from '@dbeaver/ui-kit'; import styles from './Notifications.module.css'; import { NotificationsItem } from './NotificationsItem/NotificationsItem.js'; diff --git a/webapp/packages/core-notifications/tsconfig.json b/webapp/packages/core-notifications/tsconfig.json index 40adf4cbe0..ca5c074904 100644 --- a/webapp/packages/core-notifications/tsconfig.json +++ b/webapp/packages/core-notifications/tsconfig.json @@ -7,6 +7,9 @@ "composite": true }, "references": [ + { + "path": "../../common-react/@dbeaver/ui-kit" + }, { "path": "../core-blocks" }, diff --git a/webapp/packages/core-ui/package.json b/webapp/packages/core-ui/package.json index a43ad85f91..99d005d47f 100644 --- a/webapp/packages/core-ui/package.json +++ b/webapp/packages/core-ui/package.json @@ -42,7 +42,6 @@ "react-dnd": "^16", "react-dnd-html5-backend": "^16", "react-dom": "^19", - "reakit": "^1", "tslib": "^2" }, "devDependencies": { diff --git a/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx b/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx index cb970a2fa2..36c547c471 100644 --- a/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx +++ b/webapp/packages/core-ui/src/ContextMenu/ContextMenu.tsx @@ -14,7 +14,7 @@ import { MenuButton, MenuProvider, Menu, type HovercardStoreState, useMenuStore, import { RenderMenuItems } from './RenderMenuItems.js'; import { type IMenuContext, MenuContext } from './MenuContext.js'; -export interface IContextMenuNewProps extends Omit { +export interface IContextMenuNewProps extends IContextMenuProps { render?: React.ReactElement; placement?: HovercardStoreState['placement']; showOnHover?: boolean; diff --git a/webapp/packages/core-ui/src/ContextMenu/IContextMenuProps.ts b/webapp/packages/core-ui/src/ContextMenu/IContextMenuProps.ts index 6fe7f03387..da94454062 100644 --- a/webapp/packages/core-ui/src/ContextMenu/IContextMenuProps.ts +++ b/webapp/packages/core-ui/src/ContextMenu/IContextMenuProps.ts @@ -1,12 +1,12 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2025 DBeaver Corp and others + * Copyright (C) 2020-2026 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 type { ButtonHTMLAttributes } from 'react'; -import type { MenuInitialState } from 'reakit'; import type { IContextMenuPosition } from '@cloudbeaver/core-blocks'; import type { IMenuData } from '@cloudbeaver/core-view'; @@ -21,7 +21,6 @@ export type ContextMenuRenderingChildren = (props: IContextMenuBaseProps) => Rea export interface IContextMenuProps extends Omit, 'children'> { contextMenuPosition?: IContextMenuPosition; menu: IMenuData; - placement?: MenuInitialState['placement']; visible?: boolean; rtl?: boolean; children?: React.ReactNode; diff --git a/webapp/packages/plugin-authentication-administration/package.json b/webapp/packages/plugin-authentication-administration/package.json index 115266a3e5..0a848cc86b 100644 --- a/webapp/packages/plugin-authentication-administration/package.json +++ b/webapp/packages/plugin-authentication-administration/package.json @@ -48,7 +48,6 @@ "mobx-react-lite": "^4", "react": "^19", "react-dom": "^19", - "reakit": "^1", "tslib": "^2" }, "devDependencies": { diff --git a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx index f5669f319e..c84af42db1 100644 --- a/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx +++ b/webapp/packages/plugin-connections/src/ConnectionForm/SSH/SSHKeyUploader.tsx @@ -52,7 +52,7 @@ export const SSHKeyUploader = observer(function SSHKeyUploader({ state, s - diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/package.json b/webapp/packages/plugin-data-viewer-result-set-grouping/package.json index 4b153065e4..5ebc71e008 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/package.json +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/package.json @@ -35,6 +35,7 @@ "@cloudbeaver/core-view": "workspace:*", "@cloudbeaver/plugin-data-viewer": "workspace:*", "@cloudbeaver/plugin-sql-editor": "workspace:*", + "@dbeaver/ui-kit": "workspace:*", "mobx": "^6", "mobx-react-lite": "^4", "react": "^19", diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVGroupingColumnEditorDialog/GroupingTableItem.tsx b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVGroupingColumnEditorDialog/GroupingTableItem.tsx index b01f1b26d0..32ead62f19 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVGroupingColumnEditorDialog/GroupingTableItem.tsx +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/src/DVGroupingColumnEditorDialog/GroupingTableItem.tsx @@ -1,13 +1,15 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2026 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 { observer } from 'mobx-react-lite'; -import { IconButton, TableColumnValue, TableItem } from '@cloudbeaver/core-blocks'; +import { Icon, TableColumnValue, TableItem, useTranslate } from '@cloudbeaver/core-blocks'; +import { IconButton } from '@dbeaver/ui-kit'; interface Props { id: string; @@ -17,13 +19,17 @@ interface Props { } export const GroupingTableItem = observer(function GroupingTableItem({ id, name, className, onDelete }) { + const translate = useTranslate(); + return ( {name} - onDelete(id)} /> + onDelete(id)}> + + ); diff --git a/webapp/packages/plugin-data-viewer-result-set-grouping/tsconfig.json b/webapp/packages/plugin-data-viewer-result-set-grouping/tsconfig.json index 35c15896ac..e189710694 100644 --- a/webapp/packages/plugin-data-viewer-result-set-grouping/tsconfig.json +++ b/webapp/packages/plugin-data-viewer-result-set-grouping/tsconfig.json @@ -7,6 +7,9 @@ "composite": true }, "references": [ + { + "path": "../../common-react/@dbeaver/ui-kit" + }, { "path": "../core-blocks" }, diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx index 8af46221c3..da628777ee 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableHeader/TableWhereFilter.tsx @@ -1,10 +1,11 @@ /* * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others + * Copyright (C) 2020-2026 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 { observer } from 'mobx-react-lite'; import { useRef } from 'react'; @@ -17,6 +18,7 @@ import { useTranslate, } from '@cloudbeaver/core-blocks'; import { InlineEditor } from '@cloudbeaver/core-ui'; +import { CompositeProvider, Popover, useCompositeStore } from '@dbeaver/ui-kit'; import type { ITableHeaderPlaceholderProps } from './TableHeaderService.js'; import styles from './TableWhereFilter.module.css'; @@ -30,10 +32,15 @@ export const TableWhereFilter: PlaceholderComponent(null); + + const store = useCompositeStore(); const autocompleteState = useInputAutocomplete(inputRef, { separator: AUTOCOMPLETE_WORD_SEPARATOR, sourceHints: data.hintProposals ?? [], matchStrategy: 'fuzzy', + onNavigate: () => { + store.move(store.first()); + }, }); if (!state.supported) { @@ -55,26 +62,30 @@ export const TableWhereFilter: PlaceholderComponent - - + + 0}> + + + + + + ); }); diff --git a/webapp/packages/plugin-log-viewer/package.json b/webapp/packages/plugin-log-viewer/package.json index 69daa1426f..121a73688b 100644 --- a/webapp/packages/plugin-log-viewer/package.json +++ b/webapp/packages/plugin-log-viewer/package.json @@ -34,6 +34,7 @@ "@cloudbeaver/core-utils": "workspace:*", "@cloudbeaver/core-view": "workspace:*", "@cloudbeaver/plugin-tools-panel": "workspace:*", + "@dbeaver/ui-kit": "workspace:^", "mobx": "^6", "mobx-react-lite": "^4", "react": "^19", diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.module.css b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.module.css index 697218a078..eda3d55b93 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.module.css +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.module.css @@ -26,10 +26,6 @@ padding: 4px; } -.button { - flex: unset; -} - .type { composes: theme-typography--body2 from global; margin: 0; diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx index 80adde202b..bc7bb0a2ab 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerInfoPanel.tsx @@ -8,7 +8,8 @@ import { observer } from 'mobx-react-lite'; import { useCallback } from 'react'; -import { Container, MenuBarSmallItem, s, Textarea, useClipboard, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { Container, s, Textarea, useClipboard, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { Button } from '@dbeaver/ui-kit'; import type { ILogEntry } from './ILogEntry.js'; import classes from './LogViewerInfoPanel.module.css'; @@ -34,12 +35,25 @@ export const LogViewerInfoPanel = observer(function LogViewerInfoPanel({ - + + +
diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.module.css b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.module.css index 3d000a41c9..f18e965c6f 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.module.css +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.module.css @@ -42,11 +42,4 @@ .timestamp { width: 116px; min-width: 116px; -} - -.clearButton { - position: absolute !important; - top: 4px; - right: 16px; - z-index: 100; -} +} \ No newline at end of file diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.tsx b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.tsx index 587b7be20d..4fb754cdcb 100644 --- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.tsx +++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerTable.tsx @@ -7,7 +7,8 @@ */ import { observer } from 'mobx-react-lite'; -import { Container, MenuBarSmallItem, s, Table, TableBody, TableColumnHeader, TableHeader, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { Container, Icon, s, Table, TableBody, TableColumnHeader, TableHeader, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { Button, ButtonIcon } from '@dbeaver/ui-kit'; import type { ILogEntry } from './ILogEntry.js'; import { LogEntry } from './LogEntry.js'; @@ -26,15 +27,18 @@ export const LogViewerTable = observer(function LogViewerTable({ items, s return ( - + + + {translate('ui_clear')} - + diff --git a/webapp/packages/plugin-log-viewer/tsconfig.json b/webapp/packages/plugin-log-viewer/tsconfig.json index 35f4c3fb84..f6812f382d 100644 --- a/webapp/packages/plugin-log-viewer/tsconfig.json +++ b/webapp/packages/plugin-log-viewer/tsconfig.json @@ -10,6 +10,9 @@ { "path": "../../common-react/@dbeaver/react-tests" }, + { + "path": "../../common-react/@dbeaver/ui-kit" + }, { "path": "../../common-typescript/@dbeaver/cli" }, diff --git a/webapp/packages/plugin-object-viewer/package.json b/webapp/packages/plugin-object-viewer/package.json index 14b8772d6c..30cddb3ba2 100644 --- a/webapp/packages/plugin-object-viewer/package.json +++ b/webapp/packages/plugin-object-viewer/package.json @@ -46,7 +46,6 @@ "mobx-react-lite": "^4", "react": "^19", "react-dom": "^19", - "reakit": "^1", "tslib": "^2" }, "devDependencies": { diff --git a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/FolderContext.ts b/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/FolderContext.ts deleted file mode 100644 index cb4f3f272a..0000000000 --- a/webapp/packages/plugin-object-viewer/src/ObjectPropertiesPage/FolderContext.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 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 type { TabStateReturn } from 'reakit'; - -export const FolderContext = createContext(undefined); diff --git a/webapp/packages/plugin-sql-editor-new/src/SQLEditor/SQLCodeEditorPanel/SQLCodeEditorPanel.tsx b/webapp/packages/plugin-sql-editor-new/src/SQLEditor/SQLCodeEditorPanel/SQLCodeEditorPanel.tsx index 0e70e575ab..7d64688899 100644 --- a/webapp/packages/plugin-sql-editor-new/src/SQLEditor/SQLCodeEditorPanel/SQLCodeEditorPanel.tsx +++ b/webapp/packages/plugin-sql-editor-new/src/SQLEditor/SQLCodeEditorPanel/SQLCodeEditorPanel.tsx @@ -8,7 +8,7 @@ import { observer } from 'mobx-react-lite'; import { useState } from 'react'; -import { MenuBarSmallItem, useExecutor, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { Button, useExecutor, useS, useTranslate } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; import { DATA_CONTEXT_NAV_NODE, getNodesFromContext, NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; @@ -129,14 +129,24 @@ export const SQLCodeEditorPanel: TabContainerPanelComponent {data.isIncomingChanges && ( <> - + - + )} diff --git a/webapp/yarn.lock b/webapp/yarn.lock index af485d524b..b2d82bef4e 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -1482,8 +1482,6 @@ __metadata: react-dom: "npm:^19" react-hotkeys-hook: "npm:5.1.0" react-minisearch: "npm:^7" - reakit: "npm:^1" - reakit-utils: "npm:^0" rimraf: "npm:^6" subscript: "npm:^9" tslib: "npm:^2" @@ -1826,12 +1824,12 @@ __metadata: "@cloudbeaver/core-di": "workspace:*" "@cloudbeaver/core-events": "workspace:*" "@cloudbeaver/tsconfig": "workspace:*" + "@dbeaver/ui-kit": "workspace:^" "@types/react": "npm:^19" mobx: "npm:^6" mobx-react-lite: "npm:^4" react: "npm:^19" react-dom: "npm:^19" - reakit: "npm:^1" rimraf: "npm:^6" tslib: "npm:^2" typescript: "npm:^5" @@ -2246,7 +2244,6 @@ __metadata: react-dnd: "npm:^16" react-dnd-html5-backend: "npm:^16" react-dom: "npm:^19" - reakit: "npm:^1" rimraf: "npm:^6" tslib: "npm:^2" typescript: "npm:^5" @@ -2519,7 +2516,6 @@ __metadata: mobx-react-lite: "npm:^4" react: "npm:^19" react-dom: "npm:^19" - reakit: "npm:^1" rimraf: "npm:^6" tslib: "npm:^2" typescript: "npm:^5" @@ -3076,6 +3072,7 @@ __metadata: "@cloudbeaver/plugin-data-viewer": "workspace:*" "@cloudbeaver/plugin-sql-editor": "workspace:*" "@cloudbeaver/tsconfig": "workspace:*" + "@dbeaver/ui-kit": "workspace:*" "@types/react": "npm:^19" mobx: "npm:^6" mobx-react-lite: "npm:^4" @@ -3433,6 +3430,7 @@ __metadata: "@cloudbeaver/tsconfig": "workspace:*" "@dbeaver/cli": "workspace:*" "@dbeaver/react-tests": "workspace:*" + "@dbeaver/ui-kit": "workspace:^" "@types/react": "npm:^19" mobx: "npm:^6" mobx-react-lite: "npm:^4" @@ -3636,7 +3634,6 @@ __metadata: mobx-react-lite: "npm:^4" react: "npm:^19" react-dom: "npm:^19" - reakit: "npm:^1" rimraf: "npm:^6" tslib: "npm:^2" typescript: "npm:^5" @@ -7460,13 +7457,6 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.5.4": - version: 2.11.8 - resolution: "@popperjs/core@npm:2.11.8" - checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 - languageName: node - linkType: hard - "@react-dnd/asap@npm:^5.0.1": version: 5.0.2 resolution: "@react-dnd/asap@npm:5.0.2" @@ -10058,13 +10048,6 @@ __metadata: languageName: node linkType: hard -"body-scroll-lock@npm:^3.1.5": - version: 3.1.5 - resolution: "body-scroll-lock@npm:3.1.5" - checksum: 10c0/657c948d64ffe17d2c89958f57c2c636203cf5216e3ba33ad76604bf1b5144fd8f4b5d832d09105f8782d5b8bc96f38780331ec55f3af5f27694dff38a0cc9d7 - languageName: node - linkType: hard - "boolbase@npm:^1.0.0": version: 1.0.0 resolution: "boolbase@npm:1.0.0" @@ -10570,7 +10553,6 @@ __metadata: prettier: "npm:^3.6.2" react: "npm:^19" react-dom: "npm:^19" - reakit: "npm:^1" rimraf: "npm:^6" typescript: "npm:^5.8.3" typescript-plugin-css-modules: "npm:^5" @@ -17066,55 +17048,6 @@ __metadata: languageName: node linkType: hard -"reakit-system@npm:^0.15.2": - version: 0.15.2 - resolution: "reakit-system@npm:0.15.2" - dependencies: - reakit-utils: "npm:^0.15.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - checksum: 10c0/bd97e297b972e205656dd99a6955ed263d5102ab24212e55b90a86dd9a4eac056b63ba882af65705036922e9cb599d5903318d1202086a3e4ee45b5cc794d44e - languageName: node - linkType: hard - -"reakit-utils@npm:^0, reakit-utils@npm:^0.15.2": - version: 0.15.2 - resolution: "reakit-utils@npm:0.15.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - checksum: 10c0/258654f9510fb7622fc03f81a63021721ace6c424bdff47a8f79e3b974501ef6b1b44fdb78ab01ed1a75d3fd6867d100e97ef74138c0d848c2aa5738477bf853 - languageName: node - linkType: hard - -"reakit-warning@npm:^0.6.2": - version: 0.6.2 - resolution: "reakit-warning@npm:0.6.2" - dependencies: - reakit-utils: "npm:^0.15.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 - checksum: 10c0/e93856e9dd4b56e7cd36cd654cb5688eb05fc8f75e3d89069352bc61ab6f6cf501892405dd1612442e45880562048af5c17b3e771fd6af79348bc90a20f8d930 - languageName: node - linkType: hard - -"reakit@npm:^1": - version: 1.3.11 - resolution: "reakit@npm:1.3.11" - dependencies: - "@popperjs/core": "npm:^2.5.4" - body-scroll-lock: "npm:^3.1.5" - reakit-system: "npm:^0.15.2" - reakit-utils: "npm:^0.15.2" - reakit-warning: "npm:^0.6.2" - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - checksum: 10c0/ce5972b1242bd0704840c77faa6f687cc3bd0e66ac5f6fe84328408d2e624a4532c4bb1d82b6b6dcbc876dc0700c472b420acebf80603d59115a810ae8916e12 - languageName: node - linkType: hard - "recast@npm:^0.23.5": version: 0.23.11 resolution: "recast@npm:0.23.11"