230 lines
7.7 KiB
TypeScript
230 lines
7.7 KiB
TypeScript
import { useCallback, useEffect, useState, useMemo } from 'react';
|
|
import { useSystem } from '../contextProviders/SystemProvider';
|
|
import { ToolbarHookReturn } from './types';
|
|
import { buildButtonCommands } from '../utils';
|
|
|
|
export function useToolbar({ buttonSection = 'primary' }: withAppTypes): ToolbarHookReturn {
|
|
const { commandsManager, servicesManager } = useSystem();
|
|
const { toolbarService, viewportGridService } = servicesManager.services;
|
|
const { EVENTS } = toolbarService;
|
|
|
|
// Store all buttons returned by the toolbar service
|
|
const [toolbarButtons, setToolbarButtons] = useState(
|
|
toolbarService.getButtonSection(buttonSection as string).filter(Boolean)
|
|
);
|
|
|
|
// Store state of open/closed menu items
|
|
// Note: We keep this in local state to avoid re-evaluating the toolbar on every interaction
|
|
const [openItemIds, setOpenItemIds] = useState<Record<string, boolean>>({});
|
|
|
|
// Callback function for handling toolbar interactions
|
|
const onInteraction = useCallback(
|
|
args => {
|
|
args.event?.stopPropagation?.();
|
|
const viewportId = args.viewportId || viewportGridService.getActiveViewportId();
|
|
const refreshProps = { viewportId };
|
|
|
|
const buttonProps = toolbarService.getButtonProps(args.itemId);
|
|
const commands = buildButtonCommands(buttonProps, args, { servicesManager, commandsManager });
|
|
const computedProps = { ...buttonProps, commands };
|
|
|
|
toolbarService.recordInteraction({ ...args, ...computedProps }, { refreshProps });
|
|
},
|
|
[toolbarService, viewportGridService]
|
|
);
|
|
|
|
// Effect to handle toolbar modification events
|
|
useEffect(() => {
|
|
const handleToolbarModified = () => {
|
|
const buttons = toolbarService.getButtonSection(buttonSection as string)?.filter(Boolean);
|
|
setToolbarButtons(buttons);
|
|
};
|
|
|
|
const subs = [EVENTS.TOOL_BAR_MODIFIED, EVENTS.TOOL_BAR_STATE_MODIFIED].map(event => {
|
|
return toolbarService.subscribe(event, handleToolbarModified);
|
|
});
|
|
|
|
return () => {
|
|
subs.forEach(sub => sub.unsubscribe());
|
|
};
|
|
}, [toolbarService]);
|
|
|
|
// Effect to handle active viewportId change event
|
|
useEffect(() => {
|
|
const events = [
|
|
viewportGridService.EVENTS.ACTIVE_VIEWPORT_ID_CHANGED,
|
|
viewportGridService.EVENTS.VIEWPORTS_READY,
|
|
viewportGridService.EVENTS.LAYOUT_CHANGED,
|
|
];
|
|
|
|
const subscriptions = events.map(event => {
|
|
return viewportGridService.subscribe(event, ({ viewportId }) => {
|
|
viewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
toolbarService.refreshToolbarState({ viewportId });
|
|
});
|
|
});
|
|
|
|
return () => subscriptions.forEach(sub => sub.unsubscribe());
|
|
}, [viewportGridService, toolbarService]);
|
|
|
|
// Action API for toolbar buttons
|
|
const actions = useMemo(() => {
|
|
return {
|
|
// Lock/Unlock actions
|
|
lockItem: (itemId: string, viewportId?: string) => {
|
|
const targetViewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
const button = toolbarService.getButton(itemId);
|
|
|
|
if (button) {
|
|
// Set isLocked flag in button metadata
|
|
button.props = {
|
|
...button.props,
|
|
isLocked: true,
|
|
};
|
|
|
|
// Re-evaluate the button
|
|
toolbarService.refreshToolbarState({ viewportId: targetViewportId, itemId });
|
|
}
|
|
},
|
|
|
|
unlockItem: (itemId: string, viewportId?: string) => {
|
|
const targetViewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
const button = toolbarService.getButton(itemId);
|
|
|
|
if (button) {
|
|
// Set isLocked flag in button metadata
|
|
button.props = {
|
|
...button.props,
|
|
isLocked: false,
|
|
};
|
|
|
|
// Re-evaluate the button
|
|
toolbarService.refreshToolbarState({ viewportId: targetViewportId, itemId });
|
|
}
|
|
},
|
|
|
|
toggleLock: (itemId: string, viewportId?: string) => {
|
|
const targetViewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
const button = toolbarService.getButton(itemId);
|
|
|
|
if (button) {
|
|
// Toggle isLocked flag in button metadata
|
|
button.props = {
|
|
...button.props,
|
|
isLocked: !button.props.isLocked,
|
|
};
|
|
|
|
// Re-evaluate the button
|
|
toolbarService.refreshToolbarState({ viewportId: targetViewportId, itemId });
|
|
}
|
|
},
|
|
|
|
isItemLocked: (itemId: string, viewportId?: string): boolean => {
|
|
const button = toolbarService.getButton(itemId);
|
|
return button?.props?.isLocked === true;
|
|
},
|
|
|
|
// Visibility actions - controlled by evaluator functions in toolbar items
|
|
showItem: (itemId: string, viewportId?: string) => {
|
|
const targetViewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
const button = toolbarService.getButton(itemId);
|
|
|
|
if (button) {
|
|
// Set isVisible flag in button metadata
|
|
button.props = {
|
|
...button.props,
|
|
isVisible: true,
|
|
};
|
|
|
|
// Re-evaluate the button
|
|
toolbarService.refreshToolbarState({ viewportId: targetViewportId, itemId });
|
|
}
|
|
},
|
|
|
|
hideItem: (itemId: string, viewportId?: string) => {
|
|
const targetViewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
const button = toolbarService.getButton(itemId);
|
|
|
|
if (button) {
|
|
// Set isVisible flag in button metadata
|
|
button.props = {
|
|
...button.props,
|
|
isVisible: false,
|
|
};
|
|
|
|
// Re-evaluate the button
|
|
toolbarService.refreshToolbarState({ viewportId: targetViewportId, itemId });
|
|
}
|
|
},
|
|
|
|
toggleVisibility: (itemId: string, viewportId?: string) => {
|
|
const targetViewportId = viewportId || viewportGridService.getActiveViewportId();
|
|
const button = toolbarService.getButton(itemId);
|
|
|
|
if (button) {
|
|
// Toggle isVisible flag in button metadata
|
|
button.props = {
|
|
...button.props,
|
|
isVisible: button.props.isVisible === false ? true : false,
|
|
};
|
|
|
|
// Re-evaluate the button
|
|
toolbarService.refreshToolbarState({ viewportId: targetViewportId, itemId });
|
|
}
|
|
},
|
|
|
|
isItemVisible: (itemId: string, viewportId?: string): boolean => {
|
|
const button = toolbarService.getButton(itemId);
|
|
// If isVisible is explicitly false, return false; otherwise return true
|
|
return button?.props?.isVisible !== false;
|
|
},
|
|
|
|
// Open/Close actions - managed in local state for performance
|
|
openItem: (itemId: string, viewportId?: string) => {
|
|
setOpenItemIds(prev => {
|
|
// Close all other items
|
|
const updated = {};
|
|
// Then set the current item to open
|
|
updated[itemId] = true;
|
|
return updated;
|
|
});
|
|
},
|
|
|
|
closeItem: (itemId: string, viewportId?: string) => {
|
|
setOpenItemIds(prev => ({
|
|
...prev,
|
|
[itemId]: false,
|
|
}));
|
|
},
|
|
|
|
closeAllItems: (viewportId?: string) => {
|
|
setOpenItemIds({});
|
|
},
|
|
|
|
isItemOpen: (itemId: string, viewportId?: string): boolean => {
|
|
return openItemIds[itemId] === true;
|
|
},
|
|
};
|
|
}, [viewportGridService, toolbarService, openItemIds]);
|
|
|
|
if (!toolbarButtons?.length) {
|
|
return {
|
|
toolbarButtons: [],
|
|
onInteraction,
|
|
...actions,
|
|
};
|
|
}
|
|
|
|
// filter out buttons that are disabled and have hideWhenDisabled set to true
|
|
const filteredToolbarButtons = toolbarButtons.filter(button => {
|
|
const props = button.componentProps;
|
|
return props.visible !== false;
|
|
});
|
|
|
|
return {
|
|
toolbarButtons: filteredToolbarButtons,
|
|
onInteraction,
|
|
...actions,
|
|
};
|
|
}
|