import { Editor, TLFrameShape, track, useEditor, useValue } from '@bigbluebutton/editor' import React, { useMemo } from 'react' import { TLUiMenuSchema, compactMenuItems, menuCustom, menuGroup, menuItem, menuSubmenu, showMenuPaste, useAllowGroup, useAllowUngroup, useThreeStackableItems, } from './menuHelpers' import { useActions } from './useActions' import { useHasLinkShapeSelected } from './useHasLinkShapeSelected' import { useOnlyFlippableShape } from './useOnlyFlippableShape' import { useShowAutoSizeToggle } from './useShowAutoSizeToggle' /** @public */ export type TLUiContextTTLUiMenuSchemaContextType = TLUiMenuSchema /** @internal */ export const TLUiContextMenuSchemaContext = React.createContext( {} as TLUiContextTTLUiMenuSchemaContextType ) /** @public */ export type TLUiContextMenuSchemaProviderProps = { overrides?: ( editor: Editor, schema: TLUiContextTTLUiMenuSchemaContextType, helpers: { actions: ReturnType oneSelected: boolean twoSelected: boolean threeSelected: boolean showAutoSizeToggle: boolean showUngroup: boolean onlyFlippableShapeSelected: boolean } ) => TLUiContextTTLUiMenuSchemaContextType children: any } /** @internal */ export const TLUiContextMenuSchemaProvider = track(function TLUiContextMenuSchemaProvider({ overrides, children, }: TLUiContextMenuSchemaProviderProps) { const editor = useEditor() const actions = useActions() const showAutoSizeToggle = useShowAutoSizeToggle() const onlyFlippableShapeSelected = useOnlyFlippableShape() const selectedShapes = editor.getSelectedShapes() const selectedCount = selectedShapes.length const oneSelected = selectedCount > 0 const twoSelected = selectedCount > 1 const threeSelected = selectedCount > 2 const threeStackableItems = useThreeStackableItems() const atLeastOneShapeOnPage = useValue( 'atLeastOneShapeOnPage', () => editor.getCurrentPageShapeIds().size > 0, [] ) const isTransparentBg = useValue( 'isTransparentBg', () => editor.getInstanceState().exportBackground, [] ) const allowGroup = useAllowGroup() const allowUngroup = useAllowUngroup() const hasClipboardWrite = Boolean(window.navigator.clipboard?.write) const showEditLink = useHasLinkShapeSelected() const onlySelectedShape = editor.getOnlySelectedShape() const allowRemoveFrame = oneSelected && selectedShapes.every((shape) => editor.isShapeOfType(shape, 'frame')) const allowFitFrameToContent = onlySelectedShape && editor.isShapeOfType(onlySelectedShape, 'frame') && editor.getSortedChildIdsForParent(onlySelectedShape).length > 0 const isShapeLocked = onlySelectedShape && editor.isShapeOrAncestorLocked(onlySelectedShape) const contextTLUiMenuSchema = useMemo(() => { let contextTLUiMenuSchema: TLUiContextTTLUiMenuSchemaContextType = compactMenuItems([ menuGroup( 'selection', showAutoSizeToggle && menuItem(actions['toggle-auto-size']), showEditLink && !isShapeLocked && menuItem(actions['edit-link']), oneSelected && !isShapeLocked && menuItem(actions['duplicate']), allowGroup && !isShapeLocked && menuItem(actions['group']), allowUngroup && !isShapeLocked && menuItem(actions['ungroup']), allowRemoveFrame && !isShapeLocked && menuItem(actions['remove-frame']), allowFitFrameToContent && !isShapeLocked && menuItem(actions['fit-frame-to-content']), oneSelected && menuItem(actions['toggle-lock']) ), menuGroup( 'modify', (twoSelected || onlyFlippableShapeSelected) && menuSubmenu( 'arrange', 'context-menu.arrange', twoSelected && menuGroup( 'align', menuItem(actions['align-left']), menuItem(actions['align-center-horizontal']), menuItem(actions['align-right']), menuItem(actions['align-top']), menuItem(actions['align-center-vertical']), menuItem(actions['align-bottom']) ), threeSelected && menuGroup( 'distribute', menuItem(actions['distribute-horizontal']), menuItem(actions['distribute-vertical']) ), twoSelected && menuGroup( 'stretch', menuItem(actions['stretch-horizontal']), menuItem(actions['stretch-vertical']) ), onlyFlippableShapeSelected && !isShapeLocked && menuGroup( 'flip', menuItem(actions['flip-horizontal']), menuItem(actions['flip-vertical']) ), twoSelected && menuGroup( 'order', menuItem(actions['pack'], { disabled: !twoSelected }), threeStackableItems && menuItem(actions['stack-vertical']), threeStackableItems && menuItem(actions['stack-horizontal']) ) ), oneSelected && !isShapeLocked && menuSubmenu( 'reorder', 'context-menu.reorder', menuGroup( 'reorder', menuItem(actions['bring-to-front']), menuItem(actions['bring-forward']), menuItem(actions['send-backward']), menuItem(actions['send-to-back']) ) ), oneSelected && !isShapeLocked && menuCustom('MOVE_TO_PAGE_MENU', { readonlyOk: false }) ), menuGroup( 'clipboard-group', oneSelected && !isShapeLocked && menuItem(actions['cut']), oneSelected && menuItem(actions['copy']), showMenuPaste && menuItem(actions['paste']) ), atLeastOneShapeOnPage && menuGroup( 'conversions', menuSubmenu( 'copy-as', 'context-menu.copy-as', menuGroup( 'copy-as-group', menuItem(actions['copy-as-svg']), hasClipboardWrite && menuItem(actions['copy-as-png']), menuItem(actions['copy-as-json']) ), menuGroup( 'export-bg', menuItem(actions['toggle-transparent'], { checked: !isTransparentBg }) ) ), menuSubmenu( 'export-as', 'context-menu.export-as', menuGroup( 'export-as-group', menuItem(actions['export-as-svg']), menuItem(actions['export-as-png']), menuItem(actions['export-as-json']) ), menuGroup( 'export-bg,', menuItem(actions['toggle-transparent'], { checked: !isTransparentBg }) ) ) ), atLeastOneShapeOnPage && menuGroup( 'set-selection-group', menuItem(actions['select-all']), oneSelected && menuItem(actions['select-none']) ), oneSelected && !isShapeLocked && menuGroup('delete-group', menuItem(actions['delete'])), ]) if (overrides) { contextTLUiMenuSchema = overrides(editor, contextTLUiMenuSchema, { actions, oneSelected, twoSelected, threeSelected, showAutoSizeToggle, showUngroup: allowUngroup, onlyFlippableShapeSelected, }) } return contextTLUiMenuSchema }, [ editor, overrides, actions, oneSelected, twoSelected, threeSelected, showAutoSizeToggle, onlyFlippableShapeSelected, atLeastOneShapeOnPage, threeStackableItems, allowGroup, allowUngroup, allowRemoveFrame, allowFitFrameToContent, hasClipboardWrite, showEditLink, // oneEmbedSelected, // oneEmbeddableBookmarkSelected, isTransparentBg, isShapeLocked, ]) return ( {children} ) }) /** @public */ export function useContextMenuSchema(): TLUiMenuSchema { const ctx = React.useContext(TLUiContextMenuSchemaContext) if (!ctx) { throw new Error('useContextMenuSchema must be used inside of a TLUiContextMenuSchemaProvider.') } return ctx }