Skip to content

Commit d15839b

Browse files
authored
fix: improvements for toolbar hidden actions (#155)
1 parent c4fdcbc commit d15839b

File tree

9 files changed

+132
-65
lines changed

9 files changed

+132
-65
lines changed

src/i18n/common/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"toolbar_action_disabled": "Incompatible markup element"
3+
}

src/i18n/common/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {registerKeyset} from '../i18n';
2+
3+
import en from './en.json';
4+
import ru from './ru.json';
5+
6+
const KEYSET = 'common';
7+
8+
export const i18n = registerKeyset(KEYSET, {en, ru});

src/i18n/common/ru.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"toolbar_action_disabled": "Несовместимый элемент разметки"
3+
}

src/toolbar/FlexToolbar.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ export function FlexToolbar<E>(props: FlexToolbarProps<E>) {
6969
onClick={props.onClick}
7070
className={b('dots')}
7171
alwaysActive={true}
72-
hideDisabled={true}
7372
/>
7473
)}
7574
</div>

src/toolbar/ToolbarButton.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.ye-toolbar-button {
2+
&__action-disabled-tooltip {
3+
min-height: fit-content;
4+
padding: 6px 12px;
5+
}
6+
}

src/toolbar/ToolbarButton.tsx

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import React from 'react';
1+
import React, {useRef} from 'react';
22
import isFunction from 'lodash/isFunction';
3-
import {ActionTooltip, Button, Icon} from '@gravity-ui/uikit';
3+
import {ActionTooltip, Button, Icon, Popover} from '@gravity-ui/uikit';
44
import {cn} from '../classname';
5+
import {i18n} from '../i18n/common';
56
import {ToolbarTooltipDelay} from './const';
67
import type {ToolbarBaseProps, ToolbarItemData} from './types';
78

9+
import './ToolbarButton.scss';
10+
811
const b = cn('toolbar-button');
912

1013
export type ToolbarButtonProps<E> = ToolbarBaseProps<E> & ToolbarItemData<E>;
@@ -16,6 +19,7 @@ export function ToolbarButton<E>({
1619
hotkey,
1720
editor,
1821
icon,
22+
disabledPopoverVisible = true,
1923
exec,
2024
focus,
2125
onClick,
@@ -25,31 +29,40 @@ export function ToolbarButton<E>({
2529
const active = isActive(editor);
2630
const enabled = isEnable(editor);
2731
const disabled = !active && !enabled;
32+
const buttonRef = useRef<HTMLElement>(null);
2833

2934
const titleText: string = isFunction(title) ? title() : title;
3035

3136
return (
32-
<ActionTooltip
33-
openDelay={ToolbarTooltipDelay.Open}
34-
closeDelay={ToolbarTooltipDelay.Close}
35-
title={titleText}
36-
hotkey={hotkey}
37+
<Popover
38+
content={i18n('toolbar_action_disabled')}
39+
disabled={!disabledPopoverVisible || !disabled}
40+
tooltipContentClassName={b('action-disabled-tooltip')}
41+
placement={['bottom']}
3742
>
38-
<Button
39-
size="m"
40-
selected={active}
41-
disabled={disabled}
42-
view={active ? 'normal' : 'flat'}
43-
onClick={() => {
44-
focus();
45-
exec(editor);
46-
onClick?.(id);
47-
}}
48-
className={b(null, [className])}
49-
extraProps={{'aria-label': titleText}}
43+
<ActionTooltip
44+
openDelay={ToolbarTooltipDelay.Open}
45+
closeDelay={ToolbarTooltipDelay.Close}
46+
title={titleText}
47+
hotkey={hotkey}
5048
>
51-
<Icon data={icon.data} size={icon.size ?? 16} />
52-
</Button>
53-
</ActionTooltip>
49+
<Button
50+
ref={buttonRef}
51+
size="m"
52+
selected={active}
53+
disabled={disabled}
54+
view={active ? 'normal' : 'flat'}
55+
onClick={() => {
56+
focus();
57+
exec(editor);
58+
onClick?.(id);
59+
}}
60+
className={b(null, [className])}
61+
extraProps={{'aria-label': titleText}}
62+
>
63+
<Icon data={icon.data} size={icon.size ?? 16} />
64+
</Button>
65+
</ActionTooltip>
66+
</Popover>
5467
);
5568
}

src/toolbar/ToolbarListButton.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
display: flex;
2727
align-items: center;
2828
column-gap: 8px;
29+
30+
.yc-icon {
31+
display: block;
32+
}
2933
}
3034

3135
&__hint {
@@ -36,4 +40,17 @@
3640
display: flex;
3741
}
3842
}
43+
44+
&__action-disabled-popover {
45+
display: block;
46+
47+
.yc-popover__handler {
48+
display: block;
49+
}
50+
}
51+
52+
&__action-disabled-tooltip {
53+
min-height: fit-content;
54+
padding: 6px 12px;
55+
}
3956
}

src/toolbar/ToolbarListButton.tsx

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import React from 'react';
22
import isFunction from 'lodash/isFunction';
3-
import {Button, Hotkey, Icon, Menu, Popup, Tooltip} from '@gravity-ui/uikit';
3+
import {Button, Hotkey, Icon, Menu, Popover, Popup, Tooltip} from '@gravity-ui/uikit';
44
import {HelpPopover} from '@gravity-ui/components';
55
import {ChevronDown} from '@gravity-ui/icons';
66

