Skip to content

Commit d100d9b

Browse files
authored
feat: ability to add hidden action to toolbar (#144)
1 parent 7313f10 commit d100d9b

File tree

3 files changed

+77
-36
lines changed

3 files changed

+77
-36
lines changed

src/toolbar/FlexToolbar.tsx

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import {ToolbarListButton} from './ToolbarListButton';
88
import {shrinkToolbarData} from './flexible';
99
import {logger} from '../logger';
1010
import {useRenderTime} from '../react-utils/hooks';
11+
import {ToolbarDataType, ToolbarItemData} from './types';
1112

1213
import './FlexToolbar.scss';
1314

1415
const b = cn('flex-toolbar');
1516

1617
export type FlexToolbarProps<E> = ToolbarProps<E> & {
1718
dotsTitle: string | (() => string);
19+
hiddenActions?: ToolbarItemData<E>[];
1820
};
1921

2022
export function FlexToolbar<E>(props: FlexToolbarProps<E>) {
@@ -26,12 +28,32 @@ export function FlexToolbar<E>(props: FlexToolbarProps<E>) {
2628
});
2729
});
2830

29-
const {data, className} = props;
31+
const {data, className, hiddenActions} = props;
32+
3033
const [ref, {width}] = useMeasure<HTMLDivElement>();
31-
const {data: items, dots} = React.useMemo(
32-
() => shrinkToolbarData({data, availableWidth: width}),
33-
[data, width],
34-
);
34+
const {data: items, dots} = React.useMemo(() => {
35+
const toolbarButtonIds = data.reduce((a: string[], toolbarGroup) => {
36+
return [
37+
...a,
38+
...toolbarGroup
39+
.map((toolbarButton) => {
40+
if (toolbarButton.type === ToolbarDataType.ListButton) {
41+
return toolbarButton.data.map((v) => v.id);
42+
}
43+
return toolbarButton.id;
44+
})
45+
.flat(),
46+
];
47+
}, []);
48+
49+
// Finding only actions tha are not present in the main toolbar config
50+
const filteredHiddenAction = hiddenActions?.filter((a) => !toolbarButtonIds.includes(a.id));
51+
return shrinkToolbarData({
52+
data,
53+
availableWidth: width,
54+
hiddenActions: filteredHiddenAction,
55+
});
56+
}, [data, width, hiddenActions]);
3557

3658
return (
3759
<div ref={ref} className={b(null, [className])}>
@@ -46,6 +68,8 @@ export function FlexToolbar<E>(props: FlexToolbarProps<E>) {
4668
focus={props.focus}
4769
onClick={props.onClick}
4870
className={b('dots')}
71+
alwaysActive={true}
72+
hideDisabled={true}
4973
/>
5074
)}
5175
</div>

src/toolbar/ToolbarListButton.tsx

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export type ToolbarListButtonData<E> = {
1818
title: string | (() => string);
1919
withArrow?: boolean;
2020
data: ToolbarItemData<E>[];
21+
alwaysActive?: boolean;
22+
hideDisabled?: boolean;
2123
};
2224

2325
export type ToolbarListButtonProps<E> = ToolbarBaseProps<E> & ToolbarListButtonData<E>;
@@ -31,12 +33,14 @@ export function ToolbarListButton<E>({
3133
title,
3234
withArrow,
3335
data,
36+
alwaysActive,
37+
hideDisabled,
3438
}: ToolbarListButtonProps<E>) {
3539
const buttonRef = React.useRef<HTMLButtonElement>(null);
3640
const [open, , hide, toggleOpen] = useBooleanState(false);
3741

38-
const someActive = data.some((item) => item.isActive(editor));
39-
const everyDisabled = data.every((item) => !item.isEnable(editor));
42+
const someActive = alwaysActive ? false : data.some((item) => item.isActive(editor));
43+
const everyDisabled = alwaysActive ? false : data.every((item) => !item.isEnable(editor));
4044

4145
const popupOpen = everyDisabled ? false : open;
4246
const shouldForceHide = open && !popupOpen;
@@ -78,35 +82,41 @@ export function ToolbarListButton<E>({
7882
</Tooltip>
7983
<Popup anchorRef={buttonRef} open={popupOpen} onClose={hide}>
8084
<Menu size="l" className={b('menu')}>
81-
{data.map(({id, title, icon, hotkey, isActive, isEnable, exec, hint}) => {
82-
const titleText = isFunction(title) ? title() : title;
83-
const hintText = isFunction(hint) ? hint() : hint;
84-
return (
85-
<Menu.Item
86-
key={id}
87-
active={isActive(editor)}
88-
disabled={!isEnable(editor)}
89-
onClick={() => {
90-
hide();
91-
focus();
92-
exec(editor);
93-
onClick?.(id);
94-
}}
95-
icon={<Icon data={icon.data} size={icon.size ?? 16} />}
96-
extraProps={{'aria-label': titleText}}
97-
>
98-
<div className={b('item')}>
99-
{titleText}
100-
<div className={b('extra')}>
101-
{hotkey && <Hotkey value={hotkey} />}
102-
{hintText && (
103-
<HelpPopover className={b('hint')} content={hintText} />
104-
)}
85+
{data
86+
.map(({id, title, icon, hotkey, isActive, isEnable, exec, hint}) => {
87+
const titleText = isFunction(title) ? title() : title;
88+
const hintText = isFunction(hint) ? hint() : hint;
89+
const disabled = !isEnable(editor);
90+
return hideDisabled && disabled ? null : (
91+
<Menu.Item
92+
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}}
103+
>
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+
)}
114+
</div>
105115
</div>
106-
</div>
107-
</Menu.Item>
108-
);
109-
})}
116+
</Menu.Item>
117+
);
118+
})
119+
.filter(Boolean)}
110120
</Menu>
111121
</Popup>
112122
</>

src/toolbar/flexible.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@ const dotsWidth = B_DOTS_LEFT_GAP + B_DOTS_WIDTH;
2020
export type ShrinkToolbarDataParams<E> = {
2121
data: ToolbarData<E>;
2222
availableWidth: number;
23+
hiddenActions?: ToolbarItemData<E>[];
2324
};
2425

25-
export function shrinkToolbarData<E>({availableWidth, data}: ShrinkToolbarDataParams<E>): {
26+
export function shrinkToolbarData<E>({
27+
availableWidth,
28+
data,
29+
hiddenActions = [],
30+
}: ShrinkToolbarDataParams<E>): {
2631
data: ToolbarData<E>;
2732
dots?: ToolbarItemData<E>[];
2833
} {
@@ -64,6 +69,8 @@ export function shrinkToolbarData<E>({availableWidth, data}: ShrinkToolbarDataPa
6469
if (newGroup.length) fittingData.push(newGroup);
6570
});
6671

72+
dotsData.push(...hiddenActions);
73+
6774
return {data: fittingData, dots: dotsData.length ? dotsData : undefined};
6875
}
6976

0 commit comments

Comments
 (0)