Posted 17 April 2025, 12:01 pm EST
Hello, I’ve been unable to figure out how to dismiss the designer’s File Menu after executing custom code associated with a button I added to the menu. In my scenario I add a custom “Export Excel” button directly to the menu under the default “Info” list item:
const fileMenuPanelCommandName = DesignerGC.Spread.Sheets.Designer.CommandNames.FileMenuPanel;
initializeDesignerTemplates
Gets a copy of any default templates that need to be modified, modifies them, then
registers the updated templates.
Currently only needs to initialize the FileMenuPanelTemplate.
*/
export const initializeDesignerTemplates = () => {
const fileMenu = DesignerGC.Spread.Sheets.Designer.getTemplate(
DesignerGC.Spread.Sheets.Designer.TemplateNames.FileMenuPanelTemplate
)!;
// Mescius documentation uses square bracket notation for template modifications,
// apparently because type coersions cause the code to get too complicated.
// To make this more robust we introduce some TypeScript types with type guards
// in a targeted manner.
// Effective root of sidebar (left) and panels (right)
const root = fileMenu.content[0]['children'][0]['children'] as IColumnSetOption;
// 1. Modify items from the side menu
const menuList: (IListOption | ILabelLineOption | IButtonOption)[] = root[0].children[0].children;
...
// 1e. Add Export Excel button to the bottom
menuList.push({
type: 'Button',
margin: '10px 50px',
text: 'Export Excel',
width: 120,
height: 120,
bindingPath: 'button_custom_export_excel',
iconPosition: 'top',
iconClass: 'icon-common icon-excel'
} as IButtonOption);
...
}
...
const fileMenuCmd = DesignerGC.Spread.Sheets.Designer.getCommand(fileMenuPanelCommandName)!;
const prevExecuteFn = fileMenuCmd.execute;
...
fileMenuCmd.execute = (...args: [DesignerGC.Spread.Sheets.Designer.Designer, string, object]) => {
// args is designer, propertyName, newValue
const result = prevExecuteFn?.apply?.(fileMenuCmd, args);
const [, propertyName] = args;
...
if (propertyName === 'button_custom_export_excel') {
handleExportExcel();
}
return result;
};
...
config.commandMap = {
...config.commandMap,
fileMenuPanel: fileMenuCmd
};
designer.setConfig(config);
// Export Excel handler used by the Designer File Menu
const handleExportExcel = useCallback(() => {
if (!designer) return;
const workbook = designer.getWorkbook() as Workbook;
excelIO.save(
JSON.stringify(workbook.toJSON()),
(blob: Blob) => {
saveAs(blob, 'myfilename.xlsx');
},
({ errorMessage }: { errorCode: ExcelIO.IO.ErrorCode; errorMessage: string }) => {
notificationApi.error({
message: 'Excel export error',
description: `${errorMessage}`
});
}
);
}, [designer, excelIO, notificationApi]);
The button works, but it leaves me in the File Menu.
I’ve tried doing this:
designer.activeRibbonTab("home");
That sets the ribbon tab to “home” but doesn’t dismiss the File Menu backstage view, so I can’t even see the tabs. The user must manually click the file menu’s “back” button to return to the ribbon.