{ "version": 3, "sources": ["../../../../src/lib/ui/hooks/menuHelpers.ts"], "sourcesContent": ["import {\n\tEditor,\n\tTLArrowShape,\n\tassert,\n\texhaustiveSwitchError,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport { TLUiActionItem } from './useActions'\nimport { TLUiToolItem } from './useTools'\nimport { TLUiTranslationKey } from './useTranslation/TLUiTranslationKey'\n\n/** @public */\nexport type TLUiMenuChild = TLUiMenuItem | TLUiSubMenu | TLUiMenuGroup | TLUiCustomMenuItem\n\n/** @public */\nexport type TLUiCustomMenuItem = {\n\tid: string\n\ttype: 'custom'\n\tdisabled: boolean\n\treadonlyOk: boolean\n}\n\n/** @public */\nexport type TLUiMenuItem = {\n\tid: string\n\ttype: 'item'\n\treadonlyOk: boolean\n\tactionItem: TLUiActionItem\n\tdisabled: boolean\n\tchecked: boolean\n}\n\n/** @public */\nexport type TLUiMenuGroup = {\n\tid: string\n\ttype: 'group'\n\tcheckbox: boolean\n\tdisabled: boolean\n\treadonlyOk: boolean\n\tchildren: TLUiMenuChild[]\n}\n\n/** @public */\nexport type TLUiSubMenu = {\n\tid: string\n\ttype: 'submenu'\n\tlabel: TLUiTranslationKey\n\tdisabled: boolean\n\treadonlyOk: boolean\n\tchildren: TLUiMenuChild[]\n}\n\n/** @public */\nexport type TLUiMenuSchema = (TLUiMenuGroup | TLUiMenuItem | TLUiCustomMenuItem)[]\n\n/** @public */\nexport function compactMenuItems(arr: T[]): Exclude[] {\n\treturn arr.filter((i) => i !== undefined && i !== null && i !== false) as any\n}\n\n/** @public */\nexport function menuGroup(\n\tid: string,\n\t...children: (TLUiMenuChild | null | false)[]\n): TLUiMenuGroup | null {\n\tconst childItems = compactMenuItems(children)\n\n\tif (childItems.length === 0) return null\n\n\treturn {\n\t\tid,\n\t\ttype: 'group',\n\t\tcheckbox: childItems.every((child) => child.type === 'item' && child.actionItem.checkbox),\n\t\tdisabled: childItems.every((child) => child.disabled),\n\t\treadonlyOk: childItems.some((child) => child.readonlyOk),\n\t\tchildren: childItems,\n\t}\n}\n\n/** @public */\nexport function menuSubmenu(\n\tid: string,\n\tlabel: TLUiTranslationKey,\n\t...children: (TLUiMenuChild | null | false)[]\n): TLUiSubMenu | null {\n\tconst childItems = compactMenuItems(children)\n\tif (childItems.length === 0) return null\n\n\treturn {\n\t\tid,\n\t\ttype: 'submenu',\n\t\tlabel,\n\t\tchildren: childItems,\n\t\tdisabled: childItems.every((child) => child.disabled),\n\t\treadonlyOk: childItems.some((child) => child.readonlyOk),\n\t}\n}\n\n/** @public */\nexport function menuCustom(\n\tid: string,\n\topts = {} as Partial<{ readonlyOk: boolean; disabled: boolean }>\n) {\n\tconst { readonlyOk = true, disabled = false } = opts\n\treturn {\n\t\tid,\n\t\ttype: 'custom' as const,\n\t\tdisabled,\n\t\treadonlyOk,\n\t}\n}\n\n/** @public */\nexport function menuItem(\n\tactionItem: TLUiActionItem | TLUiToolItem,\n\topts = {} as Partial<{ checked: boolean; disabled: boolean }>\n): TLUiMenuItem {\n\tif (!actionItem) {\n\t\tthrow Error('No action item provided to menuItem')\n\t}\n\n\tif (!actionItem.label) {\n\t\tthrow Error(\"Trying to create menu item for action item that doesn't have a label\")\n\t}\n\n\tconst { checked = false, disabled = false } = opts\n\n\treturn {\n\t\tid: actionItem.id,\n\t\ttype: 'item' as const,\n\t\tactionItem,\n\t\tdisabled,\n\t\tchecked,\n\t\treadonlyOk: actionItem.readonlyOk,\n\t}\n}\n\nfunction shapesWithUnboundArrows(editor: Editor) {\n\tconst { selectedShapeIds } = editor\n\tconst selectedShapes = selectedShapeIds.map((id) => {\n\t\treturn editor.getShape(id)\n\t})\n\n\treturn selectedShapes.filter((shape) => {\n\t\tif (!shape) return false\n\t\tif (\n\t\t\teditor.isShapeOfType(shape, 'arrow') &&\n\t\t\tshape.props.start.type === 'binding'\n\t\t) {\n\t\t\treturn false\n\t\t}\n\t\tif (editor.isShapeOfType(shape, 'arrow') && shape.props.end.type === 'binding') {\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n}\n\n/** @internal */\nexport const useThreeStackableItems = () => {\n\tconst editor = useEditor()\n\treturn useValue('threeStackableItems', () => shapesWithUnboundArrows(editor).length > 2, [editor])\n}\n\n/** @internal */\nexport const useAllowGroup = () => {\n\tconst editor = useEditor()\n\treturn useValue('allowGroup', () => shapesWithUnboundArrows(editor).length > 1, [editor])\n}\n\n/** @internal */\nexport const useAllowUngroup = () => {\n\tconst editor = useEditor()\n\treturn useValue(\n\t\t'allowUngroup',\n\t\t() => editor.selectedShapeIds.some((id) => editor.getShape(id)?.type === 'group'),\n\t\t[]\n\t)\n}\n\n/** @public */\nexport function findMenuItem(menu: TLUiMenuSchema, path: string[]) {\n\tconst item = _findMenuItem(menu, path)\n\tassert(item, `Menu item ${path.join(' > ')} not found`)\n\treturn item\n}\n\nfunction _findMenuItem(\n\tmenu: TLUiMenuSchema | TLUiMenuChild[],\n\tpath: string[]\n): TLUiMenuChild | null {\n\tconst [next, ...rest] = path\n\tif (!next) return null\n\n\tconst item = menu.find((item) => item.id === next)\n\tif (!item) return null\n\n\tswitch (item.type) {\n\t\tcase 'group':\n\t\tcase 'submenu':\n\t\t\treturn rest.length === 0 ? item : _findMenuItem(item.children, rest)\n\t\tcase 'item':\n\t\tcase 'custom':\n\t\t\treturn rest.length === 0 ? item : null\n\t\tdefault:\n\t\t\texhaustiveSwitchError(item, 'type')\n\t}\n}\n\nexport const showMenuPaste =\n\ttypeof window !== 'undefined' &&\n\t'navigator' in window &&\n\tBoolean(navigator.clipboard) &&\n\tBoolean(navigator.clipboard.read)\n"], "mappings": "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", "names": ["item"] }