77
import {cn} from '../classname';
8+
import {i18n} from '../i18n/common';
89
import {useBooleanState} from '../react-utils/hooks';
910
import {ToolbarTooltipDelay} from './const';
1011
import {ToolbarBaseProps, ToolbarIconData, ToolbarItemData} from './types';
@@ -34,7 +35,6 @@ export function ToolbarListButton<E>({
3435
withArrow,
3536
data,
3637
alwaysActive,
37-
hideDisabled,
3838
}: ToolbarListButtonProps<E>) {
3939
const buttonRef = React.useRef<HTMLButtonElement>(null);
4040
const [open, , hide, toggleOpen] = useBooleanState(false);
@@ -62,58 +62,75 @@ export function ToolbarListButton<E>({
6262

6363
return (
6464
<>
65-
<Tooltip
66-
content={titleText}
67-
disabled={popupOpen}
68-
openDelay={ToolbarTooltipDelay.Open}
69-
closeDelay={ToolbarTooltipDelay.Close}
65+
<Popover
66+
className={b('action-disabled-popover')}
67+
tooltipContentClassName={b('action-disabled-tooltip')}
68+
content={i18n('toolbar_action_disabled')}
69+
placement={'bottom'}
70+
disabled={!everyDisabled}
7071
>
71-
<Button
72-
size="m"
73-
ref={buttonRef}
74-
view={someActive || popupOpen ? 'normal' : 'flat'}
75-
selected={someActive}
76-
disabled={everyDisabled}
77-
className={b({arrow: withArrow}, [className])}
78-
onClick={toggleOpen}
72+
<Tooltip
73+
content={titleText}
74+
disabled={popupOpen}
75+
openDelay={ToolbarTooltipDelay.Open}
76+
closeDelay={ToolbarTooltipDelay.Close}
7977
>
80-
{buttonContent}
81-
</Button>
82-
</Tooltip>
78+
<Button
79+
size="m"
80+
ref={buttonRef}
81+
view={someActive || popupOpen ? 'normal' : 'flat'}
82+
selected={someActive}
83+
disabled={everyDisabled}
84+
className={b({arrow: withArrow}, [className])}
85+
onClick={toggleOpen}
86+
>
87+
{buttonContent}
88+
</Button>
89+
</Tooltip>
90+
</Popover>
8391
<Popup anchorRef={buttonRef} open={popupOpen} onClose={hide}>
8492
<Menu size="l" className={b('menu')}>
8593
{data
8694
.map(({id, title, icon, hotkey, isActive, isEnable, exec, hint}) => {
8795
const titleText = isFunction(title) ? title() : title;
8896
const hintText = isFunction(hint) ? hint() : hint;
8997
const disabled = !isEnable(editor);
90-
return hideDisabled && disabled ? null : (
91-
<Menu.Item
98+
return (
99+
<Popover
100+
className={b('action-disabled-popover')}
101+
tooltipContentClassName={b('action-disabled-tooltip')}
102+
content={i18n('toolbar_action_disabled')}
103+
placement={'left'}
104+
disabled={!disabled}
92105
key={id}
93-
active={isActive(editor)}
94-
disabled={!isEnable(editor)}
95-
onClick={() => {
96-
hide();
97-
focus();
98-
exec(editor);
99-
onClick?.(id);
100-
}}
101-
icon={<Icon data={icon.data} size={icon.size ?? 16} />}
102-
extraProps={{'aria-label': titleText}}
103106
>
104-
<div className={b('item')}>
105-
{titleText}
106-
<div className={b('extra')}>
107-
{hotkey && <Hotkey value={hotkey} />}
108-
{hintText && (
109-
<HelpPopover
110-
className={b('hint')}
111-
content={hintText}
112-
/>
113-
)}
107+
<Menu.Item
108+
key={id}
109+
active={isActive(editor)}
110+
disabled={!isEnable(editor)}
111+
onClick={() => {
112+
hide();
113+
focus();
114+
exec(editor);
115+
onClick?.(id);
116+
}}
117+
icon={<Icon data={icon.data} size={icon.size ?? 16} />}
118+
extraProps={{'aria-label': titleText}}
119+
>
120+
<div className={b('item')}>
121+
{titleText}
122+
<div className={b('extra')}>
123+
{hotkey && <Hotkey value={hotkey} />}
124+
{hintText && (
125+
<HelpPopover
126+
className={b('hint')}
127+
content={hintText}
128+
/>
129+
)}
130+
</div>
114131
</div>
115-
</div>
116-
</Menu.Item>
132+
</Menu.Item>
133+
</Popover>
117134
);
118135
})
119136
.filter(Boolean)}

src/toolbar/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export type ToolbarItemData<E> = {
1616
title: string | (() => string);
1717
hint?: string | (() => string);
1818
hotkey?: HotkeyProps['value'];
19+
disabledPopoverVisible?: boolean;
1920
exec(editor: E): void;
2021
isActive(editor: E): boolean;
2122
isEnable(editor: E): boolean;

0 commit comments

Comments
 (0)