@plait/mind
Version:
Implementation of the core logic of the mind map plugin.
1 lines • 398 kB
Source Map (JSON)
{"version":3,"file":"plait-mind.mjs","sources":["../../../packages/mind/src/utils/weak-maps.ts","../../../packages/mind/src/interfaces/node.ts","../../../packages/mind/src/interfaces/layout.ts","../../../packages/mind/src/interfaces/pointer.ts","../../../packages/mind/src/constants/theme.ts","../../../packages/mind/src/interfaces/theme-color.ts","../../../packages/mind/src/constants/default.ts","../../../packages/mind/src/utils/space/emoji.ts","../../../packages/mind/src/utils/node-style/common.ts","../../../packages/mind/src/constants/node-style.ts","../../../packages/mind/src/utils/abstract/common.ts","../../../packages/mind/src/utils/node-style/branch.ts","../../../packages/mind/src/utils/node-style/shape.ts","../../../packages/mind/src/utils/node/common.ts","../../../packages/mind/src/utils/layout.ts","../../../packages/mind/src/utils/space/layout-options.ts","../../../packages/mind/src/utils/common.ts","../../../packages/mind/src/utils/node/create-node.ts","../../../packages/mind/src/constants/node-topic-style.ts","../../../packages/mind/src/utils/mind.ts","../../../packages/mind/src/constants/abstract-node.ts","../../../packages/mind/src/utils/space/node-space.ts","../../../packages/mind/src/utils/position/node.ts","../../../packages/mind/src/utils/position/emoji.ts","../../../packages/mind/src/utils/position/topic.ts","../../../packages/mind/src/utils/position/image.ts","../../../packages/mind/src/utils/node/adjust-node.ts","../../../packages/mind/src/utils/node/image.ts","../../../packages/mind/src/utils/node/dynamic-width.ts","../../../packages/mind/src/utils/dnd/common.ts","../../../packages/mind/src/utils/dnd/detector.ts","../../../packages/mind/src/utils/draw/node-shape.ts","../../../packages/mind/src/interfaces/types.ts","../../../packages/mind/src/utils/point-placement.ts","../../../packages/mind/src/utils/draw/node-link/indented-link.ts","../../../packages/mind/src/utils/draw/node-link/logic-link.ts","../../../packages/mind/src/utils/draw/node-link/draw-link.ts","../../../packages/mind/src/generators/node-emojis.generator.ts","../../../packages/mind/src/utils/draw/node-dnd.ts","../../../packages/mind/src/plugins/with-abstract-resize.board.ts","../../../packages/mind/src/utils/draw/abstract-outline.ts","../../../packages/mind/src/generators/node-active.generator.ts","../../../packages/mind/src/utils/abstract/resize.ts","../../../packages/mind/src/utils/node/right-node-count.ts","../../../packages/mind/src/utils/path.ts","../../../packages/mind/src/queries/get-correct-layout-by-element.ts","../../../packages/mind/src/queries/get-branch-layouts.ts","../../../packages/mind/src/queries/get-available-sublayouts-by-element.ts","../../../packages/mind/src/queries/get-layout-by-element.ts","../../../packages/mind/src/queries/index.ts","../../../packages/mind/src/interfaces/element.ts","../../../packages/mind/src/utils/draw/node-link/abstract-link.ts","../../../packages/mind/src/transforms/abstract-node.ts","../../../packages/mind/src/transforms/node.ts","../../../packages/mind/src/transforms/emoji.ts","../../../packages/mind/src/transforms/image.ts","../../../packages/mind/src/transforms/layout.ts","../../../packages/mind/src/transforms/property.ts","../../../packages/mind/src/transforms/index.ts","../../../packages/mind/src/generators/node-shape.generator.ts","../../../packages/mind/src/generators/node-more.generator.ts","../../../packages/mind/src/mind-node.component.ts","../../../packages/mind/src/mind.component.ts","../../../packages/mind/src/plugins/with-node-dnd.ts","../../../packages/mind/src/plugins/with-abstract-resize.ts","../../../packages/mind/src/plugins/with-mind-extend.ts","../../../packages/mind/src/plugins/with-mind-create.ts","../../../packages/mind/src/plugins/with-mind-hotkey.ts","../../../packages/mind/src/plugins/with-node-more.ts","../../../packages/mind/src/plugins/with-node-image.ts","../../../packages/mind/src/plugins/with-node-resize.ts","../../../packages/mind/src/plugins/with-node-image-resize.ts","../../../packages/mind/src/utils/clipboard.ts","../../../packages/mind/src/plugins/with-mind-fragment.ts","../../../packages/mind/src/emoji/with-emoji.ts","../../../packages/mind/src/utils/normalize.ts","../../../packages/mind/src/plugins/with-mind.ts","../../../packages/mind/src/emoji/emoji-base.component.ts","../../../packages/mind/src/public-api.ts","../../../packages/mind/src/plait-mind.ts"],"sourcesContent":["import { MindElement } from '../interfaces/element';\nimport { MindNode } from '../interfaces/node';\n\nexport const MIND_ELEMENT_TO_NODE = new WeakMap<MindElement, MindNode>();\n","import { MindLayoutType } from '@plait/layouts';\nimport { Path } from '@plait/core';\nimport { MindElement } from './element';\n\nexport interface MindNode {\n depth: number;\n x: number;\n y: number;\n width: number;\n height: number;\n hGap: number;\n vGap: number;\n children: MindNode[];\n origin: MindElement;\n parent: MindNode;\n left: boolean;\n up: boolean;\n}\n\nexport const MindNode = {\n get(root: MindNode, path: Path) {\n let node = root;\n for (let i = 0; i < path.length; i++) {\n const p = path[i];\n if (!node || !node.children || !node.children[p]) {\n throw new Error(`Cannot find a descendant at path [${path}]`);\n }\n node = node.children[p];\n }\n return node;\n }\n};\n\nexport type ExtendLayoutType = Exclude<MindLayoutType, MindLayoutType.standard>;\n\nexport type CoordinateType = {\n startX: number;\n startY: number;\n endX: number;\n endY: number;\n};\n\nexport type ExtendUnderlineCoordinateType = {\n [key in ExtendLayoutType]: CoordinateType;\n};\n\nexport type DetectResult = 'top' | 'bottom' | 'right' | 'left' | null;\n\nexport type RootBaseDirection = 'right' | 'left' | null;\n","import { MindLayoutType } from '@plait/layouts';\n\nexport enum LayoutDirection {\n 'top' = 'top',\n 'right' = 'right',\n 'bottom' = 'bottom',\n 'left' = 'left'\n}\n\nexport const LayoutDirectionsMap: LayoutDirectionMapType = {\n [MindLayoutType.right]: [LayoutDirection.right],\n [MindLayoutType.left]: [LayoutDirection.left],\n [MindLayoutType.upward]: [LayoutDirection.top],\n [MindLayoutType.downward]: [LayoutDirection.bottom],\n [MindLayoutType.rightBottomIndented]: [LayoutDirection.right, LayoutDirection.bottom],\n [MindLayoutType.rightTopIndented]: [LayoutDirection.right, LayoutDirection.top],\n [MindLayoutType.leftBottomIndented]: [LayoutDirection.left, LayoutDirection.bottom],\n [MindLayoutType.leftTopIndented]: [LayoutDirection.left, LayoutDirection.top]\n};\n\nexport type LayoutDirectionMapType = { [key: string]: LayoutDirection[] };\n","export enum MindPointerType {\n 'mind' = 'mind'\n}\n","export const DEFAULT_BRANCH_COLORS = [\n '#A287E0',\n '#6E80DB',\n '#6DC4C4',\n '#E0B75E',\n '#B1C675',\n '#77C386',\n '#C18976',\n '#E48484',\n '#E582D4',\n '#6AB1E4'\n];\n\nexport const COLORFUL_BRANCH_COLORS = [\n '#F94239',\n '#FF8612',\n '#F3D222',\n '#B3D431',\n '#00BC7B',\n '#06ADBF',\n '#476BFF',\n '#4E49BE',\n '#8957E5',\n '#FE5DA1'\n];\n\nexport const SOFT_BRANCH_COLORS = [\n '#6D89C1',\n '#F2BDC7',\n '#B796D9',\n '#5BA683',\n '#B3D431 ',\n '#F2DC6C',\n '#F7C98D',\n '#60B4D1',\n '#838F9E',\n '#C1A381'\n];\n\nexport const RETRO_BRANCH_COLORS = [\n '#459476',\n '#9A894F',\n '#D48444',\n '#E9C358 ',\n '#4B9D9D',\n '#C14C41',\n '#827086 ',\n '#60718D',\n '#D38183',\n '#9DC19D'\n];\n\nexport const DARK_BRANCH_COLORS = [\n '#3DD1AE',\n '#F6C659',\n '#A9E072',\n '#FF877B ',\n '#F693E7',\n '#5DCFFF',\n '#868AF6',\n '#4C6DC7',\n '#D97C26',\n '#268FAC'\n];\n\nexport const STARRY_BRANCH_COLORS = [\n '#E46C57',\n '#579360',\n '#B98339',\n '#3A62D1 ',\n '#B883B7',\n '#42ABE5',\n '#2B9D8F',\n '#A4705E',\n '#265833',\n '#787865'\n];\n","import {\n DefaultThemeColor,\n StarryThemeColor,\n ThemeColor,\n ThemeColorMode,\n DarkThemeColor,\n ColorfulThemeColor,\n SoftThemeColor,\n RetroThemeColor,\n DEFAULT_COLOR\n} from '@plait/core';\nimport {\n COLORFUL_BRANCH_COLORS,\n DARK_BRANCH_COLORS,\n DEFAULT_BRANCH_COLORS,\n RETRO_BRANCH_COLORS,\n SOFT_BRANCH_COLORS,\n STARRY_BRANCH_COLORS\n} from '../constants/theme';\n\nexport interface MindThemeColor extends ThemeColor {\n mode: ThemeColorMode | string;\n branchColors: string[];\n rootFill: string;\n rootTextColor: string;\n}\n\nexport const MindDefaultThemeColor: MindThemeColor = {\n ...DefaultThemeColor,\n branchColors: DEFAULT_BRANCH_COLORS,\n rootFill: '#f5f5f5',\n rootTextColor: DEFAULT_COLOR\n};\n\nexport const MindColorfulThemeColor: MindThemeColor = {\n ...ColorfulThemeColor,\n branchColors: COLORFUL_BRANCH_COLORS,\n rootFill: DEFAULT_COLOR,\n rootTextColor: '#FFFFFF'\n};\n\nexport const MindSoftThemeColor: MindThemeColor = {\n ...SoftThemeColor,\n branchColors: SOFT_BRANCH_COLORS,\n rootFill: '#FFFFFF',\n rootTextColor: DEFAULT_COLOR\n};\n\nexport const MindRetroThemeColor: MindThemeColor = {\n ...RetroThemeColor,\n branchColors: RETRO_BRANCH_COLORS,\n rootFill: '#153D5D',\n rootTextColor: '#FFFFFF'\n};\n\nexport const MindDarkThemeColor: MindThemeColor = {\n ...DarkThemeColor,\n branchColors: DARK_BRANCH_COLORS,\n rootFill: '#FFFFFF',\n rootTextColor: DEFAULT_COLOR\n};\n\nexport const MindStarryThemeColor: MindThemeColor = {\n ...StarryThemeColor,\n branchColors: STARRY_BRANCH_COLORS,\n rootFill: '#FFFFFF',\n rootTextColor: DEFAULT_COLOR\n};\n\nexport const MindThemeColors: MindThemeColor[] = [\n MindDefaultThemeColor,\n MindColorfulThemeColor,\n MindSoftThemeColor,\n MindRetroThemeColor,\n MindDarkThemeColor,\n MindStarryThemeColor\n];\n\nexport const MindThemeColor = {\n isMindThemeColor(value: any): value is MindThemeColor {\n if (value.branchColors && value.rootFill && value.rootTextColor) {\n return true;\n } else {\n return false;\n }\n }\n};\n","import { rgbaToHEX } from \"@plait/core\";\n\nexport const WithMindPluginKey = 'plait-mind-plugin-key';\n\nexport const BASE = 4;\nexport const PRIMARY_COLOR = '#6698FF';\nexport const GRAY_COLOR = '#AAAAAA';\nexport const STROKE_WIDTH = 2;\n\nexport const RESIZE_HANDLE_BUFFER_DISTANCE = 8;\n\nexport const NODE_MORE_LINE_DISTANCE = 10;\n\nexport const NODE_MORE_STROKE_WIDTH = 2;\n\nexport const NODE_MORE_ICON_DIAMETER = 20;\n\nexport const NODE_MORE_BRIDGE_DISTANCE = 10;\n\nexport const NODE_ADD_CIRCLE_COLOR = rgbaToHEX('#000000', 0.2);\n\nexport const NODE_ADD_HOVER_COLOR = '#6698FF';\n\nexport const NODE_ADD_INNER_CROSS_COLOR = 'white';\n\nexport const DEFAULT_MIND_IMAGE_WIDTH = 240;\n\nexport enum MindI18nKey {\n mindCentralText = 'mind-center-text',\n abstractNodeText = 'abstract-node-text'\n}","import { WithMindPluginKey } from '../../constants/default';\nimport { EmojiData, MindElement, PlaitMind } from '../../interfaces';\nimport { WithMindOptions } from '../../interfaces/options';\nimport { PlaitMindBoard } from '../../plugins/with-mind.board';\n\nexport function getEmojisWidthHeight(board: PlaitMindBoard, element: MindElement<EmojiData>) {\n const options = board.getPluginOptions<WithMindOptions>(WithMindPluginKey);\n const count = element.data.emojis.length;\n const fontSize = getEmojiFontSize(element);\n return {\n width: fontSize * count + count * 2 * options.emojiPadding + (count - 1) * options.spaceBetweenEmojis,\n height: element.height\n };\n}\n\nexport function getEmojiFontSize(element: MindElement<EmojiData>) {\n if (PlaitMind.isMind(element)) {\n return 18 + 2;\n } else {\n return 14 + 2;\n }\n}\n","import { PlaitBoard } from '@plait/core';\nimport { MindElement } from '../../interfaces/element';\n\nexport const getAvailableProperty = (board: PlaitBoard, element: MindElement, propertyKey: keyof MindElement) => {\n return element[propertyKey];\n};\n","import { GRAY_COLOR } from './default';\n\nexport const DefaultAbstractNodeStyle = {\n branch: { color: GRAY_COLOR, width: 2 },\n shape: {\n strokeColor: GRAY_COLOR,\n strokeWidth: 2\n }\n};\n\nexport const DefaultNodeStyle = {\n branch: {\n width: 2\n },\n shape: {\n rectangleRadius: 4,\n strokeWidth: 2,\n fill: 'none'\n }\n};\n","import { AbstractNode } from '@plait/layouts';\nimport { MindElement, PlaitMind } from '../../interfaces/element';\nimport { Path, PlaitBoard, PlaitElement, PlaitNode } from '@plait/core';\n\nexport const separateChildren = (parentElement: MindElement) => {\n const rightNodeCount = parentElement.rightNodeCount!;\n const children = parentElement.children;\n let rightChildren = [],\n leftChildren = [];\n\n for (let i = 0; i < children.length; i++) {\n const child = children[i];\n if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {\n rightChildren.push(child);\n continue;\n }\n if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {\n leftChildren.push(child);\n continue;\n }\n\n if (i < rightNodeCount) {\n rightChildren.push(child);\n } else {\n leftChildren.push(child);\n }\n }\n\n return { leftChildren, rightChildren };\n};\n\nexport const isSetAbstract = (element: PlaitElement) => {\n return !!getCorrespondingAbstract(element as MindElement);\n};\n\nexport const canSetAbstract = (element: PlaitElement) => {\n return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);\n};\n\nexport const getCorrespondingAbstract = (element: MindElement) => {\n const parent = MindElement.findParent(element as MindElement);\n if (!parent) return undefined;\n\n const elementIndex = parent.children.indexOf(element);\n return parent.children.find(child => {\n return AbstractNode.isAbstract(child) && elementIndex >= child.start! && elementIndex <= child.end!;\n });\n};\n\nexport const getBehindAbstracts = (element: MindElement) => {\n const parent = MindElement.findParent(element as MindElement);\n if (!parent) return [];\n const index = parent.children.indexOf(element);\n return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start! > index);\n};\n\n/**\n * return corresponding abstract that is not child of elements\n */\nexport const getOverallAbstracts = (board: PlaitBoard, elements: MindElement[]) => {\n const overallAbstracts: MindElement[] = [];\n elements\n .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))\n .forEach(value => {\n const abstract = getCorrespondingAbstract(value);\n if (abstract && elements.indexOf(abstract) === -1 && overallAbstracts.indexOf(abstract) === -1) {\n const { start, end } = abstract;\n const parent = MindElement.getParent(value);\n const isOverall = parent.children.slice(start!, end! + 1).every(includedElement => elements.indexOf(includedElement) > -1);\n if (isOverall) {\n overallAbstracts.push(abstract);\n }\n }\n });\n return overallAbstracts as (MindElement & AbstractNode)[];\n};\n\nexport interface AbstractRef {\n abstract: MindElement & AbstractNode;\n references: MindElement[];\n}\n\n/**\n * abstract node is valid when elements contains at least one element it is referenced with\n */\nexport const getValidAbstractRefs = (board: PlaitBoard, elements: MindElement[]) => {\n const validAbstractRefs: AbstractRef[] = [];\n elements\n .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))\n .forEach(value => {\n const abstract = getCorrespondingAbstract(value);\n if (abstract && elements.indexOf(abstract) > 0) {\n const index = validAbstractRefs.findIndex(value => value.abstract === abstract);\n if (index === -1) {\n validAbstractRefs.push({\n abstract: abstract as MindElement & AbstractNode,\n references: [value]\n });\n } else {\n validAbstractRefs[index].references.push(value);\n }\n }\n });\n return validAbstractRefs;\n};\n\nexport function getRelativeStartEndByAbstractRef(abstractRef: AbstractRef, elements: MindElement[]) {\n const start = elements.indexOf(abstractRef.references[0]);\n const end = elements.indexOf(abstractRef.references[abstractRef.references.length - 1]);\n return { start, end };\n}\n\nexport const insertElementHandleAbstract = (\n board: PlaitBoard,\n path: Path,\n step = 1,\n // This distinguishes between dragging and adding to the last node summarized in the abstract node\n isExtendPreviousNode: boolean = true,\n effectedAbstracts = new Map<MindElement, Pick<AbstractNode, 'start' | 'end'>>()\n) => {\n const parent = PlaitNode.parent(board, path) as MindElement;\n const hasPreviousNode = path[path.length - 1] !== 0;\n let behindAbstracts: MindElement[];\n\n if (!hasPreviousNode) {\n behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));\n } else {\n const selectedElement = PlaitNode.get(board, Path.previous(path)) as MindElement;\n behindAbstracts = getBehindAbstracts(selectedElement);\n }\n\n if (behindAbstracts.length) {\n behindAbstracts.forEach(abstract => {\n let newProperties = effectedAbstracts.get(abstract);\n if (!newProperties) {\n newProperties = { start: 0, end: 0 };\n effectedAbstracts.set(abstract, newProperties);\n }\n newProperties.start = newProperties.start + step;\n newProperties.end = newProperties.end + step;\n });\n }\n\n if (!hasPreviousNode) {\n return effectedAbstracts;\n }\n\n const selectedElement = PlaitNode.get(board, Path.previous(path)) as MindElement;\n const correspondingAbstract = getCorrespondingAbstract(selectedElement);\n const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;\n\n if (correspondingAbstract && !isDragToLast) {\n let newProperties = effectedAbstracts.get(correspondingAbstract);\n if (!newProperties) {\n newProperties = { start: 0, end: 0 };\n effectedAbstracts.set(correspondingAbstract, newProperties);\n }\n newProperties.end = newProperties.end + step;\n }\n\n return effectedAbstracts;\n};\n\nexport const deleteElementHandleAbstract = (\n board: PlaitBoard,\n deletableElements: MindElement[],\n effectedAbstracts = new Map<MindElement, Pick<AbstractNode, 'start' | 'end'>>()\n) => {\n deletableElements.forEach(node => {\n if (!PlaitMind.isMind(node)) {\n const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));\n if (behindAbstracts.length) {\n behindAbstracts.forEach(abstract => {\n let newProperties = effectedAbstracts.get(abstract);\n if (!newProperties) {\n newProperties = { start: 0, end: 0 };\n effectedAbstracts.set(abstract, newProperties);\n }\n newProperties.start = newProperties.start - 1;\n newProperties.end = newProperties.end - 1;\n });\n }\n\n const correspondingAbstract = getCorrespondingAbstract(node);\n if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {\n let newProperties = effectedAbstracts.get(correspondingAbstract);\n if (!newProperties) {\n newProperties = { start: 0, end: 0 };\n\n effectedAbstracts.set(correspondingAbstract, newProperties);\n }\n newProperties.end = newProperties.end - 1;\n }\n }\n });\n return effectedAbstracts;\n};\n\nexport const isChildOfAbstract = (board: PlaitBoard, element: MindElement) => {\n const ancestors = MindElement.getAncestors(board, element) as MindElement[];\n return !!ancestors.find(value => AbstractNode.isAbstract(value));\n};\n","/**\n * Processing of branch color, width, style, etc. of the mind node\n */\nimport { PlaitBoard, isNullOrUndefined } from '@plait/core';\nimport { BranchShape, MindElement } from '../../interfaces/element';\nimport { STROKE_WIDTH } from '../../constants/default';\nimport { DefaultAbstractNodeStyle } from '../../constants/node-style';\nimport { getAvailableProperty } from './common';\nimport { MindDefaultThemeColor, MindThemeColor } from '../../interfaces/theme-color';\nimport { AbstractNode } from '@plait/layouts';\nimport { isChildOfAbstract } from '../abstract/common';\n\nexport const getBranchColorByMindElement = (board: PlaitBoard, element: MindElement) => {\n if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {\n return getAbstractBranchColor(board, element);\n }\n\n const branchColor = getAvailableProperty(board, element, 'branchColor') || getAvailableProperty(board, element, 'strokeColor');\n return branchColor || getDefaultBranchColor(board, element);\n};\n\nexport const getBranchShapeByMindElement = (board: PlaitBoard, element: MindElement) => {\n const branchShape = getAvailableProperty(board, element, 'branchShape');\n return branchShape || BranchShape.bight;\n};\n\nexport const getBranchWidthByMindElement = (board: PlaitBoard, element: MindElement) => {\n const branchWidth = getAvailableProperty(board, element, 'branchWidth') || getAvailableProperty(board, element, 'strokeWidth');\n return branchWidth || STROKE_WIDTH;\n};\n\nexport const getAbstractBranchWidth = (board: PlaitBoard, element: MindElement) => {\n if (!isNullOrUndefined(element.branchWidth)) {\n return element.branchWidth as number;\n }\n return DefaultAbstractNodeStyle.branch.width;\n};\n\nexport const getAbstractBranchColor = (board: PlaitBoard, element: MindElement) => {\n if (element.branchColor || element.strokeColor) {\n return element.branchColor || element.strokeColor;\n }\n return DefaultAbstractNodeStyle.branch.color;\n};\n\nexport const getNextBranchColor = (board: PlaitBoard, root: MindElement) => {\n const index = root.children.length;\n return getDefaultBranchColorByIndex(board, index);\n};\n\nexport const getDefaultBranchColor = (board: PlaitBoard, element: MindElement) => {\n const path = PlaitBoard.findPath(board, element);\n return getDefaultBranchColorByIndex(board, path[1]);\n};\n\nexport const getDefaultBranchColorByIndex = (board: PlaitBoard, index: number) => {\n const themeColor = getMindThemeColor(board);\n const length = themeColor.branchColors.length;\n const remainder = index % length;\n return themeColor.branchColors[remainder];\n};\n\nexport const getMindThemeColor = (board: PlaitBoard) => {\n const themeColors = PlaitBoard.getThemeColors(board);\n const themeColor = themeColors.find(val => val.mode === board.theme.themeColorMode);\n if (themeColor && MindThemeColor.isMindThemeColor(themeColor)) {\n return themeColor;\n } else {\n return MindDefaultThemeColor;\n }\n};\n","import { PlaitBoard } from '@plait/core';\nimport { MindElement, MindElementShape, PlaitMind } from '../../interfaces/element';\nimport { getAvailableProperty } from './common';\nimport { getDefaultBranchColor, getMindThemeColor } from './branch';\nimport { AbstractNode } from '@plait/layouts';\nimport { isChildOfAbstract } from '../abstract/common';\nimport { DefaultAbstractNodeStyle, DefaultNodeStyle } from '../../constants/node-style';\nimport { StrokeStyle } from '@plait/common';\n\nexport const getStrokeColorByElement = (board: PlaitBoard, element: MindElement) => {\n if (PlaitMind.isMind(element)) {\n const defaultRootStroke = getMindThemeColor(board).rootFill;\n return element.strokeColor || defaultRootStroke;\n }\n\n if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {\n return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;\n }\n\n return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);\n};\n\nexport const getStrokeStyleByElement = (board: PlaitBoard, element: MindElement) => {\n return element.strokeStyle || StrokeStyle.solid;\n};\n\nexport const getStrokeWidthByElement = (board: PlaitBoard, element: MindElement) => {\n const strokeWidth =\n element.strokeWidth ||\n (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);\n return strokeWidth;\n};\n\nexport const getFillByElement = (board: PlaitBoard, element: MindElement) => {\n if (element.fill) {\n return element.fill;\n }\n const defaultRootFill = getMindThemeColor(board).rootFill;\n return PlaitMind.isMind(element) ? defaultRootFill : DefaultNodeStyle.shape.fill;\n};\n\nexport const getShapeByElement = (board: PlaitBoard, element: MindElement): MindElementShape => {\n const shape = getAvailableProperty(board, element, 'shape');\n return shape || MindElementShape.roundRectangle;\n};\n","import { PlaitBoard, PlaitElement, getSelectedElements } from '@plait/core';\nimport { MindElement } from '../../interfaces/element';\nimport { getFirstTextManage } from '@plait/common';\n\nexport function editTopic(element: MindElement) {\n const textManage = getFirstTextManage(element);\n textManage?.edit(\n () => {},\n event => {\n const keyboardEvent = event as KeyboardEvent;\n return keyboardEvent.key === 'Enter' && !keyboardEvent.shiftKey;\n }\n );\n}\n\nexport const getSelectedMindElements = (board: PlaitBoard, elements?: PlaitElement[]) => {\n const selectedElements = elements?.length ? elements : getSelectedElements(board);\n return selectedElements.filter(value => MindElement.isMindElement(board, value)) as MindElement[];\n};\n","import { LayoutDirection, LayoutDirectionsMap, MindElement, PlaitMind } from '../interfaces';\nimport { isIndentedLayout, MindLayoutType } from '@plait/layouts';\n\nexport const getBranchDirectionsByLayouts = (branchLayouts: MindLayoutType[]) => {\n const branchDirections: LayoutDirection[] = [];\n branchLayouts.forEach(l => {\n const directions = LayoutDirectionsMap[l];\n directions.forEach(d => {\n if (!branchDirections.includes(d) && !branchDirections.includes(getLayoutReverseDirection(d))) {\n branchDirections.push(d);\n }\n });\n });\n return branchDirections;\n};\n\nexport const isCorrectLayout = (root: MindElement, layout: MindLayoutType) => {\n const rootLayout = root.layout || getDefaultLayout();\n return !getInCorrectLayoutDirection(rootLayout, layout);\n};\n\nexport const isMixedLayout = (parentLayout: MindLayoutType, layout: MindLayoutType) => {\n return (!isIndentedLayout(parentLayout) && isIndentedLayout(layout)) || (isIndentedLayout(parentLayout) && !isIndentedLayout(layout));\n};\n\nexport const getInCorrectLayoutDirection = (rootLayout: MindLayoutType, layout: MindLayoutType) => {\n const directions = LayoutDirectionsMap[rootLayout];\n const subLayoutDirections = LayoutDirectionsMap[layout];\n if (!subLayoutDirections) {\n throw new Error(`unexpected layout: ${layout} on correct layout`);\n }\n return subLayoutDirections.find(d => directions.includes(getLayoutReverseDirection(d)));\n};\n\nexport const correctLayoutByDirection = (layout: MindLayoutType, direction: LayoutDirection) => {\n const isHorizontal = direction === LayoutDirection.left || direction === LayoutDirection.right ? true : false;\n let inverseDirectionLayout = MindLayoutType.standard;\n switch (layout) {\n case MindLayoutType.left:\n inverseDirectionLayout = MindLayoutType.right;\n break;\n case MindLayoutType.right:\n inverseDirectionLayout = MindLayoutType.left;\n break;\n case MindLayoutType.downward:\n inverseDirectionLayout = MindLayoutType.upward;\n break;\n case MindLayoutType.upward:\n inverseDirectionLayout = MindLayoutType.downward;\n break;\n case MindLayoutType.rightBottomIndented:\n inverseDirectionLayout = isHorizontal ? MindLayoutType.leftBottomIndented : MindLayoutType.rightTopIndented;\n break;\n case MindLayoutType.leftBottomIndented:\n inverseDirectionLayout = isHorizontal ? MindLayoutType.rightBottomIndented : MindLayoutType.leftTopIndented;\n break;\n case MindLayoutType.rightTopIndented:\n inverseDirectionLayout = isHorizontal ? MindLayoutType.leftTopIndented : MindLayoutType.rightBottomIndented;\n break;\n case MindLayoutType.leftTopIndented:\n inverseDirectionLayout = isHorizontal ? MindLayoutType.rightTopIndented : MindLayoutType.leftBottomIndented;\n break;\n }\n return inverseDirectionLayout;\n};\n\nexport const getLayoutDirection = (root: MindElement) => {\n const layout = root.layout || getDefaultLayout();\n return LayoutDirectionsMap[layout];\n};\n\nexport const getDefaultLayout = () => {\n return MindLayoutType.standard;\n};\n\nexport const getAvailableSubLayoutsByLayoutDirections = (directions: LayoutDirection[]): MindLayoutType[] => {\n const result: MindLayoutType[] = [];\n const reverseDirections = directions.map(getLayoutReverseDirection);\n for (const key in MindLayoutType) {\n const layout = MindLayoutType[key as keyof typeof MindLayoutType];\n const layoutDirections = LayoutDirectionsMap[layout];\n if (layoutDirections) {\n const hasSameDirection = layoutDirections.some(d => directions.includes(d));\n const hasReverseDirection = layoutDirections.some(r => reverseDirections.includes(r));\n if (hasSameDirection && !hasReverseDirection) {\n result.push(layout);\n }\n }\n }\n return result;\n};\n\nexport const getLayoutReverseDirection = (layoutDirection: LayoutDirection) => {\n let reverseDirection = LayoutDirection.right;\n switch (layoutDirection) {\n case LayoutDirection.top:\n reverseDirection = LayoutDirection.bottom;\n break;\n case LayoutDirection.bottom:\n reverseDirection = LayoutDirection.top;\n break;\n case LayoutDirection.right:\n reverseDirection = LayoutDirection.left;\n break;\n case LayoutDirection.left:\n reverseDirection = LayoutDirection.right;\n break;\n }\n return reverseDirection;\n};\n\nexport const getRootLayout = (root: MindElement) => {\n return root.layout || getDefaultLayout();\n};\n","import {\n ConnectingPosition,\n LayoutNode,\n LayoutOptions,\n OriginNode,\n isHorizontalLayout,\n isHorizontalLogicLayout,\n isIndentedLayout\n} from '@plait/layouts';\nimport { MindElement, MindElementShape, PlaitMind } from '../../interfaces/element';\nimport { BASE } from '../../constants/default';\nimport { getRootLayout } from '../layout';\nimport { NodeSpace } from './node-space';\nimport { PlaitMindBoard } from '../../plugins/with-mind.board';\n\nexport const getLayoutOptions = (board: PlaitMindBoard) => {\n function getMainAxle(element: MindElement, parent?: LayoutNode) {\n if (PlaitMind.isMind(element)) {\n return BASE * 12;\n }\n if (parent && parent.isRoot()) {\n return BASE * 3;\n }\n return BASE * 3;\n }\n\n function getSecondAxle(element: MindElement, parent?: LayoutNode) {\n if (PlaitMind.isMind(element)) {\n return BASE * 12;\n }\n return BASE * 8.5;\n }\n\n return {\n getHeight(element: MindElement) {\n return NodeSpace.getNodeHeight(board, element);\n },\n getWidth(element: MindElement) {\n return NodeSpace.getNodeWidth(board, element);\n },\n getHorizontalGap(element: MindElement, parent?: LayoutNode) {\n const _layout = (parent && parent.layout) || getRootLayout(element);\n const isHorizontal = isHorizontalLayout(_layout);\n if (isIndentedLayout(_layout)) {\n return BASE * 6;\n }\n if (!isHorizontal) {\n return getMainAxle(element, parent);\n } else {\n return getSecondAxle(element, parent);\n }\n },\n getVerticalGap(element: MindElement, parent?: LayoutNode) {\n const _layout = (parent && parent.layout) || getRootLayout(element);\n if (isIndentedLayout(_layout)) {\n return BASE * 3.5;\n }\n const isHorizontal = isHorizontalLayout(_layout);\n if (isHorizontal) {\n return getMainAxle(element, parent);\n } else {\n return getSecondAxle(element, parent);\n }\n },\n getVerticalConnectingPosition(element: MindElement, parent?: LayoutNode) {\n if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {\n return ConnectingPosition.bottom;\n }\n return undefined;\n },\n getExtendHeight(node: OriginNode) {\n return 0;\n },\n getIndentedCrossLevelGap() {\n return BASE * 1;\n }\n } as LayoutOptions;\n};\n","import { getI18nValue, PlaitBoard } from '@plait/core';\nimport { MindI18nKey } from '../constants/default';\n\nexport const MIND_CENTRAL_TEXT = '中心主题';\n\nexport const ABSTRACT_NODE_TEXT = '概要';\n\nexport const getDefaultMindNameText = (board: PlaitBoard) => {\n return getI18nValue(board, MindI18nKey.mindCentralText, MIND_CENTRAL_TEXT);\n};\n\nexport const getAbstractNodeText = (board: PlaitBoard) => {\n return getI18nValue(board, MindI18nKey.abstractNodeText, ABSTRACT_NODE_TEXT);\n};\n","import { PlaitBoard, Point, idCreator, isNullOrUndefined } from '@plait/core';\nimport { MindLayoutType } from '@plait/layouts';\nimport { BranchShape, MindElement, MindElementShape } from '../../interfaces/element';\nimport { Element } from 'slate';\nimport { NodeSpace } from '../space';\nimport { PlaitMindBoard } from '../../plugins/with-mind.board';\nimport { buildText } from '@plait/common';\nimport { getDefaultMindNameText } from '../common';\n\nexport const createEmptyMind = (board: PlaitBoard, point: Point) => {\n const text = getDefaultMindNameText(board);\n const element = createMindElement(text, { layout: MindLayoutType.right });\n element.type = 'mind';\n const width = NodeSpace.getNodeWidth(board as PlaitMindBoard, element);\n const height = NodeSpace.getNodeHeight(board as PlaitMindBoard, element);\n element.points = [[point[0] - width / 2, point[1] - height / 2]];\n return element;\n};\n\nexport const createMindElement = (text: string | Element, options: InheritAttribute) => {\n const newElement: MindElement = {\n id: idCreator(),\n type: 'mind_child',\n data: {\n topic: buildText(text)\n },\n children: []\n };\n let key: keyof typeof options;\n for (key in options) {\n if (!isNullOrUndefined(options[key])) {\n (newElement as any)[key] = options[key];\n }\n }\n return newElement;\n};\n\nexport interface InheritAttribute {\n fill?: string;\n strokeColor?: string;\n strokeWidth?: number;\n strokeStyle?: number;\n shape?: MindElementShape;\n layout?: MindLayoutType;\n branchColor?: string;\n branchWidth?: number;\n branchShape?: BranchShape;\n}\n\nexport const INHERIT_ATTRIBUTE_KEYS = [\n 'fill',\n 'strokeColor',\n 'strokeWidth',\n 'strokeStyle',\n 'shape',\n 'layout',\n 'branchColor',\n 'branchWidth',\n 'branchShape'\n];\n","export const TOPIC_FONT_SIZE = 14;\n\nexport const ROOT_TOPIC_FONT_SIZE = 18;\n\nexport const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;\n","import { addSelectedElement, clearSelectedElement, idCreator, Path, PlaitBoard, Transforms } from '@plait/core';\nimport { MindElement, PlaitMind } from '../interfaces/element';\nimport { editTopic } from './node/common';\nimport { createMindElement, INHERIT_ATTRIBUTE_KEYS, InheritAttribute } from './node/create-node';\nimport { MindNode } from '../interfaces/node';\nimport { PlaitMindBoard } from '../plugins/with-mind.board';\nimport { ROOT_TOPIC_FONT_SIZE, TOPIC_FONT_SIZE } from '../constants/node-topic-style';\n\nexport const getChildrenCount = (element: MindElement) => {\n const count: number = element.children.reduce((p: number, c: MindElement) => {\n return p + getChildrenCount(c);\n }, 0);\n return count + element.children.length;\n};\n\nexport const isChildElement = (origin: MindElement, child: MindElement) => {\n let parent = MindElement.findParent(child);\n while (parent) {\n if (parent === origin) {\n return true;\n }\n parent = MindElement.findParent(parent);\n }\n return false;\n};\n\nexport const getFirstLevelElement = (elements: MindElement[]) => {\n let result: MindElement[] = [];\n elements.forEach((element) => {\n const isChild = elements.some((node) => {\n return isChildElement(node, element);\n });\n\n if (!isChild) {\n result.push(element);\n }\n });\n return result;\n};\n\nexport const isChildRight = (parent: MindNode, child: MindNode) => {\n return parent.x < child.x;\n};\n\nexport const isChildUp = (parent: MindNode, child: MindNode) => {\n return parent.y > child.y;\n};\n\nexport const copyNewNode = (node: MindElement) => {\n const newNode: MindElement = { ...node };\n newNode.id = idCreator();\n newNode.children = [];\n\n for (const childNode of node.children) {\n newNode.children.push(copyNewNode(childNode));\n }\n return newNode;\n};\n\nexport const insertMindElement = (board: PlaitMindBoard, inheritNode: MindElement, path: Path) => {\n const newNode: InheritAttribute = {};\n if (!PlaitMind.isMind(inheritNode)) {\n INHERIT_ATTRIBUTE_KEYS.forEach((attr) => {\n (newNode as any)[attr] = inheritNode[attr];\n });\n delete newNode.layout;\n }\n const newElement = createMindElement('', newNode);\n Transforms.insertNode(board, newElement, path);\n clearSelectedElement(board);\n addSelectedElement(board, newElement);\n setTimeout(() => {\n editTopic(newElement);\n });\n};\n\nexport const findLastChild = (child: MindNode) => {\n let result = child;\n while (result.children.length !== 0) {\n result = result.children[result.children.length - 1];\n }\n return result;\n};\n\nexport const divideElementByParent = (elements: MindElement[]) => {\n const abstractIncludedGroups = [];\n const parentElements: MindElement[] = [];\n\n for (let i = 0; i < elements.length; i++) {\n const parent = MindElement.getParent(elements[i]);\n const parentIndex = parentElements.indexOf(parent);\n if (parentIndex === -1) {\n parentElements.push(parent);\n abstractIncludedGroups.push([elements[i]]);\n } else {\n abstractIncludedGroups[parentIndex].push(elements[i]);\n }\n }\n return { parentElements, abstractIncludedGroups };\n};\n\nexport const getDefaultFontSizeForMindElement = (element: MindElement) => {\n if (PlaitMind.isMind(element)) {\n return ROOT_TOPIC_FONT_SIZE;\n }\n if (MindElement.isMindElement(null, element)) {\n return TOPIC_FONT_SIZE;\n }\n throw new Error('can not find default font-size');\n};\n","export const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity\nexport const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;\nexport const ABSTRACT_HANDLE_LENGTH = 10;\n\nexport const ABSTRACT_HANDLE_MASK_WIDTH = 8;\n","import { BASE, WithMindPluginKey } from '../../constants/default';\nimport { PlaitMind } from '../../interfaces/element';\nimport { MindElement } from '../../interfaces/element';\nimport { EmojiData } from '../../interfaces/element-data';\nimport { WithMindOptions } from '../../interfaces/options';\nimport { PlaitMindBoard } from '../../plugins/with-mind.board';\nimport { getEmojisWidthHeight } from './emoji';\nimport { getStrokeWidthByElement } from '../node-style/shape';\nimport { getDefaultFontSizeForMindElement } from '../mind';\nimport { DEFAULT_FONT_SIZE, MarkTypes, PlaitMarkEditor } from '@plait/text-plugins';\nimport { DEFAULT_FONT_FAMILY, getElementSize } from '@plait/common';\nimport { PlaitBoard } from '@plait/core';\nimport { TOPIC_DEFAULT_MAX_WORD_COUNT } from '../../constants';\n\nconst NodeDefaultSpace = {\n horizontal: {\n nodeAndText: BASE * 2.5,\n emojiAndText: BASE * 1.5\n },\n vertical: {\n nodeAndText: BASE,\n nodeAndImage: BASE,\n imageAndText: BASE * 1.5\n }\n};\n\nconst RootDefaultSpace = {\n horizontal: {\n nodeAndText: BASE * 4,\n emojiAndText: BASE * 2\n },\n vertical: {\n nodeAndText: BASE * 2\n }\n};\n\nconst getHorizontalSpaceBetweenNodeAndText = (board: PlaitMindBoard, element: MindElement) => {\n const isMind = PlaitMind.isMind(element);\n const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;\n const strokeWidth = getStrokeWidthByElement(board, element);\n return nodeAndText + strokeWidth;\n};\n\nconst getVerticalSpaceBetweenNodeAndText = (board: PlaitMindBoard, element: MindElement) => {\n const isMind = PlaitMind.isMind(element);\n const strokeWidth = getStrokeWidthByElement(board, element);\n const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;\n return nodeAndText + strokeWidth;\n};\n\nconst getSpaceEmojiAndText = (element: MindElement) => {\n const isMind = PlaitMind.isMind(element);\n const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;\n return emojiAndText;\n};\n\nexport const NodeSpace = {\n getNodeWidth(board: PlaitMindBoard, element: MindElement) {\n const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);\n if (MindElement.hasEmojis(element)) {\n return (\n NodeSpace.getEmojiLeftSpace(board, element) +\n getEmojisWidthHeight(board, element).width +\n getSpaceEmojiAndText(element) +\n NodeSpace.getTopicDynamicWidth(board, element) +\n nodeAndText\n );\n }\n return nodeAndText + NodeSpace.getTopicDynamicWidth(board, element) + nodeAndText;\n },\n getNodeHeight(board: PlaitMindBoard, element: MindElement) {\n const topicSize = getElementSize(\n board,\n element.data.topic,\n { fontSize: DEFAULT_FONT_SIZE, fontFamily: DEFAULT_FONT_FAMILY },\n NodeSpace.getTopicMaxDynamicWidth(board, element)\n );\n const normalizedSize = normalizeWidthAndHeight(board, element, topicSize.width, topicSize.height);\n const nodeAndText = getVerticalSpaceBetweenNodeAndText(board, element);\n if (MindElement.hasImage(element)) {\n return NodeSpace.getTextTopSpace(board, element) + normalizedSize.height + nodeAndText;\n }\n return nodeAndText + normalizedSize.height + nodeAndText;\n },\n getTopicDynamicWidth(board: PlaitMindBoard, element: MindElement) {\n const topicSize = getElementSize(\n board,\n element.data.topic,\n { fontSize: getDefaultFontSizeForMindElement(element), fontFamily: DEFAULT_FONT_FAMILY },\n NodeSpace.getTopicMaxDynamicWidth(board, element)\n );\n const normalizedSize = normalizeWidthAndHeight(board, element, topicSize.width, topicSize.width);\n const width = element.manualWidth || normalizedSize.width;\n const imageWidth = MindElement.hasImage(element) ? element.data.image?.width : 0;\n return Math.max(width, imageWidth);\n },\n getTopicHeight(board: PlaitMindBoard, element: MindElement) {\n const topicSize = getElementSize(\n board,\n element.data.topic,\n { fontSize: DEFAULT_FONT_SIZE, fontFamily: DEFAULT_FONT_FAMILY },\n NodeSpace.getTopicMaxDynamicWidth(board, element)\n );\n const normalizedSize = normalizeWidthAndHeight(board, element, topicSize.width, topicSize.height);\n return normalizedSize.height;\n },\n getTopicMaxDynamicWidth(board: PlaitMindBoard, element: MindElement) {\n const fontSize = getDefaultFontSizeForMindElement(element);\n if (element.manualWidth) {\n return Math.max(element.manualWidth, MindElement.hasImage(element) ? element.data.image?.width : 0);\n }\n return Math.max(fontSize * TOPIC_DEFAULT_MAX_WORD_COUNT, MindElement.hasImage(element) ? element.data.image?.width : 0);\n },\n getNodeResizableMinWidth(board: PlaitMindBoard, element: MindElement) {\n const minTopicWidth = NodeSpace.getNodeTopicMinWidth(board, element);\n if (MindElement.hasImage(element) && element.data.image.width > minTopicWidth) {\n return element.data.image.width;\n } else {\n return minTopicWidth;\n }\n },\n getNodeTopicMinWidth(board: PlaitMindBoard, element: MindElement) {\n return getFontSizeByMindElement(board, element);\n },\n getTextLeftSpace(board: PlaitMindBoard, element: MindElement) {\n const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);\n if (MindElement.hasEmojis(element)) {\n return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);\n } else {\n return nodeAndText;\n }\n },\n getTextTopSpace(board: PlaitMindBoard, element: MindElement) {\n const nodeAndText = getVerticalSpaceBetweenNodeAndText(board, element);\n if (MindElement.hasImage(element)) {\n return NodeSpace.getImageTopSpace(board, element) + element.data.image.height + NodeDefaultSpace.vertical.imageAndText;\n } else {\n return nodeAndText;\n }\n },\n getImageTopSpace(board: PlaitMindBoard, element: MindElement) {\n const strokeWidth = getStrokeWidthByElement(board, element);\n return strokeWidth + NodeDefaultSpace.vertical.nodeAndImage;\n },\n getEmojiLeftSpace(board: PlaitMindBoard, element: MindElement<EmojiData>) {\n const options = board.getPluginOptions<WithMindOptions>(WithMindPluginKey);\n const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);\n return nodeAndText - options.emojiPadding;\n },\n getEmojiTopSpace(board: PlaitMindBoard, element: MindElement) {\n const nodeAndText = getVerticalSpaceBetweenNodeAndText(board, element);\n return nodeAndText;\n }\n};\n\nexport const getFontSizeByMindElement = (board: PlaitBoard, element: MindElement) => {\n const defaultFontSize = getDefaultFontSizeForMindElement(element);\n const marks = PlaitMarkEditor.getMarksByElement(element.data.topic);\n const fontSize = (marks[MarkTypes.fontSize] as number) || defaultFontSize;\n return fontSize;\n};\n\nexport const normalizeWidthAndHeight = (board: PlaitMindBoard, element: MindElement, width: number, height: number) => {\n const minWidth = NodeSpace.getNodeTopicMinWidth(board, element);\n const newWidth = width < minWidth ? minWidth : width;\n return { width: newWidth, height };\n};\n","import { PlaitBoard, Point, RectangleClient, distanceBetweenPointAndRectangle } from '@plait/core';\nimport { MindNode } from '../../interfaces/node';\nimport { MindElement } from '../../interfaces/element';\nimport { NodeSpace } from '../space/node-space';\nimport { PlaitMindBoard } from '../../plugins/with-mind.board';\nimport { MIND_ELEMENT_TO_NODE } from '../weak-maps';\n\nexport function getRectangleByNode(node: MindNode): RectangleClient {\n const x = node.x + node.hGap;\n let y = node.y + node.vGap;\n const width = node.width - node.hGap * 2;\n const height = node.height - node.vGap * 2;\n return {\n x,\n y,\n width,\n height\n };\n}\n\nexport function getRectangleByElement(board: PlaitMindBoard, element: MindElement) {\n const width = NodeSpace.getNodeWidth(board, element);\n const height = NodeSpace.getNodeHeight(board, element);\n const nodeRectangle = {\n x: element.points![0][0],\n y: element.points![0][1],\n width,\n height\n };\n return nodeRectangle;\n}\n\nexport function isHitMindElement(board: PlaitBoard, point: Point, element: MindElement) {\n const node = MIND_ELEMENT_TO_NODE.get(element);\n