mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-13 07:47:05 +08:00
ui fixes
This commit is contained in:
@@ -86,8 +86,6 @@
|
||||
}
|
||||
|
||||
.dbv-kit-menu__separator {
|
||||
height: 1px;
|
||||
margin: 0.25rem 0;
|
||||
background-color: var(--dbv-kit-menu-separator-color);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
--dbv-kit-menu-popover-shadow: var(--tw-shadow-md);
|
||||
--dbv-kit-menu-popover-max-height: 18rem;
|
||||
|
||||
--dbv-kit-menu-item-padding-inline: calc(var(--tw-spacing) * 3);
|
||||
--dbv-kit-menu-item-padding-block: var(--tw-spacing);
|
||||
--dbv-kit-menu-item-padding-inline: calc(var(--tw-spacing) * 5);
|
||||
--dbv-kit-menu-item-padding-block: calc(var(--tw-spacing) * 1.4);
|
||||
--dbv-kit-menu-item-hover-background: var(--tw-color-gray-200);
|
||||
--dbv-kit-menu-item-hover-foreground: var(--dbv-kit-menu-foreground);
|
||||
--dbv-kit-menu-item-selected-background: var(--dbv-kit-color-primary-100);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
}
|
||||
|
||||
.dbv-kit-menu__button {
|
||||
--dbv-kit-menu-background: var(--theme-input-background);
|
||||
--dbv-kit-menu-foreground: var(--theme-input-color);
|
||||
--dbv-kit-menu-background: transparent;
|
||||
--dbv-kit-menu-foreground: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { forwardRef, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { MenuField, useMenuStore, useStoreState, type MenuFieldProps, type MenuStoreProps } from '@dbeaver/ui-kit';
|
||||
|
||||
import { ErrorBoundary } from '../../ErrorBoundary.js';
|
||||
@@ -25,33 +25,30 @@ export interface IMenuAriaKitProps<Item> extends Omit<MenuFieldProps<Item>, 'sto
|
||||
menuStoreProps?: MenuStoreProps;
|
||||
}
|
||||
|
||||
export const MenuAriaKit = observer(
|
||||
forwardRef(function MenuAriaKit<Item>({ contextMenuPosition, menuStoreProps, ...props }: IMenuAriaKitProps<Item>) {
|
||||
const store = useMenuStore(menuStoreProps);
|
||||
const storeState = useStoreState(store);
|
||||
const menuVisible = !!storeState.open;
|
||||
export const MenuAriaKit = observer(function MenuAriaKit<Item>({ contextMenuPosition, menuStoreProps, ...props }: IMenuAriaKitProps<Item>) {
|
||||
const store = useMenuStore(menuStoreProps);
|
||||
const storeState = useStoreState(store);
|
||||
const menuVisible = !!storeState.open;
|
||||
|
||||
function getAnchorRect() {
|
||||
if (!contextMenuPosition?.position) {
|
||||
return;
|
||||
}
|
||||
|
||||
return () => contextMenuPosition.position;
|
||||
function getAnchorRect() {
|
||||
if (!contextMenuPosition?.position) {
|
||||
return;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!contextMenuPosition?.position || menuVisible) {
|
||||
return;
|
||||
}
|
||||
return () => contextMenuPosition.position;
|
||||
}
|
||||
|
||||
store.show();
|
||||
contextMenuPosition.position = null;
|
||||
}, [contextMenuPosition?.position]);
|
||||
useEffect(() => {
|
||||
if (!contextMenuPosition?.position || menuVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<MenuField store={store} getAnchorRect={getAnchorRect()} {...props} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}),
|
||||
) as <Item>(props: IMenuAriaKitProps<Item> & React.RefAttributes<HTMLButtonElement>) => React.ReactElement;
|
||||
store.show();
|
||||
}, [contextMenuPosition?.position]);
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<MenuField store={store} getAnchorRect={getAnchorRect()} {...props} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}) as <Item>(props: IMenuAriaKitProps<Item> & React.RefAttributes<HTMLButtonElement>) => React.ReactElement;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
import { getComputed, MenuAriaKit, useAutoLoad, useObjectRef, useTranslate, type IMenuAriaKitProps } from '@cloudbeaver/core-blocks';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
import { MenuActionItem, type IMenuData, type IMenuItem } from '@cloudbeaver/core-view';
|
||||
import { MenuItemRendererAriaKit } from './MenuItemRendererAriaKit.js';
|
||||
@@ -16,50 +15,52 @@ export interface IContextMenuAriaKitProps extends Omit<IMenuAriaKitProps<IMenuIt
|
||||
menu: IMenuData;
|
||||
}
|
||||
|
||||
export const ContextMenuAriaKit = observer<IContextMenuAriaKitProps, HTMLButtonElement>(
|
||||
forwardRef(function ContextMenuAriaKit({ contextMenuPosition, menu: menuData, onSwitch, ...props }, ref) {
|
||||
const translate = useTranslate();
|
||||
export const ContextMenuAriaKit = observer<IContextMenuAriaKitProps>(function ContextMenuAriaKit({
|
||||
contextMenuPosition,
|
||||
menu: menuData,
|
||||
onSwitch,
|
||||
...props
|
||||
}) {
|
||||
const translate = useTranslate();
|
||||
|
||||
const handler = menuData.handler;
|
||||
const hidden = getComputed(() => handler?.isHidden?.(menuData.context) || false);
|
||||
const loading = getComputed(() => handler?.isLoading?.(menuData.context) || menuData.loaders.some(loader => loader.isLoading()) || false);
|
||||
const disabled = getComputed(() => loading || handler?.isDisabled?.(menuData.context) || false);
|
||||
const lazy = getComputed(() => !menuData.available || hidden);
|
||||
const handler = menuData.handler;
|
||||
const hidden = getComputed(() => handler?.isHidden?.(menuData.context) || false);
|
||||
const loading = getComputed(() => handler?.isLoading?.(menuData.context) || menuData.loaders.some(loader => loader.isLoading()) || false);
|
||||
const disabled = getComputed(() => loading || handler?.isDisabled?.(menuData.context) || false);
|
||||
const lazy = getComputed(() => !menuData.available || hidden);
|
||||
|
||||
useAutoLoad({ name: `${ContextMenuAriaKit.name}(${menuData.menu.id})` }, menuData.loaders, !lazy, lazy, true);
|
||||
useAutoLoad({ name: `${ContextMenuAriaKit.name}(${menuData.menu.id})` }, menuData.loaders, !lazy, lazy, true);
|
||||
|
||||
const handlers = useObjectRef(
|
||||
() => ({
|
||||
hasBindings() {
|
||||
return this.menuData.items.some(item => item instanceof MenuActionItem && item.action.binding !== null);
|
||||
},
|
||||
handleVisibleSwitch(visible: boolean) {
|
||||
this.onSwitch?.(visible);
|
||||
const handlers = useObjectRef(
|
||||
() => ({
|
||||
hasBindings() {
|
||||
return this.menuData.items.some(item => item instanceof MenuActionItem && item.action.binding !== null);
|
||||
},
|
||||
handleVisibleSwitch(visible: boolean) {
|
||||
this.onSwitch?.(visible);
|
||||
|
||||
if (visible) {
|
||||
this.handler?.handler?.(this.menuData.context);
|
||||
}
|
||||
},
|
||||
}),
|
||||
{ menuData, handler, onSwitch },
|
||||
['hasBindings', 'handleVisibleSwitch'],
|
||||
);
|
||||
if (visible) {
|
||||
this.handler?.handler?.(this.menuData.context);
|
||||
}
|
||||
},
|
||||
}),
|
||||
{ menuData, handler, onSwitch },
|
||||
['hasBindings', 'handleVisibleSwitch'],
|
||||
);
|
||||
|
||||
if (lazy) {
|
||||
return null;
|
||||
}
|
||||
if (lazy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuAriaKit
|
||||
{...props}
|
||||
ref={ref}
|
||||
aria-label={translate(menuData.menu.info.label)}
|
||||
contextMenuPosition={contextMenuPosition}
|
||||
disabled={disabled}
|
||||
items={menuData.items}
|
||||
itemRender={item => <MenuItemRendererAriaKit key={item.id} item={item} menuData={menuData} />}
|
||||
onSwitch={handlers.handleVisibleSwitch}
|
||||
/>
|
||||
);
|
||||
}),
|
||||
);
|
||||
return (
|
||||
<MenuAriaKit
|
||||
{...props}
|
||||
aria-label={translate(menuData.menu.info.label)}
|
||||
contextMenuPosition={contextMenuPosition}
|
||||
disabled={disabled}
|
||||
items={menuData.items}
|
||||
itemRender={item => <MenuItemRendererAriaKit key={item.id} item={item} menuData={menuData} />}
|
||||
onSwitch={handlers.handleVisibleSwitch}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
+20
-13
@@ -13,6 +13,7 @@ import {
|
||||
type IMenuData,
|
||||
type IMenuItem,
|
||||
isMenuCustomItem,
|
||||
MenuActionItem,
|
||||
MenuBaseItem,
|
||||
MenuCheckboxItem,
|
||||
MenuRadioItem,
|
||||
@@ -65,12 +66,28 @@ export const MenuItemRendererAriaKit = observer<IMenuItemRendererAriaKitProps>(f
|
||||
return <AriaMenuSeparator />;
|
||||
}
|
||||
|
||||
if (item instanceof MenuActionItem) {
|
||||
return (
|
||||
<AriaMenuItem hidden={item.hidden} disabled={item.disabled} title={item.action.actionInfo.tooltip} onClick={() => onClick()}>
|
||||
{translate(item.action.actionInfo.label)}
|
||||
</AriaMenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
if (item instanceof MenuBaseItem) {
|
||||
const IconComponent = item.iconComponent?.();
|
||||
const extraProps = item.getExtraProps?.();
|
||||
|
||||
return (
|
||||
<AriaMenuItem aria-label={translate(item.label)} hidden={item.hidden} disabled={item.disabled} onClick={() => onClick()}>
|
||||
<AriaMenuItem
|
||||
id={item.id}
|
||||
aria-label={translate(item.label)}
|
||||
hidden={item.hidden}
|
||||
disabled={item.disabled}
|
||||
style={{ pointerEvents: 'auto' }}
|
||||
focusable
|
||||
onClick={() => onClick()}
|
||||
>
|
||||
{IconComponent ? <IconComponent item={item} {...extraProps} /> : item.icon}
|
||||
{translate(item.label)}
|
||||
</AriaMenuItem>
|
||||
@@ -81,6 +98,7 @@ export const MenuItemRendererAriaKit = observer<IMenuItemRendererAriaKitProps>(f
|
||||
return (
|
||||
<AriaMenuItemCheckbox
|
||||
hidden={item.hidden}
|
||||
id={item.id}
|
||||
aria-label={translate(item.label)}
|
||||
disabled={item.disabled}
|
||||
name={item.id}
|
||||
@@ -97,6 +115,7 @@ export const MenuItemRendererAriaKit = observer<IMenuItemRendererAriaKitProps>(f
|
||||
return (
|
||||
<AriaMenuItemRadio
|
||||
hidden={item.hidden}
|
||||
id={item.id}
|
||||
aria-label={translate(item.label)}
|
||||
disabled={item.disabled}
|
||||
name={item.id}
|
||||
@@ -109,17 +128,5 @@ export const MenuItemRendererAriaKit = observer<IMenuItemRendererAriaKitProps>(f
|
||||
);
|
||||
}
|
||||
|
||||
if (item instanceof MenuBaseItem) {
|
||||
const IconComponent = item.iconComponent?.();
|
||||
const extraProps = item.getExtraProps?.();
|
||||
|
||||
return (
|
||||
<AriaMenuItem aria-label={translate(item.label)} hidden={item.hidden} disabled={item.disabled} onClick={() => onClick()}>
|
||||
{IconComponent ? <IconComponent item={item} {...extraProps} /> : item.icon}
|
||||
{translate(item.label)}
|
||||
</AriaMenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
-2
@@ -7,8 +7,6 @@
|
||||
*/
|
||||
.contextMenu {
|
||||
padding: 0;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
|
||||
&:before {
|
||||
display: none;
|
||||
|
||||
+5
-7
@@ -12,7 +12,7 @@ import { ConnectionInfoResource, DATA_CONTEXT_CONNECTION } from '@cloudbeaver/co
|
||||
import { useDataContextLink } from '@cloudbeaver/core-data-context';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { DATA_CONTEXT_NAV_NODE, type INodeActions, type NavNode } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ContextMenu } from '@cloudbeaver/core-ui';
|
||||
import { ContextMenuAriaKit } from '@cloudbeaver/core-ui';
|
||||
import { useMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
import { MENU_NAV_TREE } from '../../MENU_NAV_TREE.js';
|
||||
@@ -49,14 +49,12 @@ export const TreeNodeMenu = observer<TreeNodeMenuProps>(function TreeNodeMenu({
|
||||
}
|
||||
|
||||
return (
|
||||
<ContextMenu
|
||||
<ContextMenuAriaKit
|
||||
menu={menu}
|
||||
className={s(styles, { contextMenu: true, selected })}
|
||||
contextMenuPosition={contextMenuPosition}
|
||||
modal
|
||||
onVisibleSwitch={handleVisibleSwitch}
|
||||
>
|
||||
<Icon className={s(styles, { icon: true })} name="snack" viewBox="0 0 16 10" />
|
||||
</ContextMenu>
|
||||
buttonElement={<Icon className={s(styles, { icon: true })} name="snack" viewBox="0 0 16 10" />}
|
||||
onSwitch={handleVisibleSwitch}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user