From d100d9bd8ef95a350b3d169c4cd288c92f0a768e Mon Sep 17 00:00:00 2001 From: smsochneg Date: Thu, 26 Oct 2023 13:32:15 +0200 Subject: [PATCH] feat: ability to add hidden action to toolbar (#144) --- src/toolbar/FlexToolbar.tsx | 34 ++++++++++++--- src/toolbar/ToolbarListButton.tsx | 70 ++++++++++++++++++------------- src/toolbar/flexible.tsx | 9 +++- 3 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/toolbar/FlexToolbar.tsx b/src/toolbar/FlexToolbar.tsx index 8d6c41dd..456fe360 100644 --- a/src/toolbar/FlexToolbar.tsx +++ b/src/toolbar/FlexToolbar.tsx @@ -8,6 +8,7 @@ import {ToolbarListButton} from './ToolbarListButton'; import {shrinkToolbarData} from './flexible'; import {logger} from '../logger'; import {useRenderTime} from '../react-utils/hooks'; +import {ToolbarDataType, ToolbarItemData} from './types'; import './FlexToolbar.scss'; @@ -15,6 +16,7 @@ const b = cn('flex-toolbar'); export type FlexToolbarProps = ToolbarProps & { dotsTitle: string | (() => string); + hiddenActions?: ToolbarItemData[]; }; export function FlexToolbar(props: FlexToolbarProps) { @@ -26,12 +28,32 @@ export function FlexToolbar(props: FlexToolbarProps) { }); }); - const {data, className} = props; + const {data, className, hiddenActions} = props; + const [ref, {width}] = useMeasure(); - const {data: items, dots} = React.useMemo( - () => shrinkToolbarData({data, availableWidth: width}), - [data, width], - ); + const {data: items, dots} = React.useMemo(() => { + const toolbarButtonIds = data.reduce((a: string[], toolbarGroup) => { + return [ + ...a, + ...toolbarGroup + .map((toolbarButton) => { + if (toolbarButton.type === ToolbarDataType.ListButton) { + return toolbarButton.data.map((v) => v.id); + } + return toolbarButton.id; + }) + .flat(), + ]; + }, []); + + // Finding only actions tha are not present in the main toolbar config + const filteredHiddenAction = hiddenActions?.filter((a) => !toolbarButtonIds.includes(a.id)); + return shrinkToolbarData({ + data, + availableWidth: width, + hiddenActions: filteredHiddenAction, + }); + }, [data, width, hiddenActions]); return (
@@ -46,6 +68,8 @@ export function FlexToolbar(props: FlexToolbarProps) { focus={props.focus} onClick={props.onClick} className={b('dots')} + alwaysActive={true} + hideDisabled={true} /> )}
diff --git a/src/toolbar/ToolbarListButton.tsx b/src/toolbar/ToolbarListButton.tsx index a2651b9c..ccfcf7f5 100644 --- a/src/toolbar/ToolbarListButton.tsx +++ b/src/toolbar/ToolbarListButton.tsx @@ -18,6 +18,8 @@ export type ToolbarListButtonData = { title: string | (() => string); withArrow?: boolean; data: ToolbarItemData[]; + alwaysActive?: boolean; + hideDisabled?: boolean; }; export type ToolbarListButtonProps = ToolbarBaseProps & ToolbarListButtonData; @@ -31,12 +33,14 @@ export function ToolbarListButton({ title, withArrow, data, + alwaysActive, + hideDisabled, }: ToolbarListButtonProps) { const buttonRef = React.useRef(null); const [open, , hide, toggleOpen] = useBooleanState(false); - const someActive = data.some((item) => item.isActive(editor)); - const everyDisabled = data.every((item) => !item.isEnable(editor)); + const someActive = alwaysActive ? false : data.some((item) => item.isActive(editor)); + const everyDisabled = alwaysActive ? false : data.every((item) => !item.isEnable(editor)); const popupOpen = everyDisabled ? false : open; const shouldForceHide = open && !popupOpen; @@ -78,35 +82,41 @@ export function ToolbarListButton({ - {data.map(({id, title, icon, hotkey, isActive, isEnable, exec, hint}) => { - const titleText = isFunction(title) ? title() : title; - const hintText = isFunction(hint) ? hint() : hint; - return ( - { - hide(); - focus(); - exec(editor); - onClick?.(id); - }} - icon={} - extraProps={{'aria-label': titleText}} - > -
- {titleText} -
- {hotkey && } - {hintText && ( - - )} + {data + .map(({id, title, icon, hotkey, isActive, isEnable, exec, hint}) => { + const titleText = isFunction(title) ? title() : title; + const hintText = isFunction(hint) ? hint() : hint; + const disabled = !isEnable(editor); + return hideDisabled && disabled ? null : ( + { + hide(); + focus(); + exec(editor); + onClick?.(id); + }} + icon={} + extraProps={{'aria-label': titleText}} + > +
+ {titleText} +
+ {hotkey && } + {hintText && ( + + )} +
-
- - ); - })} + + ); + }) + .filter(Boolean)}
diff --git a/src/toolbar/flexible.tsx b/src/toolbar/flexible.tsx index 9265aa1c..3918e29f 100644 --- a/src/toolbar/flexible.tsx +++ b/src/toolbar/flexible.tsx @@ -20,9 +20,14 @@ const dotsWidth = B_DOTS_LEFT_GAP + B_DOTS_WIDTH; export type ShrinkToolbarDataParams = { data: ToolbarData; availableWidth: number; + hiddenActions?: ToolbarItemData[]; }; -export function shrinkToolbarData({availableWidth, data}: ShrinkToolbarDataParams): { +export function shrinkToolbarData({ + availableWidth, + data, + hiddenActions = [], +}: ShrinkToolbarDataParams): { data: ToolbarData; dots?: ToolbarItemData[]; } { @@ -64,6 +69,8 @@ export function shrinkToolbarData({availableWidth, data}: ShrinkToolbarDataPa if (newGroup.length) fittingData.push(newGroup); }); + dotsData.push(...hiddenActions); + return {data: fittingData, dots: dotsData.length ? dotsData : undefined}; }