| { text: string } | null
-
-const getNodeText = (data: NodeData): string => {
- return data.richText ? nodeRichTextToTextWithWrap(data.text) : data.text
-}
-
-const getTitleMark = (level: number): string => {
- return new Array(level).fill('#').join('')
-}
-
-const getIndentMark = (level: number): string => {
- return new Array(level - 6).fill(' ').join('') + '*'
-}
-
-// 转换成markdown格式
-export const transformToMarkdown = (root: Node): string => {
- let content = ''
- walk(
- root,
- null,
- (node: Node, parent: Node | null, isRoot: boolean, layerIndex: number) => {
- const level = layerIndex + 1
- if (level <= 6) {
- content += getTitleMark(level)
- } else {
- content += getIndentMark(level)
- }
- content += ' ' + getNodeText(node.data)
- // 概要
- const generalization = node.data.generalization
- if (Array.isArray(generalization)) {
- content += generalization.map(item => {
- return ` [${getNodeText(item)}]`
- })
- } else if (generalization && 'text' in generalization) {
- const generalizationText = getNodeText(generalization)
- content += ` [${generalizationText}]`
- }
- content += '\n\n'
- // 备注
- if (node.data.note) {
- content += node.data.note + '\n\n'
- }
- },
- () => { },
- true
- )
- return content
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/parse/toTxt.ts b/packages/mindmap/src/parse/toTxt.ts
deleted file mode 100644
index 14ae4d6..0000000
--- a/packages/mindmap/src/parse/toTxt.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { walk, nodeRichTextToTextWithWrap } from '../utils'
-import { NodeData, Node } from "../types"
-
-
-const getNodeText = (data: NodeData): string => {
- return data.richText ? nodeRichTextToTextWithWrap(data.text) : data.text
-}
-
-const getIndent = (level: number): string => {
- return new Array(level).fill(' ').join('')
-}
-
-// 转换成txt格式
-export const transformToTxt = (root: Node): string => {
- let content = ''
- walk(
- root,
- null,
- (node: Node, parent: Node | null, isRoot: boolean, layerIndex: number) => {
- content += getIndent(layerIndex)
- content += ' ' + getNodeText(node.data)
- // 概要
- const generalization = node.data.generalization
- if (Array.isArray(generalization)) {
- content += generalization.map(item => {
- return ` [${getNodeText(item)}]`
- })
- } else if (generalization && generalization.text) {
- content += ` [${getNodeText(generalization)}]`
- }
- content += '\n\n'
- },
- () => { },
- true
- )
- return content
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/parse/xmind.js b/packages/mindmap/src/parse/xmind.js
deleted file mode 100644
index 3040e26..0000000
--- a/packages/mindmap/src/parse/xmind.js
+++ /dev/null
@@ -1,335 +0,0 @@
-import JSZip from 'jszip'
-import xmlConvert from 'xml-js'
-import { getTextFromHtml, isUndef } from '../utils/index'
-import {
- getSummaryText,
- getSummaryText2,
- getRoot,
- getItemByName,
- getElementsByType,
- addSummaryData,
- handleNodeImageFromXmind,
- handleNodeImageToXmind,
- getXmindContentXmlData,
- parseNodeGeneralizationToXmind
-} from '../utils/xmind'
-
-// 解析.xmind文件
-const parseXmindFile = (file, handleMultiCanvas) => {
- return new Promise((resolve, reject) => {
- JSZip.loadAsync(file).then(
- async zip => {
- try {
- let content = ''
- let jsonFile = zip.files['content.json']
- let xmlFile = zip.files['content.xml'] || zip.files['/content.xml']
- if (jsonFile) {
- let json = await jsonFile.async('string')
- content = await transformXmind(json, zip.files, handleMultiCanvas)
- } else if (xmlFile) {
- let xml = await xmlFile.async('string')
- let json = xmlConvert.xml2json(xml)
- content = transformOldXmind(json)
- }
- if (content) {
- resolve(content)
- } else {
- reject(new Error('解析失败'))
- }
- } catch (error) {
- reject(error)
- }
- },
- e => {
- reject(e)
- }
- )
- })
-}
-
-// 转换xmind数据
-const transformXmind = async (content, files, handleMultiCanvas) => {
- content = JSON.parse(content)
- let data = null
- if (content.length > 1 && typeof handleMultiCanvas === 'function') {
- data = await handleMultiCanvas(content)
- }
- if (!data) {
- data = content[0]
- }
- const nodeTree = data.rootTopic
- const newTree = {}
- const waitLoadImageList = []
- const walk = async (node, newNode) => {
- newNode.data = {
- // 节点内容
- text: isUndef(node.title) ? '' : node.title
- }
- // 节点备注
- if (node.notes) {
- const notesData = node.notes.realHTML || node.notes.plain
- newNode.data.note = notesData ? notesData.content || '' : ''
- }
- // 超链接
- if (node.href && /^https?:\/\//.test(node.href)) {
- newNode.data.hyperlink = node.href
- }
- // 标签
- if (node.labels && node.labels.length > 0) {
- newNode.data.tag = node.labels
- }
- // 图片
- handleNodeImageFromXmind(node, newNode, waitLoadImageList, files)
- // 概要
- const selfSummary = []
- const childrenSummary = []
- if (newNode._summary) {
- selfSummary.push(newNode._summary)
- }
- if (Array.isArray(node.summaries) && node.summaries.length > 0) {
- node.summaries.forEach(item => {
- addSummaryData(
- selfSummary,
- childrenSummary,
- () => {
- return getSummaryText(node, item.topicId)
- },
- item.range
- )
- })
- }
- newNode.data.generalization = selfSummary
- // 子节点
- newNode.children = []
- if (
- node.children &&
- node.children.attached &&
- node.children.attached.length > 0
- ) {
- node.children.attached.forEach((item, index) => {
- const newChild = {}
- newNode.children.push(newChild)
- if (childrenSummary[index]) {
- newChild._summary = childrenSummary[index]
- }
- walk(item, newChild)
- })
- }
- }
- walk(nodeTree, newTree)
- await Promise.all(waitLoadImageList)
- return newTree
-}
-
-// 转换旧版xmind数据,xmind8
-const transformOldXmind = content => {
- const data = JSON.parse(content)
- const elements = data.elements
- const root = getRoot(elements)
- const newTree = {}
- const walk = (node, newNode) => {
- const nodeElements = node.elements
- let nodeTitle = getItemByName(nodeElements, 'title')
- nodeTitle = nodeTitle && nodeTitle.elements && nodeTitle.elements[0].text
- // 节点内容
- newNode.data = {
- text: isUndef(nodeTitle) ? '' : nodeTitle
- }
- // 节点备注
- try {
- const notesElement = getItemByName(nodeElements, 'notes')
- if (notesElement) {
- newNode.data.note =
- notesElement.elements[0].elements[0].elements[0].text
- }
- } catch (error) {
- console.log(error)
- }
- // 超链接
- try {
- if (
- node.attributes &&
- node.attributes['xlink:href'] &&
- /^https?:\/\//.test(node.attributes['xlink:href'])
- ) {
- newNode.data.hyperlink = node.attributes['xlink:href']
- }
- } catch (error) {
- console.log(error)
- }
- // 标签
- try {
- const labelsElement = getItemByName(nodeElements, 'labels')
- if (labelsElement) {
- newNode.data.tag = labelsElement.elements.map(item => {
- return item.elements[0].text
- })
- }
- } catch (error) {
- console.log(error)
- }
- const childrenItem = getItemByName(nodeElements, 'children')
- // 概要
- const selfSummary = []
- const childrenSummary = []
- try {
- if (newNode._summary) {
- selfSummary.push(newNode._summary)
- }
- const summariesItem = getItemByName(nodeElements, 'summaries')
- if (
- summariesItem &&
- Array.isArray(summariesItem.elements) &&
- summariesItem.elements.length > 0
- ) {
- summariesItem.elements.forEach(item => {
- addSummaryData(
- selfSummary,
- childrenSummary,
- () => {
- return getSummaryText2(childrenItem, item.attributes['topic-id'])
- },
- item.attributes.range
- )
- })
- }
- } catch (error) {
- console.log(error)
- }
- newNode.data.generalization = selfSummary
- // 子节点
- newNode.children = []
- if (
- childrenItem &&
- childrenItem.elements &&
- childrenItem.elements.length > 0
- ) {
- const children = getElementsByType(childrenItem.elements, 'attached')
- ;(children || []).forEach((item, index) => {
- const newChild = {}
- newNode.children.push(newChild)
- if (childrenSummary[index]) {
- newChild._summary = childrenSummary[index]
- }
- walk(item, newChild)
- })
- }
- }
- walk(root, newTree)
- return newTree
-}
-
-// 数据转换为xmind文件
-// 直接转换为最新版本的xmind文件 2023.09.11172
-const transformToXmind = async (data, name) => {
- const id = 'simpleMindMap_' + Date.now()
- const imageList = []
- // 转换核心数据
- let newTree = {}
- let waitLoadImageList = []
- let walk = async (node, newNode, isRoot) => {
- let newData = {
- id: node.data.uid,
- structureClass: 'org.xmind.ui.logic.right',
- title: getTextFromHtml(node.data.text), // 节点文本
- children: {
- attached: []
- }
- }
- // 备注
- if (node.data.note !== undefined) {
- newData.notes = {
- realHTML: {
- content: node.data.note
- },
- plain: {
- content: node.data.note
- }
- }
- }
- // 超链接
- if (node.data.hyperlink !== undefined) {
- newData.href = node.data.hyperlink
- }
- // 标签
- if (node.data.tag !== undefined) {
- newData.labels = node.data.tag || []
- }
- // 图片
- handleNodeImageToXmind(node, newNode, waitLoadImageList, imageList)
- // 样式
- // 暂时不考虑样式
- if (isRoot) {
- newData.class = 'topic'
- newNode.id = id
- newNode.class = 'sheet'
- newNode.title = name
- newNode.extensions = []
- newNode.topicPositioning = 'fixed'
- newNode.topicOverlapping = 'overlap'
- newNode.coreVersion = '2.100.0'
- newNode.rootTopic = newData
- } else {
- Object.keys(newData).forEach(key => {
- newNode[key] = newData[key]
- })
- }
- // 概要
- const { summary, summaries } = parseNodeGeneralizationToXmind(node)
- if (isRoot) {
- if (summaries.length > 0) {
- newNode.rootTopic.children.summary = summary
- newNode.rootTopic.summaries = summaries
- }
- } else {
- if (summaries.length > 0) {
- newNode.children.summary = summary
- newNode.summaries = summaries
- }
- }
- // 子节点
- if (node.children && node.children.length > 0) {
- node.children.forEach(child => {
- let newChild = {}
- walk(child, newChild)
- newData.children.attached.push(newChild)
- })
- }
- }
- walk(data, newTree, true)
- await Promise.all(waitLoadImageList)
- const contentData = [newTree]
- // 创建压缩包
- const zip = new JSZip()
- zip.file('content.json', JSON.stringify(contentData))
- zip.file(
- 'metadata.json',
- `{"modifier":"","dataStructureVersion":"2","creator":{"name":"mind-map"},"layoutEngineVersion":"3","activeSheetId":"${id}"}`
- )
- zip.file('content.xml', getXmindContentXmlData())
- const manifestData = {
- 'file-entries': {
- 'content.json': {},
- 'metadata.json': {},
- 'Thumbnails/thumbnail.png': {}
- }
- }
- // 图片
- if (imageList.length > 0) {
- imageList.forEach(item => {
- manifestData['file-entries']['resources/' + item.name] = {}
- const img = zip.folder('resources')
- img.file(item.name, item.data, { base64: true })
- })
- }
- zip.file('manifest.json', JSON.stringify(manifestData))
- const zipData = await zip.generateAsync({ type: 'blob' })
- return zipData
-}
-
-export default {
- parseXmindFile,
- transformXmind,
- transformOldXmind,
- transformToXmind
-}
diff --git a/packages/mindmap/src/plugins/AssociativeLine.js b/packages/mindmap/src/plugins/AssociativeLine.js
deleted file mode 100644
index 669e8e9..0000000
--- a/packages/mindmap/src/plugins/AssociativeLine.js
+++ /dev/null
@@ -1,756 +0,0 @@
-import { walk, bfsWalk, throttle } from '../utils'
-import { v4 as uuid } from 'uuid'
-import {
- getAssociativeLineTargetIndex,
- computeCubicBezierPathPoints,
- cubicBezierPath,
- getNodePoint,
- computeNodePoints,
- getNodeLinePath
-} from './associativeLine/associativeLineUtils'
-import associativeLineControlsMethods from './associativeLine/associativeLineControls'
-import associativeLineTextMethods from './associativeLine/associativeLineText'
-
-const styleProps = [
- 'associativeLineWidth',
- 'associativeLineColor',
- 'associativeLineActiveWidth',
- 'associativeLineActiveColor',
- 'associativeLineDasharray',
- 'associativeLineTextColor',
- 'associativeLineTextFontSize',
- 'associativeLineTextLineHeight',
- 'associativeLineTextFontFamily'
-]
-
-// 关联线插件
-class AssociativeLine {
- constructor(opt = {}) {
- this.mindMap = opt.mindMap
- this.associativeLineDraw = this.mindMap.associativeLineDraw
- // 本次不要重新渲染连线
- this.isNotRenderAllLines = false
- // 当前所有连接线
- this.lineList = []
- // 当前激活的连接线
- this.activeLine = null
- // 当前正在创建连接线
- this.isCreatingLine = false // 是否正在创建连接线中
- this.creatingStartNode = null // 起始节点
- this.creatingLine = null // 创建过程中的连接线
- this.overlapNode = null // 创建过程中的目标节点
- // 是否有节点正在被拖拽
- this.isNodeDragging = false
- // 控制点
- this.controlLine1 = null
- this.controlLine2 = null
- this.controlPoint1 = null
- this.controlPoint2 = null
- this.controlPointDiameter = 10
- this.isControlPointMousedown = false
- this.mousedownControlPointKey = ''
- this.controlPointMousemoveState = {
- pos: null,
- startPoint: null,
- endPoint: null,
- targetIndex: ''
- }
- // 节流一下,不然很卡
- this.checkOverlapNode = throttle(this.checkOverlapNode, 100, this)
- // 控制点相关方法
- Object.keys(associativeLineControlsMethods).forEach(item => {
- this[item] = associativeLineControlsMethods[item].bind(this)
- })
- // 关联线文字相关方法
- Object.keys(associativeLineTextMethods).forEach(item => {
- this[item] = associativeLineTextMethods[item].bind(this)
- })
- this.bindEvent()
- }
-
- // 监听事件
- bindEvent() {
- this.renderAllLines = this.renderAllLines.bind(this)
- this.onDrawClick = this.onDrawClick.bind(this)
- this.onNodeClick = this.onNodeClick.bind(this)
- this.removeLine = this.removeLine.bind(this)
- this.addLine = this.addLine.bind(this)
- this.onMousemove = this.onMousemove.bind(this)
- this.onNodeDragging = this.onNodeDragging.bind(this)
- this.onNodeDragend = this.onNodeDragend.bind(this)
- this.onControlPointMouseup = this.onControlPointMouseup.bind(this)
- this.onBeforeDestroy = this.onBeforeDestroy.bind(this)
-
- // 节点树渲染完毕后渲染连接线
- this.mindMap.on('node_tree_render_end', this.renderAllLines)
- // 状态改变后重新渲染连接线
- this.mindMap.on('data_change', this.renderAllLines)
- // 监听画布和节点点击事件,用于清除当前激活的连接线
- this.mindMap.on('draw_click', this.onDrawClick)
- this.mindMap.on('node_click', this.onNodeClick)
- this.mindMap.on('contextmenu', this.onDrawClick)
- // 注册删除快捷键
- this.mindMap.keyCommand.addShortcut('Del|Backspace', this.removeLine)
- // 注册添加连接线的命令
- this.mindMap.command.add('ADD_ASSOCIATIVE_LINE', this.addLine)
- // 监听鼠标移动事件
- this.mindMap.on('mousemove', this.onMousemove)
- // 节点拖拽事件
- this.mindMap.on('node_dragging', this.onNodeDragging)
- this.mindMap.on('node_dragend', this.onNodeDragend)
- // 拖拽控制点
- this.mindMap.on('mouseup', this.onControlPointMouseup)
- // 缩放事件
- this.mindMap.on('scale', this.onScale)
- // 实例销毁事件
- this.mindMap.on('beforeDestroy', this.onBeforeDestroy)
- }
-
- // 解绑事件
- unBindEvent() {
- this.mindMap.off('node_tree_render_end', this.renderAllLines)
- this.mindMap.off('data_change', this.renderAllLines)
- this.mindMap.off('draw_click', this.onDrawClick)
- this.mindMap.off('node_click', this.onNodeClick)
- this.mindMap.off('contextmenu', this.onDrawClick)
- this.mindMap.keyCommand.removeShortcut('Del|Backspace', this.removeLine)
- this.mindMap.command.remove('ADD_ASSOCIATIVE_LINE', this.addLine)
- this.mindMap.off('mousemove', this.onMousemove)
- this.mindMap.off('node_dragging', this.onNodeDragging)
- this.mindMap.off('node_dragend', this.onNodeDragend)
- this.mindMap.off('mouseup', this.onControlPointMouseup)
- this.mindMap.off('scale', this.onScale)
- this.mindMap.off('beforeDestroy', this.onBeforeDestroy)
- }
-
- // 获取关联线的样式配置
- // 优先级:关联线自定义样式、节点自定义样式、主题的节点层级样式、主题的最外层样式
- getStyleConfig(node, toNode) {
- let lineStyle = {}
- if (toNode) {
- const associativeLineStyle = node.getData('associativeLineStyle') || {}
- lineStyle = associativeLineStyle[toNode.getData('uid')] || {}
- }
- const res = {}
- styleProps.forEach(prop => {
- if (typeof lineStyle[prop] !== 'undefined') {
- res[prop] = lineStyle[prop]
- } else {
- res[prop] = node.getStyle(prop)
- }
- })
- return res
- }
-
- // 实例销毁时清除关联线文字编辑框
- onBeforeDestroy() {
- this.hideEditTextBox()
- this.removeTextEditEl()
- }
-
- // 画布点击事件
- onDrawClick() {
- // 取消创建关联线
- if (this.isCreatingLine) {
- this.cancelCreateLine()
- }
- // 取消激活关联线
- if (!this.isControlPointMousedown) {
- this.clearActiveLine()
- }
- }
-
- // 节点点击事件
- onNodeClick(node) {
- if (this.isCreatingLine) {
- this.completeCreateLine(node)
- } else {
- this.clearActiveLine()
- }
- }
-
- // 创建箭头
- createMarker(callback = () => {}) {
- return this.associativeLineDraw.marker(20, 20, add => {
- add.ref(12, 5)
- add.size(10, 10)
- add.attr('orient', 'auto-start-reverse')
- callback(add.path('M0,0 L2,5 L0,10 L10,5 Z'))
- })
- }
-
- // 判断关联线坐标是否变更,有变更则使用变化后的坐标,无则默认坐标
- updateAllLinesPos(node, toNode, associativeLinePoint) {
- associativeLinePoint = associativeLinePoint || {}
- let [startPoint, endPoint] = computeNodePoints(node, toNode)
- let nodeRange = 0
- let nodeDir = ''
- let toNodeRange = 0
- let toNodeDir = ''
- if (associativeLinePoint.startPoint) {
- nodeRange = associativeLinePoint.startPoint.range || 0
- nodeDir = associativeLinePoint.startPoint.dir || 'right'
- startPoint = getNodePoint(node, nodeDir, nodeRange)
- }
- if (associativeLinePoint.endPoint) {
- toNodeRange = associativeLinePoint.endPoint.range || 0
- toNodeDir = associativeLinePoint.endPoint.dir || 'right'
- endPoint = getNodePoint(toNode, toNodeDir, toNodeRange)
- }
- return [startPoint, endPoint]
- }
-
- // 渲染所有连线
- renderAllLines() {
- if (this.isNotRenderAllLines) {
- this.isNotRenderAllLines = false
- return
- }
- // 先移除
- this.removeAllLines()
- this.removeControls()
- this.clearActiveLine()
- let tree = this.mindMap.renderer.root
- if (!tree) return
- let idToNode = new Map()
- let nodeToIds = new Map()
- walk(
- tree,
- null,
- cur => {
- if (!cur) return
- let data = cur.getData()
- if (
- data.associativeLineTargets &&
- data.associativeLineTargets.length > 0
- ) {
- nodeToIds.set(cur, data.associativeLineTargets)
- }
- if (data.uid) {
- idToNode.set(data.uid, cur)
- }
- },
- () => {},
- true,
- 0
- )
- nodeToIds.forEach((ids, node) => {
- ids.forEach((uid, index) => {
- let toNode = idToNode.get(uid)
- if (!node || !toNode) return
- const associativeLinePoint = (node.getData('associativeLinePoint') ||
- [])[index]
- // 切换结构和布局,都会更新坐标
- const [startPoint, endPoint] = this.updateAllLinesPos(
- node,
- toNode,
- associativeLinePoint
- )
- this.drawLine(startPoint, endPoint, node, toNode)
- })
- })
- }
-
- // 绘制连接线
- drawLine(startPoint, endPoint, node, toNode) {
- let {
- associativeLineWidth,
- associativeLineColor,
- associativeLineActiveWidth,
- associativeLineDasharray
- } = this.getStyleConfig(node, toNode)
- // 箭头
- let markerPath = null
- const marker = this.createMarker(p => {
- markerPath = p
- })
- markerPath
- .stroke({ color: associativeLineColor })
- .fill({ color: associativeLineColor })
- // 路径
- let { path: pathStr, controlPoints } = getNodeLinePath(
- startPoint,
- endPoint,
- node,
- toNode
- )
- // 虚线
- let path = this.associativeLineDraw.path()
- path
- .stroke({
- width: associativeLineWidth,
- color: associativeLineColor,
- dasharray: associativeLineDasharray || [6, 4]
- })
- .fill({ color: 'none' })
- path.plot(pathStr)
- path.marker('end', marker)
- // 不可见的点击线
- let clickPath = this.associativeLineDraw.path()
- clickPath
- .stroke({ width: associativeLineActiveWidth, color: 'transparent' })
- .fill({ color: 'none' })
- clickPath.plot(pathStr)
- // 文字
- let text = this.createText({
- path,
- clickPath,
- markerPath,
- node,
- toNode,
- startPoint,
- endPoint,
- controlPoints
- })
- // 点击事件
- clickPath.click(e => {
- e.stopPropagation()
- this.setActiveLine({
- path,
- clickPath,
- markerPath,
- text,
- node,
- toNode,
- startPoint,
- endPoint,
- controlPoints
- })
- })
- // 双击进入关联线文本编辑状态
- clickPath.dblclick(() => {
- if (!this.activeLine) return
- this.showEditTextBox(text)
- })
- // 渲染关联线文字
- this.renderText(this.getText(node, toNode), path, text, node, toNode)
- this.lineList.push([path, clickPath, text, node, toNode])
- }
-
- // 更新当前激活连线的样式,一般在自定义了节点关联线的样式后调用
- // 直接调用node.setStyle方法更新样式会直接触发关联线更新,但是关联线的激活状态会丢失
- // 所以可以调用node.setData方法更新数据,然后再调用该方法更新样式,这样关联线激活状态不会丢失
- updateActiveLineStyle() {
- if (!this.activeLine) return
- this.isNotRenderAllLines = true
- const [path, clickPath, text, node, toNode, markerPath] = this.activeLine
- const {
- associativeLineWidth,
- associativeLineColor,
- associativeLineDasharray,
- associativeLineActiveWidth,
- associativeLineActiveColor,
- associativeLineTextColor,
- associativeLineTextFontFamily,
- associativeLineTextFontSize
- } = this.getStyleConfig(node, toNode)
- path
- .stroke({
- width: associativeLineWidth,
- color: associativeLineColor,
- dasharray: associativeLineDasharray || [6, 4]
- })
- .fill({ color: 'none' })
- clickPath
- .stroke({
- width: associativeLineActiveWidth,
- color: associativeLineActiveColor
- })
- .fill({ color: 'none' })
- markerPath
- .stroke({ color: associativeLineColor })
- .fill({ color: associativeLineColor })
- text.find('text').forEach(textNode => {
- textNode
- .fill({
- color: associativeLineTextColor
- })
- .css({
- 'font-family': associativeLineTextFontFamily,
- 'font-size': associativeLineTextFontSize + 'px'
- })
- })
- if (this.controlLine1) {
- this.controlLine1.stroke({ color: associativeLineActiveColor })
- }
- if (this.controlLine2) {
- this.controlLine2.stroke({ color: associativeLineActiveColor })
- }
- if (this.controlPoint1) {
- this.controlPoint1.stroke({ color: associativeLineActiveColor })
- }
- if (this.controlPoint2) {
- this.controlPoint2.stroke({ color: associativeLineActiveColor })
- }
- }
-
- // 激活某根关联线
- setActiveLine({
- path,
- clickPath,
- markerPath,
- text,
- node,
- toNode,
- startPoint,
- endPoint,
- controlPoints
- }) {
- let { associativeLineActiveColor } = this.getStyleConfig(node, toNode)
- // 如果当前存在激活节点,那么取消激活节点
- this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
- // 否则清除当前的关联线的激活状态,如果有的话
- this.clearActiveLine()
- // 保存当前激活的关联线信息
- this.activeLine = [path, clickPath, text, node, toNode, markerPath]
- // 让不可见的点击线显示
- clickPath.stroke({ color: associativeLineActiveColor })
- // 如果没有输入过关联线文字,那么显示默认文字
- if (!this.getText(node, toNode)) {
- this.renderText(
- this.mindMap.opt.defaultAssociativeLineText,
- path,
- text,
- node,
- toNode
- )
- }
- // 渲染控制点和连线
- this.renderControls(
- startPoint,
- endPoint,
- controlPoints[0],
- controlPoints[1],
- node,
- toNode
- )
- this.mindMap.emit('associative_line_click', path, clickPath, node, toNode)
- this.front()
- }
-
- // 移除所有连接线
- removeAllLines() {
- this.lineList.forEach(line => {
- line[0].remove()
- line[1].remove()
- line[2].remove()
- })
- this.lineList = []
- }
-
- // 从当前激活节点开始创建连接线
- createLineFromActiveNode() {
- if (this.mindMap.renderer.activeNodeList.length <= 0) return
- let node = this.mindMap.renderer.activeNodeList[0]
- this.createLine(node)
- }
-
- // 创建连接线
- createLine(fromNode) {
- let {
- associativeLineWidth,
- associativeLineColor,
- associativeLineDasharray
- } = this.getStyleConfig(fromNode)
- if (this.isCreatingLine || !fromNode) return
- this.front()
- this.isCreatingLine = true
- this.creatingStartNode = fromNode
- this.creatingLine = this.associativeLineDraw.path()
- this.creatingLine
- .stroke({
- width: associativeLineWidth,
- color: associativeLineColor,
- dasharray: associativeLineDasharray || [6, 4]
- })
- .fill({ color: 'none' })
- // 箭头
- let markerPath = null
- const marker = this.createMarker(p => {
- markerPath = p
- })
- markerPath
- .stroke({ color: associativeLineColor })
- .fill({ color: associativeLineColor })
- this.creatingLine.marker('end', marker)
- }
-
- // 取消创建关联线
- cancelCreateLine() {
- this.isCreatingLine = false
- this.creatingStartNode = null
- this.creatingLine.remove()
- this.creatingLine = null
- this.overlapNode = null
- this.back()
- }
-
- // 鼠标移动事件
- onMousemove(e) {
- this.onControlPointMousemove(e)
- this.updateCreatingLine(e)
- }
-
- // 更新创建过程中的连接线
- updateCreatingLine(e) {
- if (!this.isCreatingLine) return
- let { x, y } = this.getTransformedEventPos(e)
- let startPoint = getNodePoint(this.creatingStartNode)
- let offsetX = x > startPoint.x ? -10 : 10
- let pathStr = cubicBezierPath(startPoint.x, startPoint.y, x + offsetX, y)
- this.creatingLine.plot(pathStr)
- this.checkOverlapNode(x, y)
- }
-
- // 获取转换后的鼠标事件对象的坐标
- getTransformedEventPos(e) {
- let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
- let { scaleX, scaleY, translateX, translateY } =
- this.mindMap.draw.transform()
- return {
- x: (x - translateX) / scaleX,
- y: (y - translateY) / scaleY
- }
- }
-
- // 计算节点偏移位置
- getNodePos(node) {
- const { scaleX, scaleY, translateX, translateY } =
- this.mindMap.draw.transform()
- const { left, top, width, height } = node
- let translateLeft = left * scaleX + translateX
- let translateTop = top * scaleY + translateY
- return {
- left,
- top,
- translateLeft,
- translateTop,
- width,
- height
- }
- }
-
- // 检测当前移动到的目标节点
- checkOverlapNode(x, y) {
- this.overlapNode = null
- bfsWalk(this.mindMap.renderer.root, node => {
- if (node.getData('isActive')) {
- this.mindMap.execCommand('SET_NODE_ACTIVE', node, false)
- }
- if (node.uid === this.creatingStartNode.uid || this.overlapNode) {
- return
- }
- let { left, top, width, height } = node
- let right = left + width
- let bottom = top + height
- if (x >= left && x <= right && y >= top && y <= bottom) {
- this.overlapNode = node
- }
- })
- if (this.overlapNode && !this.overlapNode.getData('isActive')) {
- this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
- }
- }
-
- // 完成创建连接线
- completeCreateLine(node) {
- if (this.creatingStartNode.uid === node.uid) return
- const { beforeAssociativeLineConnection } = this.mindMap.opt
- let stop = false
- if (typeof beforeAssociativeLineConnection === 'function') {
- stop = beforeAssociativeLineConnection(node)
- }
- if (stop) return
- this.addLine(this.creatingStartNode, node)
- if (this.overlapNode && this.overlapNode.getData('isActive')) {
- this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, false)
- }
- this.cancelCreateLine()
- }
-
- // 添加连接线
- addLine(fromNode, toNode) {
- if (!fromNode || !toNode) return
- // 目标节点如果没有id,则生成一个id
- let uid = toNode.getData('uid')
- if (!uid) {
- uid = uuid()
- this.mindMap.execCommand('SET_NODE_DATA', toNode, {
- uid
- })
- }
- // 将目标节点id保存起来
- let list = fromNode.getData('associativeLineTargets') || []
- // 连线节点是否存在相同的id,存在则阻止添加关联线
- const sameLine = list.some(item => item === uid)
- if (sameLine) {
- return
- }
- list.push(uid)
- // 保存控制点
- let [startPoint, endPoint] = computeNodePoints(fromNode, toNode)
- let controlPoints = computeCubicBezierPathPoints(
- startPoint.x,
- startPoint.y,
- endPoint.x,
- endPoint.y
- )
- // 检查是否存在固定位置的配置
- const { associativeLineInitPointsPosition } = this.mindMap.opt
- if (associativeLineInitPointsPosition) {
- const { from, to } = associativeLineInitPointsPosition
- if (from) {
- startPoint.dir = from
- }
- if (to) {
- endPoint.dir = to
- }
- }
- let offsetList =
- fromNode.getData('associativeLineTargetControlOffsets') || []
- // 保存的实际是控制点和端点的差值,否则当节点位置改变了,控制点还是原来的位置,连线就不对了
- offsetList[list.length - 1] = [
- {
- x: controlPoints[0].x - startPoint.x,
- y: controlPoints[0].y - startPoint.y
- },
- {
- x: controlPoints[1].x - endPoint.x,
- y: controlPoints[1].y - endPoint.y
- }
- ]
- let associativeLinePoint = fromNode.getData('associativeLinePoint') || []
- // 记录关联的起始|结束坐标
- associativeLinePoint[list.length - 1] = { startPoint, endPoint }
- this.mindMap.execCommand('SET_NODE_DATA', fromNode, {
- associativeLineTargets: list,
- associativeLineTargetControlOffsets: offsetList,
- associativeLinePoint
- })
- }
-
- // 删除连接线
- removeLine() {
- if (!this.activeLine) return
- let [, , , node, toNode] = this.activeLine
- this.removeControls()
- let {
- associativeLineTargets,
- associativeLinePoint,
- associativeLineTargetControlOffsets,
- associativeLineText,
- associativeLineStyle
- } = node.getData()
- associativeLinePoint = associativeLinePoint || []
- let targetIndex = getAssociativeLineTargetIndex(node, toNode)
- // 更新关联线文本数据
- let newAssociativeLineText = {}
- if (associativeLineText) {
- Object.keys(associativeLineText).forEach(item => {
- if (item !== toNode.getData('uid')) {
- newAssociativeLineText[item] = associativeLineText[item]
- }
- })
- }
- // 更新关联线样式数据
- let newAssociativeLineStyle = {}
- if (associativeLineStyle) {
- Object.keys(associativeLineStyle).forEach(item => {
- if (item !== toNode.getData('uid')) {
- newAssociativeLineStyle[item] = associativeLineStyle[item]
- }
- })
- }
- this.mindMap.execCommand('SET_NODE_DATA', node, {
- // 目标
- associativeLineTargets: associativeLineTargets.filter((_, index) => {
- return index !== targetIndex
- }),
- // 连接线坐标
- associativeLinePoint: associativeLinePoint.filter((_, index) => {
- return index !== targetIndex
- }),
- // 偏移量
- associativeLineTargetControlOffsets: associativeLineTargetControlOffsets
- ? associativeLineTargetControlOffsets.filter((_, index) => {
- return index !== targetIndex
- })
- : [],
- // 文本
- associativeLineText: newAssociativeLineText,
- // 样式
- associativeLineStyle: newAssociativeLineStyle
- })
- }
-
- // 清除激活的线
- clearActiveLine() {
- if (this.activeLine) {
- let [, clickPath, text, node, toNode] = this.activeLine
- clickPath.stroke({
- color: 'transparent'
- })
- // 隐藏关联线文本编辑框
- this.hideEditTextBox()
- // 如果当前关联线没有文字,则清空文字节点
- if (!this.getText(node, toNode)) {
- text.clear()
- }
- this.activeLine = null
- this.removeControls()
- this.back()
- this.mindMap.emit('associative_line_deactivate')
- }
- }
-
- // 处理节点正在拖拽事件
- onNodeDragging() {
- if (this.isNodeDragging) return
- this.isNodeDragging = true
- this.lineList.forEach(line => {
- line[0].hide()
- line[1].hide()
- line[2].hide()
- })
- this.hideControls()
- }
-
- // 处理节点拖拽完成事件
- onNodeDragend() {
- if (!this.isNodeDragging) return
- this.lineList.forEach(line => {
- line[0].show()
- line[1].show()
- line[2].show()
- })
- this.showControls()
- this.isNodeDragging = false
- }
-
- // 关联线顶层显示
- front() {
- if (this.mindMap.opt.associativeLineIsAlwaysAboveNode) return
- this.associativeLineDraw.front()
- }
-
- // 关联线回到原有层级
- back() {
- if (this.mindMap.opt.associativeLineIsAlwaysAboveNode) return
- this.associativeLineDraw.back() // 最底层
- this.associativeLineDraw.forward() // 连线层上面
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-AssociativeLine.instanceName = 'associativeLine'
-
-export default AssociativeLine
diff --git a/packages/mindmap/src/plugins/Cooperate.js b/packages/mindmap/src/plugins/Cooperate.js
deleted file mode 100644
index ca09a2b..0000000
--- a/packages/mindmap/src/plugins/Cooperate.js
+++ /dev/null
@@ -1,284 +0,0 @@
-import * as Y from 'yjs'
-import { WebrtcProvider } from 'y-webrtc'
-import {
- isSameObject,
- simpleDeepClone,
- getType,
- isUndef,
- transformTreeDataToObject,
- transformObjectToTreeData
-} from '../utils/index'
-
-// 协同插件
-class Cooperate {
- constructor(opt) {
- this.opt = opt
- this.mindMap = opt.mindMap
- // yjs文档
- this.ydoc = new Y.Doc()
- // 共享数据
- this.ymap = null
- // 连接提供者
- this.provider = null
- // 感知数据
- this.awareness = null
- this.currentAwarenessData = []
- this.waitNodeUidMap = {} // 该列表中的uid对应的节点还未渲染完毕
- // 当前的平级对象类型的思维导图数据
- this.currentData = null
- // 用户信息
- this.userInfo = null
- // 是否正在重新设置思维导图数据
- this.isSetData = false
- // 绑定事件
- this.bindEvent()
- // 处理实例化时传入的思维导图数据
- if (this.mindMap.opt.data) {
- this.initData(this.mindMap.opt.data)
- }
- }
-
- // 初始化数据
- initData(data) {
- data = simpleDeepClone(data)
- // 解绑原来的数据
- if (this.ymap) {
- this.ymap.unobserve(this.onObserve)
- }
- // 创建共享数据
- this.ymap = this.ydoc.getMap()
- // 思维导图树结构转平级对象结构
- this.currentData = transformTreeDataToObject(data)
- // 将思维导图数据添加到共享数据中
- Object.keys(this.currentData).forEach(uid => {
- this.ymap.set(uid, this.currentData[uid])
- })
- // 监听数据同步
- this.onObserve = this.onObserve.bind(this)
- this.ymap.observe(this.onObserve)
- }
-
- // 获取yjs doc实例
- getDoc() {
- return this.ydoc
- }
-
- // 设置连接提供者
- setProvider(provider, webrtcProviderConfig = {}) {
- const { roomName, signalingList, ...otherConfig } = webrtcProviderConfig
- this.provider =
- provider ||
- new WebrtcProvider(roomName, this.ydoc, {
- signaling: signalingList,
- ...otherConfig
- })
- this.awareness = this.provider.awareness
-
- // 监听状态同步事件
- this.onAwareness = this.onAwareness.bind(this)
- this.awareness.on('change', this.onAwareness)
- }
-
- // 绑定事件
- bindEvent() {
- // 监听思维导图改变
- this.onDataChange = this.onDataChange.bind(this)
- this.mindMap.on('data_change', this.onDataChange)
-
- // 监听思维导图节点激活事件
- this.onNodeActive = this.onNodeActive.bind(this)
- this.mindMap.on('node_active', this.onNodeActive)
-
- // 监听思维导图渲染完毕事件
- this.onNodeTreeRenderEnd = this.onNodeTreeRenderEnd.bind(this)
- this.mindMap.on('node_tree_render_end', this.onNodeTreeRenderEnd)
-
- // 监听设置思维导图数据事件
- this.onSetData = this.onSetData.bind(this)
- this.mindMap.on('set_data', this.onSetData)
- }
-
- // 解绑事件
- unBindEvent() {
- if (this.ymap) {
- this.ymap.unobserve(this.onObserve)
- }
- this.mindMap.off('data_change', this.onDataChange)
- this.mindMap.off('node_active', this.onNodeActive)
- this.mindMap.off('node_tree_render_end', this.onNodeTreeRenderEnd)
- this.mindMap.off('set_data', this.onSetData)
- this.ydoc.destroy()
- }
-
- // 数据同步时的处理,更新当前思维导图
- onObserve(event) {
- const data = event.target.toJSON()
- // 如果数据没有改变直接返回
- if (isSameObject(data, this.currentData)) return
- this.currentData = data
- // 平级对象转树结构
- const res = transformObjectToTreeData(data)
- if (!res) return
- // 更新思维导图画布
- this.mindMap.updateData(res)
- }
-
- // 当前思维导图改变后的处理,触发同步
- onDataChange(data) {
- if (this.isSetData) {
- this.isSetData = false
- return
- }
- const res = transformTreeDataToObject(data)
- this.updateChanges(res)
- }
-
- // 找出更新点
- updateChanges(data) {
- const { beforeCooperateUpdate } = this.mindMap.opt
- const oldData = this.currentData
- this.currentData = data
- this.ydoc.transact(() => {
- // 找出新增的或修改的
- const createOrUpdateList = []
- Object.keys(data).forEach(uid => {
- // 新增的或已经存在的,如果数据发生了改变
- if (!oldData[uid] || !isSameObject(oldData[uid], data[uid])) {
- createOrUpdateList.push({
- uid,
- data: data[uid],
- oldData: oldData[uid]
- })
- }
- })
- if (beforeCooperateUpdate && createOrUpdateList.length > 0) {
- beforeCooperateUpdate({
- type: 'createOrUpdate',
- list: createOrUpdateList,
- data
- })
- }
- createOrUpdateList.forEach(item => {
- this.ymap.set(item.uid, item.data)
- })
- // 找出删除的
- const deleteList = []
- Object.keys(oldData).forEach(uid => {
- if (!data[uid]) {
- deleteList.push({ uid, data: oldData[uid] })
- }
- })
- if (beforeCooperateUpdate && deleteList.length > 0) {
- beforeCooperateUpdate({
- type: 'delete',
- list: deleteList
- })
- }
- deleteList.forEach(item => {
- this.ymap.delete(item.uid)
- })
- })
- }
-
- // 节点激活状态改变后触发感知数据同步
- onNodeActive(node, nodeList) {
- if (this.userInfo) {
- this.awareness.setLocalStateField(this.userInfo.name, {
- // 用户信息
- userInfo: {
- ...this.userInfo
- },
- // 当前激活的节点id列表
- nodeIdList: nodeList.map(item => {
- return item.uid
- })
- })
- }
- }
-
- // 节点树渲染完毕事件
- onNodeTreeRenderEnd() {
- Object.keys(this.waitNodeUidMap).forEach(uid => {
- const node = this.mindMap.renderer.findNodeByUid(uid)
- if (node) {
- node.addUser(this.waitNodeUidMap[uid])
- }
- })
- this.waitNodeUidMap = {}
- }
-
- // 监听思维导图数据的重新设置事件
- onSetData(data) {
- this.isSetData = true
- this.initData(data)
- }
-
- // 设置用户信息
- /**
- * {
- * id: '', // 必传,用户唯一的id
- * name: '', // 用户名称。name和avatar两个只传一个即可,如果都传了,会显示avatar
- * avatar: '', // 用户头像
- * color: '' // 如果没有传头像,那么会以一个圆形来显示名称的第一个字,文字的颜色为白色,圆的颜色可以通过该字段设置
- * }
- **/
- setUserInfo(userInfo) {
- if (
- getType(userInfo) !== 'Object' ||
- isUndef(userInfo.id) ||
- (isUndef(userInfo.name) && isUndef(userInfo.avatar))
- )
- return
- this.userInfo = userInfo || null
- }
-
- // 监听感知数据同步事件
- onAwareness() {
- const walk = (list, callback) => {
- list.forEach(value => {
- const userName = Object.keys(value)[0]
- if (!userName) return
- const data = value[userName]
- const userInfo = data.userInfo
- const nodeIdList = data.nodeIdList
- nodeIdList.forEach(uid => {
- const node = this.mindMap.renderer.findNodeByUid(uid)
- callback(uid, node, userInfo)
- })
- })
- }
- // 清除之前的数据
- walk(this.currentAwarenessData, (uid, node, userInfo) => {
- if (node) {
- node.removeUser(userInfo)
- }
- })
- // 设置当前数据
- const data = Array.from(this.awareness.getStates().values())
- this.currentAwarenessData = data
- this.waitNodeUidMap = {}
- walk(data, (uid, node, userInfo) => {
- // 不显示自己
- if (userInfo.id === this.userInfo.id) return
- if (node) {
- node.addUser(userInfo)
- } else {
- this.waitNodeUidMap[uid] = userInfo
- }
- })
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Cooperate.instanceName = 'cooperate'
-
-export default Cooperate
diff --git a/packages/mindmap/src/plugins/Demonstrate.js b/packages/mindmap/src/plugins/Demonstrate.js
deleted file mode 100644
index 7d557d7..0000000
--- a/packages/mindmap/src/plugins/Demonstrate.js
+++ /dev/null
@@ -1,430 +0,0 @@
-import {
- walk,
- getNodeTreeBoundingRect,
- fullscrrenEvent,
- fullScreen,
- exitFullScreen,
- formatGetNodeGeneralization
-} from '../utils/index'
-import { keyMap } from '../core/command/keyMap'
-
-const defaultConfig = {
- boxShadowColor: 'rgba(0, 0, 0, 0.8)', // 高亮框四周的区域颜色
- borderRadius: '5px', // 高亮框的圆角大小
- transition: 'all 0.3s ease-out', // 高亮框动画的过渡
- zIndex: 9999, // 高亮框元素的层级
- padding: 20, // 高亮框的内边距
- margin: 50, // 高亮框的外边距
- openBlankMode: true // 是否开启填空模式,即带下划线的文本默认不显示,按回车键才依次显示
-}
-
-// 演示插件
-class Demonstrate {
- constructor(opt) {
- this.mindMap = opt.mindMap
- // 是否正在演示中
- this.isInDemonstrate = false
- // 演示的步骤列表
- this.stepList = []
- // 当前所在步骤
- this.currentStepIndex = 0
- // 当前所在步骤对应的节点实例
- this.currentStepNode = null
- // 当前所在步骤节点的下划线文本数据
- this.currentUnderlineTextData = null
- // 临时的样式剩余
- this.tmpStyleEl = null
- // 高亮样式元素
- this.highlightEl = null
- this.transformState = null
- this.renderTree = null
- this.config = Object.assign(
- { ...defaultConfig },
- this.mindMap.opt.demonstrateConfig || {}
- )
- this.needRestorePerformanceMode = false
- }
-
- // 进入演示模式
- enter() {
- // 全屏
- this.bindFullscreenEvent()
- // 如果已经全屏了
- if (document.fullscreenElement === this.mindMap.el) {
- this._enter()
- } else {
- // 否则申请全屏
- fullScreen(this.mindMap.el)
- }
- }
-
- _enter() {
- this.isInDemonstrate = true
- // 如果开启了性能模式,那么需要暂停
- this.pausePerformanceMode()
- // 添加演示用的临时的样式
- this.addTmpStyles()
- // 记录演示前的画布状态
- this.transformState = this.mindMap.view.getTransformData()
- // 记录演示前的画布数据
- this.renderTree = this.mindMap.getData()
- // 暂停收集历史记录
- this.mindMap.command.pause()
- // 暂停思维导图快捷键响应
- this.mindMap.keyCommand.pause()
- // 创建高亮元素
- this.createHighlightEl()
- // 计算步骤数据
- this.getStepList()
- // 收起所有节点
- let wait = false
- if (this.mindMap.renderer.isRendering) {
- wait = true
- }
- this.mindMap.execCommand('UNEXPAND_ALL', false)
- const onRenderEnd = () => {
- if (wait) {
- wait = false
- return
- }
- this.mindMap.off('node_tree_render_end', onRenderEnd)
- // 聚焦到第一步
- this.jump(this.currentStepIndex)
- this.bindEvent()
- }
- this.mindMap.on('node_tree_render_end', onRenderEnd)
- }
-
- // 退出演示模式
- exit() {
- exitFullScreen(this.mindMap.el)
- this.mindMap.updateData(this.renderTree)
- this.mindMap.view.setTransformData(this.transformState)
- this.renderTree = null
- this.transformState = null
- this.stepList = []
- this.currentStepIndex = 0
- this.currentStepNode = null
- this.currentUnderlineTextData = null
- this.unBindEvent()
- this.removeTmpStyles()
- this.removeHighlightEl()
- this.mindMap.command.recovery()
- this.mindMap.keyCommand.recovery()
- this.restorePerformanceMode()
- this.mindMap.emit('exit_demonstrate')
- this.isInDemonstrate = false
- }
-
- // 暂停性能模式
- pausePerformanceMode() {
- const { openPerformance } = this.mindMap.opt
- if (openPerformance) {
- this.needRestorePerformanceMode = true
- this.mindMap.opt.openPerformance = false
- this.mindMap.renderer.forceLoadNode()
- }
- }
-
- // 恢复性能模式
- restorePerformanceMode() {
- if (!this.needRestorePerformanceMode) return
- this.mindMap.opt.openPerformance = true
- this.mindMap.renderer.forceLoadNode()
- }
-
- // 添加临时的样式
- addTmpStyles() {
- this.tmpStyleEl = document.createElement('style')
- let cssText = `
- /* 画布所有元素禁止响应鼠标事件 */
- .smm-mind-map-container {
- pointer-events: none;
- }
- /* 超链接图标允许响应鼠标事件 */
- .smm-node a {
- pointer-events: all;
- }
- /* 备注图标允许响应鼠标事件 */
- .smm-node .smm-node-note {
- pointer-events: all;
- }
- `
- if (this.config.openBlankMode) {
- cssText += `
- /* 带下划线的文本内容全部隐藏 */
- .smm-richtext-node-wrap u {
- opacity: 0;
- }
- `
- }
- this.tmpStyleEl.innerText = cssText
- document.head.appendChild(this.tmpStyleEl)
- }
-
- // 移除临时的样式
- removeTmpStyles() {
- if (this.tmpStyleEl) document.head.removeChild(this.tmpStyleEl)
- }
-
- // 创建高亮元素
- createHighlightEl() {
- if (!this.highlightEl) {
- // 高亮元素
- this.highlightEl = document.createElement('div')
- this.highlightEl.style.cssText = `
- position: absolute;
- box-shadow: 0 0 0 5000px ${this.config.boxShadowColor};
- border-radius: ${this.config.borderRadius};
- transition: ${this.config.transition};
- z-index: ${this.config.zIndex + 1};
- pointer-events: none;
- `
- this.mindMap.el.appendChild(this.highlightEl)
- }
- }
-
- // 移除高亮元素
- removeHighlightEl() {
- if (this.highlightEl) {
- this.mindMap.el.removeChild(this.highlightEl)
- this.highlightEl = null
- }
- }
-
- // 更新高亮元素的位置和大小
- updateHighlightEl({ left, top, width, height }) {
- const padding = this.config.padding
- if (left) {
- this.highlightEl.style.left = left - padding + 'px'
- }
- if (top) {
- this.highlightEl.style.top = top - padding + 'px'
- }
- if (width) {
- this.highlightEl.style.width = width + padding * 2 + 'px'
- }
- if (height) {
- this.highlightEl.style.height = height + padding * 2 + 'px'
- }
- }
-
- // 绑定事件
- bindEvent() {
- this.onKeydown = this.onKeydown.bind(this)
- window.addEventListener('keydown', this.onKeydown)
- }
-
- // 绑定全屏事件
- bindFullscreenEvent() {
- this.onFullscreenChange = this.onFullscreenChange.bind(this)
- document.addEventListener(fullscrrenEvent, this.onFullscreenChange)
- }
-
- // 解绑事件
- unBindEvent() {
- window.removeEventListener('keydown', this.onKeydown)
- document.removeEventListener(fullscrrenEvent, this.onFullscreenChange)
- }
-
- // 全屏状态改变
- onFullscreenChange() {
- if (!document.fullscreenElement) {
- this.exit()
- } else if (document.fullscreenElement === this.mindMap.el) {
- this._enter()
- }
- }
-
- // 按键事件
- onKeydown(e) {
- // 上一个
- if (e.keyCode === keyMap.Left) {
- this.prev()
- } else if (e.keyCode === keyMap.Right) {
- // 下一个
- this.next()
- } else if (e.keyCode === keyMap.Esc) {
- // 退出演示
- this.exit()
- } else if (e.keyCode === keyMap.Enter) {
- // 回车键显示隐藏的下划线文本
- this.showNextUnderlineText()
- }
- }
-
- // 上一张
- prev() {
- if (this.currentStepIndex > 0) {
- this.jump(this.currentStepIndex - 1)
- }
- }
-
- // 下一张
- next() {
- const stepLength = this.stepList.length
- if (this.currentStepIndex < stepLength - 1) {
- this.jump(this.currentStepIndex + 1)
- }
- }
-
- // 显示隐藏的下划线文本
- showNextUnderlineText() {
- if (
- !this.config.openBlankMode ||
- !this.currentStepNode ||
- !this.currentUnderlineTextData
- )
- return
- const { index, list, length } = this.currentUnderlineTextData
- if (index >= length) return
- const node = list[index]
- this.currentUnderlineTextData.index++
- node.node.style.opacity = 1
- }
-
- // 跳转到某一张
- jump(index) {
- // 移除该当前下划线元素设置的样式
- if (this.currentUnderlineTextData) {
- this.currentUnderlineTextData.list.forEach(item => {
- item.node.style.opacity = ''
- })
- this.currentUnderlineTextData = null
- }
- this.currentStepNode = null
- this.currentStepIndex = index
- this.mindMap.emit(
- 'demonstrate_jump',
- this.currentStepIndex,
- this.stepList.length
- )
- const step = this.stepList[index]
- // 这一步的节点数据
- const nodeData = step.node
- // 该节点的uid
- const uid = nodeData.data.uid
- // 根据uid在画布上找到该节点实例
- const node = this.mindMap.renderer.findNodeByUid(uid)
- // 如果该节点实例不存在,那么先展开到该节点
- if (!node) {
- this.mindMap.renderer.expandToNodeUid(uid, () => {
- const node = this.mindMap.renderer.findNodeByUid(uid)
- // 展开后还是没找到,那么就别进入了,否则会死循环
- if (node) {
- this.jump(index)
- }
- })
- return
- }
- // 1.聚焦到某个节点
- if (step.type === 'node') {
- this.currentStepNode = node
- // 当前节点存在带下划线的文本内容
- const uNodeList = this.config.openBlankMode ? node.group.find('u') : null
- if (uNodeList && uNodeList.length > 0) {
- this.currentUnderlineTextData = {
- index: 0,
- list: uNodeList,
- length: uNodeList.length
- }
- }
- // 适应画布大小
- this.mindMap.view.fit(
- () => {
- return node.group.rbox()
- },
- true,
- this.config.padding + this.config.margin
- )
- const rect = node.group.rbox()
- this.updateHighlightEl({
- left: rect.x,
- top: rect.y,
- width: rect.width,
- height: rect.height
- })
- } else {
- // 2.聚焦到某个节点的所有子节点
- // 聚焦该节点的所有子节点
- const task = () => {
- // 先收起该节点所有子节点的子节点
- nodeData.children.forEach(item => {
- item.data.expand = false
- })
- this.mindMap.render(() => {
- // 适应画布大小
- this.mindMap.view.fit(
- () => {
- const res = getNodeTreeBoundingRect(node, 0, 0, 0, 0, true)
- return {
- ...res,
- x: res.left,
- y: res.top
- }
- },
- true,
- this.config.padding + this.config.margin
- )
- const res = getNodeTreeBoundingRect(node, 0, 0, 0, 0, true)
- this.updateHighlightEl(res)
- })
- }
- // 如果该节点是收起状态,那么需要先展开
- if (!nodeData.data.expand) {
- this.mindMap.execCommand('SET_NODE_EXPAND', node, true)
- const onRenderEnd = () => {
- this.mindMap.off('node_tree_render_end', onRenderEnd)
- task()
- }
- this.mindMap.on('node_tree_render_end', onRenderEnd)
- } else {
- // 否则直接聚焦
- task()
- }
- }
- }
-
- // 深度度优先遍历所有节点,返回步骤列表
- getStepList() {
- walk(this.mindMap.renderer.renderTree, null, node => {
- this.stepList.push({
- type: 'node',
- node
- })
- // 添加概要步骤
- const generalizationList = formatGetNodeGeneralization(node.data)
- generalizationList.forEach(item => {
- // 没有uid的直接过滤掉,否则会死循环
- if (item.uid) {
- this.stepList.push({
- type: 'node',
- node: {
- data: item
- }
- })
- }
- })
- if (node.children.length > 1) {
- this.stepList.push({
- type: 'children',
- node
- })
- }
- })
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Demonstrate.instanceName = 'demonstrate'
-
-export default Demonstrate
diff --git a/packages/mindmap/src/plugins/Drag.js b/packages/mindmap/src/plugins/Drag.js
deleted file mode 100644
index 41cfe65..0000000
--- a/packages/mindmap/src/plugins/Drag.js
+++ /dev/null
@@ -1,1210 +0,0 @@
-import {
- bfsWalk,
- throttle,
- getTopAncestorsFomNodeList,
- getNodeIndexInNodeList,
- sortNodeList
-} from '../utils'
-import Base from '../layouts/Base'
-import { CONSTANTS } from '../constants/constant'
-import AutoMove from '../utils/AutoMove'
-
-// 节点拖动插件
-class Drag extends Base {
- // 构造函数
- constructor({ mindMap }) {
- super(mindMap.renderer)
- this.mindMap = mindMap
- this.autoMove = new AutoMove(mindMap)
- this.reset()
- this.bindEvent()
- }
-
- // 复位
- reset() {
- // 是否正在拖拽中
- this.isDragging = false
- // 鼠标按下的节点
- this.mousedownNode = null
- // 被拖拽中的节点列表
- this.beingDragNodeList = []
- // 当前画布节点列表
- this.nodeList = []
- // 当前重叠节点
- this.overlapNode = null
- // 当前上一个同级节点
- this.prevNode = null
- // 当前下一个同级节点
- this.nextNode = null
- // 画布的变换数据
- this.drawTransform = null
- // 克隆节点
- this.clone = null
- // 同级位置占位符
- this.placeholder = null
- this.placeholderWidth = 50
- this.placeholderHeight = 10
- this.placeHolderLine = null
- this.placeHolderExtraLines = []
- // 鼠标按下位置和节点左上角的偏移量
- this.offsetX = 0
- this.offsetY = 0
- // 当前鼠标是否按下
- this.isMousedown = false
- // 拖拽的鼠标位置变量
- this.mouseDownX = 0
- this.mouseDownY = 0
- this.mouseMoveX = 0
- this.mouseMoveY = 0
- // 鼠标移动的距离距鼠标按下的位置距离多少以上才认为是拖动事件
- this.checkDragOffset = 10
- this.minOffset = 10
- }
-
- // 绑定事件
- bindEvent() {
- this.onNodeMousedown = this.onNodeMousedown.bind(this)
- this.onMousemove = this.onMousemove.bind(this)
- this.onMouseup = this.onMouseup.bind(this)
- this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
-
- this.mindMap.on('node_mousedown', this.onNodeMousedown)
- this.mindMap.on('mousemove', this.onMousemove)
- this.mindMap.on('node_mouseup', this.onMouseup)
- this.mindMap.on('mouseup', this.onMouseup)
- }
-
- // 解绑事件
- unBindEvent() {
- this.mindMap.off('node_mousedown', this.onNodeMousedown)
- this.mindMap.off('mousemove', this.onMousemove)
- this.mindMap.off('node_mouseup', this.onMouseup)
- this.mindMap.off('mouseup', this.onMouseup)
- }
-
- // 节点鼠标按下事件
- onNodeMousedown(node, e) {
- // 只读模式、不是鼠标左键按下、按下的是概要节点或根节点直接返回
- if (
- this.mindMap.opt.readonly ||
- e.which !== 1 ||
- node.isGeneralization ||
- node.isRoot
- ) {
- return
- }
- this.isMousedown = true
- // 记录鼠标按下时的节点
- this.mousedownNode = node
- // 记录鼠标按下的坐标
- const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
- this.mouseDownX = x
- this.mouseDownY = y
- }
-
- // 鼠标移动事件
- onMousemove(e) {
- if (this.mindMap.opt.readonly || !this.isMousedown) {
- return
- }
- e.preventDefault()
- const { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
- this.mouseMoveX = x
- this.mouseMoveY = y
- // 还没开始移动时鼠标位移过小不认为是拖拽
- if (
- !this.isDragging &&
- Math.abs(x - this.mouseDownX) <= this.checkDragOffset &&
- Math.abs(y - this.mouseDownY) <= this.checkDragOffset
- ) {
- return
- }
- this.mindMap.emit('node_dragging', this.mousedownNode)
- this.handleStartMove()
- this.onMove(x, y, e)
- }
-
- // 鼠标松开事件
- async onMouseup(e) {
- if (!this.isMousedown) {
- return
- }
- const { autoMoveWhenMouseInEdgeOnDrag, enableFreeDrag, beforeDragEnd } =
- this.mindMap.opt
- // 停止自动移动
- if (autoMoveWhenMouseInEdgeOnDrag && this.mindMap.select) {
- this.autoMove.clearAutoMoveTimer()
- }
- this.isMousedown = false
- // 恢复被拖拽节点的临时设置
- this.beingDragNodeList.forEach(node => {
- node.setOpacity(1)
- node.showChildren()
- node.endDrag()
- })
- this.removeCloneNode()
- let overlapNodeUid = this.overlapNode ? this.overlapNode.getData('uid') : ''
- let prevNodeUid = this.prevNode ? this.prevNode.getData('uid') : ''
- let nextNodeUid = this.nextNode ? this.nextNode.getData('uid') : ''
- if (this.isDragging && typeof beforeDragEnd === 'function') {
- const isCancel = await beforeDragEnd({
- overlapNodeUid,
- prevNodeUid,
- nextNodeUid,
- beingDragNodeList: [...this.beingDragNodeList]
- })
- if (isCancel) {
- this.reset()
- return
- }
- }
- // 存在重叠子节点,则移动作为其子节点
- if (this.overlapNode) {
- this.removeNodeActive(this.overlapNode)
- this.mindMap.execCommand(
- 'MOVE_NODE_TO',
- this.beingDragNodeList,
- this.overlapNode
- )
- } else if (this.prevNode) {
- // 存在前一个相邻节点,作为其下一个兄弟节点
- this.removeNodeActive(this.prevNode)
- this.mindMap.execCommand(
- 'INSERT_AFTER',
- this.beingDragNodeList,
- this.prevNode
- )
- } else if (this.nextNode) {
- // 存在下一个相邻节点,作为其前一个兄弟节点
- this.removeNodeActive(this.nextNode)
- this.mindMap.execCommand(
- 'INSERT_BEFORE',
- this.beingDragNodeList,
- this.nextNode
- )
- } else if (
- this.clone &&
- enableFreeDrag &&
- this.beingDragNodeList.length === 1
- ) {
- // 如果只拖拽了一个节点,那么设置自定义位置
- let { x, y } = this.mindMap.toPos(
- e.clientX - this.offsetX,
- e.clientY - this.offsetY
- )
- let { scaleX, scaleY, translateX, translateY } = this.drawTransform
- x = (x - translateX) / scaleX
- y = (y - translateY) / scaleY
- this.mousedownNode.left = x
- this.mousedownNode.top = y
- this.mousedownNode.customLeft = x
- this.mousedownNode.customTop = y
- this.mindMap.execCommand(
- 'SET_NODE_CUSTOM_POSITION',
- this.mousedownNode,
- x,
- y
- )
- this.mindMap.render()
- }
- if (this.isDragging) {
- this.mindMap.emit('node_dragend', {
- overlapNodeUid,
- prevNodeUid,
- nextNodeUid
- })
- }
- this.reset()
- }
-
- // 移除节点的激活状态
- removeNodeActive(node) {
- if (node.getData('isActive')) {
- this.mindMap.execCommand('SET_NODE_ACTIVE', node, false)
- }
- }
-
- // 拖动中
- onMove(x, y, e) {
- if (!this.isMousedown || !this.isDragging) {
- return
- }
- // 更新克隆节点的位置
- let { scaleX, scaleY, translateX, translateY } = this.drawTransform
- let cloneNodeLeft = x - this.offsetX
- let cloneNodeTop = y - this.offsetY
- x = (cloneNodeLeft - translateX) / scaleX
- y = (cloneNodeTop - translateY) / scaleY
- let t = this.clone.transform()
- this.clone.translate(x - t.translateX, y - t.translateY)
- // 检测新位置
- this.checkOverlapNode()
- // 边缘自动移动画布
- this.drawTransform = this.mindMap.draw.transform()
- this.autoMove.clearAutoMoveTimer()
- this.autoMove.onMove(e.clientX, e.clientY)
- }
-
- // 开始拖拽时初始化一些数据
- async handleStartMove() {
- if (!this.isDragging) {
- // 鼠标按下的节点
- let node = this.mousedownNode
- // 计算鼠标按下的位置距离节点左上角的距离
- this.drawTransform = this.mindMap.draw.transform()
- let { scaleX, scaleY, translateX, translateY } = this.drawTransform
- this.offsetX = this.mouseDownX - (node.left * scaleX + translateX)
- this.offsetY = this.mouseDownY - (node.top * scaleY + translateY)
- // 如果鼠标按下的节点是激活节点,那么保存当前所有激活的节点
- if (node.getData('isActive')) {
- // 找出这些激活节点中的最顶层节点
- // 并按索引从小到大排序
- this.beingDragNodeList = sortNodeList(
- getTopAncestorsFomNodeList(
- // 过滤掉根节点和概要节点
- this.mindMap.renderer.activeNodeList.filter(item => {
- return !item.isRoot && !item.isGeneralization
- })
- )
- )
- } else {
- // 否则只拖拽按下的节点
- this.beingDragNodeList = [node]
- }
- // 拦截拖拽
- const { beforeDragStart } = this.mindMap.opt
- if (typeof beforeDragStart === 'function') {
- const stop = await beforeDragStart([...this.beingDragNodeList])
- if (stop) return
- }
- // 将节点树转为节点数组
- this.nodeTreeToList()
- // 创建克隆节点
- this.createCloneNode()
- // 清除当前所有激活的节点
- this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
- this.isDragging = true
- }
- }
-
- // 节点由树转换成数组,从子节点到根节点
- nodeTreeToList() {
- const list = []
- bfsWalk(this.mindMap.renderer.root, node => {
- // 过滤掉当前被拖拽的节点
- if (this.checkIsInBeingDragNodeList(node)) {
- return
- }
- if (!list[node.layerIndex]) {
- list[node.layerIndex] = []
- }
- list[node.layerIndex].push(node)
- })
- this.nodeList = list.reduceRight((res, cur) => {
- return [...res, ...cur]
- }, [])
- }
-
- // 创建克隆节点
- createCloneNode() {
- if (!this.clone) {
- const {
- dragMultiNodeRectConfig,
- dragPlaceholderRectFill,
- dragPlaceholderLineConfig,
- dragOpacityConfig,
- handleDragCloneNode
- } = this.mindMap.opt
- const {
- width: rectWidth,
- height: rectHeight,
- fill: rectFill
- } = dragMultiNodeRectConfig
- const node = this.beingDragNodeList[0]
- const lineColor = node.style.merge('lineColor', true)
- // 如果当前被拖拽的节点数量大于1,那么创建一个矩形示意
- if (this.beingDragNodeList.length > 1) {
- this.clone = this.mindMap.otherDraw
- .rect()
- .size(rectWidth, rectHeight)
- .radius(rectHeight / 2)
- .fill({
- color: rectFill || lineColor
- })
- this.offsetX = rectWidth / 2
- this.offsetY = rectHeight / 2
- } else {
- // 否则克隆当前的节点
- this.clone = node.group.clone()
- // 删除展开收起按钮元素
- const expandEl = this.clone.findOne('.smm-expand-btn')
- if (expandEl) {
- expandEl.remove()
- }
- this.mindMap.otherDraw.add(this.clone)
- if (typeof handleDragCloneNode === 'function') {
- handleDragCloneNode(this.clone)
- }
- }
- this.clone.opacity(dragOpacityConfig.cloneNodeOpacity)
- this.clone.css('z-index', 99999)
- // 同级位置提示元素
- this.placeholder = this.mindMap.otherDraw
- .rect()
- .fill({
- color: dragPlaceholderRectFill || lineColor
- })
- .radius(5)
- this.placeHolderLine = this.mindMap.otherDraw
- .path()
- .stroke({
- color: dragPlaceholderLineConfig.color || lineColor,
- width: dragPlaceholderLineConfig.width
- })
- .fill({ color: 'none' })
- // 当前被拖拽的节点的临时设置
- this.beingDragNodeList.forEach(node => {
- // 降低透明度
- node.setOpacity(dragOpacityConfig.beingDragNodeOpacity)
- // 隐藏连线及下级节点
- node.hideChildren()
- // 设置拖拽状态
- node.startDrag()
- })
- }
- }
-
- // 移除克隆节点
- removeCloneNode() {
- if (!this.clone) {
- return
- }
- this.clone.remove()
- this.placeholder.remove()
- this.placeHolderLine.remove()
- this.removeExtraLines()
- }
-
- // 移除额外创建的连线
- removeExtraLines() {
- this.placeHolderExtraLines.forEach(item => {
- item.remove()
- })
- this.placeHolderExtraLines = []
- }
-
- // 检测重叠节点
- checkOverlapNode() {
- if (!this.drawTransform || !this.placeholder) {
- return
- }
- const {
- LOGICAL_STRUCTURE,
- LOGICAL_STRUCTURE_LEFT,
- MIND_MAP,
- ORGANIZATION_STRUCTURE,
- CATALOG_ORGANIZATION,
- TIMELINE,
- TIMELINE2,
- VERTICAL_TIMELINE,
- FISHBONE
- } = CONSTANTS.LAYOUT
- this.overlapNode = null
- this.prevNode = null
- this.nextNode = null
- this.placeholder.size(0, 0)
- this.placeHolderLine.hide()
- this.removeExtraLines()
- this.nodeList.forEach(node => {
- if (node.getData('isActive')) {
- this.mindMap.execCommand('SET_NODE_ACTIVE', node, false)
- }
- if (this.overlapNode || (this.prevNode && this.nextNode)) {
- return
- }
- switch (this.mindMap.opt.layout) {
- case LOGICAL_STRUCTURE:
- case LOGICAL_STRUCTURE_LEFT:
- this.handleLogicalStructure(node)
- break
- case MIND_MAP:
- this.handleMindMap(node)
- break
- case ORGANIZATION_STRUCTURE:
- this.handleOrganizationStructure(node)
- break
- case CATALOG_ORGANIZATION:
- this.handleCatalogOrganization(node)
- break
- case TIMELINE:
- this.handleTimeLine(node)
- break
- case TIMELINE2:
- this.handleTimeLine2(node)
- break
- case VERTICAL_TIMELINE:
- this.handleLogicalStructure(node)
- break
- case FISHBONE:
- this.handleFishbone(node)
- break
- default:
- this.handleLogicalStructure(node)
- }
- })
- // 重叠节点,也就是添加为子节点
- if (this.overlapNode) {
- this.handleOverlapNode()
- }
- }
-
- // 处理作为子节点的情况
- handleOverlapNode() {
- const {
- LOGICAL_STRUCTURE,
- LOGICAL_STRUCTURE_LEFT,
- MIND_MAP,
- ORGANIZATION_STRUCTURE,
- CATALOG_ORGANIZATION,
- TIMELINE,
- TIMELINE2,
- VERTICAL_TIMELINE,
- FISHBONE
- } = CONSTANTS.LAYOUT
- const { LEFT, TOP, RIGHT, BOTTOM } = CONSTANTS.LAYOUT_GROW_DIR
- const layerIndex = this.overlapNode.layerIndex
- const children = this.overlapNode.children
- const marginX = this.mindMap.renderer.layout.getMarginX(layerIndex + 1)
- const marginY = this.mindMap.renderer.layout.getMarginY(layerIndex + 1)
- const halfPlaceholderWidth = this.placeholderWidth / 2
- const halfPlaceholderHeight = this.placeholderHeight / 2
- let dir = ''
- let x = ''
- let y = ''
- let rotate = false
- let notRenderPlaceholder = false
- // 目标节点存在子节点,那么基于最后一个子节点定位
- if (children.length > 0) {
- const lastChild = children[children.length - 1]
- const lastNodeRect = this.getNodeRect(lastChild)
- dir = this.getNewChildNodeDir(lastChild)
- switch (this.mindMap.opt.layout) {
- case LOGICAL_STRUCTURE:
- case MIND_MAP:
- x =
- dir === LEFT
- ? lastNodeRect.originRight - this.placeholderWidth
- : lastNodeRect.originLeft
- y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- break
- case LOGICAL_STRUCTURE_LEFT:
- x = lastNodeRect.originRight - this.placeholderWidth
- y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- break
- case ORGANIZATION_STRUCTURE:
- rotate = true
- x = lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
- y = lastNodeRect.originTop
- break
- case CATALOG_ORGANIZATION:
- if (layerIndex === 0) {
- rotate = true
- x =
- lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
- y = lastNodeRect.originTop
- } else {
- x = lastNodeRect.originLeft
- y =
- lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- }
- break
- case TIMELINE:
- if (layerIndex === 0) {
- rotate = true
- x =
- lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
- y =
- lastNodeRect.originTop +
- lastNodeRect.originHeight / 2 -
- halfPlaceholderWidth
- } else {
- x = lastNodeRect.originLeft
- y =
- lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- }
- break
- case TIMELINE2:
- if (layerIndex === 0) {
- rotate = true
- x =
- lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
- y =
- lastNodeRect.originTop +
- lastNodeRect.originHeight / 2 -
- halfPlaceholderWidth
- } else {
- x = lastNodeRect.originLeft
- if (layerIndex === 1) {
- y =
- dir === TOP
- ? lastNodeRect.originTop -
- this.placeholderHeight -
- this.minOffset +
- halfPlaceholderHeight
- : lastNodeRect.originBottom +
- this.minOffset -
- halfPlaceholderHeight
- } else {
- y =
- lastNodeRect.originBottom +
- this.minOffset -
- halfPlaceholderHeight
- }
- }
- break
- case VERTICAL_TIMELINE:
- if (layerIndex === 0) {
- x =
- lastNodeRect.originLeft +
- lastNodeRect.originWidth / 2 -
- halfPlaceholderWidth
- y =
- lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- } else {
- x =
- dir === RIGHT
- ? lastNodeRect.originLeft
- : lastNodeRect.originRight - this.placeholderWidth
- y =
- lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- }
- break
- case FISHBONE:
- if (layerIndex <= 1) {
- notRenderPlaceholder = true
- this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
- } else {
- x = lastNodeRect.originLeft
- y =
- dir === TOP
- ? lastNodeRect.originBottom +
- this.minOffset -
- halfPlaceholderHeight
- : lastNodeRect.originTop -
- this.placeholderHeight -
- this.minOffset +
- halfPlaceholderHeight
- }
- break
- default:
- }
- } else {
- // 目标节点不存在子节点,那么基于目标节点定位
- const nodeRect = this.getNodeRect(this.overlapNode)
- dir = this.getNewChildNodeDir(this.overlapNode)
- switch (this.mindMap.opt.layout) {
- case LOGICAL_STRUCTURE:
- case MIND_MAP:
- x =
- dir === RIGHT
- ? nodeRect.originRight + marginX
- : nodeRect.originLeft - this.placeholderWidth - marginX
- y =
- nodeRect.originTop +
- (nodeRect.originHeight - this.placeholderHeight) / 2
- break
- case LOGICAL_STRUCTURE_LEFT:
- x = nodeRect.originLeft - this.placeholderWidth - marginX
- y =
- nodeRect.originTop +
- (nodeRect.originHeight - this.placeholderHeight) / 2
- break
- case ORGANIZATION_STRUCTURE:
- rotate = true
- x =
- nodeRect.originLeft +
- (nodeRect.originWidth - this.placeholderHeight) / 2
- y = nodeRect.originBottom + marginX
- break
- case CATALOG_ORGANIZATION:
- if (layerIndex === 0) {
- rotate = true
- }
- x = nodeRect.originLeft + nodeRect.originWidth * 0.5
- y = nodeRect.originBottom + marginX
- break
- case TIMELINE:
- if (layerIndex === 0) {
- rotate = true
- }
- x = nodeRect.originLeft + nodeRect.originWidth * 0.5
- y = nodeRect.originBottom + marginY
- break
- case TIMELINE2:
- if (layerIndex === 0) {
- rotate = true
- }
- x = nodeRect.originLeft + nodeRect.originWidth * 0.5
- if (layerIndex === 1) {
- y =
- dir === TOP
- ? nodeRect.originTop - this.placeholderHeight - marginX
- : nodeRect.originBottom + marginX
- } else {
- y = nodeRect.originBottom + marginX
- }
- break
- case VERTICAL_TIMELINE:
- if (layerIndex === 0) {
- rotate = true
- }
- x =
- dir === RIGHT
- ? nodeRect.originRight + marginX
- : nodeRect.originLeft - this.placeholderWidth - marginX
- y =
- nodeRect.originTop +
- nodeRect.originHeight / 2 -
- halfPlaceholderHeight
- break
- case FISHBONE:
- if (layerIndex <= 1) {
- notRenderPlaceholder = true
- this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
- } else {
- x = nodeRect.originLeft + nodeRect.originWidth * 0.5
- y =
- dir === BOTTOM
- ? nodeRect.originTop -
- this.placeholderHeight -
- this.minOffset +
- halfPlaceholderHeight
- : nodeRect.originBottom + this.minOffset - halfPlaceholderHeight
- }
- break
- default:
- }
- }
- if (!notRenderPlaceholder) {
- this.setPlaceholderRect({
- x,
- y,
- dir,
- rotate
- })
- }
- }
-
- // 获取节点的生长方向
- getNewChildNodeDir(node) {
- const {
- LOGICAL_STRUCTURE,
- LOGICAL_STRUCTURE_LEFT,
- MIND_MAP,
- TIMELINE2,
- VERTICAL_TIMELINE,
- FISHBONE
- } = CONSTANTS.LAYOUT
- switch (this.mindMap.opt.layout) {
- case LOGICAL_STRUCTURE:
- return CONSTANTS.LAYOUT_GROW_DIR.RIGHT
- case LOGICAL_STRUCTURE_LEFT:
- return CONSTANTS.LAYOUT_GROW_DIR.LEFT
- case MIND_MAP:
- case TIMELINE2:
- case VERTICAL_TIMELINE:
- case FISHBONE:
- return node.dir
- default:
- return ''
- }
- }
-
- // 垂直方向比较
- // isReverse:是否反向
- handleVerticalCheck(node, checkList, isReverse = false) {
- const { layout } = this.mindMap.opt
- const { LAYOUT, LAYOUT_GROW_DIR } = CONSTANTS
- const { VERTICAL_TIMELINE, FISHBONE } = LAYOUT
- const { BOTTOM, LEFT } = LAYOUT_GROW_DIR
- const mouseMoveX = this.mouseMoveX
- const mouseMoveY = this.mouseMoveY
- const nodeRect = this.getNodeRect(node)
- const dir = this.getNewChildNodeDir(node)
- const layerIndex = node.layerIndex
- if (
- isReverse ||
- (layout === FISHBONE && dir === BOTTOM && layerIndex >= 3)
- ) {
- checkList = checkList.reverse()
- }
- let oneFourthHeight = nodeRect.originHeight / 4
- let { prevBrotherOffset, nextBrotherOffset } =
- this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'v')
- if (nodeRect.left <= mouseMoveX && nodeRect.right >= mouseMoveX) {
- // 检测兄弟节点位置
- if (
- !this.overlapNode &&
- !this.prevNode &&
- !this.nextNode &&
- !node.isRoot
- ) {
- let checkIsPrevNode =
- nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
- ? mouseMoveY > nodeRect.bottom &&
- mouseMoveY <= nodeRect.bottom + nextBrotherOffset // 那么在当前节点外底部判断
- : mouseMoveY >= nodeRect.bottom - oneFourthHeight &&
- mouseMoveY <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
- let checkIsNextNode =
- prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
- ? mouseMoveY < nodeRect.top &&
- mouseMoveY >= nodeRect.top - prevBrotherOffset // 那么在当前节点外底部判断
- : mouseMoveY >= nodeRect.top &&
- mouseMoveY <= nodeRect.top + oneFourthHeight
-
- const { scaleY } = this.drawTransform
- let x =
- dir === LEFT
- ? nodeRect.originRight - this.placeholderWidth
- : nodeRect.originLeft
- let notRenderLine = false
- switch (layout) {
- case VERTICAL_TIMELINE:
- if (layerIndex === 1) {
- x =
- nodeRect.originLeft +
- nodeRect.originWidth / 2 -
- this.placeholderWidth / 2
- }
- break
- default:
- }
- if (checkIsPrevNode) {
- if (isReverse) {
- this.nextNode = node
- } else {
- this.prevNode = node
- }
- let y =
- nodeRect.originBottom +
- nextBrotherOffset / scaleY - //nextBrotherOffset已经是实际间距的一半了
- this.placeholderHeight / 2
- switch (layout) {
- case FISHBONE:
- if (layerIndex === 2) {
- notRenderLine = true
- y =
- nodeRect.originBottom +
- this.minOffset -
- this.placeholderHeight / 2
- }
- break
- default:
- }
- this.setPlaceholderRect({
- x,
- y,
- dir,
- notRenderLine
- })
- } else if (checkIsNextNode) {
- if (isReverse) {
- this.prevNode = node
- } else {
- this.nextNode = node
- }
- let y =
- nodeRect.originTop -
- this.placeholderHeight -
- prevBrotherOffset / scaleY +
- this.placeholderHeight / 2
- switch (layout) {
- case FISHBONE:
- if (layerIndex === 2) {
- notRenderLine = true
- y =
- nodeRect.originTop -
- this.placeholderHeight -
- this.minOffset +
- this.placeholderHeight / 2
- }
- break
- default:
- }
- this.setPlaceholderRect({
- x,
- y,
- dir,
- notRenderLine
- })
- }
- }
- // 检测是否重叠
- this.checkIsOverlap({
- node,
- dir: 'v',
- prevBrotherOffset,
- nextBrotherOffset,
- size: oneFourthHeight,
- pos: mouseMoveY,
- nodeRect
- })
- }
- }
-
- // 水平方向比较
- handleHorizontalCheck(node, checkList) {
- const { layout } = this.mindMap.opt
- const { LAYOUT } = CONSTANTS
- const { FISHBONE, TIMELINE, TIMELINE2 } = LAYOUT
- let mouseMoveX = this.mouseMoveX
- let mouseMoveY = this.mouseMoveY
- let nodeRect = this.getNodeRect(node)
- let oneFourthWidth = nodeRect.originWidth / 4
- let { prevBrotherOffset, nextBrotherOffset } =
- this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'h')
- if (nodeRect.top <= mouseMoveY && nodeRect.bottom >= mouseMoveY) {
- // 检测兄弟节点位置
- if (
- !this.overlapNode &&
- !this.prevNode &&
- !this.nextNode &&
- !node.isRoot
- ) {
- let checkIsPrevNode =
- nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
- ? mouseMoveX < nodeRect.right + nextBrotherOffset &&
- mouseMoveX >= nodeRect.right // 那么在当前节点外底部判断
- : mouseMoveX <= nodeRect.right &&
- mouseMoveX >= nodeRect.right - oneFourthWidth // 否则在当前节点内底部1/4区间判断
- let checkIsNextNode =
- prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
- ? mouseMoveX > nodeRect.left - prevBrotherOffset &&
- mouseMoveX <= nodeRect.left // 那么在当前节点外底部判断
- : mouseMoveX <= nodeRect.left + oneFourthWidth &&
- mouseMoveX >= nodeRect.left
- const { scaleX } = this.drawTransform
- const layerIndex = node.layerIndex
- let y = nodeRect.originTop
- let notRenderLine = false
- switch (layout) {
- case TIMELINE:
- case TIMELINE2:
- y =
- nodeRect.originTop +
- nodeRect.originHeight / 2 -
- this.placeholderWidth / 2
- break
- case FISHBONE:
- if (layerIndex === 1) {
- notRenderLine = true
- y =
- nodeRect.originTop +
- nodeRect.originHeight / 2 -
- this.placeholderWidth / 2
- }
- break
- default:
- }
- if (checkIsPrevNode) {
- this.prevNode = node
- this.setPlaceholderRect({
- x:
- nodeRect.originRight +
- nextBrotherOffset / scaleX - //nextBrotherOffset已经是实际间距的一半了
- this.placeholderHeight / 2,
- y,
- rotate: true,
- notRenderLine
- })
- } else if (checkIsNextNode) {
- this.nextNode = node
- this.setPlaceholderRect({
- x:
- nodeRect.originLeft -
- this.placeholderHeight -
- prevBrotherOffset / scaleX +
- this.placeholderHeight / 2,
- y,
- rotate: true,
- notRenderLine
- })
- }
- }
- // 检测是否重叠
- this.checkIsOverlap({
- node,
- dir: 'h',
- prevBrotherOffset,
- nextBrotherOffset,
- size: oneFourthWidth,
- pos: mouseMoveX,
- nodeRect
- })
- }
- }
-
- // 获取节点距前一个和后一个节点的距离
- getNodeDistanceToSiblingNode(checkList, node, nodeRect, dir) {
- const { TOP, LEFT, BOTTOM, RIGHT } = CONSTANTS.LAYOUT_GROW_DIR
- let { scaleX, scaleY } = this.drawTransform
- let dir1 = dir === 'v' ? TOP : LEFT
- let dir2 = dir === 'v' ? BOTTOM : RIGHT
- let scale = dir === 'v' ? scaleY : scaleX
- let minOffset = this.minOffset * scale
- let index = getNodeIndexInNodeList(node, checkList)
- let prevBrother = null
- let nextBrother = null
- if (index !== -1) {
- if (index - 1 >= 0) {
- prevBrother = checkList[index - 1]
- }
- if (index + 1 <= checkList.length - 1) {
- nextBrother = checkList[index + 1]
- }
- }
- // 和前一个兄弟节点的距离
- let prevBrotherOffset = 0
- if (prevBrother) {
- let prevNodeRect = this.getNodeRect(prevBrother)
- prevBrotherOffset = nodeRect[dir1] - prevNodeRect[dir2]
- // 间距小于10就当它不存在
- prevBrotherOffset =
- prevBrotherOffset >= minOffset ? prevBrotherOffset / 2 : 0
- } else {
- // 没有前一个兄弟节点,那么假设和前一个节点的距离为20
- prevBrotherOffset = minOffset
- }
- // 和后一个兄弟节点的距离
- let nextBrotherOffset = 0
- if (nextBrother) {
- let nextNodeRect = this.getNodeRect(nextBrother)
- nextBrotherOffset = nextNodeRect[dir1] - nodeRect[dir2]
- nextBrotherOffset =
- nextBrotherOffset >= minOffset ? nextBrotherOffset / 2 : 0
- } else {
- nextBrotherOffset = minOffset
- }
- return {
- prevBrother,
- prevBrotherOffset,
- nextBrother,
- nextBrotherOffset
- }
- }
-
- // 设置提示元素的大小和位置
- setPlaceholderRect({ x, y, dir, rotate, notRenderLine }) {
- let w = this.placeholderWidth
- let h = this.placeholderHeight
- if (rotate) {
- const tmp = w
- w = h
- h = tmp
- }
- this.placeholder.size(w, h).move(x, y)
- if (notRenderLine) {
- return
- }
- const { dragPlaceholderLineConfig } = this.mindMap.opt
- let node = null
- let parent = null
- if (this.overlapNode) {
- node = this.overlapNode
- parent = this.overlapNode
- } else {
- node = this.prevNode || this.nextNode
- parent = node.parent
- }
- parent = parent.fakeClone()
- node = node.fakeClone()
- const tmpNode = this.beingDragNodeList[0].fakeClone()
- tmpNode.dir = dir
- tmpNode.left = x
- tmpNode.top = y
- tmpNode.width = w
- tmpNode.height = h
- parent.children = [tmpNode]
- parent._lines = []
- this.placeHolderLine.show()
- this.mindMap.renderer.layout.renderLine(
- parent,
- [this.placeHolderLine],
- (...args) => {
- // node.styleLine(...args)
- },
- node.style.getStyle('lineStyle', true)
- )
- this.placeHolderExtraLines = [...parent._lines]
- this.placeHolderExtraLines.forEach(line => {
- this.mindMap.otherDraw.add(line)
- line
- .stroke({
- color: dragPlaceholderLineConfig.color,
- width: dragPlaceholderLineConfig.width
- })
- .fill({ color: 'none' })
- })
- }
-
- // 检测是否重叠
- checkIsOverlap({
- node,
- dir,
- prevBrotherOffset,
- nextBrotherOffset,
- size,
- pos,
- nodeRect
- }) {
- const { TOP, LEFT, BOTTOM, RIGHT } = CONSTANTS.LAYOUT_GROW_DIR
- let dir1 = dir === 'v' ? TOP : LEFT
- let dir2 = dir === 'v' ? BOTTOM : RIGHT
- if (!this.overlapNode && !this.prevNode && !this.nextNode) {
- if (
- nodeRect[dir1] + (prevBrotherOffset > 0 ? 0 : size) <= pos &&
- nodeRect[dir2] - (nextBrotherOffset > 0 ? 0 : size) >= pos
- ) {
- this.overlapNode = node
- }
- }
- }
-
- // 处理逻辑结构图
- handleLogicalStructure(node) {
- const checkList = this.commonGetNodeCheckList(node)
- this.handleVerticalCheck(node, checkList)
- }
-
- // 处理思维导图
- handleMindMap(node) {
- const checkList = node.parent
- ? node.parent.children.filter(item => {
- let sameDir = true
- if (node.layerIndex === 1) {
- sameDir = item.dir === node.dir
- }
- return sameDir && !this.checkIsInBeingDragNodeList(item)
- })
- : []
- this.handleVerticalCheck(node, checkList)
- }
-
- // 处理组织结构图
- handleOrganizationStructure(node) {
- const checkList = this.commonGetNodeCheckList(node)
- this.handleHorizontalCheck(node, checkList)
- }
-
- // 处理目录组织图
- handleCatalogOrganization(node) {
- const checkList = this.commonGetNodeCheckList(node)
- if (node.layerIndex === 1) {
- this.handleHorizontalCheck(node, checkList)
- } else {
- this.handleVerticalCheck(node, checkList)
- }
- }
-
- // 处理时间轴
- handleTimeLine(node) {
- let checkList = this.commonGetNodeCheckList(node)
- if (node.layerIndex === 1) {
- this.handleHorizontalCheck(node, checkList)
- } else {
- this.handleVerticalCheck(node, checkList)
- }
- }
-
- // 处理时间轴2
- handleTimeLine2(node) {
- let checkList = this.commonGetNodeCheckList(node)
- if (node.layerIndex === 1) {
- this.handleHorizontalCheck(node, checkList)
- } else {
- // 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
- if (node.dir === CONSTANTS.LAYOUT_GROW_DIR.TOP && node.layerIndex === 2) {
- this.handleVerticalCheck(node, checkList, true)
- } else {
- this.handleVerticalCheck(node, checkList)
- }
- }
- }
-
- // 处理鱼骨图
- handleFishbone(node) {
- let checkList = node.parent
- ? node.parent.children.filter(item => {
- return item.layerIndex > 1 && !this.checkIsInBeingDragNodeList(item)
- })
- : []
- if (node.layerIndex === 1) {
- this.handleHorizontalCheck(node, checkList)
- } else {
- // 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
- if (node.dir === CONSTANTS.LAYOUT_GROW_DIR.TOP && node.layerIndex === 2) {
- this.handleVerticalCheck(node, checkList, true)
- } else {
- this.handleVerticalCheck(node, checkList)
- }
- }
- }
-
- // 获取节点的兄弟节点列表通用方法
- commonGetNodeCheckList(node) {
- return node.parent
- ? [...node.parent.children].filter(item => {
- return !this.checkIsInBeingDragNodeList(item)
- })
- : []
- }
-
- // 计算节点的位置尺寸信息
- getNodeRect(node) {
- let { scaleX, scaleY, translateX, translateY } = this.drawTransform
- let { left, top, width, height } = node
- let originWidth = width
- let originHeight = height
- let originLeft = left
- let originTop = top
- let originBottom = top + height
- let originRight = left + width
- let right = (left + width) * scaleX + translateX
- let bottom = (top + height) * scaleY + translateY
- left = left * scaleX + translateX
- top = top * scaleY + translateY
- return {
- left,
- top,
- right,
- bottom,
- originWidth,
- originHeight,
- originLeft,
- originTop,
- originBottom,
- originRight
- }
- }
-
- // 检查某个节点是否在被拖拽节点内
- checkIsInBeingDragNodeList(node) {
- return !!this.beingDragNodeList.find(item => {
- return item.uid === node.uid || item.isAncestor(node)
- })
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Drag.instanceName = 'drag'
-
-export default Drag
diff --git a/packages/mindmap/src/plugins/Export.js b/packages/mindmap/src/plugins/Export.js
deleted file mode 100644
index bb57645..0000000
--- a/packages/mindmap/src/plugins/Export.js
+++ /dev/null
@@ -1,391 +0,0 @@
-import {
- imgToDataUrl,
- downloadFile,
- readBlob,
- removeHTMLEntities,
- resizeImgSize,
- handleSelfCloseTags,
- addXmlns
-} from '../utils'
-import { SVG } from '@svgdotjs/svg.js'
-import drawBackgroundImageToCanvas from '../utils/simulateCSSBackgroundInCanvas'
-import { transformToMarkdown } from '../parse/toMarkdown'
-import { ERROR_TYPES } from '../constants/constant'
-import { transformToTxt } from '../parse/toTxt'
-
-// 导出插件
-class Export {
- // 构造函数
- constructor(opt) {
- this.mindMap = opt.mindMap
- }
-
- // 导出
- async export(type, isDownload = true, name = '思维导图', ...args) {
- if (this[type]) {
- const result = await this[type](name, ...args)
- if (isDownload) {
- downloadFile(result, name + '.' + type)
- }
- return result
- } else {
- return null
- }
- }
-
- // 创建图片url转换任务
- createTransformImgTaskList(svg, tagName, propName, getUrlFn) {
- const imageList = svg.find(tagName)
- return imageList.map(async item => {
- const imgUlr = getUrlFn(item)
- // 已经是data:URL形式不用转换
- if (/^data:/.test(imgUlr) || imgUlr === 'none') {
- return
- }
- const imgData = await imgToDataUrl(imgUlr)
- item.attr(propName, imgData)
- })
- }
-
- // 获取svg数据
- async getSvgData(node) {
- let {
- exportPaddingX,
- exportPaddingY,
- errorHandler,
- resetCss,
- addContentToHeader,
- addContentToFooter,
- handleBeingExportSvg
- } = this.mindMap.opt
- let { svg, svgHTML, clipData } = this.mindMap.getSvgData({
- paddingX: exportPaddingX,
- paddingY: exportPaddingY,
- addContentToHeader,
- addContentToFooter,
- node
- })
- if (clipData) {
- clipData.paddingX = exportPaddingX
- clipData.paddingY = exportPaddingY
- }
- let svgIsChange = false
- // svg的image标签,把图片的url转换成data:url类型,否则导出会丢失图片
- const task1 = this.createTransformImgTaskList(
- svg,
- 'image',
- 'href',
- item => {
- return item.attr('href') || item.attr('xlink:href')
- }
- )
- // html的img标签
- const task2 = this.createTransformImgTaskList(svg, 'img', 'src', item => {
- return item.attr('src')
- })
- const taskList = [...task1, ...task2]
- try {
- await Promise.all(taskList)
- } catch (error) {
- errorHandler(ERROR_TYPES.EXPORT_LOAD_IMAGE_ERROR, error)
- }
- // 开启了节点富文本编辑,需要增加一些样式
- if (this.mindMap.richText) {
- const foreignObjectList = svg.find('foreignObject')
- if (foreignObjectList.length > 0) {
- foreignObjectList[0].add(SVG(``))
- svgIsChange = true
- }
- // 如果还开启了数学公式,还要插入katex库的样式
- if (this.mindMap.formula) {
- const formulaList = svg.find('.ql-formula')
- if (formulaList.length > 0) {
- const styleText = this.mindMap.formula.getStyleText()
- if (styleText) {
- const styleEl = document.createElement('style')
- styleEl.innerHTML = styleText
- addXmlns(styleEl)
- foreignObjectList[0].add(styleEl)
- svgIsChange = true
- }
- }
- }
- }
- // 自定义处理svg的方法
- if (typeof handleBeingExportSvg === 'function') {
- svgIsChange = true
- svg = handleBeingExportSvg(svg)
- }
- // svg节点内容有变,需要重新获取html字符串
- if (taskList.length > 0 || svgIsChange) {
- svgHTML = svg.svg()
- }
- return {
- node: svg,
- str: svgHTML,
- clipData
- }
- }
-
- // svg转png
- svgToPng(svgSrc, transparent, clipData = null) {
- const { maxCanvasSize, minExportImgCanvasScale } = this.mindMap.opt
- return new Promise((resolve, reject) => {
- const img = new Image()
- // 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
- img.setAttribute('crossOrigin', 'anonymous')
- img.onload = async () => {
- try {
- const canvas = document.createElement('canvas')
- const dpr = Math.max(window.devicePixelRatio, minExportImgCanvasScale)
- let imgWidth = img.width
- let imgHeight = img.height
- // 如果是裁减操作的话,那么需要手动添加内边距,及调整图片大小为实际的裁减区域的大小,不要忘了内边距哦
- let paddingX = 0
- let paddingY = 0
- if (clipData) {
- paddingX = clipData.paddingX
- paddingY = clipData.paddingY
- imgWidth = clipData.width + paddingX * 2
- imgHeight = clipData.height + paddingY * 2
- }
- // 检查是否超出canvas支持的像素上限
- // canvas大小需要乘以dpr
- let canvasWidth = imgWidth * dpr
- let canvasHeight = imgHeight * dpr
- if (canvasWidth > maxCanvasSize || canvasHeight > maxCanvasSize) {
- let newWidth = null
- let newHeight = null
- if (canvasWidth > maxCanvasSize) {
- // 如果宽度超出限制,那么调整为上限值
- newWidth = maxCanvasSize
- } else if (canvasHeight > maxCanvasSize) {
- // 高度同理
- newHeight = maxCanvasSize
- }
- // 计算缩放后的宽高
- const res = resizeImgSize(
- canvasWidth,
- canvasHeight,
- newWidth,
- newHeight
- )
- canvasWidth = res[0]
- canvasHeight = res[1]
- }
- canvas.width = canvasWidth
- canvas.height = canvasHeight
- const styleWidth = canvasWidth / dpr
- const styleHeight = canvasHeight / dpr
- canvas.style.width = styleWidth + 'px'
- canvas.style.height = styleHeight + 'px'
- const ctx = canvas.getContext('2d')
- ctx.scale(dpr, dpr)
- // 绘制背景
- if (!transparent) {
- await this.drawBackgroundToCanvas(ctx, styleWidth, styleHeight)
- }
- // 图片绘制到canvas里
- // 如果有裁减数据,那么需要进行裁减
- if (clipData) {
- ctx.drawImage(
- img,
- clipData.left,
- clipData.top,
- clipData.width,
- clipData.height,
- paddingX,
- paddingY,
- clipData.width,
- clipData.height
- )
- } else {
- ctx.drawImage(img, 0, 0, styleWidth, styleHeight)
- }
- resolve(canvas.toDataURL())
- } catch (error) {
- reject(error)
- }
- }
- img.onerror = e => {
- reject(e)
- }
- img.src = svgSrc
- })
- }
-
- // 在canvas上绘制思维导图背景
- drawBackgroundToCanvas(ctx, width, height) {
- return new Promise((resolve, reject) => {
- const {
- backgroundColor = '#fff',
- backgroundImage,
- backgroundRepeat = 'no-repeat',
- backgroundPosition = 'center center',
- backgroundSize = 'cover'
- } = this.mindMap.themeConfig
- // 背景颜色
- ctx.save()
- ctx.rect(0, 0, width, height)
- ctx.fillStyle = backgroundColor
- ctx.fill()
- ctx.restore()
- // 背景图片
- if (backgroundImage && backgroundImage !== 'none') {
- ctx.save()
- drawBackgroundImageToCanvas(
- ctx,
- width,
- height,
- backgroundImage,
- {
- backgroundRepeat,
- backgroundPosition,
- backgroundSize
- },
- err => {
- if (err) {
- reject(err)
- } else {
- resolve()
- }
- ctx.restore()
- }
- )
- } else {
- resolve()
- }
- })
- }
-
- // 在svg上绘制思维导图背景
- drawBackgroundToSvg(svg) {
- return new Promise(async resolve => {
- const {
- backgroundColor = '#fff',
- backgroundImage,
- backgroundRepeat = 'repeat'
- } = this.mindMap.themeConfig
- // 背景颜色
- svg.css('background-color', backgroundColor)
- // 背景图片
- if (backgroundImage && backgroundImage !== 'none') {
- const imgDataUrl = await imgToDataUrl(backgroundImage)
- svg.css('background-image', `url(${imgDataUrl})`)
- svg.css('background-repeat', backgroundRepeat)
- resolve()
- } else {
- resolve()
- }
- })
- }
-
- // 导出为png
- /**
- * 方法1.把svg的图片都转化成data:url格式,再转换
- * 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换
- */
- async png(name, transparent = false, node = null) {
- this.handleNodeExport(node)
- const { str, clipData } = await this.getSvgData(node)
- const svgUrl = await this.fixSvgStrAndToBlob(str)
- const res = await this.svgToPng(svgUrl, transparent, clipData)
- return res
- }
-
- // 导出指定节点,如果该节点是激活状态,那么取消激活和隐藏展开收起按钮
- handleNodeExport(node) {
- if (node && node.getData('isActive')) {
- node.deactivate()
- const { alwaysShowExpandBtn, notShowExpandBtn } = this.mindMap.opt
- if (!alwaysShowExpandBtn && !notShowExpandBtn && node.getData('expand')) {
- node.removeExpandBtn()
- }
- }
- }
-
- // 导出为pdf
- async pdf(name, transparent = false) {
- if (!this.mindMap.doExportPDF) {
- throw new Error('请注册ExportPDF插件')
- }
- const img = await this.png(name, transparent)
- // 使用jspdf库
- // await this.mindMap.doExportPDF.pdf(name, img)
- // 使用pdf-lib库
- const res = await this.mindMap.doExportPDF.pdf(img)
- return res
- }
-
- // 导出为xmind
- async xmind(name) {
- if (!this.mindMap.doExportXMind) {
- throw new Error('请注册ExportXMind插件')
- }
- const data = this.mindMap.getData()
- const blob = await this.mindMap.doExportXMind.xmind(data, name)
- const res = await readBlob(blob)
- return res
- }
-
- // 导出为svg
- async svg(name) {
- const { node } = await this.getSvgData()
- node.first().before(SVG(`${name}`))
- await this.drawBackgroundToSvg(node)
- const str = node.svg()
- const res = await this.fixSvgStrAndToBlob(str)
- return res
- }
-
- // 修复svg字符串,并且转换为blob数据
- async fixSvgStrAndToBlob(str) {
- // 移除字符串中的html实体
- str = removeHTMLEntities(str)
- // 给html自闭合标签添加闭合状态
- str = handleSelfCloseTags(str)
- // 转换成blob数据
- const blob = new Blob([str], {
- type: 'image/svg+xml'
- })
- const res = await readBlob(blob)
- return res
- }
-
- // 导出为json
- async json(name, withConfig = true) {
- const data = this.mindMap.getData(withConfig)
- const str = JSON.stringify(data)
- const blob = new Blob([str])
- const res = await readBlob(blob)
- return res
- }
-
- // 专有文件,其实就是json文件
- async smm(name, withConfig) {
- const res = await this.json(name, withConfig)
- return res
- }
-
- // markdown文件
- async md() {
- const data = this.mindMap.getData()
- const content = transformToMarkdown(data)
- const blob = new Blob([content])
- const res = await readBlob(blob)
- return res
- }
-
- // txt文件
- async txt() {
- const data = this.mindMap.getData()
- const content = transformToTxt(data)
- const blob = new Blob([content])
- const res = await readBlob(blob)
- return res
- }
-}
-
-Export.instanceName = 'doExport'
-
-export default Export
diff --git a/packages/mindmap/src/plugins/ExportPDF.js b/packages/mindmap/src/plugins/ExportPDF.js
deleted file mode 100644
index 6cf902c..0000000
--- a/packages/mindmap/src/plugins/ExportPDF.js
+++ /dev/null
@@ -1,71 +0,0 @@
-// import JsPDF from '../utils/jspdf'
-import { PDFDocument } from 'pdf-lib'
-import { readBlob } from '../utils/index'
-
-// 导出PDF插件,需要通过Export插件使用
-class ExportPDF {
- // 构造函数
- constructor(opt) {
- this.mindMap = opt.mindMap
- }
-
- // 使用pdf-lib库导出为pdf
- async pdf(img) {
- return new Promise((resolve, reject) => {
- const image = new Image()
- image.onload = async () => {
- const imageWidth = image.width
- const imageHeight = image.height
- // 创建pdf页面,尺寸设置为图片的大小
- const pdfDoc = await PDFDocument.create()
- const page = pdfDoc.addPage()
- page.setSize(imageWidth, imageHeight)
- // 添加图片到pdf
- const pngImage = await pdfDoc.embedPng(img)
- page.drawImage(pngImage, {
- x: 0,
- y: 0,
- width: imageWidth,
- height: imageHeight
- })
- const pdfBytes = await pdfDoc.save()
- const blob = new Blob([pdfBytes])
- const res = await readBlob(blob)
- resolve(res)
- }
- image.onerror = e => {
- reject(e)
- }
- image.src = img
- })
- }
-
- // 使用jspdf库导出为pdf
- // async pdf(name, img) {
- // return new Promise((resolve, reject) => {
- // const image = new Image()
- // image.onload = () => {
- // const imageWidth = image.width
- // const imageHeight = image.height
- // const pdf = new JsPDF({
- // unit: 'px',
- // format: [imageWidth, imageHeight],
- // compress: true,
- // hotfixes: ['px_scaling'],
- // orientation: imageWidth > imageHeight ? 'landscape' : 'portrait'
- // })
- // pdf.addImage(img, 'PNG', 0, 0, imageWidth, imageHeight)
- // pdf.save(name)
- // resolve()
- // }
- // image.onerror = e => {
- // reject(e)
- // }
- // image.src = img
- // })
- // }
-}
-
-ExportPDF.instanceName = 'doExportPDF'
-
-export default ExportPDF
diff --git a/packages/mindmap/src/plugins/ExportXMind.js b/packages/mindmap/src/plugins/ExportXMind.js
deleted file mode 100644
index aeccf60..0000000
--- a/packages/mindmap/src/plugins/ExportXMind.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import xmind from '../parse/xmind'
-
-// 导出XMind插件,需要通过Export插件使用
-class ExportXMind {
- // 构造函数
- constructor(opt) {
- this.mindMap = opt.mindMap
- }
-
- // 导出xmind
- async xmind(data, name) {
- const zipData = await xmind.transformToXmind(data, name)
- return zipData
- }
-
- // 获取解析器
- getXmind() {
- return xmind
- }
-}
-
-ExportXMind.instanceName = 'doExportXMind'
-
-export default ExportXMind
diff --git a/packages/mindmap/src/plugins/Formula.ts b/packages/mindmap/src/plugins/Formula.ts
deleted file mode 100644
index ca3e577..0000000
--- a/packages/mindmap/src/plugins/Formula.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-import katex from 'katex'
-import Quill from 'quill'
-import { getChromeVersion, htmlEscape } from '../utils/index'
-import { getBaseStyleText, getFontStyleText } from './FormulaStyle'
-import MindMap from '..'
-class BaseQuillFormula {
- static create(value: string): HTMLElement {
- return document.createElement('span');
- }
-}
-let extended = false
-const QuillFormula = Quill.import('formats/formula') as typeof BaseQuillFormula
-
-interface FormulaOptions {
- mindMap: MindMap
- enableEditFormulaInRichTextEdit?: boolean
- transformRichTextOnEnterEdit?: (text: string) => string
- beforeHideRichTextEdit?: (richText: any) => void
- katexFontPath?: string
- getKatexOutputType?: () => string
- openRealtimeRenderOnNodeTextEdit?: boolean
-}
-declare global {
- interface Window {
- katex: typeof katex;
- }
-}
-
-// 数学公式支持插件
-// 该插件在富文本模式下可用
-class Formula {
- static instanceName = 'formula'
-
- private opt: FormulaOptions
- private mindMap: MindMap
- private config: {
- throwOnError: boolean
- errorColor: string
- output: 'mathml' | 'html'
- }
- private cssEl: HTMLStyleElement | null
-
- constructor(opt: FormulaOptions) {
- this.opt = opt
- this.mindMap = opt.mindMap
- window.katex = katex
- this.init()
- this.config = this.getKatexConfig()
- this.cssEl = null
- this.addStyle()
- this.extendQuill()
- this.onDestroy = this.onDestroy.bind(this)
- this.mindMap.on('beforeDestroy', this.onDestroy)
- }
-
- private onDestroy(): void {
- const instanceCount = Object.getPrototypeOf(this.mindMap).constructor
- .instanceCount
- if (instanceCount <= 1) {
- extended = false
- Quill.register('formats/formula', QuillFormula, true)
- }
- }
-
- private init(): void {
- if (this.mindMap.opt.enableEditFormulaInRichTextEdit) {
- this.mindMap.opt.transformRichTextOnEnterEdit =
- this.latexRichToText.bind(this)
- this.mindMap.opt.beforeHideRichTextEdit = this.formatLatex.bind(this)
- }
- }
-
- private getKatexConfig() {
- const config = {
- throwOnError: false,
- errorColor: '#f00',
- output: 'mathml' as 'mathml' | 'html'
- }
-
- let { getKatexOutputType } = this.mindMap.opt
- getKatexOutputType =
- getKatexOutputType ||
- function () {
- const chromeVersion = getChromeVersion()
- if (chromeVersion && chromeVersion <= 100) {
- return 'html'
- }
- return undefined
- }
- const output = getKatexOutputType() || 'mathml'
- config.output = ['mathml', 'html'].includes(output) ? output as 'mathml' | 'html' : 'mathml'
- return config
- }
-
- private extendQuill(): void {
- if (extended) return
- extended = true
-
- const self = this
-
- class CustomFormulaBlot extends QuillFormula {
- static create(value: string) {
- let node = super.create(value)
- if (typeof value === 'string') {
- katex.render(value, node, self.config)
- node.setAttribute('data-value', htmlEscape(value))
- }
- return node
- }
- }
-
- Quill.register('formats/formula', CustomFormulaBlot, true)
- }
-
- private getStyleText(): string {
- const { katexFontPath } = this.mindMap.opt
- let text = ''
- if (this.config.output === 'html') {
- text = getFontStyleText(katexFontPath)
- }
- text += getBaseStyleText()
- return text
- }
-
- private addStyle(): void {
- this.cssEl = document.createElement('style')
- this.cssEl.type = 'text/css'
- this.cssEl.innerHTML = this.getStyleText()
- document.head.appendChild(this.cssEl)
- }
-
- private removeStyle(): void {
- if (this.cssEl) {
- document.head.removeChild(this.cssEl)
- }
- }
-
- public insertFormulaToNode(node: any, formula: string): void {
- const richTextPlugin = this.mindMap.richText
- richTextPlugin.showEditText({ node })
- richTextPlugin.quill.insertEmbed(
- richTextPlugin.quill.getLength() - 1,
- 'formula',
- formula
- )
- richTextPlugin.hideEditText([node])
- }
-
- public latexRichToText(nodeText: string): string {
- if (nodeText.indexOf('class="ql-formula"') !== -1) {
- const parser = new DOMParser()
- const doc = parser.parseFromString(nodeText, 'text/html')
- const els = doc.getElementsByClassName('ql-formula')
- for (const el of els) {
- nodeText = nodeText.replace(
- el.outerHTML,
- `$${el.getAttribute('data-value')}$`
- )
- }
- if (this.mindMap.opt.openRealtimeRenderOnNodeTextEdit) {
- setTimeout(() => {
- this.mindMap.emit('node_text_edit_change', {
- node: this.mindMap.richText.node,
- text: this.mindMap.richText.getEditText(),
- richText: true
- })
- }, 0)
- }
- }
- return nodeText
- }
-
- public formatLatex(richText: any): void {
- const contents = richText.quill.getContents()
- const ops = contents.ops
- let mod = false
- for (let i = ops.length - 1; i >= 0; i--) {
- const op = ops[i]
- const insert = op.insert
- if (insert && typeof insert !== 'object' && insert !== '\n') {
- if (/\$.+?\$/g.test(insert)) {
- const m = [...insert.matchAll(/\$.+?\$/g)]
- const arr = insert.split(/\$.+?\$/g)
- for (let j = m.length - 1; j >= 0; j--) {
- const exp = m[j] && m[j][0] ? m[j][0].slice(1, -1) || null : null
- if (exp !== null && exp.trim().length > 0) {
- const isLegal = this.checkFormulaIsLegal(exp)
- if (isLegal) {
- arr.splice(j + 1, 0, { insert: { formula: exp } })
- mod = true
- } else {
- arr.splice(j + 1, 0, '')
- }
- } else arr.splice(j + 1, 0, '')
- }
- while (arr.length > 0) {
- let v = arr.pop()
- if (typeof v === 'string') {
- if (v.length < 1) continue
- v = { insert: v }
- }
- v['attributes'] = ops[i]['attributes']
- ops.splice(i + 1, 0, v)
- }
- ops.splice(i, 1)
- }
- }
- }
- if (mod) richText.quill.setContents(contents)
- }
-
- private checkFormulaIsLegal(str: string): boolean {
- try {
- katex.renderToString(str)
- return true
- } catch (e) {
- return false
- }
- }
-
- public beforePluginRemove(): void {
- this.removeStyle()
- this.mindMap.off('beforeDestroy', this.onDestroy)
- }
-
- public beforePluginDestroy(): void {
- this.removeStyle()
- this.mindMap.off('beforeDestroy', this.onDestroy)
- }
-}
-
-export default Formula
\ No newline at end of file
diff --git a/packages/mindmap/src/plugins/FormulaStyle.js b/packages/mindmap/src/plugins/FormulaStyle.js
deleted file mode 100644
index d0016ac..0000000
--- a/packages/mindmap/src/plugins/FormulaStyle.js
+++ /dev/null
@@ -1,1091 +0,0 @@
-export const getFontStyleText = fontPath => {
- return `
-@font-face {
- font-family: 'KaTeX_AMS';
- src: url(${fontPath}fonts/KaTeX_AMS-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_AMS-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_AMS-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Caligraphic';
- src: url(${fontPath}fonts/KaTeX_Caligraphic-Bold.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Caligraphic-Bold.woff) format('woff'), url(${fontPath}fonts/KaTeX_Caligraphic-Bold.ttf) format('truetype');
- font-weight: bold;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Caligraphic';
- src: url(${fontPath}fonts/KaTeX_Caligraphic-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Caligraphic-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Caligraphic-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Fraktur';
- src: url(${fontPath}fonts/KaTeX_Fraktur-Bold.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Fraktur-Bold.woff) format('woff'), url(${fontPath}fonts/KaTeX_Fraktur-Bold.ttf) format('truetype');
- font-weight: bold;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Fraktur';
- src: url(${fontPath}fonts/KaTeX_Fraktur-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Fraktur-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Fraktur-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Main';
- src: url(${fontPath}fonts/KaTeX_Main-Bold.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Main-Bold.woff) format('woff'), url(${fontPath}fonts/KaTeX_Main-Bold.ttf) format('truetype');
- font-weight: bold;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Main';
- src: url(${fontPath}fonts/KaTeX_Main-BoldItalic.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Main-BoldItalic.woff) format('woff'), url(${fontPath}fonts/KaTeX_Main-BoldItalic.ttf) format('truetype');
- font-weight: bold;
- font-style: italic;
-}
-@font-face {
- font-family: 'KaTeX_Main';
- src: url(${fontPath}fonts/KaTeX_Main-Italic.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Main-Italic.woff) format('woff'), url(${fontPath}fonts/KaTeX_Main-Italic.ttf) format('truetype');
- font-weight: normal;
- font-style: italic;
-}
-@font-face {
- font-family: 'KaTeX_Main';
- src: url(${fontPath}fonts/KaTeX_Main-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Main-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Main-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Math';
- src: url(${fontPath}fonts/KaTeX_Math-BoldItalic.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Math-BoldItalic.woff) format('woff'), url(${fontPath}fonts/KaTeX_Math-BoldItalic.ttf) format('truetype');
- font-weight: bold;
- font-style: italic;
-}
-@font-face {
- font-family: 'KaTeX_Math';
- src: url(${fontPath}fonts/KaTeX_Math-Italic.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Math-Italic.woff) format('woff'), url(${fontPath}fonts/KaTeX_Math-Italic.ttf) format('truetype');
- font-weight: normal;
- font-style: italic;
-}
-@font-face {
- font-family: 'KaTeX_SansSerif';
- src: url(${fontPath}fonts/KaTeX_SansSerif-Bold.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_SansSerif-Bold.woff) format('woff'), url(${fontPath}fonts/KaTeX_SansSerif-Bold.ttf) format('truetype');
- font-weight: bold;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_SansSerif';
- src: url(${fontPath}fonts/KaTeX_SansSerif-Italic.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_SansSerif-Italic.woff) format('woff'), url(${fontPath}fonts/KaTeX_SansSerif-Italic.ttf) format('truetype');
- font-weight: normal;
- font-style: italic;
-}
-@font-face {
- font-family: 'KaTeX_SansSerif';
- src: url(${fontPath}fonts/KaTeX_SansSerif-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_SansSerif-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_SansSerif-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Script';
- src: url(${fontPath}fonts/KaTeX_Script-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Script-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Script-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Size1';
- src: url(${fontPath}fonts/KaTeX_Size1-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Size1-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Size1-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Size2';
- src: url(${fontPath}fonts/KaTeX_Size2-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Size2-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Size2-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Size3';
- src: url(${fontPath}fonts/KaTeX_Size3-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Size3-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Size3-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Size4';
- src: url(${fontPath}fonts/KaTeX_Size4-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Size4-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Size4-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-@font-face {
- font-family: 'KaTeX_Typewriter';
- src: url(${fontPath}fonts/KaTeX_Typewriter-Regular.woff2) format('woff2'), url(${fontPath}fonts/KaTeX_Typewriter-Regular.woff) format('woff'), url(${fontPath}fonts/KaTeX_Typewriter-Regular.ttf) format('truetype');
- font-weight: normal;
- font-style: normal;
-}
- `
-}
-
-export const getBaseStyleText = () => {
- return `
-.katex {
- font: normal 1.21em KaTeX_Main, Times New Roman, serif;
- line-height: 1.2;
- text-indent: 0;
- text-rendering: auto;
-}
-.katex * {
- -ms-high-contrast-adjust: none !important;
-}
-.katex * {
- border-color: currentColor;
-}
-.katex .katex-version::after {
- content: "0.16.9";
-}
-.katex .katex-mathml {
- /* Accessibility hack to only show to screen readers
- Found at: http://a11yproject.com/posts/how-to-hide-content/ */
- position: absolute;
- clip: rect(1px, 1px, 1px, 1px);
- padding: 0;
- border: 0;
- height: 1px;
- width: 1px;
- overflow: hidden;
-}
-.katex .katex-html {
- /* \newline is an empty block at top level, between .base elements */
-}
-.katex .katex-html > .newline {
- display: block;
-}
-.katex .base {
- position: relative;
- display: inline-block;
- white-space: nowrap;
- width: -webkit-min-content;
- width: -moz-min-content;
- width: min-content;
-}
-.katex .strut {
- display: inline-block;
-}
-.katex .textbf {
- font-weight: bold;
-}
-.katex .textit {
- font-style: italic;
-}
-.katex .textrm {
- font-family: KaTeX_Main;
-}
-.katex .textsf {
- font-family: KaTeX_SansSerif;
-}
-.katex .texttt {
- font-family: KaTeX_Typewriter;
-}
-.katex .mathnormal {
- font-family: KaTeX_Math;
- font-style: italic;
-}
-.katex .mathit {
- font-family: KaTeX_Main;
- font-style: italic;
-}
-.katex .mathrm {
- font-style: normal;
-}
-.katex .mathbf {
- font-family: KaTeX_Main;
- font-weight: bold;
-}
-.katex .boldsymbol {
- font-family: KaTeX_Math;
- font-weight: bold;
- font-style: italic;
-}
-.katex .amsrm {
- font-family: KaTeX_AMS;
-}
-.katex .mathbb,
-.katex .textbb {
- font-family: KaTeX_AMS;
-}
-.katex .mathcal {
- font-family: KaTeX_Caligraphic;
-}
-.katex .mathfrak,
-.katex .textfrak {
- font-family: KaTeX_Fraktur;
-}
-.katex .mathboldfrak,
-.katex .textboldfrak {
- font-family: KaTeX_Fraktur;
- font-weight: bold;
-}
-.katex .mathtt {
- font-family: KaTeX_Typewriter;
-}
-.katex .mathscr,
-.katex .textscr {
- font-family: KaTeX_Script;
-}
-.katex .mathsf,
-.katex .textsf {
- font-family: KaTeX_SansSerif;
-}
-.katex .mathboldsf,
-.katex .textboldsf {
- font-family: KaTeX_SansSerif;
- font-weight: bold;
-}
-.katex .mathitsf,
-.katex .textitsf {
- font-family: KaTeX_SansSerif;
- font-style: italic;
-}
-.katex .mainrm {
- font-family: KaTeX_Main;
- font-style: normal;
-}
-.katex .vlist-t {
- display: inline-table;
- table-layout: fixed;
- border-collapse: collapse;
-}
-.katex .vlist-r {
- display: table-row;
-}
-.katex .vlist {
- display: table-cell;
- vertical-align: bottom;
- position: relative;
-}
-.katex .vlist > span {
- display: block;
- height: 0;
- position: relative;
-}
-.katex .vlist > span > span {
- display: inline-block;
-}
-.katex .vlist > span > .pstrut {
- overflow: hidden;
- width: 0;
-}
-.katex .vlist-t2 {
- margin-right: -2px;
-}
-.katex .vlist-s {
- display: table-cell;
- vertical-align: bottom;
- font-size: 1px;
- width: 2px;
- min-width: 2px;
-}
-.katex .vbox {
- display: inline-flex;
- flex-direction: column;
- align-items: baseline;
-}
-.katex .hbox {
- display: inline-flex;
- flex-direction: row;
- width: 100%;
-}
-.katex .thinbox {
- display: inline-flex;
- flex-direction: row;
- width: 0;
- max-width: 0;
-}
-.katex .msupsub {
- text-align: left;
-}
-.katex .mfrac > span > span {
- text-align: center;
-}
-.katex .mfrac .frac-line {
- display: inline-block;
- width: 100%;
- border-bottom-style: solid;
-}
-.katex .mfrac .frac-line,
-.katex .overline .overline-line,
-.katex .underline .underline-line,
-.katex .hline,
-.katex .hdashline,
-.katex .rule {
- min-height: 1px;
-}
-.katex .mspace {
- display: inline-block;
-}
-.katex .llap,
-.katex .rlap,
-.katex .clap {
- width: 0;
- position: relative;
-}
-.katex .llap > .inner,
-.katex .rlap > .inner,
-.katex .clap > .inner {
- position: absolute;
-}
-.katex .llap > .fix,
-.katex .rlap > .fix,
-.katex .clap > .fix {
- display: inline-block;
-}
-.katex .llap > .inner {
- right: 0;
-}
-.katex .rlap > .inner,
-.katex .clap > .inner {
- left: 0;
-}
-.katex .clap > .inner > span {
- margin-left: -50%;
- margin-right: 50%;
-}
-.katex .rule {
- display: inline-block;
- border: solid 0;
- position: relative;
-}
-.katex .overline .overline-line,
-.katex .underline .underline-line,
-.katex .hline {
- display: inline-block;
- width: 100%;
- border-bottom-style: solid;
-}
-.katex .hdashline {
- display: inline-block;
- width: 100%;
- border-bottom-style: dashed;
-}
-.katex .sqrt > .root {
- margin-left: 0.27777778em;
- margin-right: -0.55555556em;
-}
-.katex .sizing.reset-size1.size1,
-.katex .fontsize-ensurer.reset-size1.size1 {
- font-size: 1em;
-}
-.katex .sizing.reset-size1.size2,
-.katex .fontsize-ensurer.reset-size1.size2 {
- font-size: 1.2em;
-}
-.katex .sizing.reset-size1.size3,
-.katex .fontsize-ensurer.reset-size1.size3 {
- font-size: 1.4em;
-}
-.katex .sizing.reset-size1.size4,
-.katex .fontsize-ensurer.reset-size1.size4 {
- font-size: 1.6em;
-}
-.katex .sizing.reset-size1.size5,
-.katex .fontsize-ensurer.reset-size1.size5 {
- font-size: 1.8em;
-}
-.katex .sizing.reset-size1.size6,
-.katex .fontsize-ensurer.reset-size1.size6 {
- font-size: 2em;
-}
-.katex .sizing.reset-size1.size7,
-.katex .fontsize-ensurer.reset-size1.size7 {
- font-size: 2.4em;
-}
-.katex .sizing.reset-size1.size8,
-.katex .fontsize-ensurer.reset-size1.size8 {
- font-size: 2.88em;
-}
-.katex .sizing.reset-size1.size9,
-.katex .fontsize-ensurer.reset-size1.size9 {
- font-size: 3.456em;
-}
-.katex .sizing.reset-size1.size10,
-.katex .fontsize-ensurer.reset-size1.size10 {
- font-size: 4.148em;
-}
-.katex .sizing.reset-size1.size11,
-.katex .fontsize-ensurer.reset-size1.size11 {
- font-size: 4.976em;
-}
-.katex .sizing.reset-size2.size1,
-.katex .fontsize-ensurer.reset-size2.size1 {
- font-size: 0.83333333em;
-}
-.katex .sizing.reset-size2.size2,
-.katex .fontsize-ensurer.reset-size2.size2 {
- font-size: 1em;
-}
-.katex .sizing.reset-size2.size3,
-.katex .fontsize-ensurer.reset-size2.size3 {
- font-size: 1.16666667em;
-}
-.katex .sizing.reset-size2.size4,
-.katex .fontsize-ensurer.reset-size2.size4 {
- font-size: 1.33333333em;
-}
-.katex .sizing.reset-size2.size5,
-.katex .fontsize-ensurer.reset-size2.size5 {
- font-size: 1.5em;
-}
-.katex .sizing.reset-size2.size6,
-.katex .fontsize-ensurer.reset-size2.size6 {
- font-size: 1.66666667em;
-}
-.katex .sizing.reset-size2.size7,
-.katex .fontsize-ensurer.reset-size2.size7 {
- font-size: 2em;
-}
-.katex .sizing.reset-size2.size8,
-.katex .fontsize-ensurer.reset-size2.size8 {
- font-size: 2.4em;
-}
-.katex .sizing.reset-size2.size9,
-.katex .fontsize-ensurer.reset-size2.size9 {
- font-size: 2.88em;
-}
-.katex .sizing.reset-size2.size10,
-.katex .fontsize-ensurer.reset-size2.size10 {
- font-size: 3.45666667em;
-}
-.katex .sizing.reset-size2.size11,
-.katex .fontsize-ensurer.reset-size2.size11 {
- font-size: 4.14666667em;
-}
-.katex .sizing.reset-size3.size1,
-.katex .fontsize-ensurer.reset-size3.size1 {
- font-size: 0.71428571em;
-}
-.katex .sizing.reset-size3.size2,
-.katex .fontsize-ensurer.reset-size3.size2 {
- font-size: 0.85714286em;
-}
-.katex .sizing.reset-size3.size3,
-.katex .fontsize-ensurer.reset-size3.size3 {
- font-size: 1em;
-}
-.katex .sizing.reset-size3.size4,
-.katex .fontsize-ensurer.reset-size3.size4 {
- font-size: 1.14285714em;
-}
-.katex .sizing.reset-size3.size5,
-.katex .fontsize-ensurer.reset-size3.size5 {
- font-size: 1.28571429em;
-}
-.katex .sizing.reset-size3.size6,
-.katex .fontsize-ensurer.reset-size3.size6 {
- font-size: 1.42857143em;
-}
-.katex .sizing.reset-size3.size7,
-.katex .fontsize-ensurer.reset-size3.size7 {
- font-size: 1.71428571em;
-}
-.katex .sizing.reset-size3.size8,
-.katex .fontsize-ensurer.reset-size3.size8 {
- font-size: 2.05714286em;
-}
-.katex .sizing.reset-size3.size9,
-.katex .fontsize-ensurer.reset-size3.size9 {
- font-size: 2.46857143em;
-}
-.katex .sizing.reset-size3.size10,
-.katex .fontsize-ensurer.reset-size3.size10 {
- font-size: 2.96285714em;
-}
-.katex .sizing.reset-size3.size11,
-.katex .fontsize-ensurer.reset-size3.size11 {
- font-size: 3.55428571em;
-}
-.katex .sizing.reset-size4.size1,
-.katex .fontsize-ensurer.reset-size4.size1 {
- font-size: 0.625em;
-}
-.katex .sizing.reset-size4.size2,
-.katex .fontsize-ensurer.reset-size4.size2 {
- font-size: 0.75em;
-}
-.katex .sizing.reset-size4.size3,
-.katex .fontsize-ensurer.reset-size4.size3 {
- font-size: 0.875em;
-}
-.katex .sizing.reset-size4.size4,
-.katex .fontsize-ensurer.reset-size4.size4 {
- font-size: 1em;
-}
-.katex .sizing.reset-size4.size5,
-.katex .fontsize-ensurer.reset-size4.size5 {
- font-size: 1.125em;
-}
-.katex .sizing.reset-size4.size6,
-.katex .fontsize-ensurer.reset-size4.size6 {
- font-size: 1.25em;
-}
-.katex .sizing.reset-size4.size7,
-.katex .fontsize-ensurer.reset-size4.size7 {
- font-size: 1.5em;
-}
-.katex .sizing.reset-size4.size8,
-.katex .fontsize-ensurer.reset-size4.size8 {
- font-size: 1.8em;
-}
-.katex .sizing.reset-size4.size9,
-.katex .fontsize-ensurer.reset-size4.size9 {
- font-size: 2.16em;
-}
-.katex .sizing.reset-size4.size10,
-.katex .fontsize-ensurer.reset-size4.size10 {
- font-size: 2.5925em;
-}
-.katex .sizing.reset-size4.size11,
-.katex .fontsize-ensurer.reset-size4.size11 {
- font-size: 3.11em;
-}
-.katex .sizing.reset-size5.size1,
-.katex .fontsize-ensurer.reset-size5.size1 {
- font-size: 0.55555556em;
-}
-.katex .sizing.reset-size5.size2,
-.katex .fontsize-ensurer.reset-size5.size2 {
- font-size: 0.66666667em;
-}
-.katex .sizing.reset-size5.size3,
-.katex .fontsize-ensurer.reset-size5.size3 {
- font-size: 0.77777778em;
-}
-.katex .sizing.reset-size5.size4,
-.katex .fontsize-ensurer.reset-size5.size4 {
- font-size: 0.88888889em;
-}
-.katex .sizing.reset-size5.size5,
-.katex .fontsize-ensurer.reset-size5.size5 {
- font-size: 1em;
-}
-.katex .sizing.reset-size5.size6,
-.katex .fontsize-ensurer.reset-size5.size6 {
- font-size: 1.11111111em;
-}
-.katex .sizing.reset-size5.size7,
-.katex .fontsize-ensurer.reset-size5.size7 {
- font-size: 1.33333333em;
-}
-.katex .sizing.reset-size5.size8,
-.katex .fontsize-ensurer.reset-size5.size8 {
- font-size: 1.6em;
-}
-.katex .sizing.reset-size5.size9,
-.katex .fontsize-ensurer.reset-size5.size9 {
- font-size: 1.92em;
-}
-.katex .sizing.reset-size5.size10,
-.katex .fontsize-ensurer.reset-size5.size10 {
- font-size: 2.30444444em;
-}
-.katex .sizing.reset-size5.size11,
-.katex .fontsize-ensurer.reset-size5.size11 {
- font-size: 2.76444444em;
-}
-.katex .sizing.reset-size6.size1,
-.katex .fontsize-ensurer.reset-size6.size1 {
- font-size: 0.5em;
-}
-.katex .sizing.reset-size6.size2,
-.katex .fontsize-ensurer.reset-size6.size2 {
- font-size: 0.6em;
-}
-.katex .sizing.reset-size6.size3,
-.katex .fontsize-ensurer.reset-size6.size3 {
- font-size: 0.7em;
-}
-.katex .sizing.reset-size6.size4,
-.katex .fontsize-ensurer.reset-size6.size4 {
- font-size: 0.8em;
-}
-.katex .sizing.reset-size6.size5,
-.katex .fontsize-ensurer.reset-size6.size5 {
- font-size: 0.9em;
-}
-.katex .sizing.reset-size6.size6,
-.katex .fontsize-ensurer.reset-size6.size6 {
- font-size: 1em;
-}
-.katex .sizing.reset-size6.size7,
-.katex .fontsize-ensurer.reset-size6.size7 {
- font-size: 1.2em;
-}
-.katex .sizing.reset-size6.size8,
-.katex .fontsize-ensurer.reset-size6.size8 {
- font-size: 1.44em;
-}
-.katex .sizing.reset-size6.size9,
-.katex .fontsize-ensurer.reset-size6.size9 {
- font-size: 1.728em;
-}
-.katex .sizing.reset-size6.size10,
-.katex .fontsize-ensurer.reset-size6.size10 {
- font-size: 2.074em;
-}
-.katex .sizing.reset-size6.size11,
-.katex .fontsize-ensurer.reset-size6.size11 {
- font-size: 2.488em;
-}
-.katex .sizing.reset-size7.size1,
-.katex .fontsize-ensurer.reset-size7.size1 {
- font-size: 0.41666667em;
-}
-.katex .sizing.reset-size7.size2,
-.katex .fontsize-ensurer.reset-size7.size2 {
- font-size: 0.5em;
-}
-.katex .sizing.reset-size7.size3,
-.katex .fontsize-ensurer.reset-size7.size3 {
- font-size: 0.58333333em;
-}
-.katex .sizing.reset-size7.size4,
-.katex .fontsize-ensurer.reset-size7.size4 {
- font-size: 0.66666667em;
-}
-.katex .sizing.reset-size7.size5,
-.katex .fontsize-ensurer.reset-size7.size5 {
- font-size: 0.75em;
-}
-.katex .sizing.reset-size7.size6,
-.katex .fontsize-ensurer.reset-size7.size6 {
- font-size: 0.83333333em;
-}
-.katex .sizing.reset-size7.size7,
-.katex .fontsize-ensurer.reset-size7.size7 {
- font-size: 1em;
-}
-.katex .sizing.reset-size7.size8,
-.katex .fontsize-ensurer.reset-size7.size8 {
- font-size: 1.2em;
-}
-.katex .sizing.reset-size7.size9,
-.katex .fontsize-ensurer.reset-size7.size9 {
- font-size: 1.44em;
-}
-.katex .sizing.reset-size7.size10,
-.katex .fontsize-ensurer.reset-size7.size10 {
- font-size: 1.72833333em;
-}
-.katex .sizing.reset-size7.size11,
-.katex .fontsize-ensurer.reset-size7.size11 {
- font-size: 2.07333333em;
-}
-.katex .sizing.reset-size8.size1,
-.katex .fontsize-ensurer.reset-size8.size1 {
- font-size: 0.34722222em;
-}
-.katex .sizing.reset-size8.size2,
-.katex .fontsize-ensurer.reset-size8.size2 {
- font-size: 0.41666667em;
-}
-.katex .sizing.reset-size8.size3,
-.katex .fontsize-ensurer.reset-size8.size3 {
- font-size: 0.48611111em;
-}
-.katex .sizing.reset-size8.size4,
-.katex .fontsize-ensurer.reset-size8.size4 {
- font-size: 0.55555556em;
-}
-.katex .sizing.reset-size8.size5,
-.katex .fontsize-ensurer.reset-size8.size5 {
- font-size: 0.625em;
-}
-.katex .sizing.reset-size8.size6,
-.katex .fontsize-ensurer.reset-size8.size6 {
- font-size: 0.69444444em;
-}
-.katex .sizing.reset-size8.size7,
-.katex .fontsize-ensurer.reset-size8.size7 {
- font-size: 0.83333333em;
-}
-.katex .sizing.reset-size8.size8,
-.katex .fontsize-ensurer.reset-size8.size8 {
- font-size: 1em;
-}
-.katex .sizing.reset-size8.size9,
-.katex .fontsize-ensurer.reset-size8.size9 {
- font-size: 1.2em;
-}
-.katex .sizing.reset-size8.size10,
-.katex .fontsize-ensurer.reset-size8.size10 {
- font-size: 1.44027778em;
-}
-.katex .sizing.reset-size8.size11,
-.katex .fontsize-ensurer.reset-size8.size11 {
- font-size: 1.72777778em;
-}
-.katex .sizing.reset-size9.size1,
-.katex .fontsize-ensurer.reset-size9.size1 {
- font-size: 0.28935185em;
-}
-.katex .sizing.reset-size9.size2,
-.katex .fontsize-ensurer.reset-size9.size2 {
- font-size: 0.34722222em;
-}
-.katex .sizing.reset-size9.size3,
-.katex .fontsize-ensurer.reset-size9.size3 {
- font-size: 0.40509259em;
-}
-.katex .sizing.reset-size9.size4,
-.katex .fontsize-ensurer.reset-size9.size4 {
- font-size: 0.46296296em;
-}
-.katex .sizing.reset-size9.size5,
-.katex .fontsize-ensurer.reset-size9.size5 {
- font-size: 0.52083333em;
-}
-.katex .sizing.reset-size9.size6,
-.katex .fontsize-ensurer.reset-size9.size6 {
- font-size: 0.5787037em;
-}
-.katex .sizing.reset-size9.size7,
-.katex .fontsize-ensurer.reset-size9.size7 {
- font-size: 0.69444444em;
-}
-.katex .sizing.reset-size9.size8,
-.katex .fontsize-ensurer.reset-size9.size8 {
- font-size: 0.83333333em;
-}
-.katex .sizing.reset-size9.size9,
-.katex .fontsize-ensurer.reset-size9.size9 {
- font-size: 1em;
-}
-.katex .sizing.reset-size9.size10,
-.katex .fontsize-ensurer.reset-size9.size10 {
- font-size: 1.20023148em;
-}
-.katex .sizing.reset-size9.size11,
-.katex .fontsize-ensurer.reset-size9.size11 {
- font-size: 1.43981481em;
-}
-.katex .sizing.reset-size10.size1,
-.katex .fontsize-ensurer.reset-size10.size1 {
- font-size: 0.24108004em;
-}
-.katex .sizing.reset-size10.size2,
-.katex .fontsize-ensurer.reset-size10.size2 {
- font-size: 0.28929605em;
-}
-.katex .sizing.reset-size10.size3,
-.katex .fontsize-ensurer.reset-size10.size3 {
- font-size: 0.33751205em;
-}
-.katex .sizing.reset-size10.size4,
-.katex .fontsize-ensurer.reset-size10.size4 {
- font-size: 0.38572806em;
-}
-.katex .sizing.reset-size10.size5,
-.katex .fontsize-ensurer.reset-size10.size5 {
- font-size: 0.43394407em;
-}
-.katex .sizing.reset-size10.size6,
-.katex .fontsize-ensurer.reset-size10.size6 {
- font-size: 0.48216008em;
-}
-.katex .sizing.reset-size10.size7,
-.katex .fontsize-ensurer.reset-size10.size7 {
- font-size: 0.57859209em;
-}
-.katex .sizing.reset-size10.size8,
-.katex .fontsize-ensurer.reset-size10.size8 {
- font-size: 0.69431051em;
-}
-.katex .sizing.reset-size10.size9,
-.katex .fontsize-ensurer.reset-size10.size9 {
- font-size: 0.83317261em;
-}
-.katex .sizing.reset-size10.size10,
-.katex .fontsize-ensurer.reset-size10.size10 {
- font-size: 1em;
-}
-.katex .sizing.reset-size10.size11,
-.katex .fontsize-ensurer.reset-size10.size11 {
- font-size: 1.19961427em;
-}
-.katex .sizing.reset-size11.size1,
-.katex .fontsize-ensurer.reset-size11.size1 {
- font-size: 0.20096463em;
-}
-.katex .sizing.reset-size11.size2,
-.katex .fontsize-ensurer.reset-size11.size2 {
- font-size: 0.24115756em;
-}
-.katex .sizing.reset-size11.size3,
-.katex .fontsize-ensurer.reset-size11.size3 {
- font-size: 0.28135048em;
-}
-.katex .sizing.reset-size11.size4,
-.katex .fontsize-ensurer.reset-size11.size4 {
- font-size: 0.32154341em;
-}
-.katex .sizing.reset-size11.size5,
-.katex .fontsize-ensurer.reset-size11.size5 {
- font-size: 0.36173633em;
-}
-.katex .sizing.reset-size11.size6,
-.katex .fontsize-ensurer.reset-size11.size6 {
- font-size: 0.40192926em;
-}
-.katex .sizing.reset-size11.size7,
-.katex .fontsize-ensurer.reset-size11.size7 {
- font-size: 0.48231511em;
-}
-.katex .sizing.reset-size11.size8,
-.katex .fontsize-ensurer.reset-size11.size8 {
- font-size: 0.57877814em;
-}
-.katex .sizing.reset-size11.size9,
-.katex .fontsize-ensurer.reset-size11.size9 {
- font-size: 0.69453376em;
-}
-.katex .sizing.reset-size11.size10,
-.katex .fontsize-ensurer.reset-size11.size10 {
- font-size: 0.83360129em;
-}
-.katex .sizing.reset-size11.size11,
-.katex .fontsize-ensurer.reset-size11.size11 {
- font-size: 1em;
-}
-.katex .delimsizing.size1 {
- font-family: KaTeX_Size1;
-}
-.katex .delimsizing.size2 {
- font-family: KaTeX_Size2;
-}
-.katex .delimsizing.size3 {
- font-family: KaTeX_Size3;
-}
-.katex .delimsizing.size4 {
- font-family: KaTeX_Size4;
-}
-.katex .delimsizing.mult .delim-size1 > span {
- font-family: KaTeX_Size1;
-}
-.katex .delimsizing.mult .delim-size4 > span {
- font-family: KaTeX_Size4;
-}
-.katex .nulldelimiter {
- display: inline-block;
- width: 0.12em;
-}
-.katex .delimcenter {
- position: relative;
-}
-.katex .op-symbol {
- position: relative;
-}
-.katex .op-symbol.small-op {
- font-family: KaTeX_Size1;
-}
-.katex .op-symbol.large-op {
- font-family: KaTeX_Size2;
-}
-.katex .op-limits > .vlist-t {
- text-align: center;
-}
-.katex .accent > .vlist-t {
- text-align: center;
-}
-.katex .accent .accent-body {
- position: relative;
-}
-.katex .accent .accent-body:not(.accent-full) {
- width: 0;
-}
-.katex .overlay {
- display: block;
-}
-.katex .mtable .vertical-separator {
- display: inline-block;
- min-width: 1px;
-}
-.katex .mtable .arraycolsep {
- display: inline-block;
-}
-.katex .mtable .col-align-c > .vlist-t {
- text-align: center;
-}
-.katex .mtable .col-align-l > .vlist-t {
- text-align: left;
-}
-.katex .mtable .col-align-r > .vlist-t {
- text-align: right;
-}
-.katex .svg-align {
- text-align: left;
-}
-.katex svg {
- display: block;
- position: absolute;
- width: 100%;
- height: inherit;
- fill: currentColor;
- stroke: currentColor;
- fill-rule: nonzero;
- fill-opacity: 1;
- stroke-width: 1;
- stroke-linecap: butt;
- stroke-linejoin: miter;
- stroke-miterlimit: 4;
- stroke-dasharray: none;
- stroke-dashoffset: 0;
- stroke-opacity: 1;
-}
-.katex svg path {
- stroke: none;
-}
-.katex img {
- border-style: none;
- min-width: 0;
- min-height: 0;
- max-width: none;
- max-height: none;
-}
-.katex .stretchy {
- width: 100%;
- display: block;
- position: relative;
- overflow: hidden;
-}
-.katex .stretchy::before,
-.katex .stretchy::after {
- content: "";
-}
-.katex .hide-tail {
- width: 100%;
- position: relative;
- overflow: hidden;
-}
-.katex .halfarrow-left {
- position: absolute;
- left: 0;
- width: 50.2%;
- overflow: hidden;
-}
-.katex .halfarrow-right {
- position: absolute;
- right: 0;
- width: 50.2%;
- overflow: hidden;
-}
-.katex .brace-left {
- position: absolute;
- left: 0;
- width: 25.1%;
- overflow: hidden;
-}
-.katex .brace-center {
- position: absolute;
- left: 25%;
- width: 50%;
- overflow: hidden;
-}
-.katex .brace-right {
- position: absolute;
- right: 0;
- width: 25.1%;
- overflow: hidden;
-}
-.katex .x-arrow-pad {
- padding: 0 0.5em;
-}
-.katex .cd-arrow-pad {
- padding: 0 0.55556em 0 0.27778em;
-}
-.katex .x-arrow,
-.katex .mover,
-.katex .munder {
- text-align: center;
-}
-.katex .boxpad {
- padding: 0 0.3em;
-}
-.katex .fbox,
-.katex .fcolorbox {
- box-sizing: border-box;
- border: 0.04em solid;
-}
-.katex .cancel-pad {
- padding: 0 0.2em;
-}
-.katex .cancel-lap {
- margin-left: -0.2em;
- margin-right: -0.2em;
-}
-.katex .sout {
- border-bottom-style: solid;
- border-bottom-width: 0.08em;
-}
-.katex .angl {
- box-sizing: border-box;
- border-top: 0.049em solid;
- border-right: 0.049em solid;
- margin-right: 0.03889em;
-}
-.katex .anglpad {
- padding: 0 0.03889em;
-}
-.katex .eqn-num::before {
- counter-increment: katexEqnNo;
- content: "(" counter(katexEqnNo) ")";
-}
-.katex .mml-eqn-num::before {
- counter-increment: mmlEqnNo;
- content: "(" counter(mmlEqnNo) ")";
-}
-.katex .mtr-glue {
- width: 50%;
-}
-.katex .cd-vert-arrow {
- display: inline-block;
- position: relative;
-}
-.katex .cd-label-left {
- display: inline-block;
- position: absolute;
- right: calc(50% + 0.3em);
- text-align: left;
-}
-.katex .cd-label-right {
- display: inline-block;
- position: absolute;
- left: calc(50% + 0.3em);
- text-align: right;
-}
-.katex-display {
- display: block;
- margin: 1em 0;
- text-align: center;
-}
-.katex-display > .katex {
- display: block;
- text-align: center;
- white-space: nowrap;
-}
-.katex-display > .katex > .katex-html {
- display: block;
- position: relative;
-}
-.katex-display > .katex > .katex-html > .tag {
- position: absolute;
- right: 0;
-}
-.katex-display.leqno > .katex > .katex-html > .tag {
- left: 0;
- right: auto;
-}
-.katex-display.fleqn > .katex {
- text-align: left;
- padding-left: 2em;
-}
-body {
- counter-reset: katexEqnNo mmlEqnNo;
-}
-`
-}
diff --git a/packages/mindmap/src/plugins/KeyboardNavigation.js b/packages/mindmap/src/plugins/KeyboardNavigation.js
deleted file mode 100644
index 972e25e..0000000
--- a/packages/mindmap/src/plugins/KeyboardNavigation.js
+++ /dev/null
@@ -1,287 +0,0 @@
-import { bfsWalk } from '../utils'
-import { CONSTANTS } from '../constants/constant'
-
-// 键盘导航插件
-class KeyboardNavigation {
- // 构造函数
- constructor(opt) {
- this.opt = opt
- this.mindMap = opt.mindMap
-
- this.addShortcut()
- }
-
- addShortcut() {
- this.onLeftKeyUp = this.onLeftKeyUp.bind(this)
- this.onUpKeyUp = this.onUpKeyUp.bind(this)
- this.onRightKeyUp = this.onRightKeyUp.bind(this)
- this.onDownKeyUp = this.onDownKeyUp.bind(this)
-
- this.mindMap.keyCommand.addShortcut(
- CONSTANTS.KEY_DIR.LEFT,
- this.onLeftKeyUp
- )
- this.mindMap.keyCommand.addShortcut(CONSTANTS.KEY_DIR.UP, this.onUpKeyUp)
- this.mindMap.keyCommand.addShortcut(
- CONSTANTS.KEY_DIR.RIGHT,
- this.onRightKeyUp
- )
- this.mindMap.keyCommand.addShortcut(
- CONSTANTS.KEY_DIR.DOWN,
- this.onDownKeyUp
- )
- }
-
- removeShortcut() {
- this.mindMap.keyCommand.removeShortcut(
- CONSTANTS.KEY_DIR.LEFT,
- this.onLeftKeyUp
- )
- this.mindMap.keyCommand.removeShortcut(CONSTANTS.KEY_DIR.UP, this.onUpKeyUp)
- this.mindMap.keyCommand.removeShortcut(
- CONSTANTS.KEY_DIR.RIGHT,
- this.onRightKeyUp
- )
- this.mindMap.keyCommand.removeShortcut(
- CONSTANTS.KEY_DIR.DOWN,
- this.onDownKeyUp
- )
- }
-
- onLeftKeyUp() {
- this.onKeyup(CONSTANTS.KEY_DIR.LEFT)
- }
-
- onUpKeyUp() {
- this.onKeyup(CONSTANTS.KEY_DIR.UP)
- }
-
- onRightKeyUp() {
- this.onKeyup(CONSTANTS.KEY_DIR.RIGHT)
- }
-
- onDownKeyUp() {
- this.onKeyup(CONSTANTS.KEY_DIR.DOWN)
- }
-
- // 处理按键事件
- onKeyup(dir) {
- if (this.mindMap.renderer.activeNodeList.length > 0) {
- this.focus(dir)
- } else {
- let root = this.mindMap.renderer.root
- this.mindMap.execCommand('GO_TARGET_NODE', root)
- }
- }
-
- // 聚焦到下一个节点
- focus(dir) {
- // 当前聚焦的节点
- let currentActiveNode = this.mindMap.renderer.activeNodeList[0]
- // 当前聚焦节点的位置信息
- let currentActiveNodeRect = this.getNodeRect(currentActiveNode)
- // 寻找的下一个聚焦节点
- let targetNode = null
- let targetDis = Infinity
- // 保存并维护距离最近的节点
- let checkNodeDis = (rect, node) => {
- let dis = this.getDistance(currentActiveNodeRect, rect)
- if (dis < targetDis) {
- targetNode = node
- targetDis = dis
- }
- }
-
- // 第一优先级:阴影算法
- this.getFocusNodeByShadowAlgorithm({
- currentActiveNode,
- currentActiveNodeRect,
- dir,
- checkNodeDis
- })
-
- // 第二优先级:区域算法
- if (!targetNode) {
- this.getFocusNodeByAreaAlgorithm({
- currentActiveNode,
- currentActiveNodeRect,
- dir,
- checkNodeDis
- })
- }
-
- // 第三优先级:简单算法
- if (!targetNode) {
- this.getFocusNodeBySimpleAlgorithm({
- currentActiveNode,
- currentActiveNodeRect,
- dir,
- checkNodeDis
- })
- }
-
- // 找到了则让目标节点聚焦
- if (targetNode) {
- this.mindMap.execCommand('GO_TARGET_NODE', targetNode)
- }
- }
-
- // 1.简单算法
- getFocusNodeBySimpleAlgorithm({
- currentActiveNode,
- currentActiveNodeRect,
- dir,
- checkNodeDis
- }) {
- // 遍历节点树
- bfsWalk(this.mindMap.renderer.root, node => {
- // 跳过当前聚焦的节点
- if (node.uid === currentActiveNode.uid) return
- // 当前遍历到的节点的位置信息
- let rect = this.getNodeRect(node)
- let { left, top, right, bottom } = rect
- let match = false
- // 按下了左方向键
- if (dir === CONSTANTS.KEY_DIR.LEFT) {
- // 判断节点是否在当前节点的左侧
- match = right <= currentActiveNodeRect.left
- // 按下了右方向键
- } else if (dir === CONSTANTS.KEY_DIR.RIGHT) {
- // 判断节点是否在当前节点的右侧
- match = left >= currentActiveNodeRect.right
- // 按下了上方向键
- } else if (dir === CONSTANTS.KEY_DIR.UP) {
- // 判断节点是否在当前节点的上面
- match = bottom <= currentActiveNodeRect.top
- // 按下了下方向键
- } else if (dir === CONSTANTS.KEY_DIR.DOWN) {
- // 判断节点是否在当前节点的下面
- match = top >= currentActiveNodeRect.bottom
- }
- // 符合要求,判断是否是最近的节点
- if (match) {
- checkNodeDis(rect, node)
- }
- })
- }
-
- // 2.阴影算法
- getFocusNodeByShadowAlgorithm({
- currentActiveNode,
- currentActiveNodeRect,
- dir,
- checkNodeDis
- }) {
- bfsWalk(this.mindMap.renderer.root, node => {
- if (node.uid === currentActiveNode.uid) return
- let rect = this.getNodeRect(node)
- let { left, top, right, bottom } = rect
- let match = false
- if (dir === CONSTANTS.KEY_DIR.LEFT) {
- match =
- left < currentActiveNodeRect.left &&
- top < currentActiveNodeRect.bottom &&
- bottom > currentActiveNodeRect.top
- } else if (dir === CONSTANTS.KEY_DIR.RIGHT) {
- match =
- right > currentActiveNodeRect.right &&
- top < currentActiveNodeRect.bottom &&
- bottom > currentActiveNodeRect.top
- } else if (dir === CONSTANTS.KEY_DIR.UP) {
- match =
- top < currentActiveNodeRect.top &&
- left < currentActiveNodeRect.right &&
- right > currentActiveNodeRect.left
- } else if (dir === CONSTANTS.KEY_DIR.DOWN) {
- match =
- bottom > currentActiveNodeRect.bottom &&
- left < currentActiveNodeRect.right &&
- right > currentActiveNodeRect.left
- }
- if (match) {
- checkNodeDis(rect, node)
- }
- })
- }
-
- // 3.区域算法
- getFocusNodeByAreaAlgorithm({
- currentActiveNode,
- currentActiveNodeRect,
- dir,
- checkNodeDis
- }) {
- // 当前聚焦节点的中心点
- let cX = (currentActiveNodeRect.right + currentActiveNodeRect.left) / 2
- let cY = (currentActiveNodeRect.bottom + currentActiveNodeRect.top) / 2
- bfsWalk(this.mindMap.renderer.root, node => {
- if (node.uid === currentActiveNode.uid) return
- let rect = this.getNodeRect(node)
- let { left, top, right, bottom } = rect
- // 遍历到的节点的中心点
- let ccX = (right + left) / 2
- let ccY = (bottom + top) / 2
- // 节点的中心点坐标和当前聚焦节点的中心点坐标的差值
- let offsetX = ccX - cX
- let offsetY = ccY - cY
- if (offsetX === 0 && offsetY === 0) return
- let match = false
- if (dir === CONSTANTS.KEY_DIR.LEFT) {
- match = offsetX <= 0 && offsetX <= offsetY && offsetX <= -offsetY
- } else if (dir === CONSTANTS.KEY_DIR.RIGHT) {
- match = offsetX > 0 && offsetX >= -offsetY && offsetX >= offsetY
- } else if (dir === CONSTANTS.KEY_DIR.UP) {
- match = offsetY <= 0 && offsetY < offsetX && offsetY < -offsetX
- } else if (dir === CONSTANTS.KEY_DIR.DOWN) {
- match = offsetY > 0 && -offsetY < offsetX && offsetY > offsetX
- }
- if (match) {
- checkNodeDis(rect, node)
- }
- })
- }
-
- // 获取节点的位置信息
- getNodeRect(node) {
- let { scaleX, scaleY, translateX, translateY } =
- this.mindMap.draw.transform()
- let { left, top, width, height } = node
- return {
- right: (left + width) * scaleX + translateX,
- bottom: (top + height) * scaleY + translateY,
- left: left * scaleX + translateX,
- top: top * scaleY + translateY
- }
- }
-
- // 获取两个节点的距离
- getDistance(node1Rect, node2Rect) {
- let center1 = this.getCenter(node1Rect)
- let center2 = this.getCenter(node2Rect)
- return Math.sqrt(
- Math.pow(center1.x - center2.x, 2) + Math.pow(center1.y - center2.y, 2)
- )
- }
-
- // 获取节点的中心点
- getCenter({ left, right, top, bottom }) {
- return {
- x: (left + right) / 2,
- y: (top + bottom) / 2
- }
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.removeShortcut()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.removeShortcut()
- }
-}
-
-KeyboardNavigation.instanceName = 'keyboardNavigation'
-
-export default KeyboardNavigation
diff --git a/packages/mindmap/src/plugins/MindMapLayoutPro.js b/packages/mindmap/src/plugins/MindMapLayoutPro.js
deleted file mode 100644
index 130b618..0000000
--- a/packages/mindmap/src/plugins/MindMapLayoutPro.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import { CONSTANTS } from '../constants/constant'
-
-// 该插件会向节点数据的data中添加dir字段
-/*
- 需要更新数据的情况:
-
- 1.实例化时的数据
- 2.调用setData和updateData方法
- 3.执行完命令
- 4.切换结构
-*/
-
-class MindMapLayoutPro {
- constructor(opt) {
- this.opt = opt
- this.mindMap = opt.mindMap
- this.init()
- }
-
- init() {
- this.updateNodeTree = this.updateNodeTree.bind(this)
- this.afterExecCommand = this.afterExecCommand.bind(this)
- this.layoutChange = this.layoutChange.bind(this)
-
- // 处理实例化时传入的数据
- if (this.mindMap.opt.data && this.isMindMapLayout()) {
- this.updateNodeTree(this.mindMap.opt.data)
- }
-
- this.mindMap.on('layout_change', this.layoutChange)
- this.mindMap.on('afterExecCommand', this.afterExecCommand)
- this.mindMap.on('before_update_data', this.updateNodeTree)
- this.mindMap.on('before_set_data', this.updateNodeTree)
- }
-
- restore() {
- this.mindMap.off('layout_change', this.layoutChange)
- this.mindMap.off('afterExecCommand', this.afterExecCommand)
- this.mindMap.off('before_update_data', this.updateNodeTree)
- this.mindMap.off('before_set_data', this.updateNodeTree)
- }
-
- // 监听命令执行后的事件
- afterExecCommand(name) {
- if (!this.isMindMapLayout()) return
- if (
- ![
- 'BACK',
- 'FORWARD',
- 'INSERT_NODE',
- 'INSERT_MULTI_NODE',
- 'INSERT_CHILD_NODE',
- 'INSERT_MULTI_CHILD_NODE',
- 'INSERT_PARENT_NODE',
- 'UP_NODE',
- 'DOWN_NODE',
- 'MOVE_UP_ONE_LEVEL',
- 'INSERT_AFTER',
- 'INSERT_BEFORE',
- 'MOVE_NODE_TO',
- 'REMOVE_NODE',
- 'REMOVE_CURRENT_NODE',
- 'PASTE_NODE',
- 'CUT_NODE'
- ].includes(name)
- )
- return
- this.updateRenderTree()
- }
-
- // 更新布局结构
- layoutChange(layout) {
- if (layout === CONSTANTS.LAYOUT.MIND_MAP) {
- this.updateRenderTree()
- }
- }
-
- // 更新当前的渲染树
- updateRenderTree() {
- this.updateNodeTree(this.mindMap.renderer.renderTree)
- }
-
- // 更新节点树,修改二级节点的排列位置
- updateNodeTree(tree) {
- if (!this.isMindMapLayout()) return
- const root = tree
- const childrenLength = root.children.length
- if (childrenLength <= 0) return
- const center = Math.ceil(childrenLength / 2)
- root.children.forEach((item, index) => {
- if (index + 1 <= center) {
- item.data.dir = CONSTANTS.LAYOUT_GROW_DIR.RIGHT
- } else {
- item.data.dir = CONSTANTS.LAYOUT_GROW_DIR.LEFT
- }
- })
- }
-
- // 判断当前是否是思维导图布局结构
- isMindMapLayout() {
- return this.mindMap.opt.layout === CONSTANTS.LAYOUT.MIND_MAP
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.restore()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.restore()
- }
-}
-
-MindMapLayoutPro.instanceName = 'mindMapLayoutPro'
-
-export default MindMapLayoutPro
diff --git a/packages/mindmap/src/plugins/MiniMap.js b/packages/mindmap/src/plugins/MiniMap.js
deleted file mode 100644
index 9f77c89..0000000
--- a/packages/mindmap/src/plugins/MiniMap.js
+++ /dev/null
@@ -1,224 +0,0 @@
-import {
- isWhite,
- isTransparent,
- getVisibleColorFromTheme,
- readBlob
-} from '../utils/index'
-
-// 小地图插件
-class MiniMap {
- // 构造函数
- constructor(opt) {
- this.mindMap = opt.mindMap
- this.isMousedown = false
- this.mousedownPos = {
- x: 0,
- y: 0
- }
- this.startViewPos = {
- x: 0,
- y: 0
- }
- this.currentState = null
- }
-
- // 计算小地图的渲染数据
- /**
- * boxWidth:小地图容器的宽度
- * boxHeight:小地图容器的高度
- */
- calculationMiniMap(boxWidth, boxHeight) {
- let { svg, rect, origWidth, origHeight, scaleX, scaleY } =
- this.mindMap.getSvgData({
- ignoreWatermark: true
- })
- // 计算数据
- const elRect = this.mindMap.elRect
- rect.x -= elRect.left
- rect.x2 -= elRect.left
- rect.y -= elRect.top
- rect.y2 -= elRect.top
- let boxRatio = boxWidth / boxHeight
- let actWidth = 0
- let actHeight = 0
- if (boxRatio > rect.ratio) {
- // 高度以box为准,缩放宽度
- actHeight = boxHeight
- actWidth = rect.ratio * actHeight
- } else {
- // 宽度以box为准,缩放高度
- actWidth = boxWidth
- actHeight = actWidth / rect.ratio
- }
- // svg图形的缩放及位置
- let miniMapBoxScale = actWidth / rect.width
- let miniMapBoxLeft = (boxWidth - actWidth) / 2
- let miniMapBoxTop = (boxHeight - actHeight) / 2
- // 当前思维导图图形实际的宽高,即在缩放后的宽高
- let _rectWidth = rect.width * scaleX
- let _rectHeight = rect.height * scaleY
- // 视口框大小及位置
- let _rectWidthOffsetHalf = (_rectWidth - rect.width) / 2
- let _rectHeightOffsetHalf = (_rectHeight - rect.height) / 2
- let _rectX = rect.x - _rectWidthOffsetHalf
- let _rectX2 = rect.x2 + _rectWidthOffsetHalf
- let _rectY = rect.y - _rectHeightOffsetHalf
- let _rectY2 = rect.y2 + _rectHeightOffsetHalf
- let viewBoxStyle = {
- left: 0,
- top: 0,
- right: 0,
- bottom: 0
- }
- viewBoxStyle.left =
- Math.max(0, (-_rectX / _rectWidth) * actWidth) + miniMapBoxLeft
- viewBoxStyle.right =
- Math.max(0, ((_rectX2 - origWidth) / _rectWidth) * actWidth) +
- miniMapBoxLeft
-
- viewBoxStyle.top =
- Math.max(0, (-_rectY / _rectHeight) * actHeight) + miniMapBoxTop
- viewBoxStyle.bottom =
- Math.max(0, ((_rectY2 - origHeight) / _rectHeight) * actHeight) +
- miniMapBoxTop
-
- if (viewBoxStyle.top > miniMapBoxTop + actHeight) {
- viewBoxStyle.top = miniMapBoxTop + actHeight
- }
- if (viewBoxStyle.left > miniMapBoxLeft + actWidth) {
- viewBoxStyle.left = miniMapBoxLeft + actWidth
- }
-
- Object.keys(viewBoxStyle).forEach(key => {
- viewBoxStyle[key] = viewBoxStyle[key] + 'px'
- })
- this.removeNodeContent(svg)
- const svgStr = svg.svg()
- this.currentState = {
- viewBoxStyle: {
- ...viewBoxStyle
- },
- miniMapBoxScale,
- miniMapBoxLeft,
- miniMapBoxTop
- }
- return {
- getImgUrl: async callback => {
- const res = await this.mindMap.doExport.fixSvgStrAndToBlob(svgStr)
- callback(res)
- },
- svgHTML: svgStr, // 小地图html
- viewBoxStyle, // 视图框的位置信息
- miniMapBoxScale, // 视图框的缩放值
- miniMapBoxLeft, // 视图框的left值
- miniMapBoxTop // 视图框的top值
- }
- }
-
- // 移除节点的内容
- removeNodeContent(svg) {
- if (svg.hasClass('smm-node')) {
- let shape = svg.findOne('.smm-node-shape')
- let fill = shape.attr('fill')
- if (isWhite(fill) || isTransparent(fill)) {
- shape.attr('fill', getVisibleColorFromTheme(this.mindMap.themeConfig))
- }
- svg.clear()
- svg.add(shape)
- return
- }
- let children = svg.children()
- if (children && children.length > 0) {
- children.forEach(node => {
- this.removeNodeContent(node)
- })
- }
- }
-
- // 小地图鼠标按下事件
- onMousedown(e) {
- this.isMousedown = true
- this.mousedownPos = {
- x: e.clientX,
- y: e.clientY
- }
- // 保存视图当前的偏移量
- let transformData = this.mindMap.view.getTransformData()
- this.startViewPos = {
- x: transformData.state.x,
- y: transformData.state.y
- }
- }
-
- // 小地图鼠标移动事件
- onMousemove(e, sensitivityNum = 5) {
- if (!this.isMousedown || this.isViewBoxMousedown) {
- return
- }
- let ox = e.clientX - this.mousedownPos.x
- let oy = e.clientY - this.mousedownPos.y
- // 在视图最初偏移量上累加更新量
- this.mindMap.view.translateXTo(ox * sensitivityNum + this.startViewPos.x)
- this.mindMap.view.translateYTo(oy * sensitivityNum + this.startViewPos.y)
- }
-
- // 小地图鼠标松开事件
- onMouseup() {
- this.isMousedown = false
- this.isViewBoxMousedown = false
- }
-
- // 视口框鼠标按下事件
- onViewBoxMousedown(e) {
- this.isViewBoxMousedown = true
- this.mousedownPos = {
- x: e.clientX,
- y: e.clientY
- }
- // 保存视图当前的偏移量
- let transformData = this.mindMap.view.getTransformData()
- this.startViewPos = {
- x: transformData.state.x,
- y: transformData.state.y
- }
- }
-
- // 视口框鼠标移动事件
- onViewBoxMousemove(e) {
- if (!this.isViewBoxMousedown || !this.currentState || this.isMousedown)
- return
- let ox = e.clientX - this.mousedownPos.x
- let oy = e.clientY - this.mousedownPos.y
- const { viewBoxStyle, miniMapBoxScale, miniMapBoxLeft, miniMapBoxTop } =
- this.currentState
- const left = Math.max(
- miniMapBoxLeft,
- Number.parseFloat(viewBoxStyle.left) + ox
- )
- const right = Math.max(
- miniMapBoxLeft,
- Number.parseFloat(viewBoxStyle.right) - ox
- )
- const top = Math.max(
- miniMapBoxTop,
- Number.parseFloat(viewBoxStyle.top) + oy
- )
- const bottom = Math.max(
- miniMapBoxTop,
- Number.parseFloat(viewBoxStyle.bottom) - oy
- )
- this.mindMap.emit('mini_map_view_box_position_change', {
- left: left + 'px',
- right: right + 'px',
- top: top + 'px',
- bottom: bottom + 'px'
- })
- // 在视图最初偏移量上累加更新量
- this.mindMap.view.translateXTo(-ox / miniMapBoxScale + this.startViewPos.x)
- this.mindMap.view.translateYTo(-oy / miniMapBoxScale + this.startViewPos.y)
- }
-}
-
-MiniMap.instanceName = 'miniMap'
-
-export default MiniMap
diff --git a/packages/mindmap/src/plugins/NodeImgAdjust.js b/packages/mindmap/src/plugins/NodeImgAdjust.js
deleted file mode 100644
index ce2a17d..0000000
--- a/packages/mindmap/src/plugins/NodeImgAdjust.js
+++ /dev/null
@@ -1,337 +0,0 @@
-// 节点图片大小调整插件
-import { resizeImgSizeByOriginRatio } from '../utils/index'
-import btnsSvg from '../svg/btns'
-
-class NodeImgAdjust {
- // 构造函数
- constructor({ mindMap }) {
- this.mindMap = mindMap
- this.handleEl = null // 自定义元素,用来渲染临时图片、调整按钮
- this.isShowHandleEl = false // 自定义元素是否在显示中
- this.node = null // 当前节点实例
- this.img = null // 当前节点的图片节点
- this.rect = null // 当前图片节点的尺寸信息
- this.isMousedown = false // 当前是否是按住调整按钮状态
- this.mousedownDrawTransform = null //鼠标按下时对当前画布的变换
- this.mousedownOffset = {
- // 鼠标按下时位置和图片右下角相差的距离
- x: 0,
- y: 0
- }
- this.currentImgWidth = 0 // 当前拖拽实时图片的大小
- this.currentImgHeight = 0
- this.isAdjusted = false // 是否是拖拽结束后的渲染期间
- this.bindEvent()
- }
-
- // 监听事件
- bindEvent() {
- this.onNodeImgMouseleave = this.onNodeImgMouseleave.bind(this)
- this.onNodeImgMousemove = this.onNodeImgMousemove.bind(this)
- this.onMousemove = this.onMousemove.bind(this)
- this.onMouseup = this.onMouseup.bind(this)
- this.onRenderEnd = this.onRenderEnd.bind(this)
- this.mindMap.on('node_img_mouseleave', this.onNodeImgMouseleave)
- this.mindMap.on('node_img_mousemove', this.onNodeImgMousemove)
- this.mindMap.on('mousemove', this.onMousemove)
- this.mindMap.on('mouseup', this.onMouseup)
- this.mindMap.on('node_mouseup', this.onMouseup)
- this.mindMap.on('node_tree_render_end', this.onRenderEnd)
- }
-
- // 解绑事件
- unBindEvent() {
- this.mindMap.off('node_img_mouseleave', this.onNodeImgMouseleave)
- this.mindMap.off('node_img_mousemove', this.onNodeImgMousemove)
- this.mindMap.off('mousemove', this.onMousemove)
- this.mindMap.off('mouseup', this.onMouseup)
- this.mindMap.off('node_mouseup', this.onMouseup)
- this.mindMap.off('node_tree_render_end', this.onRenderEnd)
- }
-
- // 节点图片鼠标移动事件
- onNodeImgMousemove(node, img) {
- // 如果当前正在拖动调整中那么直接返回
- if (this.isMousedown || this.isAdjusted || this.mindMap.opt.readonly) return
- // 如果在当前节点内移动,以及自定义元素已经是显示状态,那么直接返回
- if (this.node && this.node.uid === node.uid && this.isShowHandleEl) return
- // 更新当前节点信息
- this.node = node
- this.img = img
- this.rect = this.img.rbox()
- // 显示自定义元素
- this.showHandleEl()
- }
-
- // 节点图片鼠标移出事件
- onNodeImgMouseleave() {
- if (this.isMousedown) return
- this.hideHandleEl()
- }
-
- // 隐藏节点实际的图片
- hideNodeImage() {
- if (!this.img) return
- this.img.hide()
- }
-
- // 显示节点实际的图片
- showNodeImage() {
- if (!this.img) return
- this.img.show()
- }
-
- // 显示自定义元素
- showHandleEl() {
- if (this.isShowHandleEl) return
- if (!this.handleEl) {
- this.createResizeBtnEl()
- }
- this.setHandleElRect()
- this.handleEl.style.display = 'block'
- this.isShowHandleEl = true
- }
-
- // 隐藏自定义元素
- hideHandleEl() {
- if (!this.isShowHandleEl) return
- this.isShowHandleEl = false
- this.handleEl.style.display = 'none'
- this.handleEl.style.backgroundImage = ``
- this.handleEl.style.width = 0
- this.handleEl.style.height = 0
- this.handleEl.style.left = 0
- this.handleEl.style.top = 0
- }
-
- // 设置自定义元素尺寸位置信息
- setHandleElRect() {
- let { width, height, x, y } = this.rect
- this.handleEl.style.left = `${x}px`
- this.handleEl.style.top = `${y}px`
- this.currentImgWidth = width
- this.currentImgHeight = height
- this.updateHandleElSize()
- }
-
- // 更新自定义元素宽高
- updateHandleElSize() {
- this.handleEl.style.width = `${this.currentImgWidth}px`
- this.handleEl.style.height = `${this.currentImgHeight}px`
- }
-
- // 创建调整按钮元素
- createResizeBtnEl() {
- const { imgResizeBtnSize } = this.mindMap.opt
- // 容器元素
- this.handleEl = document.createElement('div')
- this.handleEl.style.cssText = `
- pointer-events: none;
- position: fixed;
- display:none;
- background-size: cover;
- `
- this.handleEl.className = 'node-img-handle'
- // 调整按钮元素
- const btnEl = document.createElement('div')
- btnEl.innerHTML = btnsSvg.imgAdjust
- btnEl.style.cssText = `
- position: absolute;
- right: 0;
- bottom: 0;
- pointer-events: auto;
- background-color: rgba(0, 0, 0, 0.3);
- width: ${imgResizeBtnSize}px;
- height: ${imgResizeBtnSize}px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: nwse-resize;
- `
- btnEl.className = 'node-image-resize'
- // 给按钮元素绑定事件
- btnEl.addEventListener('mouseenter', () => {
- // 移入按钮,会触发节点图片的移出事件,所以需要再次显示按钮
- this.showHandleEl()
- })
- btnEl.addEventListener('mouseleave', () => {
- // 移除按钮,需要隐藏按钮
- if (this.isMousedown) return
- this.hideHandleEl()
- })
- btnEl.addEventListener('mousedown', e => {
- e.stopPropagation()
- e.preventDefault()
- this.onMousedown(e)
- })
- btnEl.addEventListener('mouseup', e => {
- setTimeout(() => {
- //点击后直接松开异常处理; 其他事件响应之后处理
- this.hideHandleEl()
- this.isAdjusted = false
- }, 0)
- })
- btnEl.addEventListener('click', e => {
- e.stopPropagation()
- })
- this.handleEl.appendChild(btnEl)
- // 删除按钮
- const btnRemove = document.createElement('div')
- this.handleEl.prepend(btnRemove)
- btnRemove.className = 'node-image-remove'
- btnRemove.innerHTML = btnsSvg.remove
- btnRemove.style.cssText = `
- position: absolute;
- right: 0;top:0;color:#fff;
- pointer-events: auto;
- background-color: rgba(0, 0, 0, 0.3);
- width: ${imgResizeBtnSize}px;
- height: ${imgResizeBtnSize}px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- `
- btnRemove.addEventListener('mouseenter', e => {
- this.showHandleEl()
- })
- btnRemove.addEventListener('mouseleave', e => {
- if (this.isMousedown) return
- this.hideHandleEl()
- })
- btnRemove.addEventListener('click', async e => {
- let stop = false
- if (typeof this.mindMap.opt.beforeDeleteNodeImg === 'function') {
- stop = await this.mindMap.opt.beforeDeleteNodeImg(this.node)
- }
- if (!stop) {
- this.mindMap.execCommand('SET_NODE_IMAGE', this.node, { url: null })
- }
- })
- // 添加元素到页面
- const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
- targetNode.appendChild(this.handleEl)
- }
-
- // 鼠标按钮按下事件
- onMousedown(e) {
- this.isMousedown = true
- this.mousedownDrawTransform = this.mindMap.draw.transform()
- // 隐藏节点实际图片
- this.hideNodeImage()
- this.mousedownOffset.x = e.clientX - this.rect.x2
- this.mousedownOffset.y = e.clientY - this.rect.y2
- // 将节点图片渲染到自定义元素上
- this.handleEl.style.backgroundImage = `url(${this.node.getData('image')})`
- }
-
- // 鼠标移动
- onMousemove(e) {
- if (!this.isMousedown) return
- e.preventDefault()
- const { scaleX, scaleY } = this.mousedownDrawTransform
- // 图片原始大小
- const { width: imageOriginWidth, height: imageOriginHeight } =
- this.node.getData('imageSize')
- let {
- minImgResizeWidth,
- minImgResizeHeight,
- maxImgResizeWidthInheritTheme,
- maxImgResizeWidth,
- maxImgResizeHeight
- } = this.mindMap.opt
- // 主题设置的最小图片宽高
- const minRatio = minImgResizeWidth / minImgResizeHeight
- const oRatio = imageOriginWidth / imageOriginHeight
- if (minRatio > oRatio) {
- // 如果最小值比例大于图片原始比例,那么要调整高度最小值
- minImgResizeHeight = minImgResizeWidth / oRatio
- } else {
- // 否则调整宽度最小值
- minImgResizeWidth = minImgResizeHeight * oRatio
- }
- // 主题设置的最大图片宽高
- let imgMaxWidth, imgMaxHeight
- if (maxImgResizeWidthInheritTheme) {
- imgMaxWidth = this.mindMap.getThemeConfig('imgMaxWidth')
- imgMaxHeight = this.mindMap.getThemeConfig('imgMaxHeight')
- } else {
- imgMaxWidth = maxImgResizeWidth
- imgMaxHeight = maxImgResizeHeight
- }
- imgMaxWidth = imgMaxWidth * scaleX
- imgMaxHeight = imgMaxHeight * scaleY
- // 计算当前拖拽位置对应的图片的实时大小
- let newWidth = Math.abs(e.clientX - this.rect.x - this.mousedownOffset.x)
- let newHeight = Math.abs(e.clientY - this.rect.y - this.mousedownOffset.y)
- // 限制最小值
- if (newWidth < minImgResizeWidth) newWidth = minImgResizeWidth
- if (newHeight < minImgResizeHeight) newHeight = minImgResizeHeight
- // 限制最大值
- if (newWidth > imgMaxWidth) newWidth = imgMaxWidth
- if (newHeight > imgMaxHeight) newHeight = imgMaxHeight
- const [actWidth, actHeight] = resizeImgSizeByOriginRatio(
- imageOriginWidth,
- imageOriginHeight,
- newWidth,
- newHeight
- )
- this.currentImgWidth = actWidth
- this.currentImgHeight = actHeight
- this.updateHandleElSize()
- }
-
- // 鼠标松开
- onMouseup() {
- if (!this.isMousedown) return
- // 显示节点实际图片
- this.showNodeImage()
- // 隐藏自定义元素
- this.hideHandleEl()
- // 更新节点图片为新的大小
- const { image, imageTitle } = this.node.getData()
- const { scaleX, scaleY } = this.mousedownDrawTransform
- const newWidth = this.currentImgWidth / scaleX
- const newHeight = this.currentImgHeight / scaleY
- if (
- Math.abs(newWidth - this.rect.width) > 1 ||
- Math.abs(newHeight - this.rect.height) > 1
- ) {
- this.mindMap.execCommand('SET_NODE_IMAGE', this.node, {
- url: image,
- title: imageTitle,
- width: newWidth,
- height: newHeight,
- custom: true // 代表自定义了图片大小
- })
- this.isAdjusted = true
- }
- this.isMousedown = false
- this.mousedownDrawTransform = null
- this.mousedownOffset.x = 0
- this.mousedownOffset.y = 0
- }
-
- // 渲染完成事件
- onRenderEnd() {
- if (!this.isAdjusted) {
- this.hideHandleEl()
- return
- }
- this.isAdjusted = false
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-NodeImgAdjust.instanceName = 'nodeImgAdjust'
-
-export default NodeImgAdjust
diff --git a/packages/mindmap/src/plugins/OuterFrame.js b/packages/mindmap/src/plugins/OuterFrame.js
deleted file mode 100644
index 2bcffcd..0000000
--- a/packages/mindmap/src/plugins/OuterFrame.js
+++ /dev/null
@@ -1,406 +0,0 @@
-import {
- formatDataToArray,
- walk,
- getTopAncestorsFomNodeList,
- getNodeListBoundingRect,
- createUid
-} from '../utils'
-
-// 解析要添加外框的节点实例列表
-const parseAddNodeList = list => {
- // 找出顶层节点
- list = getTopAncestorsFomNodeList(list)
- const cache = {}
- const uidToParent = {}
- // 找出列表中节点在兄弟节点中的索引,并和父节点关联起来
- list.forEach(node => {
- const parent = node.parent
- if (parent) {
- const pUid = parent.uid
- uidToParent[pUid] = parent
- const index = node.getIndexInBrothers()
- const data = {
- node,
- index
- }
- if (cache[pUid]) {
- if (
- !cache[pUid].find(item => {
- return item.index === data.index
- })
- ) {
- cache[pUid].push(data)
- }
- } else {
- cache[pUid] = [data]
- }
- }
- })
- const res = []
- Object.keys(cache).forEach(uid => {
- const indexList = cache[uid]
- const parentNode = uidToParent[uid]
- if (indexList.length > 1) {
- // 多个节点
- const rangeList = indexList
- .map(item => {
- return item.index
- })
- .sort((a, b) => {
- return a - b
- })
- const minIndex = rangeList[0]
- const maxIndex = rangeList[rangeList.length - 1]
- let curStart = -1
- let curEnd = -1
- for (let i = minIndex; i <= maxIndex; i++) {
- // 连续索引
- if (rangeList.includes(i)) {
- if (curStart === -1) {
- curStart = i
- }
- curEnd = i
- } else {
- // 连续断开
- if (curStart !== -1 && curEnd !== -1) {
- res.push({
- node: parentNode,
- range: [curStart, curEnd]
- })
- }
- curStart = -1
- curEnd = -1
- }
- }
- // 不要忘了最后一段索引
- if (curStart !== -1 && curEnd !== -1) {
- res.push({
- node: parentNode,
- range: [curStart, curEnd]
- })
- }
- } else {
- // 单个节点
- res.push({
- node: parentNode,
- range: [indexList[0].index, indexList[0].index]
- })
- }
- })
- return res
-}
-
-// 解析获取节点的子节点生成的外框列表
-const getNodeOuterFrameList = node => {
- const children = node.children
- if (!children || children.length <= 0) return
- const res = []
- const map = {}
- children.forEach((item, index) => {
- const outerFrameData = item.getData('outerFrame')
- if (!outerFrameData) return
- const groupId = outerFrameData.groupId
- if (groupId) {
- if (!map[groupId]) {
- map[groupId] = []
- }
- map[groupId].push({
- node: item,
- index
- })
- } else {
- res.push({
- nodeList: [item],
- range: [index, index]
- })
- }
- })
- Object.keys(map).forEach(id => {
- const list = map[id]
- res.push({
- nodeList: list.map(item => {
- return item.node
- }),
- range: [list[0].index, list[list.length - 1].index]
- })
- })
- return res
-}
-
-// 默认外框样式
-const defaultStyle = {
- radius: 5,
- strokeWidth: 2,
- strokeColor: '#0984e3',
- strokeDasharray: '5,5',
- fill: 'rgba(9,132,227,0.05)'
-}
-
-// 外框插件
-class OuterFrame {
- constructor(opt = {}) {
- this.mindMap = opt.mindMap
- this.draw = null
- this.createDrawContainer()
- this.outerFrameElList = []
- this.activeOuterFrame = null
- this.bindEvent()
- }
-
- // 创建容器
- createDrawContainer() {
- this.draw = this.mindMap.draw.group()
- this.draw.addClass('smm-outer-frame-container')
- this.draw.back() // 最底层
- this.draw.forward() // 连线层上面
- }
-
- // 绑定事件
- bindEvent() {
- this.renderOuterFrames = this.renderOuterFrames.bind(this)
- this.mindMap.on('node_tree_render_end', this.renderOuterFrames)
- this.mindMap.on('data_change', this.renderOuterFrames)
- // 监听画布和节点点击事件,用于清除当前激活的连接线
- this.clearActiveOuterFrame = this.clearActiveOuterFrame.bind(this)
- this.mindMap.on('draw_click', this.clearActiveOuterFrame)
- this.mindMap.on('node_click', this.clearActiveOuterFrame)
-
- this.addOuterFrame = this.addOuterFrame.bind(this)
- this.mindMap.command.add('ADD_OUTER_FRAME', this.addOuterFrame)
-
- this.removeActiveOuterFrame = this.removeActiveOuterFrame.bind(this)
- this.mindMap.keyCommand.addShortcut(
- 'Del|Backspace',
- this.removeActiveOuterFrame
- )
- }
-
- // 解绑事件
- unBindEvent() {
- this.mindMap.off('node_tree_render_end', this.renderOuterFrames)
- this.mindMap.off('data_change', this.renderOuterFrames)
- this.mindMap.off('draw_click', this.clearActiveOuterFrame)
- this.mindMap.off('node_click', this.clearActiveOuterFrame)
- this.mindMap.command.remove('ADD_OUTER_FRAME', this.addOuterFrame)
- this.mindMap.keyCommand.removeShortcut(
- 'Del|Backspace',
- this.removeActiveOuterFrame
- )
- }
-
- // 给节点添加外框数据
- /*
- config: {
- text: '',
- radius: 5,
- strokeWidth: 2,
- strokeColor: '#0984e3',
- strokeDasharray: '5,5',
- fill: 'rgba(9,132,227,0.05)'
- }
- */
- addOuterFrame(appointNodes, config = {}) {
- appointNodes = formatDataToArray(appointNodes)
- const activeNodeList = this.mindMap.renderer.activeNodeList
- if (activeNodeList.length <= 0 && appointNodes.length <= 0) {
- return
- }
- let nodeList = appointNodes.length > 0 ? appointNodes : activeNodeList
- nodeList = nodeList.filter(node => {
- return !node.isRoot && !node.isGeneralization
- })
- const list = parseAddNodeList(nodeList)
- list.forEach(({ node, range }) => {
- const childNodeList = node.children.slice(range[0], range[1] + 1)
- const groupId = createUid()
- childNodeList.forEach(child => {
- let outerFrame = child.getData('outerFrame')
- // 检查该外框是否已存在
- if (outerFrame) {
- outerFrame = {
- ...outerFrame,
- ...config,
- groupId
- }
- } else {
- outerFrame = {
- ...config,
- groupId
- }
- }
- this.mindMap.execCommand('SET_NODE_DATA', child, {
- outerFrame
- })
- })
- })
- }
-
- // 获取当前激活的外框
- getActiveOuterFrame() {
- return this.activeOuterFrame
- ? {
- ...this.activeOuterFrame
- }
- : null
- }
-
- // 删除当前激活的外框
- removeActiveOuterFrame() {
- if (!this.activeOuterFrame) return
- const { node, range } = this.activeOuterFrame
- this.getRangeNodeList(node, range).forEach(child => {
- this.mindMap.execCommand('SET_NODE_DATA', child, {
- outerFrame: null
- })
- })
- this.mindMap.emit('outer_frame_delete')
- }
-
- // 更新当前激活的外框
- // 执行了该方法后请立即隐藏你的样式面板,因为会清除当前激活的外框
- updateActiveOuterFrame(config = {}) {
- if (!this.activeOuterFrame) return
- const { node, range } = this.activeOuterFrame
- this.getRangeNodeList(node, range).forEach(node => {
- const outerFrame = node.getData('outerFrame')
- this.mindMap.execCommand('SET_NODE_DATA', node, {
- outerFrame: {
- ...outerFrame,
- ...config
- }
- })
- })
- }
-
- // 获取某个节点指定范围的带外框的子节点列表
- getRangeNodeList(node, range) {
- return node.children.slice(range[0], range[1] + 1).filter(child => {
- return child.getData('outerFrame')
- })
- }
-
- // 渲染外框
- renderOuterFrames() {
- this.clearOuterFrameElList()
- let tree = this.mindMap.renderer.root
- if (!tree) return
- const t = this.mindMap.draw.transform()
- const { outerFramePaddingX, outerFramePaddingY } = this.mindMap.opt
- walk(
- tree,
- null,
- cur => {
- if (!cur) return
- const outerFrameList = getNodeOuterFrameList(cur)
- if (outerFrameList && outerFrameList.length > 0) {
- outerFrameList.forEach(({ nodeList, range }) => {
- if (range[0] === -1 || range[1] === -1) return
- const { left, top, width, height } =
- getNodeListBoundingRect(nodeList)
- if (
- !Number.isFinite(left) ||
- !Number.isFinite(top) ||
- !Number.isFinite(width) ||
- !Number.isFinite(height)
- )
- return
- const el = this.createOuterFrameEl(
- (left -
- outerFramePaddingX -
- this.mindMap.elRect.left -
- t.translateX) /
- t.scaleX,
- (top -
- outerFramePaddingY -
- this.mindMap.elRect.top -
- t.translateY) /
- t.scaleY,
- (width + outerFramePaddingX * 2) / t.scaleX,
- (height + outerFramePaddingY * 2) / t.scaleY,
- nodeList[0].getData('outerFrame') // 使用第一个节点的外框样式
- )
- el.on('click', e => {
- e.stopPropagation()
- this.setActiveOuterFrame(el, cur, range)
- })
- })
- }
- },
- () => {},
- true,
- 0
- )
- }
-
- // 激活外框
- setActiveOuterFrame(el, node, range) {
- this.mindMap.execCommand('CLEAR_ACTIVE_NODE')
- this.clearActiveOuterFrame()
- this.activeOuterFrame = {
- el,
- node,
- range
- }
- el.stroke({
- dasharray: 'none'
- })
- this.mindMap.emit('outer_frame_active', el, node, range)
- }
-
- // 清除当前激活的外框
- clearActiveOuterFrame() {
- if (!this.activeOuterFrame) return
- const { el } = this.activeOuterFrame
- el.stroke({
- dasharray: el.cacheStyle.dasharray || defaultStyle.strokeDasharray
- })
- this.activeOuterFrame = null
- }
-
- // 创建外框元素
- createOuterFrameEl(x, y, width, height, styleConfig = {}) {
- styleConfig = { ...defaultStyle, ...styleConfig }
- const el = this.draw
- .rect()
- .size(width, height)
- .radius(styleConfig.radius)
- .stroke({
- width: styleConfig.strokeWidth,
- color: styleConfig.strokeColor,
- dasharray: styleConfig.strokeDasharray
- })
- .fill({
- color: styleConfig.fill
- })
- .x(x)
- .y(y)
- el.cacheStyle = {
- dasharray: styleConfig.strokeDasharray
- }
- this.outerFrameElList.push(el)
- return el
- }
-
- // 清除外框元素
- clearOuterFrameElList() {
- this.outerFrameElList.forEach(item => {
- item.remove()
- })
- this.outerFrameElList = []
- this.activeOuterFrame = null
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-OuterFrame.instanceName = 'outerFrame'
-
-export default OuterFrame
diff --git a/packages/mindmap/src/plugins/Painter.js b/packages/mindmap/src/plugins/Painter.js
deleted file mode 100644
index 3b7be75..0000000
--- a/packages/mindmap/src/plugins/Painter.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { checkIsNodeStyleDataKey } from '../utils/index'
-
-// 格式刷插件
-class Painter {
- constructor({ mindMap }) {
- this.mindMap = mindMap
- this.isInPainter = false
- this.painterNode = null
- this.bindEvent()
- }
-
- bindEvent() {
- this.painterOneNode = this.painterOneNode.bind(this)
- this.onEndPainter = this.onEndPainter.bind(this)
- this.mindMap.on('node_click', this.painterOneNode)
- this.mindMap.on('draw_click', this.onEndPainter)
- }
-
- unBindEvent() {
- this.mindMap.off('node_click', this.painterOneNode)
- this.mindMap.off('draw_click', this.onEndPainter)
- }
-
- // 开始格式刷
- startPainter() {
- if (this.mindMap.opt.readonly) return
- let activeNodeList = this.mindMap.renderer.activeNodeList
- if (activeNodeList.length <= 0) return
- this.painterNode = activeNodeList[0]
- this.isInPainter = true
- this.mindMap.emit('painter_start')
- }
-
- // 结束格式刷
- endPainter() {
- this.painterNode = null
- this.isInPainter = false
- }
-
- onEndPainter() {
- if (!this.isInPainter) return
- this.endPainter()
- this.mindMap.emit('painter_end')
- }
-
- // 格式刷某个节点
- painterOneNode(node) {
- if (
- !node ||
- !this.isInPainter ||
- !this.painterNode ||
- !node ||
- node.uid === this.painterNode.uid
- )
- return
- let style = {}
- // 格式刷节点所有生效的样式
- if (!this.mindMap.opt.onlyPainterNodeCustomStyles) {
- style = {
- ...this.painterNode.effectiveStyles
- }
- }
- const painterNodeData = this.painterNode.getData()
- Object.keys(painterNodeData).forEach(key => {
- if (checkIsNodeStyleDataKey(key)) {
- style[key] = painterNodeData[key]
- }
- })
- // 先去除目标节点的样式
- this.mindMap.renderer._handleRemoveCustomStyles(node.getData())
- node.setStyles(style)
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Painter.instanceName = 'painter'
-
-export default Painter
diff --git a/packages/mindmap/src/plugins/RainbowLines.js b/packages/mindmap/src/plugins/RainbowLines.js
deleted file mode 100644
index 42bfaeb..0000000
--- a/packages/mindmap/src/plugins/RainbowLines.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { walk, getNodeDataIndex } from '../utils/index'
-
-const defaultColorsList = [
- 'rgb(255, 213, 73)',
- 'rgb(255, 136, 126)',
- 'rgb(107, 225, 141)',
- 'rgb(151, 171, 255)',
- 'rgb(129, 220, 242)',
- 'rgb(255, 163, 125)',
- 'rgb(152, 132, 234)'
-]
-
-// 彩虹线条插件
-class RainbowLines {
- constructor({ mindMap }) {
- this.mindMap = mindMap
- }
-
- // 更新彩虹线条配置
- updateRainLinesConfig(config = {}) {
- const newConfig = this.mindMap.opt.rainbowLinesConfig || {}
- newConfig.open = !!config.open
- newConfig.colorsList = Array.isArray(config.colorsList)
- ? config.colorsList
- : []
- // 如果开启彩虹线条,那么先移除所有节点的自定义连线颜色配置
- if (this.mindMap.opt.rainbowLinesConfig.open) {
- this.removeNodeLineColor()
- }
- this.mindMap.render()
- }
-
- // 删除所有节点的连线颜色
- removeNodeLineColor() {
- const tree = this.mindMap.renderer.renderTree
- if (!tree) return
- walk(
- tree,
- null,
- cur => {
- delete cur.data.lineColor
- },
- null,
- true
- )
- this.mindMap.command.addHistory()
- }
-
- // 获取一个节点的第二层级的祖先节点
- getSecondLayerAncestor(node) {
- if (node.layerIndex === 0) {
- return null
- } else if (node.layerIndex === 1) {
- return node
- } else {
- let res = null
- let parent = node.parent
- while (parent) {
- if (parent.layerIndex === 1) {
- return parent
- }
- parent = parent.parent
- }
- return res
- }
- }
-
- // 获取颜色列表
- getColorsList() {
- const { rainbowLinesConfig } = this.mindMap.opt
- return rainbowLinesConfig &&
- Array.isArray(rainbowLinesConfig.colorsList) &&
- rainbowLinesConfig.colorsList.length > 0
- ? rainbowLinesConfig.colorsList
- : [...defaultColorsList]
- }
-
- // 获取一个节点的彩虹线条颜色
- getNodeColor(node) {
- const { rainbowLinesConfig } = this.mindMap.opt
- if (!rainbowLinesConfig || !rainbowLinesConfig.open) return ''
- const ancestor = this.getSecondLayerAncestor(node)
- if (!ancestor) return
- const index = getNodeDataIndex(ancestor)
- const colorsList = this.getColorsList()
- return colorsList[index % colorsList.length]
- }
-}
-
-RainbowLines.instanceName = 'rainbowLines'
-
-export default RainbowLines
diff --git a/packages/mindmap/src/plugins/RichText.js b/packages/mindmap/src/plugins/RichText.js
deleted file mode 100644
index a01116a..0000000
--- a/packages/mindmap/src/plugins/RichText.js
+++ /dev/null
@@ -1,826 +0,0 @@
-import Quill from 'quill'
-import Delta from 'quill-delta'
-import 'quill/dist/quill.snow.css'
-import {
- walk,
- getTextFromHtml,
- isUndef,
- checkSmmFormatData,
- formatGetNodeGeneralization,
- nodeRichTextToTextWithWrap,
- getNodeRichTextStyles,
- htmlEscape,
- compareVersion
-} from '../utils'
-import { CONSTANTS, richTextSupportStyleList } from '../constants/constant'
-import MindMapNode from '../core/render/node/MindMapNode'
-import { Scope } from 'parchment'
-
-let extended = false
-
-// 扩展quill的字体列表
-let fontFamilyList = [
- '宋体, SimSun, Songti SC',
- '微软雅黑, Microsoft YaHei',
- '楷体, 楷体_GB2312, SimKai, STKaiti',
- '黑体, SimHei, Heiti SC',
- '隶书, SimLi',
- 'andale mono',
- 'arial, helvetica, sans-serif',
- 'arial black, avant garde',
- 'comic sans ms',
- 'impact, chicago',
- 'times new roman',
- 'sans-serif',
- 'serif'
-]
-
-// 扩展quill的字号列表
-let fontSizeList = new Array(100).fill(0).map((_, index) => {
- return index + 'px'
-})
-
-// 富文本编辑插件
-class RichText {
- constructor({ mindMap, pluginOpt }) {
- this.mindMap = mindMap
- this.pluginOpt = pluginOpt
- this.textEditNode = null
- this.showTextEdit = false
- this.quill = null
- this.range = null
- this.lastRange = null
- this.pasteUseRange = null
- this.node = null
- this.isInserting = false
- this.styleEl = null
- this.cacheEditingText = ''
- this.isCompositing = false
- this.textNodePaddingX = 6
- this.textNodePaddingY = 4
- this.initOpt()
- this.extendQuill()
- this.appendCss()
- this.bindEvent()
-
- this.handleDataToRichTextOnInit()
- }
-
- // 绑定事件
- bindEvent() {
- this.onCompositionStart = this.onCompositionStart.bind(this)
- this.onCompositionUpdate = this.onCompositionUpdate.bind(this)
- this.onCompositionEnd = this.onCompositionEnd.bind(this)
- this.handleSetData = this.handleSetData.bind(this)
- window.addEventListener('compositionstart', this.onCompositionStart)
- window.addEventListener('compositionupdate', this.onCompositionUpdate)
- window.addEventListener('compositionend', this.onCompositionEnd)
- this.mindMap.on('before_update_data', this.handleSetData)
- this.mindMap.on('before_set_data', this.handleSetData)
- }
-
- // 解绑事件
- unbindEvent() {
- window.removeEventListener('compositionstart', this.onCompositionStart)
- window.removeEventListener('compositionupdate', this.onCompositionUpdate)
- window.removeEventListener('compositionend', this.onCompositionEnd)
- this.mindMap.off('before_update_data', this.handleSetData)
- this.mindMap.off('before_set_data', this.handleSetData)
- }
-
- // 插入样式
- appendCss() {
- this.mindMap.appendCss(
- 'richText',
- `
- .smm-richtext-node-wrap {
- word-break: break-all;
- user-select: none;
- }
- `
- )
- let cssText = `
- .${CONSTANTS.EDIT_NODE_CLASS.RICH_TEXT_EDIT_WRAP} {
- overflow: hidden;
- padding: 0;
- height: auto;
- line-height: 1.2;
- -webkit-user-select: text;
- }
-
- .ql-container {
- height: auto;
- font-size: inherit;
- }
-
- .ql-container.ql-snow {
- border: none;
- }
- `
- this.styleEl = document.createElement('style')
- this.styleEl.type = 'text/css'
- this.styleEl.innerHTML = cssText
- document.head.appendChild(this.styleEl)
- }
-
- // 处理选项参数
- initOpt() {
- if (
- this.pluginOpt.fontFamilyList &&
- Array.isArray(this.pluginOpt.fontFamilyList)
- ) {
- fontFamilyList = this.pluginOpt.fontFamilyList
- }
- if (
- this.pluginOpt.fontSizeList &&
- Array.isArray(this.pluginOpt.fontSizeList)
- ) {
- fontSizeList = this.pluginOpt.fontSizeList
- }
- }
-
- // 扩展quill编辑器
- extendQuill() {
- if (extended) {
- return
- }
- extended = true
-
- this.extendFont([])
-
- // 扩展quill的字号列表
- const SizeAttributor = Quill.import('attributors/class/size')
- SizeAttributor.whitelist = fontSizeList
- Quill.register(SizeAttributor, true)
-
- const SizeStyle = Quill.import('attributors/style/size')
- SizeStyle.whitelist = fontSizeList
- Quill.register(SizeStyle, true)
- }
-
- // 扩展字体列表
- extendFont(list = [], cover = false) {
- fontFamilyList = cover ? [...list] : [...fontFamilyList, ...list]
-
- // 扩展quill的字体列表
- const FontAttributor = Quill.import('attributors/class/font')
- FontAttributor.whitelist = fontFamilyList
- Quill.register(FontAttributor, true)
-
- const FontStyle = Quill.import('attributors/style/font')
- FontStyle.whitelist = fontFamilyList
- Quill.register(FontStyle, true)
- }
-
- // 显示文本编辑控件
- showEditText({ node, rect, isInserting, isFromKeyDown, isFromScale }) {
- if (this.showTextEdit) {
- return
- }
- let {
- customInnerElsAppendTo,
- nodeTextEditZIndex,
- textAutoWrapWidth,
- selectTextOnEnterEditText,
- transformRichTextOnEnterEdit,
- openRealtimeRenderOnNodeTextEdit,
- autoEmptyTextWhenKeydownEnterEdit
- } = this.mindMap.opt
- textAutoWrapWidth = node.hasCustomWidth()
- ? node.customTextWidth
- : textAutoWrapWidth
- this.node = node
- this.isInserting = isInserting
- if (!rect) rect = node._textData.node.node.getBoundingClientRect()
- if (!isFromScale) {
- this.mindMap.emit('before_show_text_edit')
- }
- this.mindMap.renderer.textEdit.registerTmpShortcut()
- // 原始宽高
- let g = node._textData.node
- let originWidth = g.attr('data-width')
- let originHeight = g.attr('data-height')
- // 缩放值
- const scaleX = Math.ceil(rect.width) / originWidth
- const scaleY = Math.ceil(rect.height) / originHeight
- // 内边距
- let paddingX = this.textNodePaddingX
- let paddingY = this.textNodePaddingY
- if (!this.textEditNode) {
- this.textEditNode = document.createElement('div')
- this.textEditNode.classList.add('smm-richtext-node-edit-wrap')
- this.textEditNode.style.cssText = `
- position:fixed;
- box-sizing: border-box;
- ${
- openRealtimeRenderOnNodeTextEdit
- ? ''
- : 'box-shadow: 0 0 20px rgba(0,0,0,.5);'
- }
- outline: none;
- word-break: break-all;
- padding: ${paddingY}px ${paddingX}px;
- line-height: 1.2;
- `
- this.textEditNode.addEventListener('click', e => {
- e.stopPropagation()
- })
- this.textEditNode.addEventListener('mousedown', e => {
- e.stopPropagation()
- })
- this.textEditNode.addEventListener('keydown', e => {
- if (this.mindMap.renderer.textEdit.checkIsAutoEnterTextEditKey(e)) {
- e.stopPropagation()
- }
- })
- const targetNode = customInnerElsAppendTo || document.body
- targetNode.appendChild(this.textEditNode)
- }
- this.addNodeTextStyleToTextEditNode(node)
- this.textEditNode.style.marginLeft = `-${paddingX * scaleX}px`
- this.textEditNode.style.marginTop = `-${paddingY * scaleY}px`
- this.textEditNode.style.zIndex = nodeTextEditZIndex
- if (!openRealtimeRenderOnNodeTextEdit) {
- this.textEditNode.style.background =
- this.mindMap.renderer.textEdit.getBackground(node)
- }
- this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
- this.textEditNode.style.minHeight = originHeight + 'px'
- this.textEditNode.style.left = rect.left + 'px'
- this.textEditNode.style.top = rect.top + 'px'
- this.textEditNode.style.display = 'block'
- this.textEditNode.style.maxWidth = textAutoWrapWidth + paddingX * 2 + 'px'
- this.textEditNode.style.transform = `scale(${scaleX}, ${scaleY})`
- this.textEditNode.style.transformOrigin = 'left top'
- // 节点文本内容
- let nodeText = node.getData('text')
- if (typeof transformRichTextOnEnterEdit === 'function') {
- nodeText = transformRichTextOnEnterEdit(nodeText)
- }
- // 是否是空文本
- const isEmptyText = isUndef(nodeText)
- // 是否是非空的非富文本
- const noneEmptyNoneRichText = !node.getData('richText') && !isEmptyText
- if (isFromKeyDown && autoEmptyTextWhenKeydownEnterEdit) {
- this.textEditNode.innerHTML = ''
- } else if (noneEmptyNoneRichText) {
- // 还不是富文本
- let text = String(nodeText).split(/\n/gim).join('
')
- let html = `${text}
`
- this.textEditNode.innerHTML = this.cacheEditingText || html
- } else {
- // 已经是富文本
- this.textEditNode.innerHTML = this.cacheEditingText || nodeText
- }
- this.initQuillEditor()
- this.setQuillContainerMinHeight(originHeight)
- this.showTextEdit = true
- // 如果是刚创建的节点,那么默认全选,否则普通激活不全选,除非selectTextOnEnterEditText配置为true
- // 在selectTextOnEnterEditText时,如果是在keydown事件进入的节点编辑,也不需要全选
- this.focus(
- isInserting || (selectTextOnEnterEditText && !isFromKeyDown) ? 0 : null
- )
- this.cacheEditingText = ''
- }
-
- // 当openRealtimeRenderOnNodeTextEdit配置更新后需要更新编辑框样式
- onOpenRealtimeRenderOnNodeTextEditConfigUpdate(
- openRealtimeRenderOnNodeTextEdit
- ) {
- if (!this.textEditNode) return
- this.textEditNode.style.background = openRealtimeRenderOnNodeTextEdit
- ? 'transparent'
- : this.node
- ? this.mindMap.renderer.textEdit.getBackground(this.node)
- : ''
- this.textEditNode.style.boxShadow = openRealtimeRenderOnNodeTextEdit
- ? 'none'
- : '0 0 20px rgba(0,0,0,.5)'
- }
-
- // 将指定节点的文本样式添加到编辑框元素上
- addNodeTextStyleToTextEditNode(node) {
- const style = getNodeRichTextStyles(node)
- Object.keys(style).forEach(prop => {
- this.textEditNode.style[prop] = style[prop]
- })
- }
-
- // 设置quill编辑器容器的最小高度
- setQuillContainerMinHeight(minHeight) {
- document.querySelector(
- '.' + CONSTANTS.EDIT_NODE_CLASS.RICH_TEXT_EDIT_WRAP
- ).style.minHeight = minHeight + 'px'
- }
-
- // 更新文本编辑框的大小和位置
- updateTextEditNode() {
- if (!this.node) return
- const g = this.node._textData.node
- const rect = g.node.getBoundingClientRect()
- const originWidth = g.attr('data-width')
- const originHeight = g.attr('data-height')
- this.textEditNode.style.minWidth =
- originWidth + this.textNodePaddingX * 2 + 'px'
- this.textEditNode.style.minHeight = originHeight + 'px'
- this.textEditNode.style.left = rect.left + 'px'
- this.textEditNode.style.top = rect.top + 'px'
- this.setQuillContainerMinHeight(originHeight)
- }
-
- // 删除文本编辑框元素
- removeTextEditEl() {
- if (!this.textEditNode) return
- const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
- targetNode.removeChild(this.textEditNode)
- }
-
- // 获取当前正在编辑的内容
- getEditText() {
- // https://github.com/slab/quill/issues/4509
- return this.quill.container.firstChild.innerHTML.replaceAll(/ +/g, match =>
- ' '.repeat(match.length)
- )
- // 去除ql-cursor节点
- // https://github.com/wanglin2/mind-map/commit/138cc4b3e824671143f0bf70e5c46796f48520d0
- // https://github.com/wanglin2/mind-map/commit/0760500cebe8ec4e8ad84ab63f877b8b2a193aa1
- // html = removeHtmlNodeByClass(html, '.ql-cursor')
- // 去除最后的空行
- // return html.replace(/
<\/p>$/, '')
- }
-
- // 隐藏文本编辑控件,即完成编辑
- hideEditText(nodes) {
- if (!this.showTextEdit) {
- return
- }
- const { beforeHideRichTextEdit } = this.mindMap.opt
- if (typeof beforeHideRichTextEdit === 'function') {
- beforeHideRichTextEdit(this)
- }
- const html = this.getEditText()
- const list = nodes && nodes.length > 0 ? nodes : [this.node]
- const node = this.node
- this.textEditNode.style.display = 'none'
- this.showTextEdit = false
- this.mindMap.emit('rich_text_selection_change', false)
- this.node = null
- this.isInserting = false
- list.forEach(node => {
- this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
- // if (node.isGeneralization) {
- // 概要节点
- // node.generalizationBelongNode.updateGeneralization()
- // }
- this.mindMap.render()
- })
- this.mindMap.emit('hide_text_edit', this.textEditNode, list, node)
- }
-
- // 初始化Quill富文本编辑器
- initQuillEditor() {
- this.quill = new Quill(this.textEditNode, {
- modules: {
- toolbar: false,
- keyboard: {
- bindings: {
- enter: {
- key: 'Enter',
- handler: function () {
- // 覆盖默认的回车键,禁止换行
- }
- },
- shiftEnter: {
- key: 'Enter',
- shiftKey: true,
- handler: function (range, context) {
- // 覆盖默认的换行,默认情况下新行的样式会丢失
- const lineFormats = Object.keys(context.format).reduce(
- (formats, format) => {
- if (
- this.quill.scroll.query(format, Scope.BLOCK) &&
- !Array.isArray(context.format[format])
- ) {
- formats[format] = context.format[format]
- }
- return formats
- },
- {}
- )
- const delta = new Delta()
- .retain(range.index)
- .delete(range.length)
- .insert('\n', lineFormats)
- this.quill.updateContents(delta, Quill.sources.USER)
- this.quill.setSelection(range.index + 1, Quill.sources.SILENT)
- this.quill.focus()
- Object.keys(context.format).forEach(name => {
- if (lineFormats[name] != null) return
- if (Array.isArray(context.format[name])) return
- if (name === 'code' || name === 'link') return
- this.quill.format(
- name,
- context.format[name],
- Quill.sources.USER
- )
- })
- }
- },
- tab: {
- key: 9,
- handler: function () {
- // 覆盖默认的tab键
- }
- }
- }
- }
- },
- formats: [
- 'bold',
- 'italic',
- 'underline',
- 'strike',
- 'color',
- 'background',
- 'font',
- 'size',
- 'formula'
- ], // 明确指定允许的格式,不包含有序列表,无序列表等
- theme: 'snow'
- })
- // 拦截复制事件,即Ctrl + c,去除多余的空行
- this.quill.root.addEventListener('copy', event => {
- event.preventDefault()
- const sel = window.getSelection()
- const originStr = sel.toString()
- try {
- const range = sel.getRangeAt(0)
- const div = document.createElement('div')
- div.appendChild(range.cloneContents())
- const text = nodeRichTextToTextWithWrap(div.innerHTML)
- event.clipboardData.setData('text/plain', text)
- } catch (e) {
- event.clipboardData.setData('text/plain', originStr)
- }
- })
- this.quill.on('selection-change', range => {
- // 刚创建的节点全选不需要显示操作条
- if (this.isInserting) return
- this.lastRange = this.range
- this.range = null
- if (range) {
- this.pasteUseRange = range
- let bounds = this.quill.getBounds(range.index, range.length)
- let rect = this.textEditNode.getBoundingClientRect()
- let rectInfo = {
- left: bounds.left + rect.left,
- top: bounds.top + rect.top,
- right: bounds.right + rect.left,
- bottom: bounds.bottom + rect.top,
- width: bounds.width
- }
- let formatInfo = this.quill.getFormat(range.index, range.length)
- let hasRange = false
- if (range.length == 0) {
- hasRange = false
- } else {
- this.range = range
- hasRange = true
- }
- this.mindMap.emit(
- 'rich_text_selection_change',
- hasRange,
- rectInfo,
- formatInfo
- )
- } else {
- this.mindMap.emit('rich_text_selection_change', false, null, null)
- }
- })
- this.quill.on('text-change', () => {
- this.mindMap.emit('node_text_edit_change', {
- node: this.node,
- text: this.getEditText(),
- richText: true
- })
- })
- // 拦截粘贴,只允许粘贴纯文本
- // this.quill.clipboard.addMatcher(Node.TEXT_NODE, node => {
- // let style = this.getPasteTextStyle()
- // return new Delta().insert(this.formatPasteText(node.data), style)
- // })
- // 剪贴板里只要存在文本就会走这里,所以当剪贴板里是纯文本,或文本+图片都可以监听到和拦截,但是只有纯图片时不会走这里,所以无法拦截
- this.quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => {
- let ops = []
- let style = this.getPasteTextStyle()
- delta.ops.forEach(op => {
- // 过滤出文本内容,过滤掉换行
- if (op.insert && typeof op.insert === 'string') {
- ops.push({
- attributes: { ...style },
- insert: this.formatPasteText(op.insert)
- })
- }
- })
- delta.ops = ops
- return delta
- })
- // 拦截图片的粘贴,当剪贴板里是纯图片,或文本+图片都可以拦截到,但是带来的问题是文本+图片时里面的文本也无法粘贴
- this.quill.root.addEventListener(
- 'paste',
- e => {
- if (
- e.clipboardData &&
- e.clipboardData.files &&
- e.clipboardData.files.length
- ) {
- e.preventDefault()
- }
- },
- true
- )
- }
-
- // 获取粘贴的文本的样式
- getPasteTextStyle() {
- // 粘贴的数据使用当前光标位置处的文本样式
- if (this.pasteUseRange) {
- return this.quill.getFormat(
- this.pasteUseRange.index,
- this.pasteUseRange.length
- )
- }
- return {}
- }
-
- // 处理粘贴的文本内容
- formatPasteText(text) {
- const { isSmm, data } = checkSmmFormatData(text)
- if (isSmm && data[0] && data[0].data) {
- // 只取第一个节点的纯文本
- return getTextFromHtml(data[0].data.text)
- } else {
- return text
- }
- }
-
- // 正则输入中文
- onCompositionStart() {
- if (!this.showTextEdit) {
- return
- }
- this.isCompositing = true
- }
-
- // 中文输入中
- onCompositionUpdate() {
- if (!this.showTextEdit || !this.node) return
- this.mindMap.emit('node_text_edit_change', {
- node: this.node,
- text: this.getEditText(),
- richText: true
- })
- }
-
- // 中文输入结束
- onCompositionEnd() {
- if (!this.showTextEdit) {
- return
- }
- this.isCompositing = false
- }
-
- // 选中全部
- selectAll() {
- this.quill.setSelection(0, this.quill.getLength())
- }
-
- // 聚焦
- focus(start) {
- const len = this.quill.getLength()
- this.quill.setSelection(typeof start === 'number' ? start : len, len)
- }
-
- // 格式化当前选中的文本
- formatText(config = {}, clear = false) {
- if (!this.range && !this.lastRange) return
- const rangeLost = !this.range
- const range = rangeLost ? this.lastRange : this.range
- clear
- ? this.quill.removeFormat(range.index, range.length)
- : this.quill.formatText(range.index, range.length, config)
- if (rangeLost) {
- this.quill.setSelection(this.lastRange.index, this.lastRange.length)
- }
- }
-
- // 清除当前选中文本的样式
- removeFormat() {
- this.formatText({}, true)
- }
-
- // 格式化指定范围的文本
- formatRangeText(range, config = {}) {
- if (!range) return
- this.quill.formatText(range.index, range.length, config)
- }
-
- // 格式化所有文本
- formatAllText(config = {}) {
- this.quill.formatText(0, this.quill.getLength(), config)
- }
-
- // 将普通节点样式对象转换成富文本样式对象
- normalStyleToRichTextStyle(style) {
- const config = {}
- Object.keys(style).forEach(prop => {
- const value = style[prop]
- switch (prop) {
- case 'fontFamily':
- config.font = value
- break
- case 'fontSize':
- config.size = value + 'px'
- break
- case 'fontWeight':
- config.bold = value === 'bold'
- break
- case 'fontStyle':
- config.italic = value === 'italic'
- break
- case 'textDecoration':
- config.underline = value === 'underline'
- config.strike = value === 'line-through'
- break
- case 'color':
- config.color = value
- break
- default:
- break
- }
- })
- return config
- }
-
- // 将富文本样式对象转换成普通节点样式对象
- richTextStyleToNormalStyle(config) {
- const data = {}
- Object.keys(config).forEach(prop => {
- const value = config[prop]
- switch (prop) {
- case 'font':
- data.fontFamily = value
- break
- case 'size':
- data.fontSize = parseFloat(value)
- break
- case 'bold':
- data.fontWeight = value ? 'bold' : 'normal'
- break
- case 'italic':
- data.fontStyle = value ? 'italic' : 'normal'
- break
- case 'underline':
- data.textDecoration = value ? 'underline' : 'none'
- break
- case 'strike':
- data.textDecoration = value ? 'line-through' : 'none'
- break
- case 'color':
- data.color = value
- break
- default:
- break
- }
- })
- return data
- }
-
- // 判断一个对象是否包含了富文本支持的样式字段
- isHasRichTextStyle(obj) {
- const keys = Object.keys(obj)
- for (let i = 0; i < keys.length; i++) {
- const key = keys[i]
- if (richTextSupportStyleList.includes(key)) {
- return true
- }
- }
- return false
- }
-
- // 检查指定节点是否存在自定义的富文本样式
- checkNodeHasCustomRichTextStyle(node) {
- const nodeData = node instanceof MindMapNode ? node.getData() : node
- for (let i = 0; i < richTextSupportStyleList.length; i++) {
- if (nodeData[richTextSupportStyleList[i]] !== undefined) {
- return true
- }
- }
- return false
- }
-
- // 转换数据后的渲染操作
- afterHandleData() {
- // 清空历史数据,并且触发数据变化
- this.mindMap.command.clearHistory()
- this.mindMap.command.addHistory()
- this.mindMap.render()
- }
-
- // 插件实例化时处理思维导图数据,转换为富文本数据
- handleDataToRichTextOnInit() {
- // 处理数据,转成富文本格式
- if (this.mindMap.renderer.renderTree) {
- // 如果已经存在渲染树了,那么直接更新渲染树,并且触发重新渲染
- this.handleSetData(this.mindMap.renderer.renderTree)
- this.afterHandleData()
- } else if (this.mindMap.opt.data) {
- this.handleSetData(this.mindMap.opt.data)
- }
- }
-
- // 将所有节点转换成非富文本节点
- transformAllNodesToNormalNode() {
- const renderTree = this.mindMap.renderer.renderTree
- if (!renderTree) return
- walk(
- renderTree,
- null,
- node => {
- if (node.data.richText) {
- node.data.richText = false
- node.data.text = getTextFromHtml(node.data.text)
- }
- // 概要
- if (node.data) {
- const generalizationList = formatGetNodeGeneralization(node.data)
- generalizationList.forEach(item => {
- item.richText = false
- item.text = getTextFromHtml(item.text)
- })
- }
- },
- null,
- true,
- 0,
- 0
- )
- this.afterHandleData()
- }
-
- handleDataToRichText(data) {
- const oldIsRichText = data.richText
- data.richText = true
- data.resetRichText = true
- // 如果原本就是富文本,那么不能转换
- if (!oldIsRichText) {
- data.text = htmlEscape(data.text)
- }
- }
-
- // 处理导入数据
- handleSetData(data) {
- // 短期处理,为了兼容老数据,长期会去除
- const isOldRichTextVersion =
- !data.smmVersion || compareVersion(data.smmVersion, '0.13.0') === '<'
- const walk = root => {
- if (root.data && (!root.data.richText || isOldRichTextVersion)) {
- this.handleDataToRichText(root.data)
- }
- // 概要
- if (root.data) {
- const generalizationList = formatGetNodeGeneralization(root.data)
- generalizationList.forEach(item => {
- if (!item.richText || isOldRichTextVersion) {
- this.handleDataToRichText(item)
- }
- })
- }
- if (root.children && root.children.length > 0) {
- Array.from(root.children).forEach(item => {
- walk(item)
- })
- }
- }
- walk(data)
- return data
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.transformAllNodesToNormalNode()
- document.head.removeChild(this.styleEl)
- this.unbindEvent()
- this.mindMap.removeAppendCss('richText')
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- document.head.removeChild(this.styleEl)
- this.unbindEvent()
- }
-}
-
-RichText.instanceName = 'richText'
-
-export default RichText
diff --git a/packages/mindmap/src/plugins/Scrollbar.js b/packages/mindmap/src/plugins/Scrollbar.js
deleted file mode 100644
index 7e1c8f3..0000000
--- a/packages/mindmap/src/plugins/Scrollbar.js
+++ /dev/null
@@ -1,281 +0,0 @@
-import { throttle } from '../utils/index'
-import { CONSTANTS } from '../constants/constant'
-
-// 滚动条插件
-class Scrollbar {
- // 构造函数
- constructor(opt) {
- this.mindMap = opt.mindMap
- this.scrollbarWrapSize = {
- width: 0, // 水平滚动条的容器宽度
- height: 0 // 垂直滚动条的容器高度
- }
- // 思维导图实际高度
- this.chartHeight = 0
- this.chartWidth = 0
- this.reset()
- this.bindEvent()
- }
-
- // 复位数据
- reset() {
- // 当前拖拽的滚动条类型
- this.currentScrollType = ''
- this.isMousedown = false
- this.mousedownPos = {
- x: 0,
- y: 0
- }
- // 鼠标按下时,滚动条位置
- this.mousedownScrollbarPos = 0
- }
-
- // 绑定事件
- bindEvent() {
- this.onMousemove = this.onMousemove.bind(this)
- this.onMouseup = this.onMouseup.bind(this)
- this.updateScrollbar = this.updateScrollbar.bind(this)
- this.updateScrollbar = throttle(this.updateScrollbar, 16, this) // 加个节流
- this.mindMap.on('mousemove', this.onMousemove)
- this.mindMap.on('mouseup', this.onMouseup)
- this.mindMap.on('node_tree_render_end', this.updateScrollbar)
- this.mindMap.on('view_data_change', this.updateScrollbar)
- this.mindMap.on('resize', this.updateScrollbar)
- }
-
- // 解绑事件
- unBindEvent() {
- this.mindMap.off('mousemove', this.onMousemove)
- this.mindMap.off('mouseup', this.onMouseup)
- this.mindMap.off('node_tree_render_end', this.updateScrollbar)
- this.mindMap.off('view_data_change', this.updateScrollbar)
- this.mindMap.off('resize', this.updateScrollbar)
- }
-
- // 渲染后、数据改变需要更新滚动条
- updateScrollbar() {
- // 当前正在拖拽滚动条时不需要更新
- if (this.isMousedown) return
- const res = this.calculationScrollbar()
- this.emitEvent(res)
- }
-
- // 发送滚动条改变事件
- emitEvent(data) {
- this.mindMap.emit('scrollbar_change', data)
- }
-
- // 设置滚动条容器的大小,指滚动条容器的大小,对于水平滚动条,即宽度,对于垂直滚动条,即高度
- setScrollBarWrapSize(width, height) {
- this.scrollbarWrapSize.width = width
- this.scrollbarWrapSize.height = height
- }
-
- // 计算滚动条大小和位置
- calculationScrollbar() {
- const rect = this.mindMap.draw.rbox()
- // 减去画布距离浏览器窗口左上角的距离
- const elRect = this.mindMap.elRect
- rect.x -= elRect.left
- rect.y -= elRect.top
-
- // 垂直滚动条
- const canvasHeight = this.mindMap.height // 画布高度
- const paddingY = canvasHeight / 2 // 首尾允许超出的距离,默认为高度的一半
- const chartHeight = rect.height + paddingY * 2 // 思维导图高度
- this.chartHeight = chartHeight
- const chartTop = rect.y - paddingY // 思维导图顶部距画布顶部的距离
- const height = Math.min((canvasHeight / chartHeight) * 100, 100) // 滚动条高度 = 画布高度 / 思维导图高度
- let top = (-chartTop / chartHeight) * 100 // 滚动条距离 = 思维导图顶部距画布顶部的距离 / 思维导图高度
- // 判断是否到达边界
- if (top < 0) {
- top = 0
- }
- if (top > 100 - height) {
- top = 100 - height
- }
-
- // 水平滚动条
- const canvasWidth = this.mindMap.width
- const paddingX = canvasWidth / 2
- const chartWidth = rect.width + paddingX * 2
- this.chartWidth = chartWidth
- const chartLeft = rect.x - paddingX
- const width = Math.min((canvasWidth / chartWidth) * 100, 100)
- let left = (-chartLeft / chartWidth) * 100
- if (left < 0) {
- left = 0
- }
- if (left > 100 - width) {
- left = 100 - width
- }
-
- const res = {
- // 垂直滚动条
- vertical: {
- top,
- height
- },
- // 水平滚动条
- horizontal: {
- left,
- width
- }
- }
-
- return res
- }
-
- // 滚动条鼠标按下事件处理函数
- onMousedown(e, type) {
- e.preventDefault()
- e.stopPropagation()
- this.currentScrollType = type
- this.isMousedown = true
- this.mousedownPos = {
- x: e.clientX,
- y: e.clientY
- }
- // 保存滚动条当前的位置
- const styles = window.getComputedStyle(e.target)
- if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
- this.mousedownScrollbarPos = Number.parseFloat(styles.top)
- } else {
- this.mousedownScrollbarPos = Number.parseFloat(styles.left)
- }
- }
-
- // 鼠标移动事件处理函数
- onMousemove(e) {
- if (!this.isMousedown) {
- return
- }
- e.preventDefault()
- e.stopPropagation()
- if (this.currentScrollType === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
- const oy = e.clientY - this.mousedownPos.y + this.mousedownScrollbarPos
- this.updateMindMapView(CONSTANTS.SCROLL_BAR_DIR.VERTICAL, oy)
- } else {
- const ox = e.clientX - this.mousedownPos.x + this.mousedownScrollbarPos
- this.updateMindMapView(CONSTANTS.SCROLL_BAR_DIR.HORIZONTAL, ox)
- }
- }
-
- // 鼠标松开事件处理函数
- onMouseup() {
- this.isMousedown = false
- this.reset()
- }
-
- // 更新视图
- updateMindMapView(type, offset) {
- const scrollbarData = this.calculationScrollbar()
- const t = this.mindMap.draw.transform()
- const drawRect = this.mindMap.draw.rbox()
- const rootRect = this.mindMap.renderer.root.group.rbox()
- const rootCenterOffset = this.mindMap.renderer.layout.getRootCenterOffset(
- rootRect.width,
- rootRect.height
- )
- if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
- // 滚动条新位置
- let oy = offset
- // 判断是否达到首尾
- if (oy <= 0) {
- oy = 0
- }
- const max =
- ((100 - scrollbarData.vertical.height) / 100) *
- this.scrollbarWrapSize.height
- if (oy >= max) {
- oy = max
- }
- // 转换成百分比
- const oyPercentage = (oy / this.scrollbarWrapSize.height) * 100
- // 转换成相对于图形高度的距离
- const oyPx = (-oyPercentage / 100) * this.chartHeight
- // 节点中心点到图形最上方的距离
- const yOffset = rootRect.y - drawRect.y
- // 内边距
- const paddingY = this.mindMap.height / 2
- // 图形新位置
- const chartTop =
- oyPx +
- yOffset -
- paddingY * t.scaleY +
- paddingY -
- rootCenterOffset.y * t.scaleY +
- ((this.mindMap.height - this.mindMap.initHeight) / 2) * t.scaleY // 画布宽高改变了,但是思维导图元素变换的中心点依旧是原有位置,所以需要加上中心点变化量
- this.mindMap.view.translateYTo(chartTop)
- this.emitEvent({
- horizontal: scrollbarData.horizontal,
- vertical: {
- top: oyPercentage,
- height: scrollbarData.vertical.height
- }
- })
- } else {
- // 滚动条新位置
- let ox = offset
- // 判断是否达到首尾
- if (ox <= 0) {
- ox = 0
- }
- const max =
- ((100 - scrollbarData.horizontal.width) / 100) *
- this.scrollbarWrapSize.width
- if (ox >= max) {
- ox = max
- }
- // 转换成百分比
- const oxPercentage = (ox / this.scrollbarWrapSize.width) * 100
- // 转换成相对于图形宽度的距离
- const oxPx = (-oxPercentage / 100) * this.chartWidth
- // 节点中心点到图形最左边的距离
- const xOffset = rootRect.x - drawRect.x
- // 内边距
- const paddingX = this.mindMap.width / 2
- // 图形新位置
- const chartLeft =
- oxPx +
- xOffset -
- paddingX * t.scaleX +
- paddingX -
- rootCenterOffset.x * t.scaleX +
- ((this.mindMap.width - this.mindMap.initWidth) / 2) * t.scaleX // 画布宽高改变了,但是思维导图元素变换的中心点依旧是原有位置,所以需要加上中心点变化量
- this.mindMap.view.translateXTo(chartLeft)
- this.emitEvent({
- vertical: scrollbarData.vertical,
- horizontal: {
- left: oxPercentage,
- width: scrollbarData.horizontal.width
- }
- })
- }
- }
-
- // 滚动条的点击事件
- onClick(e, type) {
- let offset = 0
- if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
- offset = e.clientY - e.currentTarget.getBoundingClientRect().top
- } else {
- offset = e.clientX - e.currentTarget.getBoundingClientRect().left
- }
- this.updateMindMapView(type, offset)
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Scrollbar.instanceName = 'scrollbar'
-
-export default Scrollbar
diff --git a/packages/mindmap/src/plugins/Search.js b/packages/mindmap/src/plugins/Search.js
deleted file mode 100644
index 47de8e9..0000000
--- a/packages/mindmap/src/plugins/Search.js
+++ /dev/null
@@ -1,321 +0,0 @@
-import {
- bfsWalk,
- getTextFromHtml,
- isUndef,
- replaceHtmlText,
- formatGetNodeGeneralization
-} from '../utils/index'
-import MindMapNode from '../core/render/node/MindMapNode'
-import { CONSTANTS } from '../constants/constant'
-
-// 搜索插件
-class Search {
- // 构造函数
- constructor({ mindMap }) {
- this.mindMap = mindMap
- // 是否正在搜索
- this.isSearching = false
- // 搜索文本
- this.searchText = ''
- // 匹配的节点列表
- this.matchNodeList = []
- // 当前所在的节点列表索引
- this.currentIndex = -1
- // 不要复位搜索文本
- this.notResetSearchText = false
- // 是否自动跳转下一个匹配节点
- this.isJumpNext = false
-
- this.bindEvent()
- }
-
- bindEvent() {
- this.onDataChange = this.onDataChange.bind(this)
- this.onModeChange = this.onModeChange.bind(this)
- this.mindMap.on('data_change', this.onDataChange)
- this.mindMap.on('mode_change', this.onModeChange)
- }
-
- unBindEvent() {
- this.mindMap.off('data_change', this.onDataChange)
- this.mindMap.off('mode_change', this.onModeChange)
- }
-
- // 节点数据改变了,需要重新搜索
- onDataChange() {
- if (this.isJumpNext) {
- this.isJumpNext = false
- this.search(this.searchText)
- return
- }
- if (this.notResetSearchText) {
- this.notResetSearchText = false
- return
- }
- this.searchText = ''
- }
-
- // 监听只读模式切换
- onModeChange(mode) {
- const isReadonly = mode === CONSTANTS.MODE.READONLY
- // 如果是由只读模式切换为非只读模式,需要清除只读模式下的节点高亮
- if (
- !isReadonly &&
- this.isSearching &&
- this.matchNodeList[this.currentIndex]
- ) {
- this.matchNodeList[this.currentIndex].closeHighlight()
- }
- }
-
- // 搜索
- search(text, callback = () => {}) {
- if (isUndef(text)) return this.endSearch()
- text = String(text)
- this.isSearching = true
- if (this.searchText === text) {
- // 和上一次搜索文本一样,那么搜索下一个
- this.searchNext(callback)
- } else {
- // 和上次搜索文本不一样,那么重新开始
- this.searchText = text
- this.doSearch()
- this.searchNext(callback)
- }
- this.emitEvent()
- }
-
- // 更新匹配节点列表
- updateMatchNodeList(list) {
- this.matchNodeList = list
- this.mindMap.emit('search_match_node_list_change', list)
- }
-
- // 结束搜索
- endSearch() {
- if (!this.isSearching) return
- if (this.mindMap.opt.readonly && this.matchNodeList[this.currentIndex]) {
- this.matchNodeList[this.currentIndex].closeHighlight()
- }
- this.searchText = ''
- this.updateMatchNodeList([])
- this.currentIndex = -1
- this.notResetSearchText = false
- this.isSearching = false
- this.emitEvent()
- }
-
- // 搜索匹配的节点
- doSearch() {
- this.clearHighlightOnReadonly()
- this.updateMatchNodeList([])
- this.currentIndex = -1
- const { isOnlySearchCurrentRenderNodes } = this.mindMap.opt
- // 如果要搜索收起来的节点,那么要遍历渲染树而不是节点树
- const tree = isOnlySearchCurrentRenderNodes
- ? this.mindMap.renderer.root
- : this.mindMap.renderer.renderTree
- if (!tree) return
- const matchList = []
- bfsWalk(tree, node => {
- let { richText, text, generalization } = isOnlySearchCurrentRenderNodes
- ? node.getData()
- : node.data
- if (richText) {
- text = getTextFromHtml(text)
- }
- if (text.includes(this.searchText)) {
- matchList.push(node)
- }
- // 概要节点
- const generalizationList = formatGetNodeGeneralization({
- generalization
- })
- generalizationList.forEach(gNode => {
- let { richText, text, uid } = gNode
- if (
- isOnlySearchCurrentRenderNodes &&
- !this.mindMap.renderer.findNodeByUid(uid)
- ) {
- return
- }
- if (richText) {
- text = getTextFromHtml(text)
- }
- if (text.includes(this.searchText)) {
- matchList.push({
- data: gNode
- })
- }
- })
- })
- this.updateMatchNodeList(matchList)
- }
-
- // 判断对象是否是节点实例
- isNodeInstance(node) {
- return node instanceof MindMapNode
- }
-
- // 搜索下一个或指定索引,定位到下一个匹配节点
- searchNext(callback, index) {
- if (!this.isSearching || this.matchNodeList.length <= 0) return
- if (
- index !== undefined &&
- Number.isInteger(index) &&
- index >= 0 &&
- index < this.matchNodeList.length
- ) {
- this.currentIndex = index
- } else {
- if (this.currentIndex < this.matchNodeList.length - 1) {
- this.currentIndex++
- } else {
- this.currentIndex = 0
- }
- }
- const { readonly } = this.mindMap.opt
- // 只读模式下需要清除之前节点的高亮
- this.clearHighlightOnReadonly()
- const currentNode = this.matchNodeList[this.currentIndex]
- this.notResetSearchText = true
- const uid = this.isNodeInstance(currentNode)
- ? currentNode.getData('uid')
- : currentNode.data.uid
- const targetNode = this.mindMap.renderer.findNodeByUid(uid)
- this.mindMap.execCommand('GO_TARGET_NODE', uid, node => {
- if (!this.isNodeInstance(currentNode)) {
- this.matchNodeList[this.currentIndex] = node
- this.updateMatchNodeList(this.matchNodeList)
- }
- callback()
- // 只读模式下节点无法激活,所以通过高亮的方式
- if (readonly) {
- node.highlight()
- }
- // 如果当前节点实例已经存在,则不会触发data_change事件,那么需要手动把标志复位
- if (targetNode) {
- this.notResetSearchText = false
- }
- })
- }
-
- // 只读模式下清除现有匹配节点的高亮
- clearHighlightOnReadonly() {
- const { readonly } = this.mindMap.opt
- if (readonly) {
- this.matchNodeList.forEach(node => {
- if (this.isNodeInstance(node)) {
- node.closeHighlight()
- }
- })
- }
- }
-
- // 定位到指定搜索结果索引的节点
- jump(index, callback = () => {}) {
- this.searchNext(callback, index)
- }
-
- // 替换当前节点
- replace(replaceText, jumpNext = false) {
- if (
- replaceText === null ||
- replaceText === undefined ||
- !this.isSearching ||
- this.matchNodeList.length <= 0
- )
- return
- // 自动跳转下一个匹配节点
- this.isJumpNext = jumpNext
- replaceText = String(replaceText)
- let currentNode = this.matchNodeList[this.currentIndex]
- if (!currentNode) return
- // 如果当前搜索文本是替换文本的子串,那么该节点还是符合搜索结果的
- const keep = replaceText.includes(this.searchText)
- const text = this.getReplacedText(currentNode, this.searchText, replaceText)
- this.notResetSearchText = true
- currentNode.setText(text, currentNode.getData('richText'))
- if (keep) {
- this.updateMatchNodeList(this.matchNodeList)
- return
- }
- const newList = this.matchNodeList.filter(node => {
- return currentNode !== node
- })
- this.updateMatchNodeList(newList)
- if (this.currentIndex > this.matchNodeList.length - 1) {
- this.currentIndex = -1
- } else {
- this.currentIndex--
- }
- this.emitEvent()
- }
-
- // 替换所有
- replaceAll(replaceText) {
- if (
- replaceText === null ||
- replaceText === undefined ||
- !this.isSearching ||
- this.matchNodeList.length <= 0
- )
- return
- replaceText = String(replaceText)
- // 如果当前搜索文本是替换文本的子串,那么该节点还是符合搜索结果的
- const keep = replaceText.includes(this.searchText)
- this.notResetSearchText = true
- this.matchNodeList.forEach(node => {
- const text = this.getReplacedText(node, this.searchText, replaceText)
- if (this.isNodeInstance(node)) {
- const data = {
- text
- }
- this.mindMap.renderer.setNodeDataRender(node, data, true)
- } else {
- node.data.text = text
- }
- })
- this.mindMap.render()
- this.mindMap.command.addHistory()
- if (keep) {
- this.updateMatchNodeList(this.matchNodeList)
- } else {
- this.endSearch()
- }
- }
-
- // 获取某个节点替换后的文本
- getReplacedText(node, searchText, replaceText) {
- let { richText, text } = this.isNodeInstance(node)
- ? node.getData()
- : node.data
- if (richText) {
- return replaceHtmlText(text, searchText, replaceText)
- } else {
- return text.replaceAll(searchText, replaceText)
- }
- }
-
- // 发送事件
- emitEvent() {
- this.mindMap.emit('search_info_change', {
- currentIndex: this.currentIndex,
- total: this.matchNodeList.length
- })
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Search.instanceName = 'search'
-
-export default Search
diff --git a/packages/mindmap/src/plugins/Select.js b/packages/mindmap/src/plugins/Select.js
deleted file mode 100644
index eaf93f9..0000000
--- a/packages/mindmap/src/plugins/Select.js
+++ /dev/null
@@ -1,239 +0,0 @@
-import { bfsWalk, throttle, checkTwoRectIsOverlap } from '../utils'
-import AutoMove from '../utils/AutoMove'
-
-// 节点选择插件
-class Select {
- // 构造函数
- constructor({ mindMap }) {
- this.mindMap = mindMap
- this.rect = null
- this.isMousedown = false
- this.mouseDownX = 0
- this.mouseDownY = 0
- this.mouseMoveX = 0
- this.mouseMoveY = 0
- this.isSelecting = false
- this.cacheActiveList = []
- this.autoMove = new AutoMove(mindMap)
- this.bindEvent()
- }
-
- // 绑定事件
- bindEvent() {
- this.onMousedown = this.onMousedown.bind(this)
- this.onMousemove = this.onMousemove.bind(this)
- this.onMouseup = this.onMouseup.bind(this)
- this.checkInNodes = throttle(this.checkInNodes, 300, this)
-
- this.mindMap.on('mousedown', this.onMousedown)
- this.mindMap.on('mousemove', this.onMousemove)
- this.mindMap.on('mouseup', this.onMouseup)
- this.mindMap.on('node_mouseup', this.onMouseup)
- }
-
- // 解绑事件
- unBindEvent() {
- this.mindMap.off('mousedown', this.onMousedown)
- this.mindMap.off('mousemove', this.onMousemove)
- this.mindMap.off('mouseup', this.onMouseup)
- this.mindMap.off('node_mouseup', this.onMouseup)
- }
-
- // 鼠标按下
- onMousedown(e) {
- const { readonly, mousedownEventPreventDefault } = this.mindMap.opt
- if (readonly) {
- return
- }
- let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
- if (
- !(e.ctrlKey || e.metaKey) &&
- (useLeftKeySelectionRightKeyDrag ? e.which !== 1 : e.which !== 3)
- ) {
- return
- }
- if (mousedownEventPreventDefault) {
- e.preventDefault()
- }
- this.isMousedown = true
- this.cacheActiveList = [...this.mindMap.renderer.activeNodeList]
- let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
- this.mouseDownX = x
- this.mouseDownY = y
- this.createRect(x, y)
- }
-
- // 鼠标移动
- onMousemove(e) {
- if (this.mindMap.opt.readonly) {
- return
- }
- if (!this.isMousedown) {
- return
- }
- let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
- this.mouseMoveX = x
- this.mouseMoveY = y
- if (
- Math.abs(x - this.mouseDownX) <= 10 &&
- Math.abs(y - this.mouseDownY) <= 10
- ) {
- return
- }
- this.autoMove.clearAutoMoveTimer()
- this.autoMove.onMove(
- e.clientX,
- e.clientY,
- () => {
- this.isSelecting = true
- // 绘制矩形
- if (this.rect) {
- this.rect.plot([
- [this.mouseDownX, this.mouseDownY],
- [this.mouseMoveX, this.mouseDownY],
- [this.mouseMoveX, this.mouseMoveY],
- [this.mouseDownX, this.mouseMoveY]
- ])
- }
- this.checkInNodes()
- },
- (dir, step) => {
- switch (dir) {
- case 'left':
- this.mouseDownX += step
- break
- case 'top':
- this.mouseDownY += step
- break
- case 'right':
- this.mouseDownX -= step
- break
- case 'bottom':
- this.mouseDownY -= step
- break
- default:
- break
- }
- }
- )
- }
-
- // 结束框选
- onMouseup() {
- if (this.mindMap.opt.readonly) {
- return
- }
- if (!this.isMousedown) {
- return
- }
- this.checkTriggerNodeActiveEvent()
- this.autoMove.clearAutoMoveTimer()
- this.isMousedown = false
- this.cacheActiveList = []
- if (this.rect) this.rect.remove()
- this.rect = null
- setTimeout(() => {
- this.isSelecting = false
- }, 0)
- }
-
- // 如果激活节点改变了,那么触发事件
- checkTriggerNodeActiveEvent() {
- let isNumChange =
- this.cacheActiveList.length !==
- this.mindMap.renderer.activeNodeList.length
- let isNodeChange = false
- if (!isNumChange) {
- for (let i = 0; i < this.cacheActiveList.length; i++) {
- let cur = this.cacheActiveList[i]
- if (
- !this.mindMap.renderer.activeNodeList.find(item => {
- return item.getData('uid') === cur.getData('uid')
- })
- ) {
- isNodeChange = true
- break
- }
- }
- }
- if (isNumChange || isNodeChange) {
- this.mindMap.renderer.emitNodeActiveEvent()
- }
- }
-
- // 创建矩形
- createRect(x, y) {
- if (this.rect) this.rect.remove()
- this.rect = this.mindMap.svg
- .polygon()
- .stroke({
- color: '#0984e3'
- })
- .fill({
- color: 'rgba(9,132,227,0.3)'
- })
- .plot([[x, y]])
- }
-
- // 检测在选区里的节点
- checkInNodes() {
- let { scaleX, scaleY, translateX, translateY } =
- this.mindMap.draw.transform()
- let minx = Math.min(this.mouseDownX, this.mouseMoveX)
- let miny = Math.min(this.mouseDownY, this.mouseMoveY)
- let maxx = Math.max(this.mouseDownX, this.mouseMoveX)
- let maxy = Math.max(this.mouseDownY, this.mouseMoveY)
-
- const check = node => {
- let { left, top, width, height } = node
- let right = (left + width) * scaleX + translateX
- let bottom = (top + height) * scaleY + translateY
- left = left * scaleX + translateX
- top = top * scaleY + translateY
- if (
- checkTwoRectIsOverlap(minx, maxx, miny, maxy, left, right, top, bottom)
- ) {
- if (node.getData('isActive')) {
- return
- }
- this.mindMap.renderer.addNodeToActiveList(node)
- this.mindMap.renderer.emitNodeActiveEvent()
- } else if (node.getData('isActive')) {
- if (!node.getData('isActive')) {
- return
- }
- this.mindMap.renderer.removeNodeFromActiveList(node)
- this.mindMap.renderer.emitNodeActiveEvent()
- }
- }
-
- bfsWalk(this.mindMap.renderer.root, node => {
- check(node)
- // 概要节点
- if (node._generalizationList && node._generalizationList.length > 0) {
- node._generalizationList.forEach(item => {
- check(item.generalizationNode)
- })
- }
- })
- }
-
- // 是否存在选区
- hasSelectRange() {
- return this.isSelecting
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-Select.instanceName = 'select'
-
-export default Select
diff --git a/packages/mindmap/src/plugins/TouchEvent.js b/packages/mindmap/src/plugins/TouchEvent.js
deleted file mode 100644
index d13569c..0000000
--- a/packages/mindmap/src/plugins/TouchEvent.js
+++ /dev/null
@@ -1,193 +0,0 @@
-import { getTwoPointDistance } from '../utils'
-
-// 手势事件支持插件
-class TouchEvent {
- // 构造函数
- constructor({ mindMap }) {
- this.mindMap = mindMap
- this.touchesNum = 0
- this.singleTouchstartEvent = null
- this.clickNum = 0
- this.touchStartScaleView = null
- this.lastTouchStartPosition = null
- this.lastTouchStartDistance = 0
- this.bindEvent()
- }
-
- // 绑定事件
- bindEvent() {
- this.onTouchstart = this.onTouchstart.bind(this)
- this.onTouchmove = this.onTouchmove.bind(this)
- this.onTouchcancel = this.onTouchcancel.bind(this)
- this.onTouchend = this.onTouchend.bind(this)
- window.addEventListener('touchstart', this.onTouchstart, { passive: false })
- window.addEventListener('touchmove', this.onTouchmove, { passive: false })
- window.addEventListener('touchcancel', this.onTouchcancel, {
- passive: false
- })
- window.addEventListener('touchend', this.onTouchend, { passive: false })
- }
-
- // 解绑事件
- unBindEvent() {
- window.removeEventListener('touchstart', this.onTouchstart)
- window.removeEventListener('touchmove', this.onTouchmove)
- window.removeEventListener('touchcancel', this.onTouchcancel)
- window.removeEventListener('touchend', this.onTouchend)
- }
-
- // 手指按下事件
- onTouchstart(e) {
- this.touchesNum = e.touches.length
- this.touchStartScaleView = null
- if (this.touchesNum === 1) {
- let touch = e.touches[0]
- if (this.lastTouchStartPosition) {
- this.lastTouchStartDistance = getTwoPointDistance(
- this.lastTouchStartPosition.x,
- this.lastTouchStartPosition.y,
- touch.clientX,
- touch.clientY
- )
- }
- this.lastTouchStartPosition = {
- x: touch.clientX,
- y: touch.clientY
- }
- this.singleTouchstartEvent = touch
- this.dispatchMouseEvent('mousedown', touch.target, touch)
- }
- }
-
- // 手指移动事件
- onTouchmove(e) {
- let len = e.touches.length
- if (len === 1) {
- let touch = e.touches[0]
- this.dispatchMouseEvent('mousemove', touch.target, touch)
- } else if (len === 2) {
- let { disableTouchZoom, minTouchZoomScale, maxTouchZoomScale } =
- this.mindMap.opt
- if (disableTouchZoom) return
- minTouchZoomScale =
- minTouchZoomScale === -1 ? -Infinity : minTouchZoomScale / 100
- maxTouchZoomScale =
- maxTouchZoomScale === -1 ? Infinity : maxTouchZoomScale / 100
- let touch1 = e.touches[0]
- let touch2 = e.touches[1]
- let ox = touch1.clientX - touch2.clientX
- let oy = touch1.clientY - touch2.clientY
- let distance = Math.sqrt(Math.pow(ox, 2) + Math.pow(oy, 2))
- // 以两指中心点进行缩放
- let { x: touch1ClientX, y: touch1ClientY } = this.mindMap.toPos(
- touch1.clientX,
- touch1.clientY
- )
- let { x: touch2ClientX, y: touch2ClientY } = this.mindMap.toPos(
- touch2.clientX,
- touch2.clientY
- )
- let cx = (touch1ClientX + touch2ClientX) / 2
- let cy = (touch1ClientY + touch2ClientY) / 2
- // 手势缩放,基于最开始的位置进行缩放(基于前一个位置缩放不是线性关系); 缩放同时支持位置拖动
- const view = this.mindMap.view
- if (!this.touchStartScaleView) {
- this.touchStartScaleView = {
- distance: distance,
- scale: view.scale,
- x: view.x,
- y: view.y,
- cx: cx,
- cy: cy
- }
- return
- }
- const viewBefore = this.touchStartScaleView
- let scale = viewBefore.scale * (distance / viewBefore.distance)
- if (Math.abs(distance - viewBefore.distance) <= 10) {
- scale = viewBefore.scale
- }
- scale =
- scale < minTouchZoomScale
- ? minTouchZoomScale
- : scale > maxTouchZoomScale
- ? maxTouchZoomScale
- : scale
- const ratio = 1 - scale / viewBefore.scale
- view.scale = scale
- view.x =
- viewBefore.x +
- (cx - viewBefore.x) * ratio +
- (cx - viewBefore.cx) * scale
- view.y =
- viewBefore.y +
- (cy - viewBefore.y) * ratio +
- (cy - viewBefore.cy) * scale
- view.transform()
- this.mindMap.emit('scale', scale)
- }
- }
-
- // 手指取消事件
- onTouchcancel(e) {}
-
- // 手指松开事件
- onTouchend(e) {
- this.dispatchMouseEvent('mouseup', e.target)
- if (this.touchesNum === 1) {
- // 模拟双击事件
- this.clickNum++
- setTimeout(() => {
- this.clickNum = 0
- this.lastTouchStartPosition = null
- this.lastTouchStartDistance = 0
- }, 300)
- let ev = this.singleTouchstartEvent
- if (this.clickNum > 1 && this.lastTouchStartDistance <= 5) {
- this.clickNum = 0
- this.dispatchMouseEvent('dblclick', ev.target, ev)
- } else {
- // 点击事件应该不用模拟
- // this.dispatchMouseEvent('click', ev.target, ev)
- }
- }
- this.touchesNum = 0
- this.singleTouchstartEvent = null
- this.touchStartScaleView = null
- }
-
- // 发送鼠标事件
- dispatchMouseEvent(eventName, target, e) {
- let opt = {}
- if (e) {
- opt = {
- screenX: e.screenX,
- screenY: e.screenY,
- clientX: e.clientX,
- clientY: e.clientY,
- which: 1
- }
- }
- let event = new MouseEvent(eventName, {
- view: document.defaultView,
- bubbles: true,
- cancelable: true,
- ...opt
- })
- target.dispatchEvent(event)
- }
-
- // 插件被移除前做的事情
- beforePluginRemove() {
- this.unBindEvent()
- }
-
- // 插件被卸载前做的事情
- beforePluginDestroy() {
- this.unBindEvent()
- }
-}
-
-TouchEvent.instanceName = 'touchEvent'
-
-export default TouchEvent
diff --git a/packages/mindmap/src/plugins/Watermark.ts b/packages/mindmap/src/plugins/Watermark.ts
deleted file mode 100644
index 1bfd04f..0000000
--- a/packages/mindmap/src/plugins/Watermark.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-import { Text, G } from '@svgdotjs/svg.js'
-import { degToRad, camelCaseToHyphen } from '../utils'
-import merge from 'deepmerge'
-import MindMap from '..'
-
-interface WatermarkOptions {
- mindMap: MindMap
-}
-
-interface WatermarkConfig {
- text?: string | number
- lineSpacing?: number
- textSpacing?: number
- angle?: number
- textStyle?: Record
- belowNode?: boolean
- onlyExport?: boolean
-}
-
-interface TextStyle {
- [key: string]: any
-}
-
-// 水印插件
-class Watermark {
- static instanceName: string = 'watermark'
-
- private mindMap: any
- private lineSpacing: number
- private textSpacing: number
- private angle: number
- private text: string
- private textStyle: TextStyle
- private watermarkDraw: G | null
- private isInExport: boolean
- private maxLong: number
-
- constructor(opt: WatermarkOptions = {} as WatermarkOptions) {
- this.mindMap = opt.mindMap
- this.lineSpacing = 0
- this.textSpacing = 0
- this.angle = 0
- this.text = ''
- this.textStyle = {}
- this.watermarkDraw = null
- this.isInExport = false
- this.maxLong = this.getMaxLong()
- this.updateWatermark(this.mindMap.opt.watermarkConfig || {})
- this.bindEvent()
- }
-
- private getMaxLong(): number {
- return Math.sqrt(
- Math.pow(this.mindMap.width, 2) + Math.pow(this.mindMap.height, 2)
- )
- }
-
- private bindEvent(): void {
- this.onResize = this.onResize.bind(this)
- this.mindMap.on('resize', this.onResize)
- }
-
- private unBindEvent(): void {
- this.mindMap.off('resize', this.onResize)
- }
-
- private onResize(): void {
- this.maxLong = this.getMaxLong()
- this.draw()
- }
-
- private createContainer(): void {
- if (this.watermarkDraw) return
- this.watermarkDraw = new G()
- .css({
- pointerEvents: 'none',
- userSelect: 'none'
- })
- .addClass('smm-water-mark-container')
- this.updateLayer()
- }
- private updateLayer(): void {
- if (!this.watermarkDraw) return
- const { belowNode } = this.mindMap.opt.watermarkConfig
- if (belowNode) {
- this.watermarkDraw.insertBefore(this.mindMap.draw)
- } else {
- this.mindMap.svg.add(this.watermarkDraw)
- }
- }
-
- private removeContainer(): void {
- if (!this.watermarkDraw) {
- return
- }
- this.watermarkDraw.remove()
- this.watermarkDraw = null
- }
-
- private hasWatermark(): boolean {
- return !!this.text.trim()
- }
-
- private handleConfig({ text, lineSpacing, textSpacing, angle, textStyle }: WatermarkConfig): void {
- this.text = text === undefined ? '' : String(text).trim()
- this.lineSpacing =
- typeof lineSpacing === 'number' && lineSpacing > 0 ? lineSpacing : 100
- this.textSpacing =
- typeof textSpacing === 'number' && textSpacing > 0 ? textSpacing : 100
- this.angle =
- typeof angle === 'number' && angle >= 0 && angle <= 90 ? angle : 30
- this.textStyle = Object.assign(this.textStyle, textStyle || {})
- }
-
- private clear(): void {
- if (this.watermarkDraw) this.watermarkDraw.clear()
- }
-
- private draw(): void {
- this.clear()
- const { onlyExport } = this.mindMap.opt.watermarkConfig
- if (onlyExport && !this.isInExport) return
- if (!this.hasWatermark()) {
- this.removeContainer()
- return
- }
- this.createContainer()
- let x = 0
- while (x < this.mindMap.width) {
- this.drawText(x)
- x += this.lineSpacing / Math.sin(degToRad(this.angle))
- }
-
- let yOffset =
- this.lineSpacing / Math.cos(degToRad(this.angle)) || this.lineSpacing
- let y = yOffset
- while (y < this.mindMap.height) {
- this.drawText(0, y)
- y += yOffset
- }
- }
-
- private drawText(x: number, y?: number): void {
- let long = Math.min(
- this.maxLong,
- (this.mindMap.width - x) / Math.cos(degToRad(this.angle))
- )
- let g = new G()
- let bbox = null
- let bboxWidth = 0
- let textHeight = -1
- while (bboxWidth < long) {
- let text = new Text().text(this.text)
- g.add(text)
- text.transform({
- translateX: bboxWidth
- })
- this.setTextStyle(text)
- bbox = g.bbox()
- if (textHeight === -1) {
- textHeight = bbox.height
- }
- bboxWidth = bbox.width + this.textSpacing
- }
- let params = {
- rotate: this.angle,
- origin: 'top left',
- translateX: x,
- translateY: textHeight
- }
- if (y !== undefined) {
- params.translateY = y + textHeight
- }
- g.transform(params)
- this.watermarkDraw?.add(g)
- }
-
- private setTextStyle(text: Text): void {
- Object.keys(this.textStyle).forEach(item => {
- let value = this.textStyle[item]
- if (item === 'color') {
- text.fill(value)
- } else {
- text.css(camelCaseToHyphen(item) as CSSStyleName, value)
- }
- })
- }
-
- public updateWatermark(config: WatermarkConfig): void {
- this.mindMap.opt.watermarkConfig = merge(
- this.mindMap.opt.watermarkConfig,
- config
- )
- this.updateLayer()
- this.handleConfig(config)
- this.draw()
- }
-
- public beforePluginRemove(): void {
- this.unBindEvent()
- this.removeContainer()
- }
-
- public beforePluginDestroy(): void {
- this.unBindEvent()
- this.removeContainer()
- }
-}
-
-export default Watermark
\ No newline at end of file
diff --git a/packages/mindmap/src/plugins/associativeLine/associativeLineControls.js b/packages/mindmap/src/plugins/associativeLine/associativeLineControls.js
deleted file mode 100644
index bd380f7..0000000
--- a/packages/mindmap/src/plugins/associativeLine/associativeLineControls.js
+++ /dev/null
@@ -1,294 +0,0 @@
-import {
- getAssociativeLineTargetIndex,
- joinCubicBezierPath,
- getNodePoint,
- getDefaultControlPointOffsets
-} from './associativeLineUtils'
-
-// 创建控制点、连线节点
-function createControlNodes(node, toNode) {
- let { associativeLineActiveColor } = this.getStyleConfig(node, toNode)
- // 连线
- this.controlLine1 = this.associativeLineDraw
- .line()
- .stroke({ color: associativeLineActiveColor, width: 2 })
- this.controlLine2 = this.associativeLineDraw
- .line()
- .stroke({ color: associativeLineActiveColor, width: 2 })
- // 控制点
- this.controlPoint1 = this.createOneControlNode('controlPoint1', node, toNode)
- this.controlPoint2 = this.createOneControlNode('controlPoint2', node, toNode)
-}
-
-// 创建控制点
-function createOneControlNode(pointKey, node, toNode) {
- let { associativeLineActiveColor } = this.getStyleConfig(node, toNode)
- return this.associativeLineDraw
- .circle(this.controlPointDiameter)
- .stroke({ color: associativeLineActiveColor })
- .fill({ color: '#fff' })
- .click(e => {
- e.stopPropagation()
- })
- .mousedown(e => {
- this.onControlPointMousedown(e, pointKey)
- })
-}
-
-// 控制点的鼠标按下事件
-function onControlPointMousedown(e, pointKey) {
- e.stopPropagation()
- e.preventDefault()
- this.isControlPointMousedown = true
- this.mousedownControlPointKey = pointKey
-}
-
-// 控制点的鼠标移动事件
-function onControlPointMousemove(e) {
- if (
- !this.isControlPointMousedown ||
- !this.mousedownControlPointKey ||
- !this[this.mousedownControlPointKey]
- )
- return
- e.stopPropagation()
- e.preventDefault()
- let radius = this.controlPointDiameter / 2
- // 转换鼠标当前的位置
- let { x, y } = this.getTransformedEventPos(e)
- this.controlPointMousemoveState.pos = {
- x,
- y
- }
- // 更新当前拖拽的控制点的位置
- this[this.mousedownControlPointKey].x(x - radius).y(y - radius)
- let [, , , node, toNode] = this.activeLine
- let targetIndex = getAssociativeLineTargetIndex(node, toNode)
- let { associativeLinePoint, associativeLineTargetControlOffsets } =
- node.getData()
- associativeLinePoint = associativeLinePoint || []
- const nodePos = this.getNodePos(node)
- const toNodePos = this.getNodePos(toNode)
- let [startPoint, endPoint] = this.updateAllLinesPos(
- node,
- toNode,
- associativeLinePoint[targetIndex]
- )
- this.controlPointMousemoveState.startPoint = startPoint
- this.controlPointMousemoveState.endPoint = endPoint
- this.controlPointMousemoveState.targetIndex = targetIndex
- let offsets = []
- if (!associativeLineTargetControlOffsets) {
- // 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
- offsets = getDefaultControlPointOffsets(startPoint, endPoint)
- } else {
- offsets = associativeLineTargetControlOffsets[targetIndex]
- }
- let point1 = null
- let point2 = null
- const { x: clientX, y: clientY } = this.mindMap.toPos(e.clientX, e.clientY)
- const _e = {
- clientX,
- clientY
- }
- // 拖拽的是控制点1
- if (this.mousedownControlPointKey === 'controlPoint1') {
- startPoint = getNodePoint(nodePos, '', 0, _e)
- point1 = {
- x,
- y
- }
- point2 = {
- x: endPoint.x + offsets[1].x,
- y: endPoint.y + offsets[1].y
- }
- if (startPoint) {
- // 保存更新后的坐标
- this.controlPointMousemoveState.startPoint = startPoint
- // 更新控制点1的连线
- this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
- }
- } else {
- // 拖拽的是控制点2
- endPoint = getNodePoint(toNodePos, '', 0, _e)
- point1 = {
- x: startPoint.x + offsets[0].x,
- y: startPoint.y + offsets[0].y
- }
- point2 = {
- x,
- y
- }
- if (endPoint) {
- // 保存更新后结束节点的坐标
- this.controlPointMousemoveState.endPoint = endPoint
- // 更新控制点2的连线
- this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
- }
- }
- this.updataAassociativeLine(
- startPoint,
- endPoint,
- point1,
- point2,
- this.activeLine
- )
-}
-
-function updataAassociativeLine(
- startPoint,
- endPoint,
- point1,
- point2,
- activeLine
-) {
- const [path, clickPath, text] = activeLine
- // 更新关联线
- const pathStr = joinCubicBezierPath(startPoint, endPoint, point1, point2)
- path.plot(pathStr)
- clickPath.plot(pathStr)
- this.updateTextPos(path, text)
- this.updateTextEditBoxPos(text)
-}
-
-// 控制点的鼠标松开事件
-function onControlPointMouseup(e) {
- if (!this.isControlPointMousedown) return
- e.stopPropagation()
- e.preventDefault()
- let { pos, startPoint, endPoint, targetIndex } =
- this.controlPointMousemoveState
- let [, , , node] = this.activeLine
- let offsetList = []
- let { associativeLinePoint, associativeLineTargetControlOffsets } =
- node.getData()
- if (!associativeLinePoint) {
- associativeLinePoint = []
- }
- associativeLinePoint[targetIndex] = associativeLinePoint[targetIndex] || {
- startPoint,
- endPoint
- }
- if (!associativeLineTargetControlOffsets) {
- // 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
- offsetList[targetIndex] = getDefaultControlPointOffsets(
- startPoint,
- endPoint
- )
- } else {
- offsetList = associativeLineTargetControlOffsets
- }
- let offset1 = null
- let offset2 = null
- if (this.mousedownControlPointKey === 'controlPoint1') {
- // 更新控制点1数据
- offset1 = {
- x: pos.x - startPoint.x,
- y: pos.y - startPoint.y
- }
- offset2 = offsetList[targetIndex][1]
- associativeLinePoint[targetIndex].startPoint = startPoint
- } else {
- // 更新控制点2数据
- offset1 = offsetList[targetIndex][0]
- offset2 = {
- x: pos.x - endPoint.x,
- y: pos.y - endPoint.y
- }
- associativeLinePoint[targetIndex].endPoint = endPoint
- }
- offsetList[targetIndex] = [offset1, offset2]
- this.mindMap.execCommand('SET_NODE_DATA', node, {
- associativeLineTargetControlOffsets: offsetList,
- associativeLinePoint
- })
- this.isNotRenderAllLines = true
- // 这里要加个setTimeout0是因为draw_click事件比mouseup事件触发的晚,所以重置isControlPointMousedown需要等draw_click事件触发完以后
- setTimeout(() => {
- this.resetControlPoint()
- }, 0)
-}
-
-// 复位控制点移动
-function resetControlPoint() {
- this.isControlPointMousedown = false
- this.mousedownControlPointKey = ''
- this.controlPointMousemoveState = {
- pos: null,
- startPoint: null,
- endPoint: null,
- targetIndex: ''
- }
-}
-
-// 渲染控制点
-function renderControls(startPoint, endPoint, point1, point2, node, toNode) {
- if (!this.mindMap.opt.enableAdjustAssociativeLinePoints) return
- if (!this.controlLine1) {
- this.createControlNodes(node, toNode)
- }
- let radius = this.controlPointDiameter / 2
- // 控制点和起终点的连线
- this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
- this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
- // 控制点
- this.controlPoint1.x(point1.x - radius).y(point1.y - radius)
- this.controlPoint2.x(point2.x - radius).y(point2.y - radius)
-}
-
-// 删除控制点
-function removeControls() {
- if (!this.controlLine1) return
- ;[
- this.controlLine1,
- this.controlLine2,
- this.controlPoint1,
- this.controlPoint2
- ].forEach(item => {
- item.remove()
- })
- this.controlLine1 = null
- this.controlLine2 = null
- this.controlPoint1 = null
- this.controlPoint2 = null
-}
-
-// 隐藏控制点
-function hideControls() {
- if (!this.controlLine1) return
- ;[
- this.controlLine1,
- this.controlLine2,
- this.controlPoint1,
- this.controlPoint2
- ].forEach(item => {
- item.hide()
- })
-}
-
-// 显示控制点
-function showControls() {
- if (!this.controlLine1) return
- ;[
- this.controlLine1,
- this.controlLine2,
- this.controlPoint1,
- this.controlPoint2
- ].forEach(item => {
- item.show()
- })
-}
-
-export default {
- createControlNodes,
- createOneControlNode,
- onControlPointMousedown,
- onControlPointMousemove,
- onControlPointMouseup,
- resetControlPoint,
- renderControls,
- removeControls,
- hideControls,
- showControls,
- updataAassociativeLine
-}
diff --git a/packages/mindmap/src/plugins/associativeLine/associativeLineText.js b/packages/mindmap/src/plugins/associativeLine/associativeLineText.js
deleted file mode 100644
index a2147d1..0000000
--- a/packages/mindmap/src/plugins/associativeLine/associativeLineText.js
+++ /dev/null
@@ -1,200 +0,0 @@
-import { Text } from '@svgdotjs/svg.js'
-import {
- getStrWithBrFromHtml,
- focusInput,
- selectAllInput
-} from '../../utils/index'
-
-// 创建文字节点
-function createText(data) {
- let g = this.associativeLineDraw.group()
- const setActive = () => {
- if (
- !this.activeLine ||
- this.activeLine[3] !== data.node ||
- this.activeLine[4] !== data.toNode
- ) {
- this.setActiveLine({
- ...data,
- text: g
- })
- }
- }
- g.click(e => {
- e.stopPropagation()
- setActive()
- })
- g.on('dblclick', e => {
- e.stopPropagation()
- setActive()
- if (!this.activeLine) return
- this.showEditTextBox(g)
- })
- return g
-}
-
-// 显示文本编辑框
-function showEditTextBox(g) {
- this.mindMap.emit('before_show_text_edit')
- // 注册回车快捷键
- this.mindMap.keyCommand.addShortcut('Enter', () => {
- this.hideEditTextBox()
- })
- // 输入框元素没有创建过,则先创建
- if (!this.textEditNode) {
- this.textEditNode = document.createElement('div')
- this.textEditNode.className = 'associative-line-text-edit-warp'
- this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
- this.textEditNode.setAttribute('contenteditable', true)
- this.textEditNode.addEventListener('keyup', e => {
- e.stopPropagation()
- })
- this.textEditNode.addEventListener('click', e => {
- e.stopPropagation()
- })
- const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
- targetNode.appendChild(this.textEditNode)
- }
- let [, , , node, toNode] = this.activeLine
- let {
- associativeLineTextFontSize,
- associativeLineTextFontFamily,
- associativeLineTextLineHeight
- } = this.getStyleConfig(node, toNode)
- let { defaultAssociativeLineText, nodeTextEditZIndex } = this.mindMap.opt
- let scale = this.mindMap.view.scale
- let text = this.getText(node, toNode)
- let textLines = (text || defaultAssociativeLineText).split(/\n/gim)
- this.textEditNode.style.fontFamily = associativeLineTextFontFamily
- this.textEditNode.style.fontSize = associativeLineTextFontSize * scale + 'px'
- this.textEditNode.style.lineHeight =
- textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
- this.textEditNode.style.zIndex = nodeTextEditZIndex
- this.textEditNode.innerHTML = textLines.join('
')
- this.textEditNode.style.display = 'block'
- this.updateTextEditBoxPos(g)
- this.showTextEdit = true
- // 如果是默认文本要全选输入框
- if (text === '' || text === defaultAssociativeLineText) {
- selectAllInput(this.textEditNode)
- } else {
- // 否则聚焦即可
- focusInput(this.textEditNode)
- }
-}
-
-// 删除文本编辑框元素
-function removeTextEditEl() {
- if (!this.textEditNode) return
- const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
- targetNode.removeChild(this.textEditNode)
-}
-
-// 处理画布缩放
-function onScale() {
- this.hideEditTextBox()
-}
-
-// 更新文本编辑框位置
-function updateTextEditBoxPos(g) {
- let rect = g.node.getBoundingClientRect()
- if (this.textEditNode) {
- this.textEditNode.style.minWidth = `${rect.width + 10}px`
- this.textEditNode.style.minHeight = `${rect.height + 6}px`
- this.textEditNode.style.left = `${rect.left}px`
- this.textEditNode.style.top = `${rect.top}px`
- }
-}
-
-// 隐藏文本编辑框
-function hideEditTextBox() {
- if (!this.showTextEdit) {
- return
- }
- let [path, , text, node, toNode] = this.activeLine
- let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
- // 如果是默认文本,那么不保存
- let isDefaultText = str === this.mindMap.opt.defaultAssociativeLineText
- str = isDefaultText ? '' : str
- this.mindMap.execCommand('SET_NODE_DATA', node, {
- associativeLineText: {
- ...(node.getData('associativeLineText') || {}),
- [toNode.getData('uid')]: str
- }
- })
- this.textEditNode.style.display = 'none'
- this.textEditNode.innerHTML = ''
- this.showTextEdit = false
- this.renderText(str, path, text, node, toNode)
- this.mindMap.emit('hide_text_edit')
-}
-
-// 获取某根关联线的文字
-function getText(node, toNode) {
- let obj = node.getData('associativeLineText')
- if (!obj) {
- return ''
- }
- return obj[toNode.getData('uid')] || ''
-}
-
-// 渲染关联线文字
-function renderText(str, path, text, node, toNode) {
- if (!str) return
- let { associativeLineTextFontSize, associativeLineTextLineHeight } =
- this.getStyleConfig(node, toNode)
- text.clear()
- let textArr = str.replace(/\n$/g, '').split(/\n/gim)
- textArr.forEach((item, index) => {
- // 避免尾部的空行不占宽度,导致文本编辑框定位异常的问题
- if (item === '') {
- item = ''
- }
- let textNode = new Text().text(item)
- textNode.y(
- associativeLineTextFontSize * associativeLineTextLineHeight * index
- )
- this.styleText(textNode, node, toNode)
- text.add(textNode)
- })
- updateTextPos(path, text)
-}
-
-// 给文本设置样式
-function styleText(textNode, node, toNode) {
- let {
- associativeLineTextColor,
- associativeLineTextFontSize,
- associativeLineTextFontFamily
- } = this.getStyleConfig(node, toNode)
- textNode
- .fill({
- color: associativeLineTextColor
- })
- .css({
- 'font-family': associativeLineTextFontFamily,
- 'font-size': associativeLineTextFontSize + 'px'
- })
-}
-
-// 更新关联线文字位置
-function updateTextPos(path, text) {
- let pathLength = path.length()
- let centerPoint = path.pointAt(pathLength / 2)
- let { width: textWidth, height: textHeight } = text.bbox()
- text.x(centerPoint.x - textWidth / 2)
- text.y(centerPoint.y - textHeight / 2)
-}
-
-export default {
- getText,
- createText,
- styleText,
- onScale,
- showEditTextBox,
- removeTextEditEl,
- hideEditTextBox,
- updateTextEditBoxPos,
- renderText,
- updateTextPos
-}
diff --git a/packages/mindmap/src/plugins/associativeLine/associativeLineUtils.js b/packages/mindmap/src/plugins/associativeLine/associativeLineUtils.js
deleted file mode 100644
index b1626b3..0000000
--- a/packages/mindmap/src/plugins/associativeLine/associativeLineUtils.js
+++ /dev/null
@@ -1,336 +0,0 @@
-import { getRectRelativePosition } from '../../utils/index'
-
-// 获取目标节点在起始节点的目标数组中的索引
-export const getAssociativeLineTargetIndex = (node, toNode) => {
- return node.getData('associativeLineTargets').findIndex(item => {
- return item === toNode.getData('uid')
- })
-}
-
-// 计算贝塞尔曲线的控制点
-export const computeCubicBezierPathPoints = (x1, y1, x2, y2) => {
- const min = 5
- let cx1 = x1 + (x2 - x1) / 2
- let cy1 = y1
- let cx2 = cx1
- let cy2 = y2
- if (Math.abs(x1 - x2) <= min) {
- cx1 = x1 + (y2 - y1) / 2
- cx2 = cx1
- }
- if (Math.abs(y1 - y2) <= min) {
- cx1 = x1
- cy1 = y1 - (x2 - x1) / 2
- cx2 = x2
- cy2 = cy1
- }
- return [
- {
- x: cx1,
- y: cy1
- },
- {
- x: cx2,
- y: cy2
- }
- ]
-}
-
-// 拼接贝塞尔曲线路径
-export const joinCubicBezierPath = (startPoint, endPoint, point1, point2) => {
- return `M ${startPoint.x},${startPoint.y} C ${point1.x},${point1.y} ${point2.x},${point2.y} ${endPoint.x},${endPoint.y}`
-}
-
-// 获取节点的位置信息
-const getNodeRect = node => {
- let { left, top, width, height } = node
- return {
- right: left + width,
- bottom: top + height,
- left,
- top,
- width,
- height
- }
-}
-
-// 三次贝塞尔曲线
-export const cubicBezierPath = (x1, y1, x2, y2) => {
- let points = computeCubicBezierPathPoints(x1, y1, x2, y2)
- return joinCubicBezierPath(
- { x: x1, y: y1 },
- { x: x2, y: y2 },
- points[0],
- points[1]
- )
-}
-
-export const calcPoint = (node, e) => {
- const { left, top, translateLeft, translateTop, width, height } = node
- const clientX = e.clientX
- const clientY = e.clientY
- // 中心点的坐标
- const centerX = translateLeft + width / 2
- const centerY = translateTop + height / 2
- const translateCenterX = left + width / 2
- const translateCenterY = top + height / 2
- const theta = Math.atan(height / width)
- // 矩形左上角坐标
- const deltaX = clientX - centerX
- const deltaY = centerY - clientY
- // 方向值
- const direction = Math.atan2(deltaY, deltaX)
- // 默认坐标
- let x = left + width
- let y = top + height
- if (direction < theta && direction >= -theta) {
- // 右边
- // 正切值 = 对边/邻边,对边 = 正切值*邻边
- const range = direction * (width / 2)
- if (direction < theta && direction >= 0) {
- // 中心点上边
- y = translateCenterY - range
- } else if (direction >= -theta && direction < 0) {
- // 中心点下方
- y = translateCenterY - range
- }
- return {
- x,
- y,
- dir: 'right',
- range
- }
- } else if (direction >= theta && direction < Math.PI - theta) {
- // 上边
- y = top
- let range = 0
- if (direction < Math.PI / 2 - theta && direction >= theta) {
- // 正切值 = 对边/邻边,邻边 = 对边/正切值
- const side = height / 2 / direction
- range = -side
- // 中心点右侧
- x = translateCenterX + side
- } else if (
- direction >= Math.PI / 2 - theta &&
- direction < Math.PI - theta
- ) {
- // 中心点左侧
- const tanValue = (centerX - clientX) / (centerY - clientY)
- const side = (height / 2) * tanValue
- range = side
- x = translateCenterX - side
- }
- return {
- x,
- y,
- dir: 'top',
- range
- }
- } else if (direction < -theta && direction >= theta - Math.PI) {
- // 下边
- let range = 0
- if (direction >= theta - Math.PI / 2 && direction < -theta) {
- // 中心点右侧
- // 正切值 = 对边/邻边,邻边 = 对边/正切值
- const side = height / 2 / direction
- range = side
- x = translateCenterX - side
- } else if (
- direction < theta - Math.PI / 2 &&
- direction >= theta - Math.PI
- ) {
- // 中心点左侧
- const tanValue = (centerX - clientX) / (centerY - clientY)
- const side = (height / 2) * tanValue
- range = -side
- x = translateCenterX + side
- }
- return {
- x,
- y,
- dir: 'bottom',
- range
- }
- }
- // 左边
- x = left
- const tanValue = (centerY - clientY) / (centerX - clientX)
- const range = tanValue * (width / 2)
- if (direction >= -Math.PI && direction < theta - Math.PI) {
- // 中心点右侧
- y = translateCenterY - range
- } else if (direction < Math.PI && direction >= Math.PI - theta) {
- // 中心点左侧
- y = translateCenterY - range
- }
- return {
- x,
- y,
- dir: 'left',
- range
- }
-}
-// 获取节点的连接点
-export const getNodePoint = (node, dir = 'right', range = 0, e = null) => {
- let { left, top, width, height } = node
- if (e) {
- return calcPoint(node, e)
- }
- switch (dir) {
- case 'left':
- return {
- x: left,
- y: top + height / 2 - range,
- dir
- }
- case 'right':
- return {
- x: left + width,
- y: top + height / 2 - range,
- dir
- }
- case 'top':
- return {
- x: left + width / 2 - range,
- y: top,
- dir
- }
- case 'bottom':
- return {
- x: left + width / 2 - range,
- y: top + height,
- dir
- }
- default:
- break
- }
-}
-
-// 根据两个节点的位置计算节点的连接点
-export const computeNodePoints = (fromNode, toNode) => {
- const fromRect = getNodeRect(fromNode)
- const toRect = getNodeRect(toNode)
- let fromDir = ''
- let toDir = ''
- const dir = getRectRelativePosition(
- {
- x: fromRect.left,
- y: fromRect.top,
- width: fromRect.width,
- height: fromRect.height
- },
- {
- x: toRect.left,
- y: toRect.top,
- width: toRect.width,
- height: toRect.height
- }
- )
- // 起始矩形在结束矩形的什么方向
- switch (dir) {
- case 'left-top':
- fromDir = 'right'
- toDir = 'top'
- break
- case 'right-top':
- fromDir = 'left'
- toDir = 'top'
- break
- case 'right-bottom':
- fromDir = 'left'
- toDir = 'bottom'
- break
- case 'left-bottom':
- fromDir = 'right'
- toDir = 'bottom'
- break
- case 'left':
- fromDir = 'right'
- toDir = 'left'
- break
- case 'right':
- fromDir = 'left'
- toDir = 'right'
- break
- case 'top':
- fromDir = 'right'
- toDir = 'right'
- break
- case 'bottom':
- fromDir = 'left'
- toDir = 'left'
- break
- case 'overlap':
- fromDir = 'right'
- toDir = 'right'
- break
- default:
- break
- }
- return [getNodePoint(fromNode, fromDir), getNodePoint(toNode, toDir)]
-}
-
-// 获取节点的关联线路径
-export const getNodeLinePath = (startPoint, endPoint, node, toNode) => {
- let targetIndex = getAssociativeLineTargetIndex(node, toNode)
- // 控制点
- let controlPoints = []
- let associativeLineTargetControlOffsets = node.getData(
- 'associativeLineTargetControlOffsets'
- )
- if (
- associativeLineTargetControlOffsets &&
- associativeLineTargetControlOffsets[targetIndex]
- ) {
- // 节点保存了控制点差值
- let offsets = associativeLineTargetControlOffsets[targetIndex]
- controlPoints = [
- {
- x: startPoint.x + offsets[0].x,
- y: startPoint.y + offsets[0].y
- },
- {
- x: endPoint.x + offsets[1].x,
- y: endPoint.y + offsets[1].y
- }
- ]
- } else {
- // 没有保存控制点则生成默认的
- controlPoints = computeCubicBezierPathPoints(
- startPoint.x,
- startPoint.y,
- endPoint.x,
- endPoint.y
- )
- }
- // 根据控制点拼接贝塞尔曲线路径
- return {
- path: joinCubicBezierPath(
- startPoint,
- endPoint,
- controlPoints[0],
- controlPoints[1]
- ),
- controlPoints
- }
-}
-
-// 获取默认的控制点差值
-export const getDefaultControlPointOffsets = (startPoint, endPoint) => {
- let controlPoints = computeCubicBezierPathPoints(
- startPoint.x,
- startPoint.y,
- endPoint.x,
- endPoint.y
- )
- return [
- {
- x: controlPoints[0].x - startPoint.x,
- y: controlPoints[0].y - startPoint.y
- },
- {
- x: controlPoints[1].x - endPoint.x,
- y: controlPoints[1].y - endPoint.y
- }
- ]
-}
diff --git a/packages/mindmap/src/svg/btns.ts b/packages/mindmap/src/svg/btns.ts
deleted file mode 100644
index a4b67ed..0000000
--- a/packages/mindmap/src/svg/btns.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-// 展开按钮
-const open = ``
-
-// 收缩按钮
-const close = ``
-
-// 删除按钮
-const remove = ``
-
-// 图片调整按钮
-const imgAdjust = ``
-
-export default {
- open,
- close,
- remove,
- imgAdjust
-}
diff --git a/packages/mindmap/src/svg/icons.ts b/packages/mindmap/src/svg/icons.ts
deleted file mode 100644
index fa7cd94..0000000
--- a/packages/mindmap/src/svg/icons.ts
+++ /dev/null
@@ -1,322 +0,0 @@
-import { mergerIconList } from '../utils'
-interface IconItem {
- name: string;
- icon: string;
-}
-
-interface IconGroup {
- type: string;
- list: IconItem[];
-}
-// 超链接图标
-const hyperlink =
- ''
-
-// 备注图标
-const note =
- ''
-
-// 附件图标
-const attachment =
- ''
-
-// 节点icon
-export const nodeIconList = [
- {
- name: '优先级图标',
- type: 'priority',
- list: [
- {
- name: '1',
- icon: ``
- },
- {
- name: '2',
- icon: ``
- },
- {
- name: '3',
- icon: ``
- },
- {
- name: '4',
- icon: ``
- },
- {
- name: '5',
- icon: ``
- },
- {
- name: '6',
- icon: ``
- },
- {
- name: '7',
- icon: ``
- },
- {
- name: '8',
- icon: ``
- },
- {
- name: '9',
- icon: ``
- },
- {
- name: '10',
- icon: ``
- }
- ]
- },
- {
- name: '进度图标',
- type: 'progress',
- list: [
- {
- name: '1',
- icon: ``
- },
- {
- name: '2',
- icon: ``
- },
- {
- name: '3',
- icon: ``
- },
- {
- name: '4',
- icon: ``
- },
- {
- name: '5',
- icon: ``
- },
- {
- name: '6',
- icon: ``
- },
- {
- name: '7',
- icon: ``
- },
- {
- name: '8',
- icon: ``
- }
- ]
- },
- {
- name: '表情图标',
- type: 'expression',
- list: [
- {
- name: '1',
- icon: ``
- },
- {
- name: '2',
- icon: ``
- },
- {
- name: '3',
- icon: ``
- },
- {
- name: '4',
- icon: ``
- },
- {
- name: '5',
- icon: ``
- },
- {
- name: '6',
- icon: ``
- },
- {
- name: '7',
- icon: ``
- },
- {
- name: '8',
- icon: ``
- },
- {
- name: '9',
- icon: ``
- },
- {
- name: '10',
- icon: ``
- },
- {
- name: '11',
- icon: ``
- },
- {
- name: '12',
- icon: ``
- },
- {
- name: '13',
- icon: ``
- },
- {
- name: '14',
- icon: ``
- },
- {
- name: '15',
- icon: ``
- },
- {
- name: '16',
- icon: ``
- },
- {
- name: '17',
- icon: ``
- },
- {
- name: '18',
- icon: ``
- },
- {
- name: '19',
- icon: ``
- },
- {
- name: '20',
- icon: ``
- }
- ]
- },
- {
- name: '标记图标',
- type: 'sign',
- list: [
- {
- name: '1',
- icon: ``
- },
- {
- name: '2',
- icon: ``
- },
- {
- name: '3',
- icon: ``
- },
- {
- name: '4',
- icon: ``
- },
- {
- name: '5',
- icon: ``
- },
- {
- name: '6',
- icon: ``
- },
- {
- name: '7',
- icon: ``
- },
- {
- name: '8',
- icon: ``
- },
- {
- name: '9',
- icon: ``
- },
- {
- name: '10',
- icon: ``
- },
- {
- name: '11',
- icon: ``
- },
- {
- name: '12',
- icon: ``
- },
- {
- name: '13',
- icon: ``
- },
- {
- name: '14',
- icon: ``
- },
- {
- name: '15',
- icon: ``
- },
- {
- name: '16',
- icon: ``
- },
- {
- name: '17',
- icon: ``
- },
- {
- name: '18',
- icon: ``
- },
- {
- name: '19',
- icon: ``
- },
- {
- name: '20',
- icon: ``
- },
- {
- name: '21',
- icon: ``
- },
- {
- name: '22',
- icon: ``
- },
- {
- name: '23',
- icon: ``
- }
- ]
- }
-]
-const getNodeIconListIcon = (name: string, extendIconList: IconGroup[] = []): string => {
- const arr: string[] = name.split('_');
- const iconList: IconGroup[] = mergerIconList([...nodeIconList, ...extendIconList]);
-
- const typeData: IconGroup | undefined = iconList.find(item =>
- item.type === arr[0]
- );
-
- if (typeData) {
- const typeName: IconItem | undefined = typeData.list.find(item =>
- item.name === arr[1]
- );
-
- if (typeName) {
- return typeName.icon;
- }
- return '';
- }
- return '';
-}
-
-// Export with type annotations
-export default {
- hyperlink,
- note,
- attachment,
- nodeIconList,
- getNodeIconListIcon
-} as const;
\ No newline at end of file
diff --git a/packages/mindmap/src/theme/default.ts b/packages/mindmap/src/theme/default.ts
deleted file mode 100644
index 3c724d0..0000000
--- a/packages/mindmap/src/theme/default.ts
+++ /dev/null
@@ -1,301 +0,0 @@
-// 定义主题接口
-export interface ThemeConfig {
- paddingX: number;
- paddingY: number;
- imgMaxWidth: number;
- imgMaxHeight: number;
- iconSize: number;
- lineWidth: number;
- lineColor: string;
- lineDasharray: string;
- lineFlow: boolean;
- lineFlowDuration: number;
- lineFlowForward: boolean;
- lineStyle: 'curve' | 'straight' | 'direct';
- rootLineKeepSameInCurve: boolean;
- rootLineStartPositionKeepSameInCurve: boolean;
- lineRadius: number;
- showLineMarker: boolean;
- generalizationLineWidth: number;
- generalizationLineColor: string;
- generalizationLineMargin: number;
- generalizationNodeMargin: number;
- associativeLineWidth: number;
- associativeLineColor: string;
- associativeLineActiveWidth: number;
- associativeLineActiveColor: string;
- associativeLineDasharray: number[];
- associativeLineTextColor: string;
- associativeLineTextFontSize: number;
- associativeLineTextLineHeight: number;
- associativeLineTextFontFamily: string;
- backgroundColor: string;
- backgroundImage: string;
- backgroundRepeat: string;
- backgroundPosition: string;
- backgroundSize: string;
- nodeUseLineStyle: boolean;
- root: NodeStyle;
- second: NodeStyle;
- node: NodeStyle;
- generalization: NodeStyle;
-}
-
-export interface NodeStyle {
- shape: string;
- fillColor: string;
- fontFamily: string;
- color: string;
- fontSize: number;
- fontWeight: string;
- fontStyle: string;
- borderColor: string;
- borderWidth: number;
- borderDasharray: string;
- borderRadius: number;
- textDecoration: string;
- gradientStyle: boolean;
- startColor: string;
- endColor: string;
- startDir: number[];
- endDir: number[];
- lineMarkerDir?: string;
- hoverRectColor: string;
- hoverRectRadius: number;
- marginX?: number;
- marginY?: number;
-}
-// 默认主题
-export const defaultTheme: ThemeConfig = {
- // 节点内边距
- paddingX: 15,
- paddingY: 5,
- // 图片显示的最大宽度
- imgMaxWidth: 200,
- // 图片显示的最大高度
- imgMaxHeight: 100,
- // icon的大小
- iconSize: 20,
- // 连线的粗细
- lineWidth: 1,
- // 连线的颜色
- lineColor: '#549688',
- // 连线样式
- lineDasharray: 'none',
- // 连线是否开启流动效果,仅在虚线时有效(需要注册LineFlow插件)
- lineFlow: false,
- // 流动效果一个周期的时间,单位:s
- lineFlowDuration: 1,
- // 流动方向是否是从父节点到子节点
- lineFlowForward: true,
- // 连线风格
- lineStyle: 'straight', // 曲线(curve)【仅支持logicalStructure、mindMap、verticalTimeline三种结构】、直线(straight)、直连(direct)【仅支持logicalStructure、mindMap、organizationStructure、verticalTimeline四种结构】
- // 曲线连接时,根节点和其他节点的连接线样式保持统一,默认根节点为 ( 型,其他节点为 { 型,设为true后,都为 { 型。仅支持logicalStructure、mindMap两种结构
- rootLineKeepSameInCurve: true,
- // 曲线连接时,根节点和其他节点的连线起始位置保持统一,默认根节点的连线起始位置在节点中心,其他节点在节点右侧(或左侧),如果该配置设为true,那么根节点的连线起始位置也会在节点右侧(或左侧)
- rootLineStartPositionKeepSameInCurve: false,
- // 直线连接(straight)时,连线的圆角大小,设置为0代表没有圆角,仅支持logicalStructure、mindMap、verticalTimeline三种结构
- lineRadius: 5,
- // 连线是否显示标记,目前只支持箭头
- showLineMarker: false,
- // 概要连线的粗细
- generalizationLineWidth: 1,
- // 概要连线的颜色
- generalizationLineColor: '#549688',
- // 概要曲线距节点的距离
- generalizationLineMargin: 0,
- // 概要节点距节点的距离
- generalizationNodeMargin: 20,
- // 关联线默认状态的粗细
- associativeLineWidth: 2,
- // 关联线默认状态的颜色
- associativeLineColor: 'rgb(51, 51, 51)',
- // 关联线激活状态的粗细
- associativeLineActiveWidth: 8,
- // 关联线激活状态的颜色
- associativeLineActiveColor: 'rgba(2, 167, 240, 1)',
- // 关联线样式
- associativeLineDasharray: [6, 4],
- // 关联线文字颜色
- associativeLineTextColor: 'rgb(51, 51, 51)',
- // 关联线文字大小
- associativeLineTextFontSize: 14,
- // 关联线文字行高
- associativeLineTextLineHeight: 1.2,
- // 关联线文字字体
- associativeLineTextFontFamily: '微软雅黑, Microsoft YaHei',
- // 背景颜色
- backgroundColor: '#fafafa',
- // 背景图片
- backgroundImage: 'none',
- // 背景重复
- backgroundRepeat: 'no-repeat',
- // 设置背景图像的起始位置
- backgroundPosition: 'center center',
- // 设置背景图片大小
- backgroundSize: 'cover',
- // 节点使用只有底边横线的样式,仅支持logicalStructure、mindMap、catalogOrganization、organizationStructure四种结构
- nodeUseLineStyle: false,
- // 根节点样式
- root: {
- shape: 'rectangle',
- fillColor: '#549688',
- fontFamily: '微软雅黑, Microsoft YaHei',
- color: '#fff',
- fontSize: 16,
- fontWeight: 'bold',
- fontStyle: 'normal',
- borderColor: 'transparent',
- borderWidth: 0,
- borderDasharray: 'none',
- borderRadius: 5,
- textDecoration: 'none',
- gradientStyle: false,
- startColor: '#549688',
- endColor: '#fff',
- startDir: [0, 0],
- endDir: [1, 0],
- // 连线标记的位置,start(头部)、end(尾部),该配置在showLineMarker配置为true时生效
- lineMarkerDir: 'end',
- // 节点鼠标hover和激活时显示的矩形边框的颜色,主题里不设置,默认会取hoverRectColor实例化选项的值
- hoverRectColor: '',
- // 点鼠标hover和激活时显示的矩形边框的圆角大小
- hoverRectRadius: 5
- // 下列样式也支持给节点设置,用于覆盖最外层的设置
- // paddingX,
- // paddingY,
- // lineWidth,
- // lineColor,
- // lineDasharray,
- // lineFlow,
- // lineFlowDuration,
- // lineFlowForward
- // 关联线的所有样式
- },
- // 二级节点样式
- second: {
- shape: 'rectangle',
- marginX: 100,
- marginY: 40,
- fillColor: '#fff',
- fontFamily: '微软雅黑, Microsoft YaHei',
- color: '#565656',
- fontSize: 16,
- fontWeight: 'normal',
- fontStyle: 'normal',
- borderColor: '#549688',
- borderWidth: 1,
- borderDasharray: 'none',
- borderRadius: 5,
- textDecoration: 'none',
- gradientStyle: false,
- startColor: '#549688',
- endColor: '#fff',
- startDir: [0, 0],
- endDir: [1, 0],
- lineMarkerDir: 'end',
- hoverRectColor: '',
- hoverRectRadius: 5
- },
- // 三级及以下节点样式
- node: {
- shape: 'rectangle',
- marginX: 50,
- marginY: 0,
- fillColor: 'transparent',
- fontFamily: '微软雅黑, Microsoft YaHei',
- color: '#6a6d6c',
- fontSize: 14,
- fontWeight: 'normal',
- fontStyle: 'normal',
- borderColor: 'transparent',
- borderWidth: 0,
- borderRadius: 5,
- borderDasharray: 'none',
- textDecoration: 'none',
- gradientStyle: false,
- startColor: '#549688',
- endColor: '#fff',
- startDir: [0, 0],
- endDir: [1, 0],
- lineMarkerDir: 'end',
- hoverRectColor: '',
- hoverRectRadius: 5
- },
- // 概要节点样式
- generalization: {
- shape: 'rectangle',
- marginX: 100,
- marginY: 40,
- fillColor: '#fff',
- fontFamily: '微软雅黑, Microsoft YaHei',
- color: '#565656',
- fontSize: 16,
- fontWeight: 'normal',
- fontStyle: 'normal',
- borderColor: '#549688',
- borderWidth: 1,
- borderDasharray: 'none',
- borderRadius: 5,
- textDecoration: 'none',
- gradientStyle: false,
- startColor: '#549688',
- endColor: '#fff',
- startDir: [0, 0],
- endDir: [1, 0],
- hoverRectColor: '',
- hoverRectRadius: 5
- }
-}
-
-export const theme = {
- default: defaultTheme
-}
-// 检测主题配置是否是节点大小无关的
-const nodeSizeIndependenceList = [
- 'lineWidth',
- 'lineColor',
- 'lineDasharray',
- 'lineStyle',
- 'generalizationLineWidth',
- 'generalizationLineColor',
- 'associativeLineWidth',
- 'associativeLineColor',
- 'associativeLineActiveWidth',
- 'associativeLineActiveColor',
- 'associativeLineTextColor',
- 'associativeLineTextFontSize',
- 'associativeLineTextLineHeight',
- 'associativeLineTextFontFamily',
- 'backgroundColor',
- 'backgroundImage',
- 'backgroundRepeat',
- 'backgroundPosition',
- 'backgroundSize',
- 'rootLineKeepSameInCurve',
- 'rootLineStartPositionKeepSameInCurve',
- 'showLineMarker',
- 'lineRadius',
- 'hoverRectColor',
- 'hoverRectRadius',
- 'lineFlow',
- 'lineFlowDuration',
- 'lineFlowForward'
-]
-export const checkIsNodeSizeIndependenceConfig = (config: Partial): boolean => {
- const keys = Object.keys(config);
- return keys.every(key => nodeSizeIndependenceList.includes(key));
-}
-
-
-// 连线的样式
-export const lineStyleProps = [
- 'lineColor',
- 'lineDasharray',
- 'lineWidth',
- 'lineMarkerDir',
- 'lineFlow',
- 'lineFlowDuration',
- 'lineFlowForward'
-]
-
diff --git a/packages/mindmap/src/theme/index.ts b/packages/mindmap/src/theme/index.ts
deleted file mode 100644
index 274b8fa..0000000
--- a/packages/mindmap/src/theme/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./default"
\ No newline at end of file
diff --git a/packages/mindmap/src/types.ts b/packages/mindmap/src/types.ts
deleted file mode 100644
index b7a9350..0000000
--- a/packages/mindmap/src/types.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-export interface Node {
- [key: string]: any;
- parent?: Node | null;
- isAncestor?: (node: Node) => boolean;
- getIndexInBrothers?: () => number;
- data?: {
- text: string; // 节点文本,支持富文本(html)
- richText?: boolean; // 是否为富文本模式
- expand?: boolean; // 节点是否展开
- uid?: string; // 节点唯一id
- icon?: string[]; // 节点图标
- image?: string; // 图片URL
- imageTitle?: string; // 图片标题
- imageSize?: {
- width: number; // 图片宽度
- height: number; // 图片高度
- custom?: boolean; // 是否自定义大小
- };
- hyperlink?: string; // 超链接地址
- hyperlinkTitle?: string; // 超链接标题
- note?: string; // 备注内容
- attachmentUrl?: string; // 附件URL (v0.9.10+)
- attachmentName?: string; // 附件名称 (v0.9.10+)
- tag?: Array;
- generalization?: Array<{ // 节点概要
- text: string;
- richText?: boolean;
- [key: string]: any; // 支持其他普通节点字段(除children外)
- }>;
- associativeLineTargets?: string[]; // 关联线目标节点uid列表
- associativeLineText?: string; // 关联线文本
- [key: string]: any; // 其他样式字段
- };
- children?: Node[]; // 子节点
- nodeData?: {
- children?: any[];
- };
-}
-
-export interface DrawOptions {
- sx: number
- sy: number
- swidth: number
- sheight: number
- x: number
- y: number
- width: number
- height: number
-}
-
-export interface TreeNode {
-
- data?: NodeData;
- children?: TreeNode[];
- nodeData?: TreeNode;
- [key: string]: any;
-}
-
-export interface NodeData {
- uid?: string;
- isActive?: boolean;
- [key: string]: any;
-}
-
-export interface BoundingRect {
- left: number
- top: number
- width: number
- height: number
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/AutoMove.ts b/packages/mindmap/src/utils/AutoMove.ts
deleted file mode 100644
index d86e5ea..0000000
--- a/packages/mindmap/src/utils/AutoMove.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * @file AutoMove.ts
- * @description 思维导图画布自动移动管理类
- * @usage 用于处理画布在鼠标接近边缘时的自动移动效果
- */
-
-
-
-/**
- * @class AutoMove
- * @description 画布自动移动控制类
- * @pattern 单例模式 - 每个画布实例对应一个自动移动实例
- * @example
- * ```ts
- * const autoMove = new AutoMove(mindMap)
- * autoMove.onMove(x, y)
- * ```
- */
-class AutoMove {
- private mindMap: any
- private autoMoveTimer: number | null
-
- /**
- * @constructor
- * @param mindMap - 思维导图实例
- */
- constructor(mindMap: any) {
- this.mindMap = mindMap
- this.autoMoveTimer = null
- }
-
- /**
- * @method onMove
- * @description 处理鼠标移动事件,检测是否需要自动移动画布
- * @param x - 鼠标X坐标
- * @param y - 鼠标Y坐标
- * @param callback - 移动回调函数
- * @param handle - 边缘处理函数
- * @throws 无异常抛出
- */
- onMove(
- x: number,
- y: number,
- callback: () => void = () => { },
- handle: (direction: string, step: number) => void = () => { }
- ): void {
- callback()
- // 获取移动配置参数
- const step = this.mindMap.opt.selectTranslateStep
- const limit = this.mindMap.opt.selectTranslateLimit
- let count = 0
-
- // 检测四个方向的边缘,触发相应的画布移动
- if (x <= this.mindMap.elRect.left + limit) {
- handle('left', step)
- this.mindMap.view.translateX(step)
- count++
- }
- if (x >= this.mindMap.elRect.right - limit) {
- handle('right', step)
- this.mindMap.view.translateX(-step)
- count++
- }
- if (y <= this.mindMap.elRect.top + limit) {
- handle('top', step)
- this.mindMap.view.translateY(step)
- count++
- }
- if (y >= this.mindMap.elRect.bottom - limit) {
- handle('bottom', step)
- this.mindMap.view.translateY(-step)
- count++
- }
-
- // 如果触发了边缘移动,则启动自动移动
- if (count > 0) {
- this.startAutoMove(x, y, callback, handle)
- }
- }
-
- /**
- * @method startAutoMove
- * @description 启动自动移动定时器
- * @param x - 鼠标X坐标
- * @param y - 鼠标Y坐标
- * @param callback - 移动回调函数
- * @param handle - 边缘处理函数
- */
- private startAutoMove(
- x: number,
- y: number,
- callback: () => void,
- handle: (direction: string, step: number) => void
- ): void {
- this.autoMoveTimer = window.setTimeout(() => {
- this.onMove(x, y, callback, handle)
- }, 20)
- }
-
- /**
- * @method clearAutoMoveTimer
- * @description 清除自动移动定时器
- */
- clearAutoMoveTimer(): void {
- if (this.autoMoveTimer) {
- clearTimeout(this.autoMoveTimer)
- }
- }
-}
-
-export default AutoMove
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/BatchExecution.ts b/packages/mindmap/src/utils/BatchExecution.ts
deleted file mode 100644
index 9a3057d..0000000
--- a/packages/mindmap/src/utils/BatchExecution.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * 批量执行器模块
- * 用于管理和执行异步任务队列,支持任务去重和批量处理
- *
- * 使用场景:
- * 1. 需要对频繁触发的操作进行批量处理
- * 2. 需要确保相同任务只执行最新一次
- * 3. 需要在下一个事件循环统一处理多个任务
- */
-
-import { nextTick } from './Task'
-
-/**
- * 批量执行器类
- *
- * 核心功能:
- * - 维护异步任务队列
- * - 支持任务去重和替换
- * - 批量执行队列中的任务
- *
- * 设计模式:
- * - 使用单例模式确保任务队列的唯一性
- * - 采用发布订阅模式处理异步任务
- *
- * 使用示例:
- * ```typescript
- * const batch = new BatchExecution()
- * batch.push('task1', () => console.log('执行任务1'))
- * batch.push('task2', () => console.log('执行任务2'))
- * ```
- */
-class BatchExecution {
- // 任务状态映射表
- private has: Record
- // 任务队列
- private queue: Array<{ name: string, fn: () => void }>
- // 下一帧执行函数
- private nextTick: () => void
-
- constructor() {
- this.has = {}
- this.queue = []
- this.nextTick = nextTick(this.flush, this)
- }
-
- /**
- * 添加任务到执行队列
- * @param name - 任务唯一标识
- * @param fn - 待执行的任务函数
- * @returns void
- *
- * 异常处理:
- * - 如果任务已存在,将替换为新任务
- * - 任务函数执行错误不会影响队列中其他任务
- */
- push(name: string, fn: () => void): void {
- if (this.has[name]) {
- this.replaceTask(name, fn)
- return
- }
- this.has[name] = true
- this.queue.push({
- name,
- fn
- })
- this.nextTick()
- }
-
- /**
- * 替换已存在的任务
- * @param name - 任务唯一标识
- * @param fn - 新的任务函数
- * @returns void
- */
- private replaceTask(name: string, fn: () => void): void {
- const index = this.queue.findIndex(item => {
- return item.name === name
- })
- if (index !== -1) {
- this.queue[index] = {
- name,
- fn
- }
- }
- }
-
- /**
- * 执行队列中的所有任务
- * 执行完成后清空队列
- * @returns void
- */
- private flush(): void {
- // 复制队列以避免执行过程中的队列变化
- let fns = this.queue.slice(0)
- this.queue = []
- fns.forEach(({ name, fn }) => {
- this.has[name] = false
- fn()
- })
- }
-}
-
-export default BatchExecution
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Dom.ts b/packages/mindmap/src/utils/Dom.ts
deleted file mode 100644
index 06fc77f..0000000
--- a/packages/mindmap/src/utils/Dom.ts
+++ /dev/null
@@ -1,243 +0,0 @@
-import { htmlEscape } from "./String";
-
-// DOM element references
-let getTextFromHtmlEl: HTMLDivElement | null = null;
-let nodeToHTMLWrapEl: HTMLDivElement | null = null;
-let addHtmlStyleEl: HTMLDivElement | null = null;
-let replaceHtmlTextEl: HTMLDivElement | null = null;
-let removeHtmlNodeByClassEl: HTMLDivElement | null = null;
-let nodeRichTextToTextWithWrapEl: HTMLDivElement | null = null;
-let textToNodeRichTextWithWrapEl: HTMLDivElement | null = null;
-let removeRichTextStyesEl: HTMLDivElement | null = null;
-
-// Extract plain text from HTML string
-export const getTextFromHtml = (html: string): string => {
- if (!getTextFromHtmlEl) {
- getTextFromHtmlEl = document.createElement('div');
- }
- getTextFromHtmlEl.innerHTML = html;
- return getTextFromHtmlEl.textContent || '';
-}
-
-// Convert DOM node to HTML string
-export const nodeToHTML = (node: Node): string => {
- if (!nodeToHTMLWrapEl) {
- nodeToHTMLWrapEl = document.createElement('div');
- }
- nodeToHTMLWrapEl.innerHTML = '';
- nodeToHTMLWrapEl.appendChild(node);
- return nodeToHTMLWrapEl.innerHTML;
-}
-
-// Add inline styles to specified tags in HTML
-export const addHtmlStyle = (html: string, tag: string | string[], style: string): string => {
- if (!addHtmlStyleEl) {
- addHtmlStyleEl = document.createElement('div');
- }
- const tags = Array.isArray(tag) ? tag : [tag];
- addHtmlStyleEl.innerHTML = html;
-
- const walk = (root: Node): void => {
- let childNodes = root.childNodes;
- childNodes.forEach(node => {
- if (node.nodeType === 1) {
- if (tags.includes((node as Element).tagName.toLowerCase())) {
- (node as HTMLElement).style.cssText = style;
- } else {
- walk(node);
- }
- }
- });
- }
- walk(addHtmlStyleEl);
- return addHtmlStyleEl.innerHTML;
-}
-
-// Remove HTML entities from string
-export const removeHTMLEntities = (str: string): string => {
- [[' ', ' ']].forEach(item => {
- str = str.replaceAll(item[0], item[1]);
- });
- return str;
-}
-
-// Remove inline styles from HTML string
-export const removeHtmlStyle = (html: string): string => {
- return html.replaceAll(/(<[^\s]+)\s+style=["'][^'"]+["']\s*(>)/g, '$1$2');
-}
-
-// Search and replace text in HTML string
-export const replaceHtmlText = (html: string, searchText: string, replaceText: string): string => {
- if (!replaceHtmlTextEl) {
- replaceHtmlTextEl = document.createElement('div');
- }
- replaceHtmlTextEl.innerHTML = html;
-
- const walk = (root: Node): void => {
- let childNodes = root.childNodes;
- childNodes.forEach(node => {
- if (node.nodeType === 1) {
- walk(node);
- } else if (node.nodeType === 3) {
- root.replaceChild(
- document.createTextNode(
- node.nodeValue?.replaceAll(searchText, replaceText) || ''
- ),
- node
- );
- }
- });
- }
- walk(replaceHtmlTextEl);
- return replaceHtmlTextEl.innerHTML;
-}
-
-// Remove node by class selector from HTML string
-export const removeHtmlNodeByClass = (html: string, selector: string): string => {
- if (!removeHtmlNodeByClassEl) {
- removeHtmlNodeByClassEl = document.createElement('div');
- }
- removeHtmlNodeByClassEl.innerHTML = html;
- const node = removeHtmlNodeByClassEl.querySelector(selector);
- if (node) {
- node.parentNode?.removeChild(node);
- }
- return removeHtmlNodeByClassEl.innerHTML;
-}
-
-// Remove formula tags from DOM node
-export const removeFormulaTags = (node: Node): void => {
- const walk = (root: Node): void => {
- const childNodes = root.childNodes;
- childNodes.forEach(node => {
- if (node.nodeType === 1) {
- if ((node as Element).classList.contains('ql-formula')) {
- node.parentNode?.removeChild(node);
- } else {
- walk(node);
- }
- }
- });
- }
- walk(node);
-}
-
-// Convert rich text node content to text with newlines
-export const nodeRichTextToTextWithWrap = (html: string): string => {
- if (!nodeRichTextToTextWithWrapEl) {
- nodeRichTextToTextWithWrapEl = document.createElement('div');
- }
- nodeRichTextToTextWithWrapEl.innerHTML = html;
- const childNodes = nodeRichTextToTextWithWrapEl.childNodes;
- let res = '';
- for (let i = 0; i < childNodes.length; i++) {
- const node = childNodes[i];
- if (node.nodeType === 1) {
- removeFormulaTags(node);
- if ((node as Element).tagName.toLowerCase() === 'p') {
- res += node.textContent + '\n';
- } else {
- res += node.textContent;
- }
- } else if (node.nodeType === 3) {
- res += node.nodeValue;
- }
- }
- return res.replace(/\n$/, '');
-}
-
-// Convert text with
to rich text node content
-export const textToNodeRichTextWithWrap = (html: string): string => {
- if (!textToNodeRichTextWithWrapEl) {
- textToNodeRichTextWithWrapEl = document.createElement('div');
- }
- textToNodeRichTextWithWrapEl.innerHTML = html;
- const childNodes = textToNodeRichTextWithWrapEl.childNodes;
- let list: string[] = [];
- let str = '';
- for (let i = 0; i < childNodes.length; i++) {
- const node = childNodes[i];
- if (node.nodeType === 1) {
- if ((node as Element).tagName.toLowerCase() === 'br') {
- list.push(str);
- str = '';
- } else {
- str += node.textContent;
- }
- } else if (node.nodeType === 3) {
- str += node.nodeValue;
- }
- }
- if (str) {
- list.push(str);
- }
- return list
- .map(item => {
- return `${htmlEscape(item)}
`;
- })
- .join('');
-}
-
-// Remove rich text styles but preserve math formulas
-export const removeRichTextStyes = (html: string): string => {
- if (!removeRichTextStyesEl) {
- removeRichTextStyesEl = document.createElement('div');
- }
- removeRichTextStyesEl.innerHTML = html;
-
- const formulaList = removeRichTextStyesEl.querySelectorAll('.ql-formula');
- Array.from(formulaList).forEach(el => {
- const placeholder = document.createTextNode('$smmformula$');
- el.parentNode?.replaceChild(placeholder, el);
- });
-
- const childNodes = removeRichTextStyesEl.childNodes;
- let list: string[] = [];
- for (let i = 0; i < childNodes.length; i++) {
- const node = childNodes[i];
- if (node.nodeType === 1 || node.nodeType === 3) {
- list.push(node.textContent || node.nodeValue || '');
- }
- }
-
- html = list
- .map(item => {
- return `${htmlEscape(item)}
`;
- })
- .join('');
-
- if (formulaList.length > 0) {
- html = html.replace(/\$smmformula\$/g, '');
- removeRichTextStyesEl.innerHTML = html;
- const els = removeRichTextStyesEl.querySelectorAll('.smmformula');
- Array.from(els).forEach((el, index) => {
- el.parentNode?.replaceChild(formulaList[index], el);
- });
- html = removeRichTextStyesEl.innerHTML;
- }
- return html;
-}
-
-// Focus input element
-export const focusInput = (el: HTMLElement): void => {
- let selection = window.getSelection();
- let range = document.createRange();
- range.selectNodeContents(el);
- range.collapse();
- selection?.removeAllRanges();
- selection?.addRange(range);
-}
-
-// Focus and select all in input element
-export const selectAllInput = (el: HTMLElement): void => {
- let selection = window.getSelection();
- let range = document.createRange();
- range.selectNodeContents(el);
- selection?.removeAllRanges();
- selection?.addRange(range);
-}
-
-// Add xmlns attribute to element
-export const addXmlns = (el: Element): void => {
- el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/File.ts b/packages/mindmap/src/utils/File.ts
deleted file mode 100644
index 118eba5..0000000
--- a/packages/mindmap/src/utils/File.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-// 将blob转成data:url
-export const readBlob = (blob: Blob): Promise => {
- return new Promise((resolve, reject) => {
- const reader = new FileReader()
- reader.onload = (evt: ProgressEvent) => {
- if (evt.target?.result) {
- resolve(evt.target.result as string)
- }
- }
- reader.onerror = (err: ProgressEvent) => {
- reject(err)
- }
- reader.readAsDataURL(blob)
- })
-}
-
-// 下载文件
-export const downloadFile = (file: string, fileName: string): void => {
- const a = document.createElement('a')
- a.href = file
- a.download = fileName
- a.click()
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Image.ts b/packages/mindmap/src/utils/Image.ts
deleted file mode 100644
index 602e8d7..0000000
--- a/packages/mindmap/src/utils/Image.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-// 按原比例缩放图片
-export const resizeImgSizeByOriginRatio = (
- width: number,
- height: number,
- newWidth: number,
- newHeight: number
-): [number, number] => {
- let arr: [number, number] = [0, 0]
- const nRatio = width / height
- const mRatio = newWidth / newHeight
- if (nRatio > mRatio) {
- // 固定宽度
- arr = [newWidth, newWidth / nRatio]
- } else {
- // 固定高度
- arr = [nRatio * newHeight, newHeight]
- }
- return arr
-}
-
-// 缩放图片尺寸
-export const resizeImgSize = (
- width: number,
- height: number,
- maxWidth?: number,
- maxHeight?: number
-): [number, number] => {
- const nRatio = width / height
- let arr: [number, number] = [0, 0]
- if (maxWidth && maxHeight) {
- if (width <= maxWidth && height <= maxHeight) {
- arr = [width, height]
- } else {
- const mRatio = maxWidth / maxHeight
- if (nRatio > mRatio) {
- // 固定宽度
- arr = [maxWidth, maxWidth / nRatio]
- } else {
- // 固定高度
- arr = [nRatio * maxHeight, maxHeight]
- }
- }
- } else if (maxWidth) {
- if (width <= maxWidth) {
- arr = [width, height]
- } else {
- arr = [maxWidth, maxWidth / nRatio]
- }
- } else if (maxHeight) {
- if (height <= maxHeight) {
- arr = [width, height]
- } else {
- arr = [nRatio * maxHeight, maxHeight]
- }
- }
- return arr
-}
-
-interface ImageSize {
- width: number
- height: number
-}
-
-interface LoadImageResult {
- url: string
- size: ImageSize
-}
-
-// 缩放图片
-export const resizeImg = (
- imgUrl: string,
- maxWidth?: number,
- maxHeight?: number
-): Promise<[number, number]> => {
- return new Promise((resolve, reject) => {
- const img = new Image()
- img.src = imgUrl
- img.onload = () => {
- const arr = resizeImgSize(
- img.naturalWidth,
- img.naturalHeight,
- maxWidth,
- maxHeight
- )
- resolve(arr)
- }
- img.onerror = (e: Event | string) => {
- reject(e)
- }
- })
-}
-
-// 获取图片大小
-export const getImageSize = (src: string): Promise => {
- return new Promise(resolve => {
- const img = new Image()
- img.src = src
- img.onload = () => {
- resolve({
- width: img.width,
- height: img.height
- })
- }
- img.onerror = () => {
- resolve({
- width: 0,
- height: 0
- })
- }
- })
-}
-
-// 加载图片文件
-export const loadImage = (imgFile: File): Promise => {
- return new Promise((resolve, reject) => {
- const fr = new FileReader()
- fr.readAsDataURL(imgFile)
- fr.onload = async (e: ProgressEvent) => {
- const url = e.target?.result as string
- const size = await getImageSize(url)
- resolve({
- url,
- size
- })
- }
- fr.onerror = (error: ProgressEvent) => {
- reject(error)
- }
- })
-}
-
-// 图片转成dataURL
-export const imgToDataUrl = (
- src: string,
- returnBlob: boolean = false
-): Promise => {
- return new Promise((resolve, reject) => {
- const img = new Image()
- // 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
- img.setAttribute('crossOrigin', 'anonymous')
- img.onload = () => {
- try {
- const canvas = document.createElement('canvas')
- canvas.width = img.width
- canvas.height = img.height
- const ctx = canvas.getContext('2d')
- if (!ctx) {
- throw new Error('Failed to get canvas context')
- }
- // 图片绘制到canvas里
- ctx.drawImage(img, 0, 0, img.width, img.height)
- if (returnBlob) {
- canvas.toBlob(blob => {
- if (blob) {
- resolve(blob)
- } else {
- reject(new Error('Failed to create blob'))
- }
- })
- } else {
- resolve(canvas.toDataURL())
- }
- } catch (e) {
- reject(e)
- }
- }
- img.onerror = (e: Event | string) => {
- reject(e)
- }
- img.src = src
- })
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Lru.ts b/packages/mindmap/src/utils/Lru.ts
deleted file mode 100644
index d08b8ea..0000000
--- a/packages/mindmap/src/utils/Lru.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * LRU (Least Recently Used) 缓存实现
- *
- * 用途:
- * - 用于缓存有限数量的键值对数据
- * - 适用于需要限制内存使用的场景
- * - 常用于性能优化,避免重复计算
- */
-
-/**
- * LRU缓存类
- *
- * 设计说明:
- * - 采用Map数据结构存储键值对
- * - 通过size属性跟踪当前缓存数量
- * - 支持最大容量限制
- *
- * 使用示例:
- * ```ts
- * const cache = new Lru(100);
- * cache.add('key', 'value');
- * const value = cache.get('key');
- * ```
- */
-export default class Lru {
- /** 缓存最大容量 */
- private max: number;
- /** 当前缓存数量 */
- private size: number;
- /** 缓存池,使用Map存储键值对 */
- private pool: Map;
-
- /**
- * 构造函数
- * @param max - 缓存的最大容量,默认为1000
- */
- constructor(max?: number) {
- this.max = max || 1000;
- this.size = 0;
- this.pool = new Map();
- }
-
- /**
- * 添加键值对到缓存
- * @param key - 缓存键
- * @param value - 缓存值
- * @returns 添加是否成功
- *
- * 处理逻辑:
- * 1. 检查键是否存在
- * 2. 如果不存在且达到容量上限,则添加失败
- * 3. 如果键已存在,则先删除旧值
- * 4. 添加新的键值对
- */
- add(key: K, value: V): boolean {
- const isExist = this.has(key);
- // 如果该key之前不存在,并且现在数量已经超出最大值,则不再继续添加
- if (!isExist && this.size >= this.max) {
- return false;
- }
- // 已经存在则可以更新,因为不影响数量
- // 如果该key是否已经存在,则先删除
- this.delete(key);
- // 添加新值
- this.pool.set(key, value);
- this.size++;
- return true;
- }
-
- /**
- * 从缓存中删除指定键值对
- * @param key - 要删除的键
- */
- delete(key: K): void {
- if (this.pool.has(key)) {
- this.pool.delete(key);
- this.size--;
- }
- }
-
- /**
- * 检查键是否存在于缓存中
- * @param key - 要检查的键
- * @returns 是否存在
- */
- has(key: K): boolean {
- return this.pool.has(key);
- }
-
- /**
- * 获取缓存中指定键的值
- * @param key - 要获取的键
- * @returns 对应的值,如果不存在则返回undefined
- */
- get(key: K): V | undefined {
- if (this.pool.has(key)) {
- return this.pool.get(key);
- }
- return undefined;
- }
-
- /**
- * 清空缓存
- * 重置size为0并创建新的Map实例
- */
- clear(): void {
- this.size = 0;
- this.pool = new Map();
- }
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/NodeTools.ts b/packages/mindmap/src/utils/NodeTools.ts
deleted file mode 100644
index 0a3473f..0000000
--- a/packages/mindmap/src/utils/NodeTools.ts
+++ /dev/null
@@ -1,279 +0,0 @@
-import { addXmlns } from "./Dom"
-import { ForeignObject } from '@svgdotjs/svg.js'
-import { BoundingRect, Node } from "../types"
-
-
-
-
-interface ForeignObjectConfig {
- el: HTMLElement
- width?: number
- height?: number
-}
-
-interface ExtraContentConfig {
- addContentToHeader?: () => {
- el: HTMLElement
- cssText?: string
- height: number
- } | void
- addContentToFooter?: () => {
- el: HTMLElement
- cssText?: string
- height: number
- } | void
-}
-
-interface ExtraContentResult {
- cssTextList: string[]
- header: ForeignObject | null
- headerHeight: number
- footer: ForeignObject | null
- footerHeight: number
-}
-
-// Get bounding rect for node tree
-export const getNodeTreeBoundingRect = (
- node: Node,
- x: number = 0,
- y: number = 0,
- paddingX: number = 0,
- paddingY: number = 0,
- excludeSelf: boolean = false,
- excludeGeneralization: boolean = false
-): BoundingRect => {
- let minX: number = Infinity
- let maxX: number = -Infinity
- let minY: number = Infinity
- let maxY: number = -Infinity
-
- const walk = (root: Node, isRoot: boolean): void => {
- if (!(isRoot && excludeSelf) && root.group) {
- try {
- const { x, y, width, height } = root.group
- .findOne('.smm-node-shape')
- .rbox()
- if (x < minX) {
- minX = x
- }
- if (x + width > maxX) {
- maxX = x + width
- }
- if (y < minY) {
- minY = y
- }
- if (y + height > maxY) {
- maxY = y + height
- }
- } catch (e) { }
- }
- if (!excludeGeneralization && root._generalizationList.length > 0) {
- root._generalizationList.forEach(item => {
- walk(item.generalizationNode, false)
- })
- }
- if (root.children) {
- root.children.forEach(item => {
- walk(item, false)
- })
- }
- }
- walk(node, true)
-
- minX = minX - x + paddingX
- minY = minY - y + paddingY
- maxX = maxX - x + paddingX
- maxY = maxY - y + paddingY
-
- return {
- left: minX,
- top: minY,
- width: maxX - minX,
- height: maxY - minY
- }
-}
-
-// Get bounding rect for multiple nodes
-export const getNodeListBoundingRect = (
- nodeList: Node[],
- x: number = 0,
- y: number = 0,
- paddingX: number = 0,
- paddingY: number = 0
-): BoundingRect => {
- let minX: number = Infinity
- let maxX: number = -Infinity
- let minY: number = Infinity
- let maxY: number = -Infinity
-
- nodeList.forEach(node => {
- const { left, top, width, height } = getNodeTreeBoundingRect(
- node,
- x,
- y,
- paddingX,
- paddingY,
- false,
- true
- )
- if (left < minX) {
- minX = left
- }
- if (left + width > maxX) {
- maxX = left + width
- }
- if (top < minY) {
- minY = top
- }
- if (top + height > maxY) {
- maxY = top + height
- }
- })
- return {
- left: minX,
- top: minY,
- width: maxX - minX,
- height: maxY - minY
- }
-}
-
-// Create foreignObject node
-export const createForeignObjectNode = ({ el, width, height }: ForeignObjectConfig): ForeignObject => {
- const foreignObject = new ForeignObject()
- if (width !== undefined) {
- foreignObject.width(width)
- }
- if (height !== undefined) {
- foreignObject.height(height)
- }
- // 使用 node 属性直接设置原生 DOM 元素
- foreignObject.node.appendChild(el)
- return foreignObject
-}
-
-// Format node generalization data
-export const formatGetNodeGeneralization = (data: any) => {
- const generalization = data.generalization
- if (generalization) {
- return Array.isArray(generalization) ? generalization : [generalization]
- } else {
- return []
- }
-}
-
-// Sort node list by sortIndex
-export const sortNodeList = (nodeList: Node[]): Node[] => {
- nodeList = [...nodeList]
- nodeList.sort((a, b) => {
- return a.sortIndex - b.sortIndex
- })
- return nodeList
-}
-
-// Check if node is outside canvas
-export const checkNodeOuter = (mindMap: {
- elRect: { width: number, height: number },
- draw: {
- transform: () => {
- scaleX: number,
- scaleY: number,
- translateX: number,
- translateY: number
- }
- }
-}, node: Node): {
- isOuter: boolean,
- offsetLeft: number,
- offsetTop: number
-} => {
- let elRect = mindMap.elRect
- let { scaleX, scaleY, translateX, translateY } = mindMap.draw.transform()
- let { left, top, width, height } = node
- let right = (left + width) * scaleX + translateX
- let bottom = (top + height) * scaleY + translateY
- left = left * scaleX + translateX
- top = top * scaleY + translateY
- let offsetLeft = 0
- let offsetTop = 0
- if (left < 0) {
- offsetLeft = -left
- }
- if (right > elRect.width) {
- offsetLeft = -(right - elRect.width)
- }
- if (top < 0) {
- offsetTop = -top
- }
- if (bottom > elRect.height) {
- offsetTop = -(bottom - elRect.height)
- }
- return {
- isOuter: offsetLeft !== 0 || offsetTop !== 0,
- offsetLeft,
- offsetTop
- }
-}
-
-// Check if two node lists contain same nodes
-export const checkNodeListIsEqual = (list1: Node[], list2: Node[]): boolean => {
- if (list1.length !== list2.length) return false
- for (let i = 0; i < list1.length; i++) {
- if (
- !list2.find(item => {
- return item.uid === list1[i].uid
- })
- ) {
- return false
- }
- }
- return true
-}
-
-// Handle extra content when getting SVG content
-export const handleGetSvgDataExtraContent = ({
- addContentToHeader,
- addContentToFooter
-}: ExtraContentConfig): ExtraContentResult => {
- const cssTextList: string[] = []
- let header: ForeignObject | null = null
- let headerHeight = 0
- let footer: ForeignObject | null = null
- let footerHeight = 0
-
- const handle = (fn: (() => {
- el: HTMLElement,
- cssText?: string,
- height: number
- } | void) | undefined, callback: (foreignObject: ForeignObject, height: number) => void): void => {
- if (typeof fn === 'function') {
- const res = fn()
- if (!res) return
- const { el, cssText, height } = res
- if (el instanceof HTMLElement) {
- addXmlns(el)
- const foreignObject = createForeignObjectNode({ el, height })
- callback(foreignObject, height)
- }
- if (cssText) {
- cssTextList.push(cssText)
- }
- }
- }
-
- handle(addContentToHeader, (foreignObject, height) => {
- header = foreignObject
- headerHeight = height
- })
- handle(addContentToFooter, (foreignObject, height) => {
- footer = foreignObject
- footerHeight = height
- })
-
- return {
- cssTextList,
- header,
- headerHeight,
- footer,
- footerHeight
- }
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Nodes.ts b/packages/mindmap/src/utils/Nodes.ts
deleted file mode 100644
index 3770544..0000000
--- a/packages/mindmap/src/utils/Nodes.ts
+++ /dev/null
@@ -1,217 +0,0 @@
-import { nodeDataNoStylePropList } from "../constants/constant"
-import { lineStyleProps, ThemeConfig } from "../theme"
-import { createUid } from "./Number"
-import { isUndef } from "./Object"
-import { FontOptions, joinFontStr } from "./Theme"
-import { Node } from "../types"
-
-// 判断一个字段是否是节点数据中的样式字段
-export const checkIsNodeStyleDataKey = (key: string): boolean => {
- // 用户自定义字段
- if (/^_/.test(key)) return false
- // 不在节点非样式字段列表里,那么就是样式字段
- if (!nodeDataNoStylePropList.includes(key)) {
- return true
- }
- return false
-}
-
-// 判断一个对象是否不需要触发节点重新创建
-export const isNodeNotNeedRenderData = (config: Record): boolean => {
- const list: string[] = [...lineStyleProps] // 节点连线样式
- const keys = Object.keys(config)
- for (let i = 0; i < keys.length; i++) {
- if (!list.includes(keys[i])) {
- return false
- }
- }
- return true
-}
-
-
-// 从节点实例列表里找出顶层的节点
-export const getTopAncestorsFomNodeList = (list: Node[]): Node[] => {
- let res: Node[] = []
- list.forEach(node => {
- if (
- !list.find(item => {
- return item.uid !== node.uid && item.isAncestor(node)
- })
- ) {
- res.push(node)
- }
- })
- return res
-}
-
-// 从给定的节点实例列表里判断是否存在上下级关系
-export const checkHasSupSubRelation = (list: Node[]): boolean => {
- for (let i = 0; i < list.length; i++) {
- const cur = list[i]
- if (
- list.find(item => {
- return item.uid !== cur.uid && cur.isAncestor(item)
- })
- ) {
- return true
- }
- }
- return false
-}
-
-interface GeneralizationNode {
- node: Node
- range?: [number, number]
-}
-
-// 解析要添加概要的节点实例列表
-export const parseAddGeneralizationNodeList = (list: Node[]): GeneralizationNode[] => {
- const cache: Record> = {}
- const uidToParent: Record = {}
- list.forEach(node => {
- const parent = node.parent
- if (parent) {
- const pUid = parent.uid
- uidToParent[pUid] = parent
- const index = node.getIndexInBrothers()
- const data = {
- node,
- index
- }
- if (cache[pUid]) {
- if (
- !cache[pUid].find(item => {
- return item.index === data.index
- })
- ) {
- cache[pUid].push(data)
- }
- } else {
- cache[pUid] = [data]
- }
- }
- })
- const res: GeneralizationNode[] = []
- Object.keys(cache).forEach(uid => {
- if (cache[uid].length > 1) {
- const rangeList = cache[uid]
- .map(item => {
- return item.index
- })
- .sort((a, b) => {
- return a - b
- })
- res.push({
- node: uidToParent[uid],
- range: [rangeList[0], rangeList[rangeList.length - 1]]
- })
- } else {
- res.push({
- node: cache[uid][0].node
- })
- }
- })
- return res
-}
-
-// 给指定的节点列表树数据添加附加数据,会修改原数据
-export const addDataToAppointNodes = (appointNodes: Node[], data: Record = {}): Node[] => {
- data = { ...data }
- const alreadyIsRichText = data && data.richText
- // 如果指定的数据就是富文本格式,那么不需要重新创建
- if (alreadyIsRichText && data.resetRichText) {
- delete data.resetRichText
- }
- const walk = (list: Node[]) => {
- list.forEach(node => {
- node.data = {
- ...node.data,
- ...data
- }
- if (node.children && node.children.length > 0) {
- walk(node.children)
- }
- })
- }
- walk(appointNodes)
- return appointNodes
-}
-
-// 给指定的节点列表树数据添加uid,会修改原数据
-export const createUidForAppointNodes = (
- appointNodes: Node[],
- createNewId: boolean = false,
- handle: ((node: Node) => void) | null = null
-): Node[] => {
- const walk = (list: Node[]) => {
- list.forEach(node => {
- if (!node.data) {
- node.data = {}
- }
- if (createNewId || isUndef(node.data.uid)) {
- node.data.uid = createUid()
- }
- handle && handle(node)
- if (node.children && node.children.length > 0) {
- walk(node.children)
- }
- })
- }
- walk(appointNodes)
- return appointNodes
-}
-
-// 获取节点在同级里的位置索引
-// 获取节点在同级里的位置索引
-export const getNodeDataIndex = (node: Node): number => {
- if (!node?.parent?.nodeData?.children) return -1
- return node.parent.nodeData.children.findIndex(item => {
- return item.data.uid === node.uid
- })
-}
-// 从一个节点列表里找出某个节点的索引
-export const getNodeIndexInNodeList = (node: Node, nodeList: Node[]): number => {
- return nodeList.findIndex(item => {
- return item.uid === node.uid
- })
-}
-
-// 从节点的父节点的nodeData.children列表中移除该节点的数据
-export const removeFromParentNodeData = (node: Node | null): void => {
- // 检查 node 和 parent 是否存在
- if (!node?.parent?.nodeData?.children) return
- const index = getNodeDataIndex(node)
- if (index === -1) return
- node.parent.nodeData.children.splice(index, 1)
-}
-
-interface TextMetrics {
- width: number
- height: number
-}
-
-//计算节点的文本长宽
-let measureTextContext: CanvasRenderingContext2D | null = null
-export const measureText = (text: string, { italic, bold, fontSize, fontFamily }: FontOptions): TextMetrics => {
- const font = joinFontStr({
- italic,
- bold,
- fontSize,
- fontFamily
- })
- if (!measureTextContext) {
- const canvas = document.createElement('canvas')
- measureTextContext = canvas.getContext('2d')
- }
- // 先进行空值检查
- if (!measureTextContext) {
- throw new Error('Failed to get 2D context')
- }
- measureTextContext?.save()
- measureTextContext.font = font
- const { width, actualBoundingBoxAscent, actualBoundingBoxDescent } =
- measureTextContext.measureText(text)
- measureTextContext.restore()
- const height = actualBoundingBoxAscent + actualBoundingBoxDescent
- return { width, height }
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Number.ts b/packages/mindmap/src/utils/Number.ts
deleted file mode 100644
index 1ad4e84..0000000
--- a/packages/mindmap/src/utils/Number.ts
+++ /dev/null
@@ -1,98 +0,0 @@
-import { v4 as uuidv4 } from 'uuid';
-
-// 角度转弧度
-export const degToRad = (deg: number): number => {
- return deg * (Math.PI / 180);
-};
-
-// 判断两个矩形是否重叠
-export const checkTwoRectIsOverlap = (
- minx1: number,
- maxx1: number,
- miny1: number,
- maxy1: number,
- minx2: number,
- maxx2: number,
- miny2: number,
- maxy2: number
-): boolean => {
- return maxx1 > minx2 && maxx2 > minx1 && maxy1 > miny2 && maxy2 > miny1;
-};
-
-// 创建节点唯一的id
-export const createUid = (): string => {
- return uuidv4();
-};
-
-// 计算两个点的直线距离
-export const getTwoPointDistance = (
- x1: number,
- y1: number,
- x2: number,
- y2: number
-): number => {
- return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
-};
-
-interface Rect {
- x: number;
- y: number;
- width: number;
- height: number;
-}
-
-type Direction =
- | 'left-top'
- | 'right-top'
- | 'right-bottom'
- | 'left-bottom'
- | 'left'
- | 'right'
- | 'top'
- | 'bottom'
- | 'overlap';
-
-// 判断两个矩形的相对位置
-// 第一个矩形在第二个矩形的什么方向
-export const getRectRelativePosition = (rect1: Rect, rect2: Rect): Direction => {
- // 获取第一个矩形的中心点坐标
- const rect1CenterX = rect1.x + rect1.width / 2;
- const rect1CenterY = rect1.y + rect1.height / 2;
-
- // 获取第二个矩形的中心点坐标
- const rect2CenterX = rect2.x + rect2.width / 2;
- const rect2CenterY = rect2.y + rect2.height / 2;
-
- // 判断第一个矩形在第二个矩形的哪个方向
- if (rect1CenterX < rect2CenterX && rect1CenterY < rect2CenterY) {
- return 'left-top';
- } else if (rect1CenterX > rect2CenterX && rect1CenterY < rect2CenterY) {
- return 'right-top';
- } else if (rect1CenterX > rect2CenterX && rect1CenterY > rect2CenterY) {
- return 'right-bottom';
- } else if (rect1CenterX < rect2CenterX && rect1CenterY > rect2CenterY) {
- return 'left-bottom';
- } else if (rect1CenterX < rect2CenterX && rect1CenterY === rect2CenterY) {
- return 'left';
- } else if (rect1CenterX > rect2CenterX && rect1CenterY === rect2CenterY) {
- return 'right';
- } else if (rect1CenterX === rect2CenterX && rect1CenterY < rect2CenterY) {
- return 'top';
- } else if (rect1CenterX === rect2CenterX && rect1CenterY > rect2CenterY) {
- return 'bottom';
- } else {
- return 'overlap';
- }
-};
-
-// 缩放宽度
-export const zoomWidth = (ratio: number, height: number): number => {
- // w / height = ratio
- return ratio * height
-}
-
-// 缩放高度
-export const zoomHeight = (ratio: number, width: number): number => {
- // width / h = ratio
- return width / ratio
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Object.ts b/packages/mindmap/src/utils/Object.ts
deleted file mode 100644
index 768056b..0000000
--- a/packages/mindmap/src/utils/Object.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-import { NodeData, TreeNode } from "../types"
-
-// 获取一个数据的类型
-export const getType = (data: any): string => {
- return Object.prototype.toString.call(data).slice(8, -1)
-}
-
-// 判断一个数据是否是null和undefined和空字符串
-export const isUndef = (data: any): boolean => {
- return data === null || data === undefined || data === ''
-}
-
-// 获取对象改变了的的属性
-export const getObjectChangedProps = (oldObject: Record, newObject: Record): Record => {
- const res: Record = {}
- Object.keys(newObject).forEach(prop => {
- const oldVal = oldObject[prop]
- const newVal = newObject[prop]
- if (getType(oldVal) !== getType(newVal)) {
- res[prop] = newVal
- return
- }
- if (getType(oldVal) === 'Object') {
- if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
- res[prop] = newVal
- return
- }
- } else {
- if (oldVal !== newVal) {
- res[prop] = newVal
- return
- }
- }
- })
- return res
-}
-
-// 判断两个对象是否相同,只处理对象或数组
-export const isSameObject = (a: any, b: any): boolean => {
- const type = getType(a)
- if (type !== getType(b)) return false
- if (type === 'Object') {
- const keysa = Object.keys(a)
- const keysb = Object.keys(b)
- if (keysa.length !== keysb.length) return false
- for (let i = 0; i < keysa.length; i++) {
- const key = keysa[i]
- if (!keysb.includes(key)) return false
- const isSame = isSameObject(a[key], b[key])
- if (!isSame) {
- return false
- }
- }
- return true
- } else if (type === 'Array') {
- if (a.length !== b.length) return false
- for (let i = 0; i < a.length; i++) {
- const itema = a[i]
- const itemb = b[i]
- const typea = getType(itema)
- const typeb = getType(itemb)
- if (typea !== typeb) return false
- const isSame = isSameObject(itema, itemb)
- if (!isSame) {
- return false
- }
- }
- return true
- } else {
- return a === b
- }
-}
-
-// 传入一个数据,如果该数据是数组,那么返回该数组,否则返回一个以该数据为成员的数组
-export const formatDataToArray = (data: T | T[]): T[] => {
- if (!data) return []
- return Array.isArray(data) ? data : [data]
-}
-
-// 极简的深拷贝
-export const simpleDeepClone = (data: T): T | null => {
- try {
- return JSON.parse(JSON.stringify(data))
- } catch (error) {
- return null
- }
-}
-
-
-interface ObjectNode {
- isRoot: boolean;
- data: NodeData;
- children: string[];
-}
-
-const _findParentUid = (data: Record, targetUid: string): string => {
- const uids = Object.keys(data)
- let res = ''
- uids.forEach(uid => {
- const children = data[uid].children
- const isParent = children.findIndex(childUid => childUid === targetUid) !== -1
- if (isParent) {
- res = uid
- }
- })
- return res
-}
-
-export const transformTreeDataToObject = (data: TreeNode): Record => {
- const res: Record = {}
- const walk = (root: TreeNode, parent: ObjectNode | null) => {
- const uid = root.data.uid
- if (parent) {
- parent.children.push(uid)
- }
- res[uid] = {
- isRoot: !parent,
- data: {
- ...root.data
- },
- children: []
- }
- if (root.children && root.children.length > 0) {
- root.children.forEach(item => {
- walk(item, res[uid])
- })
- }
- }
- walk(data, null)
- return res
-}
-
-export const transformObjectToTreeData = (data: Record): TreeNode | null => {
- const uids = Object.keys(data)
- if (uids.length <= 0) return null
- const rootKey = uids.find(uid => data[uid].isRoot)
- if (!rootKey || !data[rootKey]) return null
-
- const res: TreeNode = {
- data: simpleDeepClone(data[rootKey].data) as TreeNode['data'],
- children: []
- }
- const map: Record = {}
- map[rootKey] = res
-
- uids.forEach(uid => {
- const parentUid = _findParentUid(data, uid)
- const cur = data[uid]
- const node: TreeNode = map[uid] || {
- data: simpleDeepClone(cur.data) as TreeNode['data'],
- children: []
- }
- if (!map[uid]) {
- map[uid] = node
- }
- if (parentUid) {
- const index = data[parentUid].children.findIndex(item => item === uid)
- if (!map[parentUid]) {
- map[parentUid] = {
- data: simpleDeepClone(data[parentUid].data) as TreeNode['data'],
- children: []
- }
- }
- map[parentUid].children[index] = node
- }
- })
- return res
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Platform.ts b/packages/mindmap/src/utils/Platform.ts
deleted file mode 100644
index a2beabd..0000000
--- a/packages/mindmap/src/utils/Platform.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// 判断是否是移动端环境
-export const isMobile = () => {
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
- navigator.userAgent
- )
- }
- // 检查navigator.clipboard对象的读取是否可用
-export const checkClipboardReadEnable = () => {
- return navigator.clipboard && typeof navigator.clipboard.read === 'function'
- }// 获取浏览器的chrome内核版本
-export const getChromeVersion = () => {
- const match = navigator.userAgent.match(/\s+Chrome\/(.*)\s+/)
- if (match && match[1]) {
- return Number.parseFloat(match[1])
- }
- return ''
- }
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Security.ts b/packages/mindmap/src/utils/Security.ts
deleted file mode 100644
index e1a7551..0000000
--- a/packages/mindmap/src/utils/Security.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * 防御 XSS 攻击,过滤恶意 HTML 标签和属性
- * @param {string} text 需要过滤的文本
- * @returns {string} 过滤后的文本
- */
-export const defenseXSS = (text: string | number): string => {
- text = String(text)
-
- // 初始化结果变量
- let result: string = text
-
- // 使用正则表达式匹配 HTML 标签
- const match: RegExpMatchArray | null = text.match(/<(\S*?)[^>]*>.*?|<.*? \/>/g)
- if (match == null) {
- // 如果没有匹配到任何标签,则直接返回原始文本
- return text
- }
-
- // 遍历匹配到的标签
- for (const value of match) {
- // 定义白名单属性正则表达式(style、target、href)
- const whiteAttrRegex: RegExp = new RegExp(/(style|target|href)=["'][^"']*["']/g)
-
- // 定义黑名单href正则表达式(javascript:)
- const aHrefBlackRegex: RegExp = new RegExp(/href=["']javascript:/g)
-
- // 过滤 HTML 标签
- const filterHtml: string = value.replace(
- // 匹配属性键值对(如:key="value")
- /([a-zA-Z-]+)\s*=\s*["']([^"']*)["']/g,
- (text: string): string => {
- // 如果属性值包含黑名单href或不在白名单中,则删除该属性
- if (aHrefBlackRegex.test(text) || !whiteAttrRegex.test(text)) {
- return ''
- }
-
- // 否则,保留该属性
- return text
- }
- )
-
- // 将过滤后的标签替换回原始文本
- result = result.replace(value, filterHtml)
- }
-
- // 返回最终结果
- return result
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/String.ts b/packages/mindmap/src/utils/String.ts
deleted file mode 100644
index 8d4171e..0000000
--- a/packages/mindmap/src/utils/String.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import { selfCloseTagList } from "../constants/constant"
-
-// 驼峰转连字符
-export const camelCaseToHyphen = (str: string): string => {
- return str.replace(/([a-z])([A-Z])/g, (...args: string[]): string => {
- return args[1] + '-' + args[2].toLowerCase()
- })
-}
-
-// 检查一个字符串是否是富文本字符
-let checkIsRichTextEl: HTMLDivElement | null = null
-export const checkIsRichText = (str: string): boolean => {
- if (!checkIsRichTextEl) {
- checkIsRichTextEl = document.createElement('div')
- }
- checkIsRichTextEl.innerHTML = str
- for (let c = checkIsRichTextEl.childNodes, i = c.length; i--;) {
- if (c[i].nodeType === 1) return true
- }
- return false
-}
-
-// html转义
-export const htmlEscape = (str?: string): string => {
- [
- ['&', '&'],
- ['<', '<'],
- ['>', '>']
- ].forEach((item: string[]) => {
- str = str?.replace(new RegExp(item[0], 'g'), item[1])
- })
- return str || ''
-}
-
-// 给html自闭合标签添加闭合状态
-export const handleSelfCloseTags = (str: string): string => {
- selfCloseTagList.forEach((tagName: string) => {
- str = str.replaceAll(
- new RegExp(`<${tagName}([^>]*)>`, 'g'),
- `<${tagName} $1 />`
- )
- })
- return str
-}
-
-// 从头html结构字符串里获取带换行符的字符串
-export const getStrWithBrFromHtml = (str: string): string => {
- str = str.replace(/
/gim, '\n')
- const el = document.createElement('div')
- el.innerHTML = str
- str = el.textContent || ''
- return str
-}
-
-interface DataUrlResult {
- type: string
- base64: string
-}
-
-// 解析dataUrl
-export const parseDataUrl = (data: string): string | DataUrlResult => {
- if (!/^data:/.test(data)) return data
- const [typeStr, base64] = data.split(',')
- const res = /^data:[^/]+\/([^;]+);/.exec(typeStr)
- if (!res) throw new Error('Invalid data URL')
- const type = res[1]
- return {
- type,
- base64
- }
-}
-
-// 将以空格分隔的字符串值转换成成数字/单位/值数组
-export const getNumberValueFromStr = (value: string | number) => {
- let arr = String(value).split(/\s+/)
- return arr.map(item => {
- if (/^[\d.]+/.test(item)) {
- // 数字+单位
- let res = /^([\d.]+)(.*)$/.exec(item)
- if (!res) return item
- return [Number(res[1]), res[2]]
- } else {
- // 单个值
- return item
- }
- })
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Task.ts b/packages/mindmap/src/utils/Task.ts
deleted file mode 100644
index 5c7c8f9..0000000
--- a/packages/mindmap/src/utils/Task.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-// 在下一个事件循环里执行任务
-export const nextTick = function (fn: Function, ctx?: any): () => void {
- let pending = false;
- let timerFunc: Function | null = null;
- let handle = (): void => {
- pending = false;
- ctx ? fn.call(ctx) : fn();
- };
-
- // 支持MutationObserver接口的话使用MutationObserver
- if (typeof MutationObserver !== 'undefined') {
- let counter = 1;
- let observer = new MutationObserver(handle);
- let textNode = document.createTextNode(String(counter));
- observer.observe(textNode, {
- characterData: true // 设为 true 表示监视指定目标节点或子节点树中节点所包含的字符数据的变化
- });
- timerFunc = function (): void {
- counter = (counter + 1) % 2; // counter会在0和1两者循环变化
- textNode.data = String(counter); // 节点变化会触发回调handle
- };
- } else {
- // 否则使用定时器
- timerFunc = setTimeout;
- }
-
- return function (): void {
- if (pending) return;
- pending = true;
- timerFunc(handle, 0);
- };
-};
-
-// 节流函数
-export const throttle = any>(
- fn: T,
- time: number = 300,
- ctx?: any
-): ((...args: Parameters) => void) => {
- let timer: ReturnType | null = null;
- return (...args: Parameters): void => {
- if (timer) {
- return;
- }
- timer = setTimeout(() => {
- fn.call(ctx, ...args);
- timer = null;
- }, time);
- };
-};
-
-// 防抖函数
-export const debounce = any>(
- fn: T,
- wait: number = 300,
- ctx?: any
-): ((...args: Parameters) => void) => {
- let timeout: ReturnType | null = null;
-
- return (...args: Parameters): void => {
- if (timeout) clearTimeout(timeout);
- const callNow = !timeout;
- timeout = setTimeout(() => {
- timeout = null;
- fn.apply(ctx, args);
- }, wait);
- if (callNow) fn.apply(ctx, args);
- };
-};
-
-// 异步执行任务队列
-export const asyncRun = (
- taskList: Array<() => void>,
- callback: () => void = () => { }
-): void => {
- let index = 0;
- let len = taskList.length;
- if (len <= 0) {
- return callback();
- }
- let loop = (): void => {
- if (index >= len) {
- callback();
- return;
- }
- taskList[index]();
- setTimeout(() => {
- index++;
- loop();
- }, 0);
- };
- loop();
-};
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Theme.ts b/packages/mindmap/src/utils/Theme.ts
deleted file mode 100644
index 5f0a4a8..0000000
--- a/packages/mindmap/src/utils/Theme.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import MersenneTwister from "./mersenneTwister"
-import { ThemeConfig } from "../theme"
-import { richTextSupportStyleList } from "../constants/constant"
-import merge from 'deepmerge'
-
-// 判断一个颜色是否是白色
-export const isWhite = (color: string): boolean => {
- color = String(color).replaceAll(/\s+/g, '')
- return (
- ['#fff', '#ffffff', '#FFF', '#FFFFFF', 'rgb(255,255,255)'].includes(
- color
- ) || /rgba\(255,255,255,[^)]+\)/.test(color)
- )
-}
-
-// 判断一个颜色是否是透明
-export const isTransparent = (color: string): boolean => {
- color = String(color).replaceAll(/\s+/g, '')
- return (
- ['', 'transparent'].includes(color) || /rgba\(\d+,\d+,\d+,0\)/.test(color)
- )
-}
-
-// 从当前主题里获取一个非透明非白色的颜色
-export const getVisibleColorFromTheme = (themeConfig: ThemeConfig): string | undefined => {
- const { lineColor, root, second, node } = themeConfig
- const list = [
- lineColor,
- root.fillColor,
- root.color,
- second.fillColor,
- second.color,
- node.fillColor,
- node.color,
- root.borderColor,
- second.borderColor,
- node.borderColor
- ]
- for (let i = 0; i < list.length; i++) {
- const color = list[i]
- if (!isTransparent(color) && !isWhite(color)) {
- return color
- }
- }
- return undefined
-}
-
-// 根据内容生成颜色
-export const generateColorByContent = (str: string): string => {
- let hash = 0
- for (let i = 0; i < str.length; i++) {
- hash = str.charCodeAt(i) + ((hash << 5) - hash)
- }
- // 这里使用伪随机数的原因是因为
- // 1. 如果字符串的内容差不多,根据hash生产的颜色就比较相近,不好区分,比如v1.1 v1.2,所以需要加入随机数来使得颜色能够区分开
- // 2. 普通的随机数每次数值不一样,就会导致每次新增标签原来的标签颜色就会发生改变,所以加入了这个方法,使得内容不变随机数也不变
- const rng = new MersenneTwister(hash)
- const h = rng.genrand_int32() % 360
- return 'hsla(' + h + ', 50%, 50%, 1)'
-}
-
-interface IconItem {
- type: string
- list: Array<{
- name: string
- icon: string
- }>
-}
-
-export const mergerIconList = (list: IconItem[]): IconItem[] => {
- return list.reduce((result: IconItem[], item) => {
- const existingItem = result.find(x => x.type === item.type)
- if (existingItem) {
- item.list.forEach(newObj => {
- const existingObj = existingItem.list.find(x => x.name === newObj.name)
- if (existingObj) {
- existingObj.icon = newObj.icon
- } else {
- existingItem.list.push(newObj)
- }
- })
- } else {
- result.push({ ...item })
- }
- return result
- }, [])
-}
-
-// 合并主题配置
-export const mergeTheme = (dest: T, source: T): T => {
- return merge(dest, source, {
- arrayMerge: (_destinationArray: any[], sourceArray: any[]) => sourceArray
- })
-}
-
-interface NodeStyle {
- merge: (prop: string) => string | number
-}
-
-interface Node {
- style: NodeStyle
-}
-
-// 获取节点实例的文本样式数据
-export const getNodeRichTextStyles = (node: Node): Record => {
- const res: Record = {}
- richTextSupportStyleList.forEach(prop => {
- let value = node.style.merge(prop)
- if (prop === 'fontSize') {
- value = value + 'px'
- }
- res[prop] = String(value)
- })
- return res
-}
-
-export interface FontOptions {
- italic?: boolean;
- bold?: boolean;
- fontSize: number;
- fontFamily: string;
-}
-
-// 拼接font字符串
-export const joinFontStr = ({ italic, bold, fontSize, fontFamily }: FontOptions): string => {
- return `${italic ? 'italic ' : ''} ${bold ? 'bold ' : ''
- } ${fontSize}px ${fontFamily} `
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Tools.ts b/packages/mindmap/src/utils/Tools.ts
deleted file mode 100644
index e32a25a..0000000
--- a/packages/mindmap/src/utils/Tools.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-import { DrawOptions } from "../types"
-import { getTextFromHtml } from "./Dom"
-import { checkClipboardReadEnable } from "./Platform"
-import { htmlEscape } from "./String"
-
-// 将数据设置到用户剪切板中
-export const setDataToClipboard = (data: any): void => {
- if (navigator.clipboard && navigator.clipboard.writeText) {
- navigator.clipboard.writeText(JSON.stringify(data))
- }
-}
-
-// 从用户剪贴板中读取文字和图片
-export const getDataFromClipboard = async (): Promise<{
- text: string | null,
- img: Blob | null
-}> => {
- let text: string | null = null
- let img: Blob | null = null
- if (checkClipboardReadEnable()) {
- const items = await navigator.clipboard.read()
- if (items && items.length > 0) {
- for (const clipboardItem of items) {
- for (const type of clipboardItem.types) {
- if (/^image\//.test(type)) {
- img = await clipboardItem.getType(type)
- } else if (type === 'text/plain') {
- const blob = await clipboardItem.getType(type)
- text = await blob.text()
- }
- }
- }
- }
- }
- return {
- text,
- img
- }
-}
-
-export const exitFullscreen = (): void => {
- if (!document.fullscreenElement) return;
- if (document.exitFullscreen) {
- document.exitFullscreen();
- } else if ((document as any).webkitExitFullscreen) {
- (document as any).webkitExitFullscreen();
- } else if ((document as any).mozCancelFullScreen) {
- (document as any).mozCancelFullScreen();
- }
-};
-
-// 全屏事件检测
-const getOnfullscreenEvent = (): string | undefined => {
- if ((document.documentElement as any).requestFullscreen) {
- return 'fullscreenchange';
- } else if ((document.documentElement as any).webkitRequestFullscreen) {
- return 'webkitfullscreenchange';
- } else if ((document.documentElement as any).mozRequestFullScreen) {
- return 'mozfullscreenchange';
- } else if ((document.documentElement as any).msRequestFullscreen) {
- return 'msfullscreenchange';
- }
- return undefined;
-};
-
-export const fullscreenEvent = getOnfullscreenEvent();
-
-// 全屏
-export const fullScreen = (element: Element): void => {
- if (element.requestFullscreen) {
- element.requestFullscreen();
- } else if ((element as any).webkitRequestFullscreen) {
- (element as any).webkitRequestFullscreen();
- } else if ((element as any).mozRequestFullScreen) {
- (element as any).mozRequestFullScreen();
- }
-};
-
-interface SmmData {
- simpleMindMap: boolean
- data: any
-}
-
-// 创建smm粘贴的粘贴数据
-export const createSmmFormatData = (data: any): SmmData => {
- return {
- simpleMindMap: true,
- data
- }
-}
-
-// 检查是否是smm粘贴格式的数据
-export const checkSmmFormatData = (data: any): {
- isSmm: boolean,
- data: any
-} => {
- let smmData: any = null
- // 如果是字符串,则尝试解析为对象
- if (typeof data === 'string') {
- try {
- const parsedData = JSON.parse(data)
- // 判断是否是对象,且存在属性标志
- if (typeof parsedData === 'object' && parsedData.simpleMindMap) {
- smmData = parsedData.data
- }
- } catch (error) { }
- } else if (typeof data === 'object' && data.simpleMindMap) {
- // 否则如果是对象,则检查属性标志
- smmData = data.data
- }
- const isSmm = !!smmData
- return {
- isSmm,
- data: isSmm ? smmData : String(data)
- }
-}
-
-// 处理输入框的粘贴事件,会去除文本的html格式、换行
-export const handleInputPasteText = (e: ClipboardEvent, text?: string): void => {
- e.preventDefault()
- const selection = window.getSelection()
- if (!selection?.rangeCount) return
- selection.deleteFromDocument()
- text = text || e.clipboardData?.getData('text')
- // 转义特殊字符
- text = htmlEscape(text)
- // 去除格式
- text = getTextFromHtml(text)
- const textArr = text.split(/\n/g)
- const fragment = document.createDocumentFragment()
- textArr.forEach((item, index) => {
- const node = document.createTextNode(item)
- fragment.appendChild(node)
- if (index < textArr.length - 1) {
- const br = document.createElement('br')
- fragment.appendChild(br)
- }
- })
- selection.getRangeAt(0).insertNode(fragment)
- selection.collapseToEnd()
-}
-
-
-export const drawImage = (
- ctx: CanvasRenderingContext2D,
- image: CanvasImageSource,
- drawOpt: DrawOptions
-): void => {
- ctx.drawImage(
- image,
- drawOpt.sx,
- drawOpt.sy,
- drawOpt.swidth,
- drawOpt.sheight,
- drawOpt.x,
- drawOpt.y,
- drawOpt.width,
- drawOpt.height
- )
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Tree.ts b/packages/mindmap/src/utils/Tree.ts
deleted file mode 100644
index 2e3d352..0000000
--- a/packages/mindmap/src/utils/Tree.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-import { Node } from "../types";
-import { formatGetNodeGeneralization } from "./NodeTools"
-import { createUid } from "./Number";
-import { simpleDeepClone } from "./Object"
-
-
-
-type WalkCallback = (
- node: Node,
- parent: Node | null,
- isRoot: boolean,
- layerIndex: number,
- index: number,
- ancestors: Node[]
-) => boolean | void;
-
-type BFSCallback = (node: Node, parent: Node | null) => 'stop' | void;
-
-export const walk = (
- root: Node,
- parent: Node | null,
- beforeCallback?: WalkCallback,
- afterCallback?: WalkCallback,
- isRoot: boolean = false,
- layerIndex: number = 0,
- index: number = 0,
- ancestors: Node[] = []
-): void => {
- let stop = false;
- if (beforeCallback) {
- stop = !!beforeCallback(root, parent, isRoot, layerIndex, index, ancestors);
- }
- if (!stop && root.children && root.children.length > 0) {
- const _layerIndex = layerIndex + 1;
- root.children.forEach((node, nodeIndex) => {
- walk(
- node,
- root,
- beforeCallback,
- afterCallback,
- false,
- _layerIndex,
- nodeIndex,
- [...ancestors, root]
- );
- });
- }
- afterCallback?.call(null, root, parent, isRoot, layerIndex, index, ancestors);
-};
-
-export const bfsWalk = (root: Node, callback: BFSCallback): void => {
- const stack: Node[] = [root];
- let isStop = false;
-
- if (callback(root, null) === 'stop') {
- isStop = true;
- }
-
- while (stack.length) {
- if (isStop) break;
-
- const cur = stack.shift()!;
- if (cur.children?.length) {
- cur.children.forEach(item => {
- if (isStop) return;
- stack.push(item);
- if (callback(item, cur) === 'stop') {
- isStop = true;
- }
- });
- }
- }
-};
-
-export const copyRenderTree = (
- tree: Node,
- root: Node,
- removeActiveState: boolean = false
-): Node => {
- tree.data = simpleDeepClone(root.data);
- if (removeActiveState) {
- tree.data.isActive = false;
- const generalizationList = formatGetNodeGeneralization(tree.data);
- generalizationList.forEach(item => {
- item.isActive = false;
- });
- }
-
- tree.children = [];
- if (root.children?.length > 0) {
- root.children.forEach((item, index) => {
- tree.children![index] = copyRenderTree({} as Node, item, removeActiveState);
- });
- }
-
- Object.keys(root).forEach(key => {
- if (!['data', 'children'].includes(key) && !/^_/.test(key)) {
- tree[key] = root[key];
- }
- });
-
- return tree;
-};
-
-export const copyNodeTree = (
- tree: Node,
- root: Node,
- removeActiveState: boolean = false,
- removeId: boolean = true
-): Node => {
- const rootData = root.nodeData ? root.nodeData : root;
- tree.data = simpleDeepClone((rootData as any).data);
-
- if (removeId) {
- delete tree.data.uid;
- } else if (!tree.data.uid) {
- tree.data.uid = createUid();
- }
-
- if (removeActiveState) {
- tree.data.isActive = false;
- }
-
- tree.children = [];
- if (root.children?.length > 0) {
- root.children.forEach((item, index) => {
- tree.children![index] = copyNodeTree({} as Node, item, removeActiveState, removeId);
- });
- } else if (root.nodeData?.children?.length > 0) {
- root.nodeData.children.forEach((item, index) => {
- tree.children![index] = copyNodeTree({} as Node, item, removeActiveState, removeId);
- });
- }
-
- Object.keys(rootData).forEach(key => {
- if (!['data', 'children'].includes(key) && !/^_/.test(key)) {
- tree[key] = (rootData as any)[key];
- }
- });
-
- return tree;
-};
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/Version.ts b/packages/mindmap/src/utils/Version.ts
deleted file mode 100644
index c5e2dd3..0000000
--- a/packages/mindmap/src/utils/Version.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-// 判断两个版本号的关系
-/*
-a > b 返回 >
-a < b 返回 <
-a = b 返回 =
-*/
-export const compareVersion = (a: string | number, b: string | number): '>' | '<' | '=' => {
- const aArr: string[] = String(a).split('.')
- const bArr: string[] = String(b).split('.')
- const max: number = Math.max(aArr.length, bArr.length)
-
- for (let i = 0; i < max; i++) {
- const ai: number = Number(aArr[i]) || 0
- const bi: number = Number(bArr[i]) || 0
- if (ai > bi) {
- return '>'
- } else if (ai < bi) {
- return '<'
- }
- }
- return '='
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/index.ts b/packages/mindmap/src/utils/index.ts
deleted file mode 100644
index bce788b..0000000
--- a/packages/mindmap/src/utils/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export * from "./AutoMove"
-export * from "./BatchExecution"
-export * from "./Dom"
-export * from "./File"
-export * from "./Image"
-export * from "./Lru"
-export * from "./mersenneTwister"
-export * from "./NodeTools"
-export * from "./Nodes"
-export * from "./Number"
-export * from "./Object"
-export * from "./Platform"
-export * from "./Security"
-export * from "./simulateCSSBackgroundInCanvas"
-export * from "./String"
-export * from "./Task"
-export * from "./Theme"
-export * from "./Tools"
-export * from "./Tree"
-export * from "./Version"
diff --git a/packages/mindmap/src/utils/mersenneTwister.ts b/packages/mindmap/src/utils/mersenneTwister.ts
deleted file mode 100644
index 6cc5b92..0000000
--- a/packages/mindmap/src/utils/mersenneTwister.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * @file Mersenne Twister 伪随机数生成器
- * @description
- * 这是一个基于 Mersenne Twister 算法的伪随机数生成器(PRNG)实现。
- * 该生成器可以根据给定的种子值生成高质量的伪随机数序列。
- *
- * @usage
- * 主要用于需要可重现随机数的场景,比如:
- * 1. 基于内容哈希值作为种子,确保相同输入产生相同的随机序列
- * 2. 游戏、模拟等需要可重复随机数的应用
- * 3. 测试用例中需要稳定随机数的场景
- */
-
-/**
- * Mersenne Twister 伪随机数生成器类
- * @class MersenneTwister
- *
- * @description
- * 实现了 MT19937 算法,是一个周期为 2^19937-1 的伪随机数生成器
- *
- * @pattern 单例模式 - 每个种子对应一个独立的随机数序列
- *
- * @example
- * ```typescript
- * const mt = new MersenneTwister(12345);
- * const randomNum = mt.genrand_int32();
- * ```
- */
-export default class MersenneTwister {
- // MT19937 算法的常量参数
- private readonly N: number = 624; // 状态向量长度
- private readonly M: number = 397; // 中间点参数
- private readonly MATRIX_A: number = 0x9908b0df; // 扭矩矩阵常量
- private readonly UPPER_MASK: number = 0x80000000; // 最高位掩码(32位)
- private readonly LOWER_MASK: number = 0x7fffffff; // 低31位掩码
-
- // 内部状态
- private mt: number[]; // 状态向量数组
- private mti: number; // 当前状态索引
-
- /**
- * 构造函数
- * @param seed - 随机数生成器的种子值
- * @throws {Error} 当seed不是数字类型时抛出异常
- */
- constructor(seed: number) {
- if (typeof seed !== 'number') {
- throw new Error('种子值必须是数字类型');
- }
-
- this.mt = new Array(this.N);
- this.mti = this.N + 1;
-
- this.init_genrand(seed);
- }
-
- /**
- * 使用种子初始化状态向量
- * @param s - 初始化种子
- * @private
- */
- private init_genrand(s: number): void {
- this.mt[0] = s >>> 0;
- for (this.mti = 1; this.mti < this.N; this.mti++) {
- // 使用递推公式生成初始状态
- s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30);
- this.mt[this.mti] = (
- ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) +
- (s & 0x0000ffff) * 1812433253 +
- this.mti
- ) >>> 0;
- }
- }
-
- /**
- * 生成一个32位的随机整数
- * @returns 范围在[0, 2^32-1]之间的随机数
- * @public
- */
- public genrand_int32(): number {
- let y: number;
- const mag01: number[] = [0x0, this.MATRIX_A];
-
- // 需要重新生成状态向量
- if (this.mti >= this.N) {
- let kk: number;
-
- // 如果没有初始化,使用默认种子
- if (this.mti === this.N + 1) {
- this.init_genrand(5489);
- }
-
- // 更新状态向量的前半部分
- for (kk = 0; kk < this.N - this.M; kk++) {
- y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);
- this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
- }
-
- // 更新状态向量的后半部分
- for (; kk < this.N - 1; kk++) {
- y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK);
- this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
- }
-
- // 处理最后一个元素
- y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK);
- this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];
-
- this.mti = 0;
- }
-
- // 获取下一个随机数
- y = this.mt[this.mti++];
-
- // Tempering变换提升随机性
- y ^= y >>> 11;
- y ^= (y << 7) & 0x9d2c5680;
- y ^= (y << 15) & 0xefc60000;
- y ^= y >>> 18;
-
- return y >>> 0;
- }
-}
\ No newline at end of file
diff --git a/packages/mindmap/src/utils/simulateCSSBackgroundInCanvas.ts b/packages/mindmap/src/utils/simulateCSSBackgroundInCanvas.ts
deleted file mode 100644
index f429766..0000000
--- a/packages/mindmap/src/utils/simulateCSSBackgroundInCanvas.ts
+++ /dev/null
@@ -1,351 +0,0 @@
-import { DrawOptions } from "../types";
-import { zoomHeight, zoomWidth } from "./Number"
-import { getNumberValueFromStr } from "./String"
-import { drawImage } from "./Tools"
-
-
-// 关键词到百分比值的映射
-const keyWordToPercentageMap: Record = {
- left: 0,
- top: 0,
- center: 50,
- bottom: 100,
- right: 100
-}
-
-interface HandleBackgroundSizeParams {
- backgroundSize: string;
- drawOpt: DrawOptions;
- imageRatio: number;
- canvasWidth: number;
- canvasHeight: number;
- canvasRatio: number;
-}
-
-
-const handleBackgroundSize = ({
- backgroundSize,
- drawOpt,
- imageRatio,
- canvasWidth,
- canvasHeight,
- canvasRatio
-}: HandleBackgroundSizeParams): void => {
- if (backgroundSize) {
- // 将值转换成数组
- const backgroundSizeValueArr = getNumberValueFromStr(backgroundSize);
-
- // 两个值都为auto,那就相当于不设置
- if (
- backgroundSizeValueArr[0] === 'auto' &&
- backgroundSizeValueArr[1] === 'auto'
- ) {
- return;
- }
-
- // 值为cover
- if (backgroundSizeValueArr[0] === 'cover') {
- if (imageRatio > canvasRatio) {
- drawOpt.height = canvasHeight;
- drawOpt.width = zoomWidth(imageRatio, canvasHeight);
- } else {
- drawOpt.width = canvasWidth;
- drawOpt.height = zoomHeight(imageRatio, canvasWidth);
- }
- return;
- }
-
- // 值为contain
- if (backgroundSizeValueArr[0] === 'contain') {
- if (imageRatio > canvasRatio) {
- drawOpt.width = canvasWidth;
- drawOpt.height = zoomHeight(imageRatio, canvasWidth);
- } else {
- drawOpt.height = canvasHeight;
- drawOpt.width = zoomWidth(imageRatio, canvasHeight);
- }
- return;
- }
-
- // 图片宽度
- let newNumberWidth: number = -1;
- if (backgroundSizeValueArr[0]) {
- if (Array.isArray(backgroundSizeValueArr[0])) {
- // 数字+单位类型
- if (backgroundSizeValueArr[0][1] === '%') {
- // %单位
- drawOpt.width = (backgroundSizeValueArr[0][0] as number / 100) * canvasWidth;
- newNumberWidth = drawOpt.width;
- } else {
- // 其他都认为是px单位
- drawOpt.width = backgroundSizeValueArr[0][0] as number
- newNumberWidth = backgroundSizeValueArr[0][0] as number
- }
- } else if (backgroundSizeValueArr[0] === 'auto') {
- // auto类型,那么根据设置的新高度以图片原宽高比进行自适应
- if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {
- if (backgroundSizeValueArr[1][1] === '%') {
- // 高度为%单位
- drawOpt.width = zoomWidth(
- imageRatio,
- (backgroundSizeValueArr[1][0] as number / 100) * canvasHeight
- );
- } else {
- // 其他都认为是px单位
- drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0] as number);
- }
- }
- }
- }
-
- // 设置了图片高度
- if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {
- // 数字+单位类型
- if (backgroundSizeValueArr[1][1] === '%') {
- // 高度为%单位
- drawOpt.height = (backgroundSizeValueArr[1][0] as number / 100) * canvasHeight;
- } else {
- // 其他都认为是px单位
- drawOpt.height = backgroundSizeValueArr[1][0] as number;
- }
- } else if (newNumberWidth !== -1) {
- // 没有设置图片高度或者设置为auto,那么根据设置的新宽度以图片原宽高比进行自适应
- drawOpt.height = zoomHeight(imageRatio, newNumberWidth);
- }
- }
-};
-
-interface BackgroundPositionOptions {
- backgroundPosition: string;
- drawOpt: DrawOptions;
- imgWidth: number;
- imgHeight: number;
- canvasWidth: number;
- canvasHeight: number;
-}
-
-interface BackgroundRepeatOptions {
- ctx: CanvasRenderingContext2D;
- image: HTMLImageElement;
- backgroundRepeat: string;
- drawOpt: DrawOptions;
- imgWidth: number;
- imgHeight: number;
- canvasWidth: number;
- canvasHeight: number;
-}
-
-
-
-// 模拟background-position
-const handleBackgroundPosition = ({
- backgroundPosition,
- drawOpt,
- imgWidth,
- imgHeight,
- canvasWidth,
- canvasHeight
-}: BackgroundPositionOptions): void => {
- if (backgroundPosition) {
- // 将值转换成数组
- let backgroundPositionValueArr = getNumberValueFromStr(backgroundPosition)
- // 将关键词转为百分比
- backgroundPositionValueArr = backgroundPositionValueArr.map(item => {
- if (typeof item === 'string') {
- return keyWordToPercentageMap[item] !== undefined
- ? [keyWordToPercentageMap[item], '%']
- : item
- }
- return item
- })
- if (Array.isArray(backgroundPositionValueArr[0])) {
- if (backgroundPositionValueArr.length === 1) {
- // 如果只设置了一个值,第二个默认为50%
- backgroundPositionValueArr.push([50, '%'])
- }
- // 水平位置
- if (backgroundPositionValueArr[0][1] === '%') {
- // 单位为%
- let canvasX = (backgroundPositionValueArr[0][0] as number / 100) * canvasWidth
- let imgX = (backgroundPositionValueArr[0][0] as number / 100) * imgWidth
- // 计算差值
- drawOpt.x = canvasX - imgX
- } else {
- // 其他单位默认都为px
- drawOpt.x = backgroundPositionValueArr[0][0] as number
- }
- // 垂直位置
- if (backgroundPositionValueArr[1][1] === '%') {
- // 单位为%
- let canvasY = (backgroundPositionValueArr[1][0] as number / 100) * canvasHeight
- let imgY = (backgroundPositionValueArr[1][0] as number / 100) * imgHeight
- // 计算差值
- drawOpt.y = canvasY - imgY
- } else {
- // 其他单位默认都为px
- drawOpt.x = backgroundPositionValueArr[0][0] as number
- }
- }
- }
-}
-
-// 模拟background-repeat
-const handleBackgroundRepeat = ({
- ctx,
- image,
- backgroundRepeat,
- drawOpt,
- imgWidth,
- imgHeight,
- canvasWidth,
- canvasHeight
-}: BackgroundRepeatOptions): boolean | void => {
- if (backgroundRepeat) {
- // 保存在handleBackgroundPosition中计算出来的x、y
- let ox = drawOpt.x
- let oy = drawOpt.y
- // 计算ox和oy能平铺的图片数量
- let oxRepeatNum = Math.ceil(ox / imgWidth)
- let oyRepeatNum = Math.ceil(oy / imgHeight)
- // 计算ox和oy第一张图片的位置
- let oxRepeatX = ox - oxRepeatNum * imgWidth
- let oxRepeatY = oy - oyRepeatNum * imgHeight
- // 将值转换成数组
- let backgroundRepeatValueArr = getNumberValueFromStr(backgroundRepeat)
- // 不处理
- if (
- backgroundRepeatValueArr[0] === 'no-repeat' ||
- (imgWidth >= canvasWidth && imgHeight >= canvasHeight)
- ) {
- return
- }
- // 水平平铺
- if (backgroundRepeatValueArr[0] === 'repeat-x') {
- if (canvasWidth > imgWidth) {
- let x = oxRepeatX
- while (x < canvasWidth) {
- drawImage(ctx, image, {
- ...drawOpt,
- x
- })
- x += imgWidth
- }
- return true
- }
- }
- // 垂直平铺
- if (backgroundRepeatValueArr[0] === 'repeat-y') {
- if (canvasHeight > imgHeight) {
- let y = oxRepeatY
- while (y < canvasHeight) {
- drawImage(ctx, image, {
- ...drawOpt,
- y
- })
- y += imgHeight
- }
- return true
- }
- }
- // 平铺
- if (backgroundRepeatValueArr[0] === 'repeat') {
- let x = oxRepeatX
- while (x < canvasWidth) {
- if (canvasHeight > imgHeight) {
- let y = oxRepeatY
- while (y < canvasHeight) {
- drawImage(ctx, image, {
- ...drawOpt,
- x,
- y
- })
- y += imgHeight
- }
- }
- x += imgWidth
- }
- return true
- }
- }
-}
-
-interface DrawBackgroundImageOptions {
- backgroundSize: string;
- backgroundPosition: string;
- backgroundRepeat: string;
-}
-
-const drawBackgroundImageToCanvas = (
- ctx: CanvasRenderingContext2D,
- width: number,
- height: number,
- img: string,
- { backgroundSize, backgroundPosition, backgroundRepeat }: DrawBackgroundImageOptions,
- callback: (error?: Error) => void = () => { }
-): void => {
- // 画布的长宽比
- let canvasRatio = width / height
- // 加载图片
- let image = new Image()
- image.src = img
- image.onload = () => {
- // 图片的宽度及长宽比
- let imgWidth = image.width
- let imgHeight = image.height
- let imageRatio = imgWidth / imgHeight
- // 绘制图片
- // drawImage方法的参数值
- let drawOpt: DrawOptions = {
- sx: 0,
- sy: 0,
- swidth: imgWidth,
- sheight: imgHeight,
- x: 0,
- y: 0,
- width: imgWidth,
- height: imgHeight
- }
- // 模拟background-size
- handleBackgroundSize({
- backgroundSize,
- drawOpt,
- imageRatio,
- canvasWidth: width,
- canvasHeight: height,
- canvasRatio
- })
-
- // 模拟background-position
- handleBackgroundPosition({
- backgroundPosition,
- drawOpt,
- imgWidth: drawOpt.width,
- imgHeight: drawOpt.height,
- canvasWidth: width,
- canvasHeight: height,
- })
-
- // 模拟background-repeat
- let notNeedDraw = handleBackgroundRepeat({
- ctx,
- image,
- backgroundRepeat,
- drawOpt,
- imgWidth: drawOpt.width,
- imgHeight: drawOpt.height,
- canvasWidth: width,
- canvasHeight: height,
- })
-
- // 绘制图片
- if (!notNeedDraw) {
- drawImage(ctx, image, drawOpt)
- }
-
- callback()
- }
- image.addEventListener('error', (e: ErrorEvent) => {
- callback(e.error);
- });
-}
-export default drawBackgroundImageToCanvas
diff --git a/packages/mindmap/src/utils/xmind.js b/packages/mindmap/src/utils/xmind.js
deleted file mode 100644
index 0477022..0000000
--- a/packages/mindmap/src/utils/xmind.js
+++ /dev/null
@@ -1,244 +0,0 @@
-import {
- getImageSize,
- imgToDataUrl,
- parseDataUrl,
- getTextFromHtml,
- createUid
-} from './index'
-import { formatGetNodeGeneralization } from './index'
-
-// 解析出新xmind的概要文本
-export const getSummaryText = (node, topicId) => {
- if (node.children.summary && node.children.summary.length > 0) {
- for (let i = 0; i < node.children.summary.length; i++) {
- const cur = node.children.summary[i]
- if (cur.id === topicId) {
- return cur.title
- }
- }
- }
-}
-
-// 解析出旧xmind的概要文本
-export const getSummaryText2 = (item, topicId) => {
- const summaryElements = getElementsByType(item.elements, 'summary')
- if (summaryElements && summaryElements && summaryElements.length > 0) {
- for (let i = 0; i < summaryElements.length; i++) {
- const cur = summaryElements[i]
- if (cur.attributes.id === topicId) {
- return cur.elements &&
- cur.elements[0] &&
- cur.elements[0].elements &&
- cur.elements[0].elements[0]
- ? cur.elements[0].elements[0].text
- : ''
- }
- }
- }
- return ''
-}
-
-// 解析旧版xmind数据时,找出根节点
-export const getRoot = list => {
- let root = null
- const walk = arr => {
- if (!arr) return
- for (let i = 0; i < arr.length; i++) {
- if (!root && arr[i].name === 'topic') {
- root = arr[i]
- return
- }
- }
- arr.forEach(item => {
- walk(item.elements)
- })
- }
- walk(list)
- return root
-}
-
-// 解析旧版xmind数据,从一个数组中根据name找出该项
-export const getItemByName = (arr, name) => {
- return arr.find(item => {
- return item.name === name
- })
-}
-
-// 解析旧版xmind数据,从一个数组中根据attributes.type找出该项
-export const getElementsByType = (arr, type) => {
- return arr.find(el => {
- return el.attributes.type === type
- }).elements
-}
-
-// 解析xmind数据,将概要转换为smm支持的结构
-export const addSummaryData = (selfList, childrenList, getText, range) => {
- const summaryData = {
- expand: true,
- isActive: false,
- text: getText(),
- range: null
- }
- const match = range.match(/\((\d+),(\d+)\)/)
- if (match) {
- const startIndex = Number(match[1])
- const endIndex = Number(match[2])
- if (startIndex === endIndex) {
- childrenList[startIndex] = summaryData
- } else {
- summaryData.range = [startIndex, endIndex]
- selfList.push(summaryData)
- }
- } else {
- selfList.push(summaryData)
- }
-}
-
-// 解析xmind数据时,解析其中的图片数据
-export const handleNodeImageFromXmind = async (
- node,
- newNode,
- promiseList,
- files
-) => {
- if (node.image && /\.(jpg|jpeg|png|gif|webp)$/.test(node.image.src)) {
- // 处理异步逻辑
- let resolve = null
- const promise = new Promise(_resolve => {
- resolve = _resolve
- })
- promiseList.push(promise)
- try {
- // 读取图片
- const imageType = /\.([^.]+)$/.exec(node.image.src)[1]
- const imageBase64 =
- `data:image/${imageType};base64,` +
- (await files['resources/' + node.image.src.split('/')[1]].async(
- 'base64'
- ))
- newNode.data.image = imageBase64
- // 如果图片尺寸不存在
- if (!node.image.width && !node.image.height) {
- const imageSize = await getImageSize(imageBase64)
- newNode.data.imageSize = {
- width: imageSize.width,
- height: imageSize.height
- }
- } else {
- newNode.data.imageSize = {
- width: node.image.width,
- height: node.image.height
- }
- }
- resolve()
- } catch (error) {
- console.log(error)
- resolve()
- }
- }
-}
-
-// 导出为xmind时,处理图片数据
-export const handleNodeImageToXmind = async (
- node,
- newData,
- promiseList,
- imageList
-) => {
- if (node.data.image) {
- // 处理异步逻辑
- let resolve = null
- let promise = new Promise(_resolve => {
- resolve = _resolve
- })
- promiseList.push(promise)
- try {
- let imgName = ''
- let imgData = node.data.image
- // base64之外的其他图片要先转换成data:url
- if (!/^data:/.test(node.data.image)) {
- imgData = await imgToDataUrl(node.data.image)
- }
- // 从data:url中解析出图片类型和ase64
- let dataUrlRes = parseDataUrl(imgData)
- imgName = 'image_' + imageList.length + '.' + dataUrlRes.type
- imageList.push({
- name: imgName,
- data: dataUrlRes.base64
- })
- newData.image = {
- src: 'xap:resources/' + imgName,
- width: node.data.imageSize.width,
- height: node.data.imageSize.height
- }
- resolve()
- } catch (error) {
- console.log(error)
- resolve()
- }
- }
-}
-
-export const getXmindContentXmlData = () => {
- return ` Warning 警告 Attention Warnung 경고 This file can not be opened normally, please do not modify and save, otherwise the contents will be permanently lost! You can try using XMind 8 Update 3 or later version to open 该文件无法正常打开,请勿修改并保存,否则文件内容将会永久性丢失! 你可以尝试使用 XMind 8 Update 3 或更新版本打开 該文件無法正常打開,請勿修改並保存,否則文件內容將會永久性丟失! 你可以嘗試使用 XMind 8 Update 3 或更新版本打開 この文書は正常に開かないので、修正して保存しないようにしてください。そうでないと、書類の内容が永久に失われます。! XMind 8 Update 3 や更新版を使って開くこともできます Datei kann nicht richtig geöffnet werden. Bitte ändern Sie diese Datei nicht und speichern Sie sie, sonst wird die Datei endgültig gelöscht werden. Bitte versuchen Sie, diese Datei mit XMind 8 Update 3 oder später zu öffnen. Ce fichier ne peut pas ouvert normalement, veuillez le rédiger et sauvegarder, sinon le fichier sera perdu en permanence. Vous pouvez essayer d'ouvrir avec XMind 8 Update 3 ou avec une version plus récente. 파일을 정상적으로 열 수 없으며, 수정 및 저장하지 마십시오. 그렇지 않으면 파일의 내용이 영구적으로 손실됩니다! XMind 8 Update 3 또는 이후 버전을 사용하여 -1 Sheet 1 `
-}
-
-// 获取节点自身的概要,非子节点区间
-const getSelfGeneralization = data => {
- const list = formatGetNodeGeneralization(data)
- return list.filter(item => {
- return !item.range || item.range.length <= 0
- })
-}
-
-// 获取节点区间概要
-const getRangeGeneralization = data => {
- const list = formatGetNodeGeneralization(data)
- return list.filter(item => {
- return item.range && item.range.length > 0
- })
-}
-
-// 导出为xmind时,将概要转换为xmind的格式
-export const parseNodeGeneralizationToXmind = node => {
- const summary = []
- const summaries = []
- const collectSummary = (item, startIndex, endIndex) => {
- const summaryTopicId = createUid()
- const summaryTitle = getTextFromHtml(item.text)
- summary.push({
- id: summaryTopicId,
- title: summaryTitle,
- attributedTitle: [
- {
- text: summaryTitle
- }
- ]
- })
- summaries.push({
- id: createUid(),
- range: '(' + startIndex + ',' + endIndex + ')',
- topicId: summaryTopicId
- })
- }
- // 在xmind中,概要都是保存在父节点的
- // 而在simple-mind-map中,区间概要保存在父节点中,不带区间的保存在自身
- // 所以先要过滤出自身的区间概要
- const generalizationList = getRangeGeneralization(node.data)
- generalizationList.forEach(item => {
- collectSummary(item, item.range[0], item.range[1])
- })
-
- // 遍历子节点,找出子节点自身的概要
- ; (node.children || []).forEach((child, childIndex) => {
- const list = getSelfGeneralization(child.data)
- list.forEach(item => {
- collectSummary(item, childIndex, childIndex)
- })
- })
-
- return {
- summary,
- summaries
- }
-}
diff --git a/packages/mindmap/tsconfig.json b/packages/mindmap/tsconfig.json
deleted file mode 100644
index 0f7bc76..0000000
--- a/packages/mindmap/tsconfig.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "compilerOptions": {
- "target": "es2022",
- "module": "esnext",
- "allowJs": true,
- "lib": [
- "DOM",
- "es2022",
- "DOM.Iterable"
- ],
- "declaration": true,
- "declarationMap": true,
- "sourceMap": true,
- "moduleResolution": "node",
- "removeComments": true,
- "skipLibCheck": true,
- "strict": true,
- "strictNullChecks": false,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "esModuleInterop": true,
- "noUnusedLocals": false,
- "noUnusedParameters": false,
- "noImplicitReturns": false,
- "noFallthroughCasesInSwitch": false,
- "noUncheckedIndexedAccess": false,
- "noImplicitOverride": false,
- "noPropertyAccessFromIndexSignature": false,
- "outDir": "dist",
- "incremental": true,
- "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
- },
- "include": [
- "src"
- ],
- "exclude": [
- "node_modules",
- "dist",
- "**/*.test.ts",
- "**/*.spec.ts",
- "**/__tests__"
- ]
-}
\ No newline at end of file
diff --git a/packages/mindmap/tsup.config.ts b/packages/mindmap/tsup.config.ts
deleted file mode 100644
index 79af640..0000000
--- a/packages/mindmap/tsup.config.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { defineConfig } from 'tsup'
-
-export default defineConfig({
- entry: ['src/index.ts'],
- format: ['esm', 'cjs'],
- dts: true,
- clean: true,
- sourcemap: true,
- minify: true,
- bundle: true,
- target: "esnext"
-})
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ae81f3d..94406e0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -12,7 +12,7 @@ importers:
dependencies:
'@nestjs/bullmq':
specifier: ^10.2.0
- version: 10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))(bullmq@5.34.8)
+ version: 10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(bullmq@5.34.8)
'@nestjs/common':
specifier: ^10.3.10
version: 10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1)
@@ -33,7 +33,7 @@ importers:
version: 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.4.15)(rxjs@7.8.1)
'@nestjs/schedule':
specifier: ^4.1.0
- version: 4.1.2(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))
+ version: 4.1.2(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)
'@nestjs/websockets':
specifier: ^10.3.10
version: 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-socket.io@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1)
@@ -142,13 +142,13 @@ importers:
devDependencies:
'@nestjs/cli':
specifier: ^10.0.0
- version: 10.4.9(@swc/core@1.10.6)
+ version: 10.4.9(@swc/core@1.10.6(@swc/helpers@0.5.15))
'@nestjs/schematics':
specifier: ^10.0.0
version: 10.2.3(chokidar@3.6.0)(typescript@5.7.2)
'@nestjs/testing':
specifier: ^10.0.0
- version: 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15))
+ version: 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-express@10.4.15)
'@types/exceljs':
specifier: ^1.3.0
version: 1.3.2
@@ -196,7 +196,7 @@ importers:
version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2)
jest:
specifier: ^29.5.0
- version: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ version: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
prettier:
specifier: ^3.0.0
version: 3.4.2
@@ -208,13 +208,13 @@ importers:
version: 6.3.4
ts-jest:
specifier: ^29.1.0
- version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)))(typescript@5.7.2)
+ version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)))(typescript@5.7.2)
ts-loader:
specifier: ^9.4.3
- version: 9.5.1(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6))
+ version: 9.5.1(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15)))
ts-node:
specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ version: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0
@@ -293,9 +293,6 @@ importers:
'@nice/iconer':
specifier: workspace:^
version: link:../../packages/iconer
- '@nice/mindmap':
- specifier: workspace:^
- version: link:../../packages/mindmap
'@nice/ui':
specifier: workspace:^
version: link:../../packages/ui
@@ -365,6 +362,9 @@ importers:
idb-keyval:
specifier: ^6.2.1
version: 6.2.1
+ mind-elixir:
+ specifier: workspace:^
+ version: link:../../packages/mind-elixir-core
mitt:
specifier: ^3.0.1
version: 3.0.1
@@ -422,7 +422,7 @@ importers:
version: 18.2.15
'@vitejs/plugin-react-swc':
specifier: ^3.5.0
- version: 3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.12)(terser@5.37.0))
+ version: 3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0))
autoprefixer:
specifier: ^10.4.20
version: 10.4.20(postcss@8.4.49)
@@ -443,7 +443,7 @@ importers:
version: 8.4.49
tailwindcss:
specifier: ^3.4.10
- version: 3.4.17(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ version: 3.4.17(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -452,7 +452,7 @@ importers:
version: 8.19.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)
vite:
specifier: ^5.4.1
- version: 5.4.11(@types/node@20.17.12)(terser@5.37.0)
+ version: 5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
packages/client:
dependencies:
@@ -504,7 +504,7 @@ importers:
version: 6.0.1
tsup:
specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ version: 8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -538,10 +538,10 @@ importers:
version: 6.0.1
ts-node:
specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ version: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
tsup:
specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ version: 8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -562,7 +562,7 @@ importers:
version: 7.18.0(eslint@8.57.1)(typescript@5.7.2)
'@vitejs/plugin-react':
specifier: ^4.3.1
- version: 4.3.4(vite@5.4.11(@types/node@20.17.12)(terser@5.37.0))
+ version: 4.3.4(vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0))
chokidar-cli:
specifier: ^3.0.0
version: 3.0.0
@@ -589,89 +589,73 @@ importers:
version: 5.7.2
vite:
specifier: ^5.3.4
- version: 5.4.11(@types/node@20.17.12)(terser@5.37.0)
+ version: 5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
vite-plugin-svgr:
specifier: ^4.2.0
- version: 4.3.0(rollup@4.30.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.12)(terser@5.37.0))
+ version: 4.3.0(rollup@4.30.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0))
- packages/mindmap:
- dependencies:
- '@svgdotjs/svg.js':
- specifier: 3.2.0
- version: 3.2.0
- deepmerge:
- specifier: ^1.5.2
- version: 1.5.2
- eventemitter3:
- specifier: ^4.0.7
- version: 4.0.7
- jszip:
- specifier: ^3.10.1
- version: 3.10.1
- katex:
- specifier: ^0.16.8
- version: 0.16.19
- mdast-util-from-markdown:
- specifier: ^1.3.0
- version: 1.3.1
- pdf-lib:
- specifier: ^1.17.1
- version: 1.17.1
- quill:
- specifier: ^2.0.3
- version: 2.0.3
- tern:
- specifier: ^0.24.3
- version: 0.24.3
- uuid:
- specifier: ^9.0.0
- version: 9.0.1
- ws:
- specifier: ^7.5.9
- version: 7.5.10
- xml-js:
- specifier: ^1.6.11
- version: 1.6.11
- y-webrtc:
- specifier: ^10.2.5
- version: 10.3.0(yjs@13.6.21)
- yjs:
- specifier: ^13.6.8
- version: 13.6.21
+ packages/mind-elixir-core:
devDependencies:
- '@types/dagre':
- specifier: ^0.7.52
- version: 0.7.52
- '@types/katex':
- specifier: ^0.16.7
- version: 0.16.7
- '@types/mdast':
- specifier: ^4.0.4
- version: 4.0.4
+ '@commitlint/cli':
+ specifier: ^17.8.1
+ version: 17.8.1(@swc/core@1.10.6(@swc/helpers@0.5.15))
+ '@commitlint/config-conventional':
+ specifier: ^17.8.1
+ version: 17.8.1
+ '@microsoft/api-documenter':
+ specifier: ^7.25.21
+ version: 7.26.7(@types/node@20.17.12)
+ '@microsoft/api-extractor':
+ specifier: ^7.47.11
+ version: 7.49.2(@types/node@20.17.12)
+ '@playwright/test':
+ specifier: ^1.44.1
+ version: 1.50.1
+ '@rollup/plugin-strip':
+ specifier: ^3.0.4
+ version: 3.0.4(rollup@4.30.1)
'@types/node':
- specifier: ^20.3.1
+ specifier: ^20.14.2
version: 20.17.12
- '@types/react':
- specifier: 18.2.38
- version: 18.2.38
- '@types/react-dom':
- specifier: 18.2.15
- version: 18.2.15
- concurrently:
- specifier: ^8.0.0
- version: 8.2.2
- rimraf:
- specifier: ^6.0.1
- version: 6.0.1
- ts-node:
- specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
- tsup:
- specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^5.62.0
+ version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/parser':
+ specifier: ^5.62.0
+ version: 5.62.0(eslint@8.57.1)(typescript@5.7.2)
+ '@viselect/vanilla':
+ specifier: ^3.9.0
+ version: 3.9.0
+ eslint:
+ specifier: ^8.57.0
+ version: 8.57.1
+ eslint-config-prettier:
+ specifier: ^8.10.0
+ version: 8.10.0(eslint@8.57.1)
+ eslint-plugin-prettier:
+ specifier: ^4.2.1
+ version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.4)
+ husky:
+ specifier: ^8.0.3
+ version: 8.0.3
+ less:
+ specifier: ^4.2.0
+ version: 4.2.2
+ lint-staged:
+ specifier: ^13.3.0
+ version: 13.3.0
+ prettier:
+ specifier: 2.8.4
+ version: 2.8.4
typescript:
- specifier: ^5.5.4
+ specifier: ^5.4.5
version: 5.7.2
+ vite:
+ specifier: ^4.5.3
+ version: 4.5.9(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
+ vite-plugin-css-injected-by-js:
+ specifier: ^3.5.1
+ version: 3.5.2(vite@4.5.9(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0))
packages/template:
devDependencies:
@@ -686,10 +670,10 @@ importers:
version: 6.0.1
ts-node:
specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ version: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
tsup:
specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ version: 8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -741,10 +725,10 @@ importers:
version: 13.2.3
ts-node:
specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ version: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
tsup:
specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ version: 8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -799,10 +783,10 @@ importers:
version: 6.0.1
ts-node:
specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ version: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
tsup:
specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ version: 8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -820,10 +804,10 @@ importers:
version: 6.0.1
ts-node:
specifier: ^10.9.1
- version: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ version: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
tsup:
specifier: ^8.3.5
- version: 8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
+ version: 8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0)
typescript:
specifier: ^5.5.4
version: 5.7.2
@@ -1286,6 +1270,75 @@ packages:
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
engines: {node: '>=0.1.90'}
+ '@commitlint/cli@17.8.1':
+ resolution: {integrity: sha512-ay+WbzQesE0Rv4EQKfNbSMiJJ12KdKTDzIt0tcK4k11FdsWmtwP0Kp1NWMOUswfIWo6Eb7p7Ln721Nx9FLNBjg==}
+ engines: {node: '>=v14'}
+ hasBin: true
+
+ '@commitlint/config-conventional@17.8.1':
+ resolution: {integrity: sha512-NxCOHx1kgneig3VLauWJcDWS40DVjg7nKOpBEEK9E5fjJpQqLCilcnKkIIjdBH98kEO1q3NpE5NSrZ2kl/QGJg==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/config-validator@17.8.1':
+ resolution: {integrity: sha512-UUgUC+sNiiMwkyiuIFR7JG2cfd9t/7MV8VB4TZ+q02ZFkHoduUS4tJGsCBWvBOGD9Btev6IecPMvlWUfJorkEA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/ensure@17.8.1':
+ resolution: {integrity: sha512-xjafwKxid8s1K23NFpL8JNo6JnY/ysetKo8kegVM7c8vs+kWLP8VrQq+NbhgVlmCojhEDbzQKp4eRXSjVOGsow==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/execute-rule@17.8.1':
+ resolution: {integrity: sha512-JHVupQeSdNI6xzA9SqMF+p/JjrHTcrJdI02PwesQIDCIGUrv04hicJgCcws5nzaoZbROapPs0s6zeVHoxpMwFQ==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/format@17.8.1':
+ resolution: {integrity: sha512-f3oMTyZ84M9ht7fb93wbCKmWxO5/kKSbwuYvS867duVomoOsgrgljkGGIztmT/srZnaiGbaK8+Wf8Ik2tSr5eg==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/is-ignored@17.8.1':
+ resolution: {integrity: sha512-UshMi4Ltb4ZlNn4F7WtSEugFDZmctzFpmbqvpyxD3la510J+PLcnyhf9chs7EryaRFJMdAKwsEKfNK0jL/QM4g==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/lint@17.8.1':
+ resolution: {integrity: sha512-aQUlwIR1/VMv2D4GXSk7PfL5hIaFSfy6hSHV94O8Y27T5q+DlDEgd/cZ4KmVI+MWKzFfCTiTuWqjfRSfdRllCA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/load@17.8.1':
+ resolution: {integrity: sha512-iF4CL7KDFstP1kpVUkT8K2Wl17h2yx9VaR1ztTc8vzByWWcbO/WaKwxsnCOqow9tVAlzPfo1ywk9m2oJ9ucMqA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/message@17.8.1':
+ resolution: {integrity: sha512-6bYL1GUQsD6bLhTH3QQty8pVFoETfFQlMn2Nzmz3AOLqRVfNNtXBaSY0dhZ0dM6A2MEq4+2d7L/2LP8TjqGRkA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/parse@17.8.1':
+ resolution: {integrity: sha512-/wLUickTo0rNpQgWwLPavTm7WbwkZoBy3X8PpkUmlSmQJyWQTj0m6bDjiykMaDt41qcUbfeFfaCvXfiR4EGnfw==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/read@17.8.1':
+ resolution: {integrity: sha512-Fd55Oaz9irzBESPCdMd8vWWgxsW3OWR99wOntBDHgf9h7Y6OOHjWEdS9Xzen1GFndqgyoaFplQS5y7KZe0kO2w==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/resolve-extends@17.8.1':
+ resolution: {integrity: sha512-W/ryRoQ0TSVXqJrx5SGkaYuAaE/BUontL1j1HsKckvM6e5ZaG0M9126zcwL6peKSuIetJi7E87PRQF8O86EW0Q==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/rules@17.8.1':
+ resolution: {integrity: sha512-2b7OdVbN7MTAt9U0vKOYKCDsOvESVXxQmrvuVUZ0rGFMCrCPJWWP1GJ7f0lAypbDAhaGb8zqtdOr47192LBrIA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/to-lines@17.8.1':
+ resolution: {integrity: sha512-LE0jb8CuR/mj6xJyrIk8VLz03OEzXFgLdivBytoooKO5xLt5yalc8Ma5guTWobw998sbR3ogDd+2jed03CFmJA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/top-level@17.8.1':
+ resolution: {integrity: sha512-l6+Z6rrNf5p333SHfEte6r+WkOxGlWK4bLuZKbtf/2TXRN+qhrvn1XE63VhD8Oe9oIHQ7F7W1nG2k/TJFhx2yA==}
+ engines: {node: '>=v14'}
+
+ '@commitlint/types@17.8.1':
+ resolution: {integrity: sha512-PXDQXkAmiMEG162Bqdh9ChML/GJZo6vU+7F03ALKDK8zYc6SuAr47LjG7hGYRqUOz+WK0dU7bQ0xzuqFMdxzeQ==}
+ engines: {node: '>=v14'}
+
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
@@ -1340,6 +1393,12 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/android-arm64@0.18.20':
+ resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm64@0.21.5':
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
@@ -1352,6 +1411,12 @@ packages:
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm@0.18.20':
+ resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-arm@0.21.5':
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
@@ -1364,6 +1429,12 @@ packages:
cpu: [arm]
os: [android]
+ '@esbuild/android-x64@0.18.20':
+ resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/android-x64@0.21.5':
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
@@ -1376,6 +1447,12 @@ packages:
cpu: [x64]
os: [android]
+ '@esbuild/darwin-arm64@0.18.20':
+ resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-arm64@0.21.5':
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
@@ -1388,6 +1465,12 @@ packages:
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-x64@0.18.20':
+ resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.21.5':
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
@@ -1400,6 +1483,12 @@ packages:
cpu: [x64]
os: [darwin]
+ '@esbuild/freebsd-arm64@0.18.20':
+ resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-arm64@0.21.5':
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
@@ -1412,6 +1501,12 @@ packages:
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.18.20':
+ resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.21.5':
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
@@ -1424,6 +1519,12 @@ packages:
cpu: [x64]
os: [freebsd]
+ '@esbuild/linux-arm64@0.18.20':
+ resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm64@0.21.5':
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
@@ -1436,6 +1537,12 @@ packages:
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm@0.18.20':
+ resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-arm@0.21.5':
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
@@ -1448,6 +1555,12 @@ packages:
cpu: [arm]
os: [linux]
+ '@esbuild/linux-ia32@0.18.20':
+ resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-ia32@0.21.5':
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
@@ -1460,6 +1573,12 @@ packages:
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-loong64@0.18.20':
+ resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-loong64@0.21.5':
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
@@ -1472,6 +1591,12 @@ packages:
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-mips64el@0.18.20':
+ resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.21.5':
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
@@ -1484,6 +1609,12 @@ packages:
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-ppc64@0.18.20':
+ resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.21.5':
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
@@ -1496,6 +1627,12 @@ packages:
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-riscv64@0.18.20':
+ resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.21.5':
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
@@ -1508,6 +1645,12 @@ packages:
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-s390x@0.18.20':
+ resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-s390x@0.21.5':
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
@@ -1520,6 +1663,12 @@ packages:
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-x64@0.18.20':
+ resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/linux-x64@0.21.5':
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
@@ -1538,6 +1687,12 @@ packages:
cpu: [arm64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.18.20':
+ resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
'@esbuild/netbsd-x64@0.21.5':
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
@@ -1556,6 +1711,12 @@ packages:
cpu: [arm64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.18.20':
+ resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.21.5':
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
@@ -1568,6 +1729,12 @@ packages:
cpu: [x64]
os: [openbsd]
+ '@esbuild/sunos-x64@0.18.20':
+ resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/sunos-x64@0.21.5':
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
@@ -1580,6 +1747,12 @@ packages:
cpu: [x64]
os: [sunos]
+ '@esbuild/win32-arm64@0.18.20':
+ resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-arm64@0.21.5':
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
@@ -1592,6 +1765,12 @@ packages:
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-ia32@0.18.20':
+ resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-ia32@0.21.5':
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
@@ -1604,6 +1783,12 @@ packages:
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-x64@0.18.20':
+ resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
'@esbuild/win32-x64@0.21.5':
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
@@ -1954,6 +2139,23 @@ packages:
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
engines: {node: '>=8'}
+ '@microsoft/api-documenter@7.26.7':
+ resolution: {integrity: sha512-VruYlHYAhQfuBNyndvyD9GBmCRWSOZ8D9+eXicygycNPMC/SPM71WWu2OwP98CTBvq/OhG/uRvUGGdL4QvgiFQ==}
+ hasBin: true
+
+ '@microsoft/api-extractor-model@7.30.3':
+ resolution: {integrity: sha512-yEAvq0F78MmStXdqz9TTT4PZ05Xu5R8nqgwI5xmUmQjWBQ9E6R2n8HB/iZMRciG4rf9iwI2mtuQwIzDXBvHn1w==}
+
+ '@microsoft/api-extractor@7.49.2':
+ resolution: {integrity: sha512-DI/WnvhbkHcucxxc4ys00ejCiViFls5EKPrEfe4NV3GGpVkoM5ZXF61HZNSGA8IG0oEV4KfTqIa59Rc3wdMopw==}
+ hasBin: true
+
+ '@microsoft/tsdoc-config@0.17.1':
+ resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==}
+
+ '@microsoft/tsdoc@0.15.1':
+ resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
+
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
cpu: [arm64]
@@ -2117,12 +2319,6 @@ packages:
engines: {node: '>=8.0.0', npm: '>=5.0.0'}
hasBin: true
- '@pdf-lib/standard-fonts@1.0.0':
- resolution: {integrity: sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==}
-
- '@pdf-lib/upng@1.0.1':
- resolution: {integrity: sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==}
-
'@phc/format@1.0.0':
resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==}
engines: {node: '>=10'}
@@ -2135,6 +2331,11 @@ packages:
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+ '@playwright/test@1.50.1':
+ resolution: {integrity: sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==}
+ engines: {node: '>=18'}
+ hasBin: true
+
'@prisma/client@5.17.0':
resolution: {integrity: sha512-N2tnyKayT0Zf7mHjwEyE8iG7FwTmXDHFZ1GnNhQp0pJUObsuel4ZZ1XwfuAYkq5mRIiC/Kot0kt0tGCfLJ70Jw==}
engines: {node: '>=16.13'}
@@ -2222,6 +2423,15 @@ packages:
resolution: {integrity: sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==}
engines: {node: '>=14.0.0'}
+ '@rollup/plugin-strip@3.0.4':
+ resolution: {integrity: sha512-LDRV49ZaavxUo2YoKKMQjCxzCxugu1rCPQa0lDYBOWLj6vtzBMr8DcoJjsmg+s450RbKbe3qI9ZLaSO+O1oNbg==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@rollup/pluginutils@5.1.4':
resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==}
engines: {node: '>=14.0.0'}
@@ -2336,6 +2546,28 @@ packages:
cpu: [x64]
os: [win32]
+ '@rushstack/node-core-library@5.11.0':
+ resolution: {integrity: sha512-I8+VzG9A0F3nH2rLpPd7hF8F7l5Xb7D+ldrWVZYegXM6CsKkvWc670RlgK3WX8/AseZfXA/vVrh0bpXe2Y2UDQ==}
+ peerDependencies:
+ '@types/node': '*'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
+ '@rushstack/rig-package@0.5.3':
+ resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==}
+
+ '@rushstack/terminal@0.14.6':
+ resolution: {integrity: sha512-4nMUy4h0u5PGXVG71kEA9uYI3l8GjVqewoHOFONiM6fuqS51ORdaJZ5ZXB2VZEGUyfg1TOTSy88MF2cdAy+lqA==}
+ peerDependencies:
+ '@types/node': '*'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
+ '@rushstack/ts-command-line@4.23.4':
+ resolution: {integrity: sha512-pqmzDJCm0TS8VyeqnzcJ7ncwXgiLDQ6LVmXXfqv2nPL6VIz+UpyTpNVfZRJpyyJ+UDxqob1vIj2liaUfBjv8/A==}
+
'@shopify/semaphore@3.1.0':
resolution: {integrity: sha512-LxonkiWEu12FbZhuOMhsdocpxCqm7By8C/2U9QgNuEoXUx2iMrlXjJv3p93RwfNC6TrdlNRo17gRer1z1309VQ==}
engines: {node: '>=18.12.0'}
@@ -2564,9 +2796,6 @@ packages:
'@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
- '@svgdotjs/svg.js@3.2.0':
- resolution: {integrity: sha512-Tr8p+QVP7y+QT1GBlq1Tt57IvedVH8zCPoYxdHLX0Oof3a/PqnC/tXAkVufv1JQJfsDHlH/UrjcDfgxSofqSNA==}
-
'@svgr/babel-plugin-add-jsx-attribute@8.0.0':
resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==}
engines: {node: '>=14'}
@@ -2766,6 +2995,9 @@ packages:
'@tsconfig/node16@1.0.4':
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+ '@types/argparse@1.0.38':
+ resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
+
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -2866,9 +3098,6 @@ packages:
'@types/jsonwebtoken@9.0.5':
resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==}
- '@types/katex@0.16.7':
- resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
-
'@types/lodash.throttle@4.1.9':
resolution: {integrity: sha512-PCPVfpfueguWZQB7pJQK890F2scYKoDUL3iM522AptHWn7d5NQmeS/LTEHIcLr5PaTzl3dK2Z0xSUHHTHwaL5g==}
@@ -2878,12 +3107,6 @@ packages:
'@types/luxon@3.4.2':
resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
- '@types/mdast@3.0.15':
- resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
-
- '@types/mdast@4.0.4':
- resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
-
'@types/methods@1.1.4':
resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
@@ -2893,6 +3116,9 @@ packages:
'@types/mime@1.3.5':
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
+ '@types/minimist@1.2.5':
+ resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==}
+
'@types/ms@0.7.34':
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
@@ -2908,6 +3134,12 @@ packages:
'@types/node@20.17.12':
resolution: {integrity: sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==}
+ '@types/node@20.5.1':
+ resolution: {integrity: sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==}
+
+ '@types/normalize-package-data@2.4.4':
+ resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
+
'@types/prop-types@15.7.14':
resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
@@ -2950,9 +3182,6 @@ packages:
'@types/supertest@6.0.2':
resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==}
- '@types/unist@2.0.11':
- resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
-
'@types/uuid@10.0.0':
resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
@@ -2965,6 +3194,17 @@ packages:
'@types/yargs@17.0.33':
resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
+ '@typescript-eslint/eslint-plugin@5.62.0':
+ resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^5.0.0
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
'@typescript-eslint/eslint-plugin@6.21.0':
resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -2995,6 +3235,16 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/parser@5.62.0':
+ resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
'@typescript-eslint/parser@6.21.0':
resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3022,6 +3272,10 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/scope-manager@5.62.0':
+ resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
'@typescript-eslint/scope-manager@6.21.0':
resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3034,6 +3288,16 @@ packages:
resolution: {integrity: sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/type-utils@5.62.0':
+ resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: '*'
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
'@typescript-eslint/type-utils@6.21.0':
resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3061,6 +3325,10 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/types@5.62.0':
+ resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
'@typescript-eslint/types@6.21.0':
resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3073,6 +3341,15 @@ packages:
resolution: {integrity: sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/typescript-estree@5.62.0':
+ resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
'@typescript-eslint/typescript-estree@6.21.0':
resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3097,6 +3374,12 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/utils@5.62.0':
+ resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+
'@typescript-eslint/utils@6.21.0':
resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3116,6 +3399,10 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
+ '@typescript-eslint/visitor-keys@5.62.0':
+ resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
'@typescript-eslint/visitor-keys@6.21.0':
resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
engines: {node: ^16.0.0 || >=18.0.0}
@@ -3131,6 +3418,9 @@ packages:
'@ungap/structured-clone@1.2.1':
resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==}
+ '@viselect/vanilla@3.9.0':
+ resolution: {integrity: sha512-E9eBgoi/crJ0SlZMAc+Yst7nU324LZ5LLvcXjzWEcrfllscdpTml2OLOKHC7O8Bbz19OybSLv6VexxnjlJrLxQ==}
+
'@vitejs/plugin-react-swc@3.7.2':
resolution: {integrity: sha512-y0byko2b2tSVVf5Gpng1eEhX1OvPC7x8yns1Fx8jDzlJp4LS6CMkCPfLw47cjyoMrshQDoQw4qcgjsU9VvlCew==}
peerDependencies:
@@ -3205,6 +3495,10 @@ packages:
'@zxing/text-encoding@0.9.0':
resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==}
+ JSONStream@1.3.5:
+ resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
+ hasBin: true
+
abstract-leveldown@6.2.3:
resolution: {integrity: sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==}
engines: {node: '>=6'}
@@ -3224,23 +3518,10 @@ packages:
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- acorn-loose@6.1.0:
- resolution: {integrity: sha512-FHhXoiF0Uch3IqsrnPpWwCtiv5PYvipTpT1k9lDMgQVVYc9iDuSl5zdJV358aI8twfHCYMFBRVYvAVki9wC/ng==}
- engines: {node: '>=0.4.0'}
-
- acorn-walk@6.2.0:
- resolution: {integrity: sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==}
- engines: {node: '>=0.4.0'}
-
acorn-walk@8.3.4:
resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
engines: {node: '>=0.4.0'}
- acorn@6.4.2:
- resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==}
- engines: {node: '>=0.4.0'}
- hasBin: true
-
acorn@8.14.0:
resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
engines: {node: '>=0.4.0'}
@@ -3267,6 +3548,14 @@ packages:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ ajv-draft-04@1.0.0:
+ resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
+ peerDependencies:
+ ajv: ^8.5.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -3275,6 +3564,14 @@ packages:
ajv:
optional: true
+ ajv-formats@3.0.1:
+ resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
+ peerDependencies:
+ ajv: ^8.0.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
ajv-keywords@3.5.2:
resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
peerDependencies:
@@ -3291,6 +3588,9 @@ packages:
ajv@8.12.0:
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
+ ajv@8.13.0:
+ resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==}
+
ajv@8.17.1:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
@@ -3302,6 +3602,10 @@ packages:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
+ ansi-escapes@5.0.0:
+ resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==}
+ engines: {node: '>=12'}
+
ansi-regex@4.1.1:
resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
engines: {node: '>=6'}
@@ -3377,6 +3681,9 @@ packages:
array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+ array-ify@1.0.0:
+ resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==}
+
array-timsort@1.0.3:
resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==}
@@ -3384,6 +3691,10 @@ packages:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
+ arrify@1.0.1:
+ resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
+ engines: {node: '>=0.10.0'}
+
asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
@@ -3524,9 +3835,6 @@ packages:
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
- buffer@6.0.3:
- resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
-
buffers@0.1.1:
resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==}
engines: {node: '>=0.2.0'}
@@ -3572,6 +3880,10 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
+ camelcase-keys@6.2.2:
+ resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
+ engines: {node: '>=8'}
+
camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
engines: {node: '>=6'}
@@ -3590,6 +3902,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
+ chalk@5.3.0:
+ resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
+ engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
+
chalk@5.4.1:
resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
@@ -3598,9 +3914,6 @@ packages:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
- character-entities@2.0.2:
- resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
-
chardet@0.7.0:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
@@ -3641,6 +3954,10 @@ packages:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
+ cli-cursor@4.0.0:
+ resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
cli-spinners@2.9.2:
resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
engines: {node: '>=6'}
@@ -3649,6 +3966,10 @@ packages:
resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==}
engines: {node: 10.* || >= 12.*}
+ cli-truncate@3.1.0:
+ resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
cli-width@3.0.0:
resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
engines: {node: '>= 10'}
@@ -3707,6 +4028,9 @@ packages:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
engines: {node: '>=12.5.0'}
+ colorette@2.0.20:
+ resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+
combine-errors@3.0.3:
resolution: {integrity: sha512-C8ikRNRMygCwaTx+Ek3Yr+OuZzgZjduCOfSQBjbM8V3MfgcjSTeto/GXP6PAwKvJz/v15b7GHZvx5rOlczFw/Q==}
@@ -3714,6 +4038,10 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
+ commander@11.0.0:
+ resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==}
+ engines: {node: '>=16'}
+
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@@ -3721,14 +4049,13 @@ packages:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
- commander@8.3.0:
- resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
- engines: {node: '>= 12'}
-
comment-json@4.2.5:
resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==}
engines: {node: '>= 6'}
+ compare-func@2.0.0:
+ resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
+
component-emitter@1.3.1:
resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
@@ -3766,6 +4093,19 @@ packages:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
+ conventional-changelog-angular@6.0.0:
+ resolution: {integrity: sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==}
+ engines: {node: '>=14'}
+
+ conventional-changelog-conventionalcommits@6.1.0:
+ resolution: {integrity: sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==}
+ engines: {node: '>=14'}
+
+ conventional-commits-parser@4.0.0:
+ resolution: {integrity: sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==}
+ engines: {node: '>=14'}
+ hasBin: true
+
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@@ -3783,6 +4123,9 @@ packages:
cookiejar@2.1.4:
resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
+ copy-anything@2.0.6:
+ resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
+
copy-anything@3.0.5:
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
engines: {node: '>=12.13'}
@@ -3797,6 +4140,15 @@ packages:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
+ cosmiconfig-typescript-loader@4.4.0:
+ resolution: {integrity: sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw==}
+ engines: {node: '>=v14.21.3'}
+ peerDependencies:
+ '@types/node': '*'
+ cosmiconfig: '>=7'
+ ts-node: '>=10'
+ typescript: '>=4'
+
cosmiconfig@8.3.6:
resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
engines: {node: '>=14'}
@@ -3903,6 +4255,10 @@ packages:
dagre@0.8.5:
resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==}
+ dargs@7.0.0:
+ resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
+ engines: {node: '>=8'}
+
date-fns@2.30.0:
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
engines: {node: '>=0.11'}
@@ -3918,6 +4274,15 @@ packages:
supports-color:
optional: true
+ debug@4.3.4:
+ resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
debug@4.3.7:
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
engines: {node: '>=6.0'}
@@ -3936,13 +4301,14 @@ packages:
supports-color:
optional: true
+ decamelize-keys@1.1.1:
+ resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
+ engines: {node: '>=0.10.0'}
+
decamelize@1.2.0:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
- decode-named-character-reference@1.0.2:
- resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
-
decode-uri-component@0.2.2:
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
engines: {node: '>=0.10'}
@@ -3958,10 +4324,6 @@ packages:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
- deepmerge@1.5.2:
- resolution: {integrity: sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==}
- engines: {node: '>=0.10.0'}
-
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
@@ -3990,10 +4352,6 @@ packages:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
- dequal@2.0.3:
- resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
- engines: {node: '>=6'}
-
destroy@1.2.0:
resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -4020,10 +4378,6 @@ packages:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
- diff@5.2.0:
- resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==}
- engines: {node: '>=0.3.1'}
-
dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@@ -4038,6 +4392,10 @@ packages:
dot-case@3.0.4:
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
+ dot-prop@5.3.0:
+ resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==}
+ engines: {node: '>=8'}
+
dotenv-expand@10.0.0:
resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==}
engines: {node: '>=12'}
@@ -4114,10 +4472,6 @@ packages:
resolution: {integrity: sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==}
engines: {node: '>=10.2.0'}
- enhanced-resolve@2.3.0:
- resolution: {integrity: sha512-n6e4bsCpzsP0OB76X+vEWhySUQI8GHPVFVK+3QkX35tbryy2WoeGeK5kQ+oxzgDVHjIZyz5fyS60Mi3EpQLc0Q==}
- engines: {node: '>=0.6'}
-
enhanced-resolve@5.18.0:
resolution: {integrity: sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==}
engines: {node: '>=10.13.0'}
@@ -4126,9 +4480,6 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
- err-code@3.0.1:
- resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==}
-
errno@0.1.8:
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
hasBin: true
@@ -4151,6 +4502,11 @@ packages:
resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
engines: {node: '>= 0.4'}
+ esbuild@0.18.20:
+ resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
+ engines: {node: '>=12'}
+ hasBin: true
+
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
@@ -4180,12 +4536,29 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
+ eslint-config-prettier@8.10.0:
+ resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
+ hasBin: true
+ peerDependencies:
+ eslint: '>=7.0.0'
+
eslint-config-prettier@9.1.0:
resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
+ eslint-plugin-prettier@4.2.1:
+ resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ eslint: '>=7.28.0'
+ eslint-config-prettier: '*'
+ prettier: '>=2.0.0'
+ peerDependenciesMeta:
+ eslint-config-prettier:
+ optional: true
+
eslint-plugin-prettier@5.2.1:
resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -4293,9 +4666,6 @@ packages:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'}
- eventemitter3@4.0.7:
- resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
-
eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
@@ -4311,6 +4681,10 @@ packages:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
+ execa@7.2.0:
+ resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==}
+ engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
+
exit@0.1.2:
resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
engines: {node: '>= 0.8.0'}
@@ -4495,12 +4869,21 @@ packages:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
+ fs-extra@11.3.0:
+ resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
+ engines: {node: '>=14.14'}
+
fs-monkey@1.0.6:
resolution: {integrity: sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==}
fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -4522,9 +4905,6 @@ packages:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
- get-browser-rtc@1.1.0:
- resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==}
-
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
@@ -4549,6 +4929,11 @@ packages:
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
engines: {node: '>=10'}
+ git-raw-commits@2.0.11:
+ resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==}
+ engines: {node: '>=10'}
+ hasBin: true
+
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -4573,6 +4958,10 @@ packages:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
+ global-dirs@0.1.1:
+ resolution: {integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==}
+ engines: {node: '>=4'}
+
globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'}
@@ -4611,6 +5000,10 @@ packages:
graphlib@2.1.8:
resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==}
+ hard-rejection@2.1.0:
+ resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
+ engines: {node: '>=6'}
+
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -4644,6 +5037,13 @@ packages:
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+ hosted-git-info@2.8.9:
+ resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
+
+ hosted-git-info@4.1.0:
+ resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
+ engines: {node: '>=10'}
+
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
@@ -4655,10 +5055,23 @@ packages:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
+ human-signals@4.3.1:
+ resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
+ engines: {node: '>=14.18.0'}
+
+ husky@8.0.3:
+ resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
+ engines: {node: '>=14'}
+ hasBin: true
+
iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
idb-keyval@6.2.1:
resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==}
@@ -4669,6 +5082,11 @@ packages:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
+ image-size@0.5.5:
+ resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+
immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
@@ -4679,6 +5097,10 @@ packages:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
+ import-lazy@4.0.0:
+ resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
+ engines: {node: '>=8'}
+
import-local@3.2.0:
resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
engines: {node: '>=8'}
@@ -4688,6 +5110,10 @@ packages:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
+ indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
@@ -4695,6 +5121,9 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ ini@1.3.8:
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+
inquirer@8.2.6:
resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==}
engines: {node: '>=12.0.0'}
@@ -4753,6 +5182,10 @@ packages:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
+ is-fullwidth-code-point@4.0.0:
+ resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+ engines: {node: '>=12'}
+
is-generator-fn@2.1.0:
resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
engines: {node: '>=6'}
@@ -4773,6 +5206,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-obj@2.0.0:
+ resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
+ engines: {node: '>=8'}
+
is-obj@3.0.0:
resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==}
engines: {node: '>=12'}
@@ -4781,6 +5218,10 @@ packages:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
+ is-plain-obj@1.1.0:
+ resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==}
+ engines: {node: '>=0.10.0'}
+
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -4793,6 +5234,14 @@ packages:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
+ is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ is-text-path@1.0.1:
+ resolution: {integrity: sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==}
+ engines: {node: '>=0.10.0'}
+
is-typed-array@1.1.15:
resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}
engines: {node: '>= 0.4'}
@@ -4801,6 +5250,9 @@ packages:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
+ is-what@3.14.1:
+ resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
+
is-what@4.1.16:
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
engines: {node: '>=12.13'}
@@ -4994,6 +5446,9 @@ packages:
resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==}
hasBin: true
+ jju@1.4.0:
+ resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
+
joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
@@ -5004,6 +5459,10 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-yaml@3.13.1:
+ resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==}
+ hasBin: true
+
js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
@@ -5049,6 +5508,10 @@ packages:
jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ jsonparse@1.3.1:
+ resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
+ engines: {'0': node >= 0.2.0}
+
jsonwebtoken@9.0.2:
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
engines: {node: '>=12', npm: '>=6'}
@@ -5062,25 +5525,26 @@ packages:
jws@3.2.2:
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
- katex@0.16.19:
- resolution: {integrity: sha512-3IA6DYVhxhBabjSLTNO9S4+OliA3Qvb8pBQXMfC4WxXJgLwZgnfDl0BmB4z6nBMdznBsZ+CGM8DrGZ5hcguDZg==}
- hasBin: true
-
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ kind-of@6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+
kleur@3.0.3:
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
engines: {node: '>=6'}
- kleur@4.1.5:
- resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
- engines: {node: '>=6'}
-
lazystream@1.0.1:
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
engines: {node: '>= 0.6.3'}
+ less@4.2.2:
+ resolution: {integrity: sha512-tkuLHQlvWUTeQ3doAqnHbNn8T6WX1KA8yvbKG9x4VtKtIjHsVKQZCH11zRgAfbDAXC2UNIg/K9BYAAcEzUIrNg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
level-codec@9.0.2:
resolution: {integrity: sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==}
engines: {node: '>=6'}
@@ -5139,6 +5603,10 @@ packages:
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
+ lilconfig@2.1.0:
+ resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
+ engines: {node: '>=10'}
+
lilconfig@3.1.3:
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
engines: {node: '>=14'}
@@ -5146,9 +5614,23 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ lint-staged@13.3.0:
+ resolution: {integrity: sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ==}
+ engines: {node: ^16.14.0 || >=18.0.0}
+ hasBin: true
+
listenercount@1.0.1:
resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
+ listr2@6.6.1:
+ resolution: {integrity: sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==}
+ engines: {node: '>=16.0.0'}
+ peerDependencies:
+ enquirer: '>= 2.3.0 < 3'
+ peerDependenciesMeta:
+ enquirer:
+ optional: true
+
load-tsconfig@0.2.5:
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -5190,6 +5672,9 @@ packages:
lodash._stringtopath@4.8.0:
resolution: {integrity: sha512-SXL66C731p0xPDC5LZg4wI5H+dJo/EO4KTqOMwLYCH3+FmmfAKJEZCm6ohGpI+T1xwsDsJCfL4OnhorllvlTPQ==}
+ lodash.camelcase@4.3.0:
+ resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
+
lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
@@ -5244,18 +5729,30 @@ packages:
lodash.isundefined@3.0.1:
resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==}
+ lodash.kebabcase@4.1.1:
+ resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==}
+
lodash.memoize@4.1.2:
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ lodash.mergewith@4.6.2:
+ resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==}
+
lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+ lodash.snakecase@4.1.1:
+ resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
+
lodash.sortby@4.7.0:
resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
+ lodash.startcase@4.4.0:
+ resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
+
lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
@@ -5268,6 +5765,9 @@ packages:
lodash.uniqby@4.5.0:
resolution: {integrity: sha512-IRt7cfTtHy6f1aRVA5n7kT8rgN3N1nH6MOWLcHfpWG2SH19E3JksLK38MktLxZDhlAjCP9jpIXkOnRXlu6oByQ==}
+ lodash.upperfirst@4.3.1:
+ resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==}
+
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@@ -5275,6 +5775,10 @@ packages:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
+ log-update@5.0.1:
+ resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@@ -5292,6 +5796,10 @@ packages:
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+
ltgt@2.2.1:
resolution: {integrity: sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==}
@@ -5303,6 +5811,10 @@ packages:
resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
engines: {node: '>=12'}
+ make-dir@2.1.0:
+ resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+ engines: {node: '>=6'}
+
make-dir@4.0.0:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
@@ -5313,16 +5825,18 @@ packages:
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+ map-obj@1.0.1:
+ resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==}
+ engines: {node: '>=0.10.0'}
+
+ map-obj@4.3.0:
+ resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==}
+ engines: {node: '>=8'}
+
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
- mdast-util-from-markdown@1.3.1:
- resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==}
-
- mdast-util-to-string@3.2.0:
- resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==}
-
media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
@@ -5334,8 +5848,9 @@ packages:
memoize-one@5.2.1:
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
- memory-fs@0.3.0:
- resolution: {integrity: sha512-QTNXnl79X97kZ9jJk/meJrtDuvgvRakX5LU7HZW1L7MsXHuSTwoMIzN9tOLLH3Xfsj/gbsSqX/ovnsqz246zKQ==}
+ meow@8.1.2:
+ resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
+ engines: {node: '>=10'}
merge-descriptors@1.0.3:
resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
@@ -5351,68 +5866,9 @@ packages:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
engines: {node: '>= 0.6'}
- micromark-core-commonmark@1.1.0:
- resolution: {integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==}
-
- micromark-factory-destination@1.1.0:
- resolution: {integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==}
-
- micromark-factory-label@1.1.0:
- resolution: {integrity: sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==}
-
- micromark-factory-space@1.1.0:
- resolution: {integrity: sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==}
-
- micromark-factory-title@1.1.0:
- resolution: {integrity: sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==}
-
- micromark-factory-whitespace@1.1.0:
- resolution: {integrity: sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==}
-
- micromark-util-character@1.2.0:
- resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==}
-
- micromark-util-chunked@1.1.0:
- resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==}
-
- micromark-util-classify-character@1.1.0:
- resolution: {integrity: sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==}
-
- micromark-util-combine-extensions@1.1.0:
- resolution: {integrity: sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==}
-
- micromark-util-decode-numeric-character-reference@1.1.0:
- resolution: {integrity: sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==}
-
- micromark-util-decode-string@1.1.0:
- resolution: {integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==}
-
- micromark-util-encode@1.1.0:
- resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==}
-
- micromark-util-html-tag-name@1.2.0:
- resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==}
-
- micromark-util-normalize-identifier@1.1.0:
- resolution: {integrity: sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==}
-
- micromark-util-resolve-all@1.1.0:
- resolution: {integrity: sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==}
-
- micromark-util-sanitize-uri@1.2.0:
- resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==}
-
- micromark-util-subtokenize@1.1.0:
- resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==}
-
- micromark-util-symbol@1.1.0:
- resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==}
-
- micromark-util-types@1.1.0:
- resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==}
-
- micromark@3.2.0:
- resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==}
+ micromatch@4.0.5:
+ resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+ engines: {node: '>=8.6'}
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
@@ -5440,10 +5896,21 @@ packages:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
+ mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+
+ min-indent@1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+
minimatch@10.0.1:
resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==}
engines: {node: 20 || >=22}
+ minimatch@3.0.8:
+ resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -5459,6 +5926,10 @@ packages:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'}
+ minimist-options@4.1.0:
+ resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
+ engines: {node: '>= 6'}
+
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@@ -5483,13 +5954,12 @@ packages:
motion-utils@11.16.0:
resolution: {integrity: sha512-ngdWPjg31rD4WGXFi0eZ00DQQqKKu04QExyv/ymlC+3k+WIgYVFbt6gS5JsFPbJODTF/r8XiE/X+SsoT9c0ocw==}
- mri@1.2.0:
- resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
- engines: {node: '>=4'}
-
ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+ ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -5533,9 +6003,17 @@ packages:
napi-macros@2.0.0:
resolution: {integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==}
+ natural-compare-lite@1.4.0:
+ resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
+
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ needle@3.3.1:
+ resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
+ engines: {node: '>= 4.4.x'}
+ hasBin: true
+
negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
@@ -5583,6 +6061,13 @@ packages:
node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+ normalize-package-data@2.5.0:
+ resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
+
+ normalize-package-data@3.0.3:
+ resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==}
+ engines: {node: '>=10'}
+
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
@@ -5595,6 +6080,10 @@ packages:
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
+ npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -5618,6 +6107,10 @@ packages:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
+ onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+
optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'}
@@ -5671,6 +6164,10 @@ packages:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
+ parse-node-version@1.0.1:
+ resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
+ engines: {node: '>= 0.10'}
+
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -5691,6 +6188,10 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
+ path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@@ -5712,9 +6213,6 @@ packages:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
- pdf-lib@1.17.1:
- resolution: {integrity: sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==}
-
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -5730,10 +6228,19 @@ packages:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
engines: {node: '>=12'}
+ pidtree@0.6.0:
+ resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
+ pify@4.0.1:
+ resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+ engines: {node: '>=6'}
+
pinyin-pro@3.26.0:
resolution: {integrity: sha512-HcBZZb0pvm0/JkPhZHWA5Hqp2cWHXrrW/WrV+OtaYYM+kf35ffvZppIUuGmyuQ7gDr1JDJKMkbEE+GN0wfMoGg==}
@@ -5745,6 +6252,16 @@ packages:
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
engines: {node: '>=8'}
+ playwright-core@1.50.1:
+ resolution: {integrity: sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.50.1:
+ resolution: {integrity: sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
@@ -5820,6 +6337,11 @@ packages:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
+ prettier@2.8.4:
+ resolution: {integrity: sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+
prettier@3.4.2:
resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==}
engines: {node: '>=14'}
@@ -5886,6 +6408,10 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ quick-lru@4.0.1:
+ resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==}
+ engines: {node: '>=8'}
+
quill-delta@5.1.0:
resolution: {integrity: sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==}
engines: {node: '>= 12.0.0'}
@@ -6234,6 +6760,14 @@ packages:
read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
+ read-pkg-up@7.0.1:
+ resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
+ engines: {node: '>=8'}
+
+ read-pkg@5.2.0:
+ resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
+ engines: {node: '>=8'}
+
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
@@ -6252,6 +6786,10 @@ packages:
resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==}
engines: {node: '>= 14.16.0'}
+ redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+
redis-errors@1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
engines: {node: '>=4'}
@@ -6294,10 +6832,6 @@ packages:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
- resolve-from@2.0.0:
- resolution: {integrity: sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==}
- engines: {node: '>=0.10.0'}
-
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -6306,6 +6840,10 @@ packages:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
+ resolve-global@1.0.0:
+ resolution: {integrity: sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==}
+ engines: {node: '>=8'}
+
resolve.exports@2.0.3:
resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
engines: {node: '>=10'}
@@ -6319,6 +6857,10 @@ packages:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
+ restore-cursor@4.0.0:
+ resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
retry@0.12.0:
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
engines: {node: '>= 4'}
@@ -6327,6 +6869,9 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ rfdc@1.4.1:
+ resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+
rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
deprecated: Rimraf versions prior to v4 are no longer supported
@@ -6342,6 +6887,11 @@ packages:
engines: {node: 20 || >=22}
hasBin: true
+ rollup@3.29.5:
+ resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==}
+ engines: {node: '>=14.18.0', npm: '>=8.0.0'}
+ hasBin: true
+
rollup@4.30.1:
resolution: {integrity: sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -6361,10 +6911,6 @@ packages:
rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
- sade@1.8.1:
- resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
- engines: {node: '>=6'}
-
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
@@ -6399,10 +6945,19 @@ packages:
scroll-into-view-if-needed@3.1.0:
resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
+ semver@5.7.2:
+ resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
+ hasBin: true
+
semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
+ semver@7.5.4:
+ resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
@@ -6489,9 +7044,6 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
- simple-peer@9.11.1:
- resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==}
-
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
@@ -6502,6 +7054,10 @@ packages:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
+ slice-ansi@5.0.0:
+ resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+ engines: {node: '>=12'}
+
slugify@1.6.6:
resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
engines: {node: '>=8.0.0'}
@@ -6545,10 +7101,25 @@ packages:
spawn-command@0.0.2:
resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==}
+ spdx-correct@3.2.0:
+ resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
+
+ spdx-exceptions@2.5.0:
+ resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==}
+
+ spdx-expression-parse@3.0.1:
+ resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+
+ spdx-license-ids@3.0.21:
+ resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==}
+
split-on-first@1.1.0:
resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
engines: {node: '>=6'}
+ split2@3.2.2:
+ resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==}
+
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
@@ -6577,6 +7148,10 @@ packages:
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
engines: {node: '>=4'}
+ string-argv@0.3.2:
+ resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
+ engines: {node: '>=0.6.19'}
+
string-convert@0.2.1:
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
@@ -6630,6 +7205,14 @@ packages:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
+ strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+
+ strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+
strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
@@ -6696,10 +7279,6 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
- tapable@0.2.9:
- resolution: {integrity: sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==}
- engines: {node: '>=0.6'}
-
tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
@@ -6708,10 +7287,6 @@ packages:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
- tern@0.24.3:
- resolution: {integrity: sha512-Z8uvtdWIlFn1GWy0HW5FhZ8VDryZwoJUdnjZU25C7/PBOltLIn1uv+WF3rVq6S1761YbsmbZYRP/l0ZJBCkvrw==}
- hasBin: true
-
terser-webpack-plugin@5.3.11:
resolution: {integrity: sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==}
engines: {node: '>= 10.13.0'}
@@ -6737,6 +7312,10 @@ packages:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'}
+ text-extensions@1.9.0:
+ resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==}
+ engines: {node: '>=0.10'}
+
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@@ -6810,6 +7389,10 @@ packages:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
+ trim-newlines@3.0.1:
+ resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
+ engines: {node: '>=8'}
+
ts-api-utils@1.4.3:
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
engines: {node: '>=16'}
@@ -6903,6 +7486,12 @@ packages:
typescript:
optional: true
+ tsutils@3.21.0:
+ resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+ engines: {node: '>= 6'}
+ peerDependencies:
+ typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+
tus-js-client@4.2.3:
resolution: {integrity: sha512-UkQUCeDWKh5AwArcasIJWcL5EP66XPypKQtsdPu82wNnTea8eAUHdpDx3DcfZgDERAiCII895zMYkXri4M1wzw==}
engines: {node: '>=18'}
@@ -6915,6 +7504,10 @@ packages:
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'}
+ type-fest@0.18.1:
+ resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==}
+ engines: {node: '>=10'}
+
type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
@@ -6923,6 +7516,18 @@ packages:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
+ type-fest@0.6.0:
+ resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
+ engines: {node: '>=8'}
+
+ type-fest@0.8.1:
+ resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
+ engines: {node: '>=8'}
+
+ type-fest@1.4.0:
+ resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
+ engines: {node: '>=10'}
+
type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
@@ -6949,9 +7554,6 @@ packages:
undici-types@6.19.8:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
- unist-util-stringify-position@3.0.3:
- resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==}
-
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@@ -7011,11 +7613,6 @@ packages:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
- uvu@0.5.6:
- resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==}
- engines: {node: '>=8'}
- hasBin: true
-
uzip@0.20201231.0:
resolution: {integrity: sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==}
@@ -7026,15 +7623,51 @@ packages:
resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
engines: {node: '>=10.12.0'}
+ validate-npm-package-license@3.0.4:
+ resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
+
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
+ vite-plugin-css-injected-by-js@3.5.2:
+ resolution: {integrity: sha512-2MpU/Y+SCZyWUB6ua3HbJCrgnF0KACAsmzOQt1UvRVJCGF6S8xdA3ZUhWcWdM9ivG4I5az8PnQmwwrkC2CAQrQ==}
+ peerDependencies:
+ vite: '>2.0.0-0'
+
vite-plugin-svgr@4.3.0:
resolution: {integrity: sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==}
peerDependencies:
vite: '>=2.6.0'
+ vite@4.5.9:
+ resolution: {integrity: sha512-qK9W4xjgD3gXbC0NmdNFFnVFLMWSNiR3swj957yutwzzN16xF/E7nmtAyp1rT9hviDroQANjE4HK3H4WqWdFtw==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': '>= 14'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+
vite@5.4.11:
resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -7152,18 +7785,6 @@ packages:
resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- ws@7.5.10:
- resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==}
- engines: {node: '>=8.3.0'}
- peerDependencies:
- bufferutil: ^4.0.1
- utf-8-validate: ^5.0.2
- peerDependenciesMeta:
- bufferutil:
- optional: true
- utf-8-validate:
- optional: true
-
ws@8.17.1:
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
engines: {node: '>=10.0.0'}
@@ -7188,10 +7809,6 @@ packages:
utf-8-validate:
optional: true
- xml-js@1.6.11:
- resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
- hasBin: true
-
xml2js@0.6.2:
resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==}
engines: {node: '>=4.0.0'}
@@ -7212,19 +7829,6 @@ packages:
peerDependencies:
yjs: ^13.0.0
- y-protocols@1.0.6:
- resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==}
- engines: {node: '>=16.0.0', npm: '>=8.0.0'}
- peerDependencies:
- yjs: ^13.0.0
-
- y-webrtc@10.3.0:
- resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==}
- engines: {node: '>=12'}
- hasBin: true
- peerDependencies:
- yjs: ^13.6.8
-
y18n@4.0.3:
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
@@ -7238,6 +7842,10 @@ packages:
yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ yaml@2.3.1:
+ resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
+ engines: {node: '>= 14'}
+
yaml@2.7.0:
resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
engines: {node: '>= 14'}
@@ -7246,6 +7854,10 @@ packages:
yargs-parser@13.1.2:
resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==}
+ yargs-parser@20.2.9:
+ resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
+ engines: {node: '>=10'}
+
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
@@ -8197,6 +8809,122 @@ snapshots:
'@colors/colors@1.5.0':
optional: true
+ '@commitlint/cli@17.8.1(@swc/core@1.10.6(@swc/helpers@0.5.15))':
+ dependencies:
+ '@commitlint/format': 17.8.1
+ '@commitlint/lint': 17.8.1
+ '@commitlint/load': 17.8.1(@swc/core@1.10.6(@swc/helpers@0.5.15))
+ '@commitlint/read': 17.8.1
+ '@commitlint/types': 17.8.1
+ execa: 5.1.1
+ lodash.isfunction: 3.0.9
+ resolve-from: 5.0.0
+ resolve-global: 1.0.0
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - '@swc/core'
+ - '@swc/wasm'
+
+ '@commitlint/config-conventional@17.8.1':
+ dependencies:
+ conventional-changelog-conventionalcommits: 6.1.0
+
+ '@commitlint/config-validator@17.8.1':
+ dependencies:
+ '@commitlint/types': 17.8.1
+ ajv: 8.17.1
+
+ '@commitlint/ensure@17.8.1':
+ dependencies:
+ '@commitlint/types': 17.8.1
+ lodash.camelcase: 4.3.0
+ lodash.kebabcase: 4.1.1
+ lodash.snakecase: 4.1.1
+ lodash.startcase: 4.4.0
+ lodash.upperfirst: 4.3.1
+
+ '@commitlint/execute-rule@17.8.1': {}
+
+ '@commitlint/format@17.8.1':
+ dependencies:
+ '@commitlint/types': 17.8.1
+ chalk: 4.1.2
+
+ '@commitlint/is-ignored@17.8.1':
+ dependencies:
+ '@commitlint/types': 17.8.1
+ semver: 7.5.4
+
+ '@commitlint/lint@17.8.1':
+ dependencies:
+ '@commitlint/is-ignored': 17.8.1
+ '@commitlint/parse': 17.8.1
+ '@commitlint/rules': 17.8.1
+ '@commitlint/types': 17.8.1
+
+ '@commitlint/load@17.8.1(@swc/core@1.10.6(@swc/helpers@0.5.15))':
+ dependencies:
+ '@commitlint/config-validator': 17.8.1
+ '@commitlint/execute-rule': 17.8.1
+ '@commitlint/resolve-extends': 17.8.1
+ '@commitlint/types': 17.8.1
+ '@types/node': 20.5.1
+ chalk: 4.1.2
+ cosmiconfig: 8.3.6(typescript@5.7.2)
+ cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.7.2))(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2))(typescript@5.7.2)
+ lodash.isplainobject: 4.0.6
+ lodash.merge: 4.6.2
+ lodash.uniq: 4.5.0
+ resolve-from: 5.0.0
+ ts-node: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - '@swc/core'
+ - '@swc/wasm'
+
+ '@commitlint/message@17.8.1': {}
+
+ '@commitlint/parse@17.8.1':
+ dependencies:
+ '@commitlint/types': 17.8.1
+ conventional-changelog-angular: 6.0.0
+ conventional-commits-parser: 4.0.0
+
+ '@commitlint/read@17.8.1':
+ dependencies:
+ '@commitlint/top-level': 17.8.1
+ '@commitlint/types': 17.8.1
+ fs-extra: 11.3.0
+ git-raw-commits: 2.0.11
+ minimist: 1.2.8
+
+ '@commitlint/resolve-extends@17.8.1':
+ dependencies:
+ '@commitlint/config-validator': 17.8.1
+ '@commitlint/types': 17.8.1
+ import-fresh: 3.3.0
+ lodash.mergewith: 4.6.2
+ resolve-from: 5.0.0
+ resolve-global: 1.0.0
+
+ '@commitlint/rules@17.8.1':
+ dependencies:
+ '@commitlint/ensure': 17.8.1
+ '@commitlint/message': 17.8.1
+ '@commitlint/to-lines': 17.8.1
+ '@commitlint/types': 17.8.1
+ execa: 5.1.1
+
+ '@commitlint/to-lines@17.8.1': {}
+
+ '@commitlint/top-level@17.8.1':
+ dependencies:
+ find-up: 5.0.0
+
+ '@commitlint/types@17.8.1':
+ dependencies:
+ chalk: 4.1.2
+
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
@@ -8247,96 +8975,144 @@ snapshots:
'@esbuild/aix-ppc64@0.24.2':
optional: true
+ '@esbuild/android-arm64@0.18.20':
+ optional: true
+
'@esbuild/android-arm64@0.21.5':
optional: true
'@esbuild/android-arm64@0.24.2':
optional: true
+ '@esbuild/android-arm@0.18.20':
+ optional: true
+
'@esbuild/android-arm@0.21.5':
optional: true
'@esbuild/android-arm@0.24.2':
optional: true
+ '@esbuild/android-x64@0.18.20':
+ optional: true
+
'@esbuild/android-x64@0.21.5':
optional: true
'@esbuild/android-x64@0.24.2':
optional: true
+ '@esbuild/darwin-arm64@0.18.20':
+ optional: true
+
'@esbuild/darwin-arm64@0.21.5':
optional: true
'@esbuild/darwin-arm64@0.24.2':
optional: true
+ '@esbuild/darwin-x64@0.18.20':
+ optional: true
+
'@esbuild/darwin-x64@0.21.5':
optional: true
'@esbuild/darwin-x64@0.24.2':
optional: true
+ '@esbuild/freebsd-arm64@0.18.20':
+ optional: true
+
'@esbuild/freebsd-arm64@0.21.5':
optional: true
'@esbuild/freebsd-arm64@0.24.2':
optional: true
+ '@esbuild/freebsd-x64@0.18.20':
+ optional: true
+
'@esbuild/freebsd-x64@0.21.5':
optional: true
'@esbuild/freebsd-x64@0.24.2':
optional: true
+ '@esbuild/linux-arm64@0.18.20':
+ optional: true
+
'@esbuild/linux-arm64@0.21.5':
optional: true
'@esbuild/linux-arm64@0.24.2':
optional: true
+ '@esbuild/linux-arm@0.18.20':
+ optional: true
+
'@esbuild/linux-arm@0.21.5':
optional: true
'@esbuild/linux-arm@0.24.2':
optional: true
+ '@esbuild/linux-ia32@0.18.20':
+ optional: true
+
'@esbuild/linux-ia32@0.21.5':
optional: true
'@esbuild/linux-ia32@0.24.2':
optional: true
+ '@esbuild/linux-loong64@0.18.20':
+ optional: true
+
'@esbuild/linux-loong64@0.21.5':
optional: true
'@esbuild/linux-loong64@0.24.2':
optional: true
+ '@esbuild/linux-mips64el@0.18.20':
+ optional: true
+
'@esbuild/linux-mips64el@0.21.5':
optional: true
'@esbuild/linux-mips64el@0.24.2':
optional: true
+ '@esbuild/linux-ppc64@0.18.20':
+ optional: true
+
'@esbuild/linux-ppc64@0.21.5':
optional: true
'@esbuild/linux-ppc64@0.24.2':
optional: true
+ '@esbuild/linux-riscv64@0.18.20':
+ optional: true
+
'@esbuild/linux-riscv64@0.21.5':
optional: true
'@esbuild/linux-riscv64@0.24.2':
optional: true
+ '@esbuild/linux-s390x@0.18.20':
+ optional: true
+
'@esbuild/linux-s390x@0.21.5':
optional: true
'@esbuild/linux-s390x@0.24.2':
optional: true
+ '@esbuild/linux-x64@0.18.20':
+ optional: true
+
'@esbuild/linux-x64@0.21.5':
optional: true
@@ -8346,6 +9122,9 @@ snapshots:
'@esbuild/netbsd-arm64@0.24.2':
optional: true
+ '@esbuild/netbsd-x64@0.18.20':
+ optional: true
+
'@esbuild/netbsd-x64@0.21.5':
optional: true
@@ -8355,30 +9134,45 @@ snapshots:
'@esbuild/openbsd-arm64@0.24.2':
optional: true
+ '@esbuild/openbsd-x64@0.18.20':
+ optional: true
+
'@esbuild/openbsd-x64@0.21.5':
optional: true
'@esbuild/openbsd-x64@0.24.2':
optional: true
+ '@esbuild/sunos-x64@0.18.20':
+ optional: true
+
'@esbuild/sunos-x64@0.21.5':
optional: true
'@esbuild/sunos-x64@0.24.2':
optional: true
+ '@esbuild/win32-arm64@0.18.20':
+ optional: true
+
'@esbuild/win32-arm64@0.21.5':
optional: true
'@esbuild/win32-arm64@0.24.2':
optional: true
+ '@esbuild/win32-ia32@0.18.20':
+ optional: true
+
'@esbuild/win32-ia32@0.21.5':
optional: true
'@esbuild/win32-ia32@0.24.2':
optional: true
+ '@esbuild/win32-x64@0.18.20':
+ optional: true
+
'@esbuild/win32-x64@0.21.5':
optional: true
@@ -8627,7 +9421,7 @@ snapshots:
jest-util: 29.7.0
slash: 3.0.0
- '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))':
+ '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))':
dependencies:
'@jest/console': 29.7.0
'@jest/reporters': 29.7.0
@@ -8641,7 +9435,7 @@ snapshots:
exit: 0.1.2
graceful-fs: 4.2.11
jest-changed-files: 29.7.0
- jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
jest-haste-map: 29.7.0
jest-message-util: 29.7.0
jest-regex-util: 29.6.3
@@ -8813,6 +9607,53 @@ snapshots:
'@lukeed/csprng@1.1.0': {}
+ '@microsoft/api-documenter@7.26.7(@types/node@20.17.12)':
+ dependencies:
+ '@microsoft/api-extractor-model': 7.30.3(@types/node@20.17.12)
+ '@microsoft/tsdoc': 0.15.1
+ '@rushstack/node-core-library': 5.11.0(@types/node@20.17.12)
+ '@rushstack/terminal': 0.14.6(@types/node@20.17.12)
+ '@rushstack/ts-command-line': 4.23.4(@types/node@20.17.12)
+ js-yaml: 3.13.1
+ resolve: 1.22.10
+ transitivePeerDependencies:
+ - '@types/node'
+
+ '@microsoft/api-extractor-model@7.30.3(@types/node@20.17.12)':
+ dependencies:
+ '@microsoft/tsdoc': 0.15.1
+ '@microsoft/tsdoc-config': 0.17.1
+ '@rushstack/node-core-library': 5.11.0(@types/node@20.17.12)
+ transitivePeerDependencies:
+ - '@types/node'
+
+ '@microsoft/api-extractor@7.49.2(@types/node@20.17.12)':
+ dependencies:
+ '@microsoft/api-extractor-model': 7.30.3(@types/node@20.17.12)
+ '@microsoft/tsdoc': 0.15.1
+ '@microsoft/tsdoc-config': 0.17.1
+ '@rushstack/node-core-library': 5.11.0(@types/node@20.17.12)
+ '@rushstack/rig-package': 0.5.3
+ '@rushstack/terminal': 0.14.6(@types/node@20.17.12)
+ '@rushstack/ts-command-line': 4.23.4(@types/node@20.17.12)
+ lodash: 4.17.21
+ minimatch: 3.0.8
+ resolve: 1.22.10
+ semver: 7.5.4
+ source-map: 0.6.1
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - '@types/node'
+
+ '@microsoft/tsdoc-config@0.17.1':
+ dependencies:
+ '@microsoft/tsdoc': 0.15.1
+ ajv: 8.12.0
+ jju: 1.4.0
+ resolve: 1.22.10
+
+ '@microsoft/tsdoc@0.15.1': {}
+
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
optional: true
@@ -8831,21 +9672,21 @@ snapshots:
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
optional: true
- '@nestjs/bull-shared@10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))':
+ '@nestjs/bull-shared@10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)':
dependencies:
'@nestjs/common': 10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core': 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1)
tslib: 2.8.1
- '@nestjs/bullmq@10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))(bullmq@5.34.8)':
+ '@nestjs/bullmq@10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(bullmq@5.34.8)':
dependencies:
- '@nestjs/bull-shared': 10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))
+ '@nestjs/bull-shared': 10.2.3(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)
'@nestjs/common': 10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core': 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1)
bullmq: 5.34.8
tslib: 2.8.1
- '@nestjs/cli@10.4.9(@swc/core@1.10.6)':
+ '@nestjs/cli@10.4.9(@swc/core@1.10.6(@swc/helpers@0.5.15))':
dependencies:
'@angular-devkit/core': 17.3.11(chokidar@3.6.0)
'@angular-devkit/schematics': 17.3.11(chokidar@3.6.0)
@@ -8855,7 +9696,7 @@ snapshots:
chokidar: 3.6.0
cli-table3: 0.6.5
commander: 4.1.1
- fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6))
+ fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15)))
glob: 10.4.5
inquirer: 8.2.6
node-emoji: 1.11.0
@@ -8864,7 +9705,7 @@ snapshots:
tsconfig-paths: 4.2.0
tsconfig-paths-webpack-plugin: 4.2.0
typescript: 5.7.2
- webpack: 5.97.1(@swc/core@1.10.6)
+ webpack: 5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))
webpack-node-externals: 3.0.0
optionalDependencies:
'@swc/core': 1.10.6(@swc/helpers@0.5.15)
@@ -8936,7 +9777,7 @@ snapshots:
- supports-color
- utf-8-validate
- '@nestjs/schedule@4.1.2(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))':
+ '@nestjs/schedule@4.1.2(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)':
dependencies:
'@nestjs/common': 10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core': 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1)
@@ -8954,7 +9795,7 @@ snapshots:
transitivePeerDependencies:
- chokidar
- '@nestjs/testing@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15))':
+ '@nestjs/testing@10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.15)(@nestjs/platform-express@10.4.15)':
dependencies:
'@nestjs/common': 10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core': 10.4.15(@nestjs/common@10.4.15(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.15)(@nestjs/websockets@10.4.15)(reflect-metadata@0.2.2)(rxjs@7.8.1)
@@ -8994,14 +9835,6 @@ snapshots:
transitivePeerDependencies:
- encoding
- '@pdf-lib/standard-fonts@1.0.0':
- dependencies:
- pako: 1.0.11
-
- '@pdf-lib/upng@1.0.1':
- dependencies:
- pako: 1.0.11
-
'@phc/format@1.0.0': {}
'@pkgjs/parseargs@0.11.0':
@@ -9009,6 +9842,10 @@ snapshots:
'@pkgr/core@0.1.1': {}
+ '@playwright/test@1.50.1':
+ dependencies:
+ playwright: 1.50.1
+
'@prisma/client@5.17.0(prisma@5.17.0)':
optionalDependencies:
prisma: 5.17.0
@@ -9111,6 +9948,14 @@ snapshots:
'@remix-run/router@1.21.0': {}
+ '@rollup/plugin-strip@3.0.4(rollup@4.30.1)':
+ dependencies:
+ '@rollup/pluginutils': 5.1.4(rollup@4.30.1)
+ estree-walker: 2.0.2
+ magic-string: 0.30.8
+ optionalDependencies:
+ rollup: 4.30.1
+
'@rollup/pluginutils@5.1.4(rollup@4.30.1)':
dependencies:
'@types/estree': 1.0.6
@@ -9176,6 +10021,40 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.30.1':
optional: true
+ '@rushstack/node-core-library@5.11.0(@types/node@20.17.12)':
+ dependencies:
+ ajv: 8.13.0
+ ajv-draft-04: 1.0.0(ajv@8.13.0)
+ ajv-formats: 3.0.1(ajv@8.13.0)
+ fs-extra: 11.3.0
+ import-lazy: 4.0.0
+ jju: 1.4.0
+ resolve: 1.22.10
+ semver: 7.5.4
+ optionalDependencies:
+ '@types/node': 20.17.12
+
+ '@rushstack/rig-package@0.5.3':
+ dependencies:
+ resolve: 1.22.10
+ strip-json-comments: 3.1.1
+
+ '@rushstack/terminal@0.14.6(@types/node@20.17.12)':
+ dependencies:
+ '@rushstack/node-core-library': 5.11.0(@types/node@20.17.12)
+ supports-color: 8.1.1
+ optionalDependencies:
+ '@types/node': 20.17.12
+
+ '@rushstack/ts-command-line@4.23.4(@types/node@20.17.12)':
+ dependencies:
+ '@rushstack/terminal': 0.14.6(@types/node@20.17.12)
+ '@types/argparse': 1.0.38
+ argparse: 1.0.10
+ string-argv: 0.3.2
+ transitivePeerDependencies:
+ - '@types/node'
+
'@shopify/semaphore@3.1.0': {}
'@sinclair/typebox@0.27.8': {}
@@ -9521,8 +10400,6 @@ snapshots:
'@socket.io/component-emitter@3.1.2': {}
- '@svgdotjs/svg.js@3.2.0': {}
-
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -9702,6 +10579,8 @@ snapshots:
'@tsconfig/node16@1.0.4': {}
+ '@types/argparse@1.0.38': {}
+
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.26.3
@@ -9833,8 +10712,6 @@ snapshots:
dependencies:
'@types/node': 20.17.12
- '@types/katex@0.16.7': {}
-
'@types/lodash.throttle@4.1.9':
dependencies:
'@types/lodash': 4.17.14
@@ -9843,20 +10720,14 @@ snapshots:
'@types/luxon@3.4.2': {}
- '@types/mdast@3.0.15':
- dependencies:
- '@types/unist': 2.0.11
-
- '@types/mdast@4.0.4':
- dependencies:
- '@types/unist': 2.0.11
-
'@types/methods@1.1.4': {}
'@types/mime-types@2.1.4': {}
'@types/mime@1.3.5': {}
+ '@types/minimist@1.2.5': {}
+
'@types/ms@0.7.34': {}
'@types/multer@1.4.12':
@@ -9873,6 +10744,10 @@ snapshots:
dependencies:
undici-types: 6.19.8
+ '@types/node@20.5.1': {}
+
+ '@types/normalize-package-data@2.4.4': {}
+
'@types/prop-types@15.7.14': {}
'@types/qs@6.9.17': {}
@@ -9930,8 +10805,6 @@ snapshots:
'@types/methods': 1.1.4
'@types/superagent': 8.1.9
- '@types/unist@2.0.11': {}
-
'@types/uuid@10.0.0': {}
'@types/ws@8.5.13':
@@ -9944,6 +10817,25 @@ snapshots:
dependencies:
'@types/yargs-parser': 21.0.3
+ '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/scope-manager': 5.62.0
+ '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2)
+ debug: 4.4.0
+ eslint: 8.57.1
+ graphemer: 1.4.0
+ ignore: 5.3.2
+ natural-compare-lite: 1.4.0
+ semver: 7.6.3
+ tsutils: 3.21.0(typescript@5.7.2)
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)':
dependencies:
'@eslint-community/regexpp': 4.12.1
@@ -9999,6 +10891,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 5.62.0
+ '@typescript-eslint/types': 5.62.0
+ '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2)
+ debug: 4.4.0
+ eslint: 8.57.1
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2)':
dependencies:
'@typescript-eslint/scope-manager': 6.21.0
@@ -10037,6 +10941,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/scope-manager@5.62.0':
+ dependencies:
+ '@typescript-eslint/types': 5.62.0
+ '@typescript-eslint/visitor-keys': 5.62.0
+
'@typescript-eslint/scope-manager@6.21.0':
dependencies:
'@typescript-eslint/types': 6.21.0
@@ -10052,6 +10961,18 @@ snapshots:
'@typescript-eslint/types': 8.19.1
'@typescript-eslint/visitor-keys': 8.19.1
+ '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2)
+ '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2)
+ debug: 4.4.0
+ eslint: 8.57.1
+ tsutils: 3.21.0(typescript@5.7.2)
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.7.2)':
dependencies:
'@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2)
@@ -10087,12 +11008,28 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/types@5.62.0': {}
+
'@typescript-eslint/types@6.21.0': {}
'@typescript-eslint/types@7.18.0': {}
'@typescript-eslint/types@8.19.1': {}
+ '@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/types': 5.62.0
+ '@typescript-eslint/visitor-keys': 5.62.0
+ debug: 4.4.0
+ globby: 11.1.0
+ is-glob: 4.0.3
+ semver: 7.6.3
+ tsutils: 3.21.0(typescript@5.7.2)
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/typescript-estree@6.21.0(typescript@5.7.2)':
dependencies:
'@typescript-eslint/types': 6.21.0
@@ -10137,6 +11074,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 5.62.0
+ '@typescript-eslint/types': 5.62.0
+ '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2)
+ eslint: 8.57.1
+ eslint-scope: 5.1.1
+ semver: 7.6.3
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
'@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.7.2)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
@@ -10173,6 +11125,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/visitor-keys@5.62.0':
+ dependencies:
+ '@typescript-eslint/types': 5.62.0
+ eslint-visitor-keys: 3.4.3
+
'@typescript-eslint/visitor-keys@6.21.0':
dependencies:
'@typescript-eslint/types': 6.21.0
@@ -10190,21 +11147,23 @@ snapshots:
'@ungap/structured-clone@1.2.1': {}
- '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.12)(terser@5.37.0))':
+ '@viselect/vanilla@3.9.0': {}
+
+ '@vitejs/plugin-react-swc@3.7.2(@swc/helpers@0.5.15)(vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0))':
dependencies:
'@swc/core': 1.10.6(@swc/helpers@0.5.15)
- vite: 5.4.11(@types/node@20.17.12)(terser@5.37.0)
+ vite: 5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
transitivePeerDependencies:
- '@swc/helpers'
- '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.12)(terser@5.37.0))':
+ '@vitejs/plugin-react@4.3.4(vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0))':
dependencies:
'@babel/core': 7.26.0
'@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
'@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
'@types/babel__core': 7.20.5
react-refresh: 0.14.2
- vite: 5.4.11(@types/node@20.17.12)(terser@5.37.0)
+ vite: 5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
transitivePeerDependencies:
- supports-color
@@ -10312,6 +11271,11 @@ snapshots:
'@zxing/text-encoding@0.9.0':
optional: true
+ JSONStream@1.3.5:
+ dependencies:
+ jsonparse: 1.3.1
+ through: 2.3.8
+
abstract-leveldown@6.2.3:
dependencies:
buffer: 5.7.1
@@ -10337,18 +11301,10 @@ snapshots:
dependencies:
acorn: 8.14.0
- acorn-loose@6.1.0:
- dependencies:
- acorn: 6.4.2
-
- acorn-walk@6.2.0: {}
-
acorn-walk@8.3.4:
dependencies:
acorn: 8.14.0
- acorn@6.4.2: {}
-
acorn@8.14.0: {}
ag-charts-community@10.3.3:
@@ -10376,6 +11332,10 @@ snapshots:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
+ ajv-draft-04@1.0.0(ajv@8.13.0):
+ optionalDependencies:
+ ajv: 8.13.0
+
ajv-formats@2.1.1(ajv@8.12.0):
optionalDependencies:
ajv: 8.12.0
@@ -10384,6 +11344,10 @@ snapshots:
optionalDependencies:
ajv: 8.17.1
+ ajv-formats@3.0.1(ajv@8.13.0):
+ optionalDependencies:
+ ajv: 8.13.0
+
ajv-keywords@3.5.2(ajv@6.12.6):
dependencies:
ajv: 6.12.6
@@ -10407,6 +11371,13 @@ snapshots:
require-from-string: 2.0.2
uri-js: 4.4.1
+ ajv@8.13.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+ uri-js: 4.4.1
+
ajv@8.17.1:
dependencies:
fast-deep-equal: 3.1.3
@@ -10420,6 +11391,10 @@ snapshots:
dependencies:
type-fest: 0.21.3
+ ansi-escapes@5.0.0:
+ dependencies:
+ type-fest: 1.4.0
+
ansi-regex@4.1.1: {}
ansi-regex@5.0.1: {}
@@ -10559,10 +11534,14 @@ snapshots:
array-flatten@1.1.1: {}
+ array-ify@1.0.0: {}
+
array-timsort@1.0.3: {}
array-union@2.1.0: {}
+ arrify@1.0.1: {}
+
asap@2.0.6: {}
async@0.2.10: {}
@@ -10745,11 +11724,6 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
- buffer@6.0.3:
- dependencies:
- base64-js: 1.5.1
- ieee754: 1.2.1
-
buffers@0.1.1: {}
bullmq@5.34.8:
@@ -10798,6 +11772,12 @@ snapshots:
camelcase-css@2.0.1: {}
+ camelcase-keys@6.2.2:
+ dependencies:
+ camelcase: 5.3.1
+ map-obj: 4.3.0
+ quick-lru: 4.0.1
+
camelcase@5.3.1: {}
camelcase@6.3.0: {}
@@ -10813,12 +11793,12 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ chalk@5.3.0: {}
+
chalk@5.4.1: {}
char-regex@1.0.2: {}
- character-entities@2.0.2: {}
-
chardet@0.7.0: {}
chokidar-cli@3.0.0:
@@ -10862,6 +11842,10 @@ snapshots:
dependencies:
restore-cursor: 3.1.0
+ cli-cursor@4.0.0:
+ dependencies:
+ restore-cursor: 4.0.0
+
cli-spinners@2.9.2: {}
cli-table3@0.6.5:
@@ -10870,6 +11854,11 @@ snapshots:
optionalDependencies:
'@colors/colors': 1.5.0
+ cli-truncate@3.1.0:
+ dependencies:
+ slice-ansi: 5.0.0
+ string-width: 5.1.2
+
cli-width@3.0.0: {}
cli-width@4.1.0: {}
@@ -10920,6 +11909,8 @@ snapshots:
color-convert: 2.0.1
color-string: 1.9.1
+ colorette@2.0.20: {}
+
combine-errors@3.0.3:
dependencies:
custom-error-instance: 2.1.1
@@ -10929,12 +11920,12 @@ snapshots:
dependencies:
delayed-stream: 1.0.0
+ commander@11.0.0: {}
+
commander@2.20.3: {}
commander@4.1.1: {}
- commander@8.3.0: {}
-
comment-json@4.2.5:
dependencies:
array-timsort: 1.0.3
@@ -10943,6 +11934,11 @@ snapshots:
has-own-prop: 2.0.0
repeat-string: 1.6.1
+ compare-func@2.0.0:
+ dependencies:
+ array-ify: 1.0.0
+ dot-prop: 5.3.0
+
component-emitter@1.3.1: {}
compress-commons@4.1.2:
@@ -10985,6 +11981,21 @@ snapshots:
content-type@1.0.5: {}
+ conventional-changelog-angular@6.0.0:
+ dependencies:
+ compare-func: 2.0.0
+
+ conventional-changelog-conventionalcommits@6.1.0:
+ dependencies:
+ compare-func: 2.0.0
+
+ conventional-commits-parser@4.0.0:
+ dependencies:
+ JSONStream: 1.3.5
+ is-text-path: 1.0.1
+ meow: 8.1.2
+ split2: 3.2.2
+
convert-source-map@2.0.0: {}
cookie-signature@1.0.6: {}
@@ -10995,6 +12006,10 @@ snapshots:
cookiejar@2.1.4: {}
+ copy-anything@2.0.6:
+ dependencies:
+ is-what: 3.14.1
+
copy-anything@3.0.5:
dependencies:
is-what: 4.1.16
@@ -11010,6 +12025,13 @@ snapshots:
object-assign: 4.1.1
vary: 1.1.2
+ cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@5.7.2))(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.5.1)(typescript@5.7.2))(typescript@5.7.2):
+ dependencies:
+ '@types/node': 20.5.1
+ cosmiconfig: 8.3.6(typescript@5.7.2)
+ ts-node: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
+ typescript: 5.7.2
+
cosmiconfig@8.3.6(typescript@5.7.2):
dependencies:
import-fresh: 3.3.0
@@ -11026,13 +12048,13 @@ snapshots:
crc-32: 1.2.2
readable-stream: 3.6.2
- create-jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)):
+ create-jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)):
dependencies:
'@jest/types': 29.6.3
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.11
- jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
jest-util: 29.7.0
prompts: 2.4.2
transitivePeerDependencies:
@@ -11127,6 +12149,8 @@ snapshots:
graphlib: 2.1.8
lodash: 4.17.21
+ dargs@7.0.0: {}
+
date-fns@2.30.0:
dependencies:
'@babel/runtime': 7.26.0
@@ -11137,6 +12161,10 @@ snapshots:
dependencies:
ms: 2.0.0
+ debug@4.3.4:
+ dependencies:
+ ms: 2.1.2
+
debug@4.3.7:
dependencies:
ms: 2.1.3
@@ -11145,11 +12173,12 @@ snapshots:
dependencies:
ms: 2.1.3
- decamelize@1.2.0: {}
-
- decode-named-character-reference@1.0.2:
+ decamelize-keys@1.1.1:
dependencies:
- character-entities: 2.0.2
+ decamelize: 1.2.0
+ map-obj: 1.0.1
+
+ decamelize@1.2.0: {}
decode-uri-component@0.2.2: {}
@@ -11157,8 +12186,6 @@ snapshots:
deep-is@0.1.4: {}
- deepmerge@1.5.2: {}
-
deepmerge@4.3.1: {}
defaults@1.0.4:
@@ -11182,8 +12209,6 @@ snapshots:
depd@2.0.0: {}
- dequal@2.0.3: {}
-
destroy@1.2.0: {}
detect-libc@2.0.3: {}
@@ -11201,8 +12226,6 @@ snapshots:
diff@4.0.2: {}
- diff@5.2.0: {}
-
dir-glob@3.0.1:
dependencies:
path-type: 4.0.0
@@ -11218,6 +12241,10 @@ snapshots:
no-case: 3.0.4
tslib: 2.8.1
+ dot-prop@5.3.0:
+ dependencies:
+ is-obj: 2.0.0
+
dotenv-expand@10.0.0: {}
dotenv@16.4.5: {}
@@ -11292,13 +12319,6 @@ snapshots:
- supports-color
- utf-8-validate
- enhanced-resolve@2.3.0:
- dependencies:
- graceful-fs: 4.2.11
- memory-fs: 0.3.0
- object-assign: 4.1.1
- tapable: 0.2.9
-
enhanced-resolve@5.18.0:
dependencies:
graceful-fs: 4.2.11
@@ -11306,8 +12326,6 @@ snapshots:
entities@4.5.0: {}
- err-code@3.0.1: {}
-
errno@0.1.8:
dependencies:
prr: 1.0.1
@@ -11326,6 +12344,31 @@ snapshots:
dependencies:
es-errors: 1.3.0
+ esbuild@0.18.20:
+ optionalDependencies:
+ '@esbuild/android-arm': 0.18.20
+ '@esbuild/android-arm64': 0.18.20
+ '@esbuild/android-x64': 0.18.20
+ '@esbuild/darwin-arm64': 0.18.20
+ '@esbuild/darwin-x64': 0.18.20
+ '@esbuild/freebsd-arm64': 0.18.20
+ '@esbuild/freebsd-x64': 0.18.20
+ '@esbuild/linux-arm': 0.18.20
+ '@esbuild/linux-arm64': 0.18.20
+ '@esbuild/linux-ia32': 0.18.20
+ '@esbuild/linux-loong64': 0.18.20
+ '@esbuild/linux-mips64el': 0.18.20
+ '@esbuild/linux-ppc64': 0.18.20
+ '@esbuild/linux-riscv64': 0.18.20
+ '@esbuild/linux-s390x': 0.18.20
+ '@esbuild/linux-x64': 0.18.20
+ '@esbuild/netbsd-x64': 0.18.20
+ '@esbuild/openbsd-x64': 0.18.20
+ '@esbuild/sunos-x64': 0.18.20
+ '@esbuild/win32-arm64': 0.18.20
+ '@esbuild/win32-ia32': 0.18.20
+ '@esbuild/win32-x64': 0.18.20
+
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
@@ -11390,10 +12433,22 @@ snapshots:
escape-string-regexp@4.0.0: {}
+ eslint-config-prettier@8.10.0(eslint@8.57.1):
+ dependencies:
+ eslint: 8.57.1
+
eslint-config-prettier@9.1.0(eslint@8.57.1):
dependencies:
eslint: 8.57.1
+ eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.4):
+ dependencies:
+ eslint: 8.57.1
+ prettier: 2.8.4
+ prettier-linter-helpers: 1.0.0
+ optionalDependencies:
+ eslint-config-prettier: 8.10.0(eslint@8.57.1)
+
eslint-plugin-prettier@5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2):
dependencies:
eslint: 8.57.1
@@ -11555,8 +12610,6 @@ snapshots:
etag@1.8.1: {}
- eventemitter3@4.0.7: {}
-
eventemitter3@5.0.1: {}
events@3.3.0: {}
@@ -11585,6 +12638,18 @@ snapshots:
signal-exit: 3.0.7
strip-final-newline: 2.0.0
+ execa@7.2.0:
+ dependencies:
+ cross-spawn: 7.0.6
+ get-stream: 6.0.1
+ human-signals: 4.3.1
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 3.0.7
+ strip-final-newline: 3.0.0
+
exit@0.1.2: {}
expect@29.7.0:
@@ -11763,7 +12828,7 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
- fork-ts-checker-webpack-plugin@9.0.2(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6)):
+ fork-ts-checker-webpack-plugin@9.0.2(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))):
dependencies:
'@babel/code-frame': 7.26.2
chalk: 4.1.2
@@ -11778,7 +12843,7 @@ snapshots:
semver: 7.6.3
tapable: 2.2.1
typescript: 5.7.2
- webpack: 5.97.1(@swc/core@1.10.6)
+ webpack: 5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))
form-data@4.0.1:
dependencies:
@@ -11816,10 +12881,19 @@ snapshots:
jsonfile: 6.1.0
universalify: 2.0.1
+ fs-extra@11.3.0:
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 6.1.0
+ universalify: 2.0.1
+
fs-monkey@1.0.6: {}
fs.realpath@1.0.0: {}
+ fsevents@2.3.2:
+ optional: true
+
fsevents@2.3.3:
optional: true
@@ -11836,8 +12910,6 @@ snapshots:
gensync@1.0.0-beta.2: {}
- get-browser-rtc@1.1.0: {}
-
get-caller-file@2.0.5: {}
get-intrinsic@1.2.7:
@@ -11864,6 +12936,14 @@ snapshots:
get-stream@6.0.1: {}
+ git-raw-commits@2.0.11:
+ dependencies:
+ dargs: 7.0.0
+ lodash: 4.17.21
+ meow: 8.1.2
+ split2: 3.2.2
+ through2: 4.0.2
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -11901,6 +12981,10 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
+ global-dirs@0.1.1:
+ dependencies:
+ ini: 1.3.8
+
globals@11.12.0: {}
globals@13.24.0:
@@ -11934,6 +13018,8 @@ snapshots:
dependencies:
lodash: 4.17.21
+ hard-rejection@2.1.0: {}
+
has-flag@4.0.0: {}
has-own-prop@2.0.0: {}
@@ -11960,6 +13046,12 @@ snapshots:
dependencies:
react-is: 16.13.1
+ hosted-git-info@2.8.9: {}
+
+ hosted-git-info@4.1.0:
+ dependencies:
+ lru-cache: 6.0.0
+
html-escaper@2.0.2: {}
http-errors@2.0.0:
@@ -11972,16 +13064,28 @@ snapshots:
human-signals@2.1.0: {}
+ human-signals@4.3.1: {}
+
+ husky@8.0.3: {}
+
iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+ optional: true
+
idb-keyval@6.2.1: {}
ieee754@1.2.1: {}
ignore@5.3.2: {}
+ image-size@0.5.5:
+ optional: true
+
immediate@3.0.6: {}
immediate@3.3.0: {}
@@ -11991,6 +13095,8 @@ snapshots:
parent-module: 1.0.1
resolve-from: 4.0.0
+ import-lazy@4.0.0: {}
+
import-local@3.2.0:
dependencies:
pkg-dir: 4.2.0
@@ -11998,6 +13104,8 @@ snapshots:
imurmurhash@0.1.4: {}
+ indent-string@4.0.0: {}
+
inflight@1.0.6:
dependencies:
once: 1.4.0
@@ -12005,6 +13113,8 @@ snapshots:
inherits@2.0.4: {}
+ ini@1.3.8: {}
+
inquirer@8.2.6:
dependencies:
ansi-escapes: 4.3.2
@@ -12086,6 +13196,8 @@ snapshots:
is-fullwidth-code-point@3.0.0: {}
+ is-fullwidth-code-point@4.0.0: {}
+
is-generator-fn@2.1.0: {}
is-generator-function@1.1.0:
@@ -12103,10 +13215,14 @@ snapshots:
is-number@7.0.0: {}
+ is-obj@2.0.0: {}
+
is-obj@3.0.0: {}
is-path-inside@3.0.3: {}
+ is-plain-obj@1.1.0: {}
+
is-regex@1.2.1:
dependencies:
call-bound: 1.0.3
@@ -12118,12 +13234,20 @@ snapshots:
is-stream@2.0.1: {}
+ is-stream@3.0.0: {}
+
+ is-text-path@1.0.1:
+ dependencies:
+ text-extensions: 1.9.0
+
is-typed-array@1.1.15:
dependencies:
which-typed-array: 1.1.18
is-unicode-supported@0.1.0: {}
+ is-what@3.14.1: {}
+
is-what@4.1.16: {}
isarray@1.0.0: {}
@@ -12226,16 +13350,16 @@ snapshots:
- babel-plugin-macros
- supports-color
- jest-cli@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)):
+ jest-cli@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)):
dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
'@jest/test-result': 29.7.0
'@jest/types': 29.6.3
chalk: 4.1.2
- create-jest: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ create-jest: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
exit: 0.1.2
import-local: 3.2.0
- jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
jest-util: 29.7.0
jest-validate: 29.7.0
yargs: 17.7.2
@@ -12245,7 +13369,7 @@ snapshots:
- supports-color
- ts-node
- jest-config@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)):
+ jest-config@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)):
dependencies:
'@babel/core': 7.26.0
'@jest/test-sequencer': 29.7.0
@@ -12271,7 +13395,7 @@ snapshots:
strip-json-comments: 3.1.1
optionalDependencies:
'@types/node': 20.17.12
- ts-node: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ ts-node: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
transitivePeerDependencies:
- babel-plugin-macros
- supports-color
@@ -12497,12 +13621,12 @@ snapshots:
merge-stream: 2.0.0
supports-color: 8.1.1
- jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)):
+ jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)):
dependencies:
- '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
'@jest/types': 29.6.3
import-local: 3.2.0
- jest-cli: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ jest-cli: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
@@ -12511,12 +13635,19 @@ snapshots:
jiti@1.21.7: {}
+ jju@1.4.0: {}
+
joycon@3.1.1: {}
js-base64@3.7.7: {}
js-tokens@4.0.0: {}
+ js-yaml@3.13.1:
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+
js-yaml@3.14.1:
dependencies:
argparse: 1.0.10
@@ -12554,6 +13685,8 @@ snapshots:
optionalDependencies:
graceful-fs: 4.2.11
+ jsonparse@1.3.1: {}
+
jsonwebtoken@9.0.2:
dependencies:
jws: 3.2.2
@@ -12585,22 +13718,32 @@ snapshots:
jwa: 1.4.1
safe-buffer: 5.2.1
- katex@0.16.19:
- dependencies:
- commander: 8.3.0
-
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
- kleur@3.0.3: {}
+ kind-of@6.0.3: {}
- kleur@4.1.5: {}
+ kleur@3.0.3: {}
lazystream@1.0.1:
dependencies:
readable-stream: 2.3.8
+ less@4.2.2:
+ dependencies:
+ copy-anything: 2.0.6
+ parse-node-version: 1.0.1
+ tslib: 2.8.1
+ optionalDependencies:
+ errno: 0.1.8
+ graceful-fs: 4.2.11
+ image-size: 0.5.5
+ make-dir: 2.1.0
+ mime: 1.6.0
+ needle: 3.3.1
+ source-map: 0.6.1
+
level-codec@9.0.2:
dependencies:
buffer: 5.7.1
@@ -12668,12 +13811,39 @@ snapshots:
dependencies:
immediate: 3.0.6
+ lilconfig@2.1.0: {}
+
lilconfig@3.1.3: {}
lines-and-columns@1.2.4: {}
+ lint-staged@13.3.0:
+ dependencies:
+ chalk: 5.3.0
+ commander: 11.0.0
+ debug: 4.3.4
+ execa: 7.2.0
+ lilconfig: 2.1.0
+ listr2: 6.6.1
+ micromatch: 4.0.5
+ pidtree: 0.6.0
+ string-argv: 0.3.2
+ yaml: 2.3.1
+ transitivePeerDependencies:
+ - enquirer
+ - supports-color
+
listenercount@1.0.1: {}
+ listr2@6.6.1:
+ dependencies:
+ cli-truncate: 3.1.0
+ colorette: 2.0.20
+ eventemitter3: 5.0.1
+ log-update: 5.0.1
+ rfdc: 1.4.1
+ wrap-ansi: 8.1.0
+
load-tsconfig@0.2.5: {}
loader-runner@4.3.0: {}
@@ -12712,6 +13882,8 @@ snapshots:
dependencies:
lodash._basetostring: 4.12.0
+ lodash.camelcase@4.3.0: {}
+
lodash.clonedeep@4.5.0: {}
lodash.debounce@4.0.8: {}
@@ -12748,14 +13920,22 @@ snapshots:
lodash.isundefined@3.0.1: {}
+ lodash.kebabcase@4.1.1: {}
+
lodash.memoize@4.1.2: {}
lodash.merge@4.6.2: {}
+ lodash.mergewith@4.6.2: {}
+
lodash.once@4.1.1: {}
+ lodash.snakecase@4.1.1: {}
+
lodash.sortby@4.7.0: {}
+ lodash.startcase@4.4.0: {}
+
lodash.throttle@4.1.1: {}
lodash.union@4.6.0: {}
@@ -12767,6 +13947,8 @@ snapshots:
lodash._baseiteratee: 4.7.0
lodash._baseuniq: 4.6.0
+ lodash.upperfirst@4.3.1: {}
+
lodash@4.17.21: {}
log-symbols@4.1.0:
@@ -12774,6 +13956,14 @@ snapshots:
chalk: 4.1.2
is-unicode-supported: 0.1.0
+ log-update@5.0.1:
+ dependencies:
+ ansi-escapes: 5.0.0
+ cli-cursor: 4.0.0
+ slice-ansi: 5.0.0
+ strip-ansi: 7.1.0
+ wrap-ansi: 8.1.0
+
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@@ -12790,6 +13980,10 @@ snapshots:
dependencies:
yallist: 3.1.1
+ lru-cache@6.0.0:
+ dependencies:
+ yallist: 4.0.0
+
ltgt@2.2.1: {}
luxon@3.5.0: {}
@@ -12798,6 +13992,12 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
+ make-dir@2.1.0:
+ dependencies:
+ pify: 4.0.1
+ semver: 5.7.2
+ optional: true
+
make-dir@4.0.0:
dependencies:
semver: 7.6.3
@@ -12808,29 +14008,12 @@ snapshots:
dependencies:
tmpl: 1.0.5
+ map-obj@1.0.1: {}
+
+ map-obj@4.3.0: {}
+
math-intrinsics@1.1.0: {}
- mdast-util-from-markdown@1.3.1:
- dependencies:
- '@types/mdast': 3.0.15
- '@types/unist': 2.0.11
- decode-named-character-reference: 1.0.2
- mdast-util-to-string: 3.2.0
- micromark: 3.2.0
- micromark-util-decode-numeric-character-reference: 1.1.0
- micromark-util-decode-string: 1.1.0
- micromark-util-normalize-identifier: 1.1.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
- unist-util-stringify-position: 3.0.3
- uvu: 0.5.6
- transitivePeerDependencies:
- - supports-color
-
- mdast-util-to-string@3.2.0:
- dependencies:
- '@types/mdast': 3.0.15
-
media-typer@0.3.0: {}
memfs@3.5.3:
@@ -12839,10 +14022,19 @@ snapshots:
memoize-one@5.2.1: {}
- memory-fs@0.3.0:
+ meow@8.1.2:
dependencies:
- errno: 0.1.8
- readable-stream: 2.3.8
+ '@types/minimist': 1.2.5
+ camelcase-keys: 6.2.2
+ decamelize-keys: 1.1.1
+ hard-rejection: 2.1.0
+ minimist-options: 4.1.0
+ normalize-package-data: 3.0.3
+ read-pkg-up: 7.0.1
+ redent: 3.0.0
+ trim-newlines: 3.0.1
+ type-fest: 0.18.1
+ yargs-parser: 20.2.9
merge-descriptors@1.0.3: {}
@@ -12852,138 +14044,10 @@ snapshots:
methods@1.1.2: {}
- micromark-core-commonmark@1.1.0:
+ micromatch@4.0.5:
dependencies:
- decode-named-character-reference: 1.0.2
- micromark-factory-destination: 1.1.0
- micromark-factory-label: 1.1.0
- micromark-factory-space: 1.1.0
- micromark-factory-title: 1.1.0
- micromark-factory-whitespace: 1.1.0
- micromark-util-character: 1.2.0
- micromark-util-chunked: 1.1.0
- micromark-util-classify-character: 1.1.0
- micromark-util-html-tag-name: 1.2.0
- micromark-util-normalize-identifier: 1.1.0
- micromark-util-resolve-all: 1.1.0
- micromark-util-subtokenize: 1.1.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
- uvu: 0.5.6
-
- micromark-factory-destination@1.1.0:
- dependencies:
- micromark-util-character: 1.2.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
-
- micromark-factory-label@1.1.0:
- dependencies:
- micromark-util-character: 1.2.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
- uvu: 0.5.6
-
- micromark-factory-space@1.1.0:
- dependencies:
- micromark-util-character: 1.2.0
- micromark-util-types: 1.1.0
-
- micromark-factory-title@1.1.0:
- dependencies:
- micromark-factory-space: 1.1.0
- micromark-util-character: 1.2.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
-
- micromark-factory-whitespace@1.1.0:
- dependencies:
- micromark-factory-space: 1.1.0
- micromark-util-character: 1.2.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
-
- micromark-util-character@1.2.0:
- dependencies:
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
-
- micromark-util-chunked@1.1.0:
- dependencies:
- micromark-util-symbol: 1.1.0
-
- micromark-util-classify-character@1.1.0:
- dependencies:
- micromark-util-character: 1.2.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
-
- micromark-util-combine-extensions@1.1.0:
- dependencies:
- micromark-util-chunked: 1.1.0
- micromark-util-types: 1.1.0
-
- micromark-util-decode-numeric-character-reference@1.1.0:
- dependencies:
- micromark-util-symbol: 1.1.0
-
- micromark-util-decode-string@1.1.0:
- dependencies:
- decode-named-character-reference: 1.0.2
- micromark-util-character: 1.2.0
- micromark-util-decode-numeric-character-reference: 1.1.0
- micromark-util-symbol: 1.1.0
-
- micromark-util-encode@1.1.0: {}
-
- micromark-util-html-tag-name@1.2.0: {}
-
- micromark-util-normalize-identifier@1.1.0:
- dependencies:
- micromark-util-symbol: 1.1.0
-
- micromark-util-resolve-all@1.1.0:
- dependencies:
- micromark-util-types: 1.1.0
-
- micromark-util-sanitize-uri@1.2.0:
- dependencies:
- micromark-util-character: 1.2.0
- micromark-util-encode: 1.1.0
- micromark-util-symbol: 1.1.0
-
- micromark-util-subtokenize@1.1.0:
- dependencies:
- micromark-util-chunked: 1.1.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
- uvu: 0.5.6
-
- micromark-util-symbol@1.1.0: {}
-
- micromark-util-types@1.1.0: {}
-
- micromark@3.2.0:
- dependencies:
- '@types/debug': 4.1.12
- debug: 4.4.0
- decode-named-character-reference: 1.0.2
- micromark-core-commonmark: 1.1.0
- micromark-factory-space: 1.1.0
- micromark-util-character: 1.2.0
- micromark-util-chunked: 1.1.0
- micromark-util-combine-extensions: 1.1.0
- micromark-util-decode-numeric-character-reference: 1.1.0
- micromark-util-encode: 1.1.0
- micromark-util-normalize-identifier: 1.1.0
- micromark-util-resolve-all: 1.1.0
- micromark-util-sanitize-uri: 1.2.0
- micromark-util-subtokenize: 1.1.0
- micromark-util-symbol: 1.1.0
- micromark-util-types: 1.1.0
- uvu: 0.5.6
- transitivePeerDependencies:
- - supports-color
+ braces: 3.0.3
+ picomatch: 2.3.1
micromatch@4.0.8:
dependencies:
@@ -13002,10 +14066,18 @@ snapshots:
mimic-fn@2.1.0: {}
+ mimic-fn@4.0.0: {}
+
+ min-indent@1.0.1: {}
+
minimatch@10.0.1:
dependencies:
brace-expansion: 2.0.1
+ minimatch@3.0.8:
+ dependencies:
+ brace-expansion: 1.1.11
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.11
@@ -13022,6 +14094,12 @@ snapshots:
dependencies:
brace-expansion: 2.0.1
+ minimist-options@4.1.0:
+ dependencies:
+ arrify: 1.0.1
+ is-plain-obj: 1.1.0
+ kind-of: 6.0.3
+
minimist@1.2.8: {}
minio@8.0.3:
@@ -13055,10 +14133,10 @@ snapshots:
motion-utils@11.16.0: {}
- mri@1.2.0: {}
-
ms@2.0.0: {}
+ ms@2.1.2: {}
+
ms@2.1.3: {}
msgpackr-extract@3.0.3:
@@ -13112,8 +14190,16 @@ snapshots:
napi-macros@2.0.0: {}
+ natural-compare-lite@1.4.0: {}
+
natural-compare@1.4.0: {}
+ needle@3.3.1:
+ dependencies:
+ iconv-lite: 0.6.3
+ sax: 1.4.1
+ optional: true
+
negotiator@0.6.3: {}
neo-async@2.6.2: {}
@@ -13148,6 +14234,20 @@ snapshots:
node-releases@2.0.19: {}
+ normalize-package-data@2.5.0:
+ dependencies:
+ hosted-git-info: 2.8.9
+ resolve: 1.22.10
+ semver: 5.7.2
+ validate-npm-package-license: 3.0.4
+
+ normalize-package-data@3.0.3:
+ dependencies:
+ hosted-git-info: 4.1.0
+ is-core-module: 2.16.1
+ semver: 7.6.3
+ validate-npm-package-license: 3.0.4
+
normalize-path@3.0.0: {}
normalize-range@0.1.2: {}
@@ -13156,6 +14256,10 @@ snapshots:
dependencies:
path-key: 3.1.1
+ npm-run-path@5.3.0:
+ dependencies:
+ path-key: 4.0.0
+
object-assign@4.1.1: {}
object-hash@3.0.0: {}
@@ -13174,6 +14278,10 @@ snapshots:
dependencies:
mimic-fn: 2.1.0
+ onetime@6.0.0:
+ dependencies:
+ mimic-fn: 4.0.0
+
optionator@0.9.4:
dependencies:
deep-is: 0.1.4
@@ -13236,6 +14344,8 @@ snapshots:
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
+ parse-node-version@1.0.1: {}
+
parseurl@1.3.3: {}
path-exists@3.0.0: {}
@@ -13246,6 +14356,8 @@ snapshots:
path-key@3.1.1: {}
+ path-key@4.0.0: {}
+
path-parse@1.0.7: {}
path-scurry@1.11.1:
@@ -13264,13 +14376,6 @@ snapshots:
path-type@4.0.0: {}
- pdf-lib@1.17.1:
- dependencies:
- '@pdf-lib/standard-fonts': 1.0.0
- '@pdf-lib/upng': 1.0.1
- pako: 1.0.11
- tslib: 1.14.1
-
picocolors@1.1.1: {}
picomatch@2.3.1: {}
@@ -13279,8 +14384,13 @@ snapshots:
picomatch@4.0.2: {}
+ pidtree@0.6.0: {}
+
pify@2.3.0: {}
+ pify@4.0.1:
+ optional: true
+
pinyin-pro@3.26.0: {}
pirates@4.0.6: {}
@@ -13289,6 +14399,14 @@ snapshots:
dependencies:
find-up: 4.1.0
+ playwright-core@1.50.1: {}
+
+ playwright@1.50.1:
+ dependencies:
+ playwright-core: 1.50.1
+ optionalDependencies:
+ fsevents: 2.3.2
+
pluralize@8.0.0: {}
possible-typed-array-names@1.0.0: {}
@@ -13305,13 +14423,13 @@ snapshots:
camelcase-css: 2.0.1
postcss: 8.4.49
- postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)):
+ postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)):
dependencies:
lilconfig: 3.1.3
yaml: 2.7.0
optionalDependencies:
postcss: 8.4.49
- ts-node: 10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)
+ ts-node: 10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.4.49)(yaml@2.7.0):
dependencies:
@@ -13345,6 +14463,8 @@ snapshots:
dependencies:
fast-diff: 1.3.0
+ prettier@2.8.4: {}
+
prettier@3.4.2: {}
pretty-format@29.7.0:
@@ -13410,6 +14530,8 @@ snapshots:
queue-microtask@1.2.3: {}
+ quick-lru@4.0.1: {}
+
quill-delta@5.1.0:
dependencies:
fast-diff: 1.3.0
@@ -13862,6 +14984,19 @@ snapshots:
dependencies:
pify: 2.3.0
+ read-pkg-up@7.0.1:
+ dependencies:
+ find-up: 4.1.0
+ read-pkg: 5.2.0
+ type-fest: 0.8.1
+
+ read-pkg@5.2.0:
+ dependencies:
+ '@types/normalize-package-data': 2.4.4
+ normalize-package-data: 2.5.0
+ parse-json: 5.2.0
+ type-fest: 0.6.0
+
readable-stream@2.3.8:
dependencies:
core-util-is: 1.0.3
@@ -13888,6 +15023,11 @@ snapshots:
readdirp@4.0.2: {}
+ redent@3.0.0:
+ dependencies:
+ indent-string: 4.0.0
+ strip-indent: 3.0.0
+
redis-errors@1.2.0: {}
redis-parser@3.0.0:
@@ -13918,12 +15058,14 @@ snapshots:
dependencies:
resolve-from: 5.0.0
- resolve-from@2.0.0: {}
-
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
+ resolve-global@1.0.0:
+ dependencies:
+ global-dirs: 0.1.1
+
resolve.exports@2.0.3: {}
resolve@1.22.10:
@@ -13937,10 +15079,17 @@ snapshots:
onetime: 5.1.2
signal-exit: 3.0.7
+ restore-cursor@4.0.0:
+ dependencies:
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+
retry@0.12.0: {}
reusify@1.0.4: {}
+ rfdc@1.4.1: {}
+
rimraf@2.7.1:
dependencies:
glob: 7.2.3
@@ -13954,6 +15103,10 @@ snapshots:
glob: 11.0.0
package-json-from-dist: 1.0.1
+ rollup@3.29.5:
+ optionalDependencies:
+ fsevents: 2.3.3
+
rollup@4.30.1:
dependencies:
'@types/estree': 1.0.6
@@ -13991,10 +15144,6 @@ snapshots:
dependencies:
tslib: 2.8.1
- sade@1.8.1:
- dependencies:
- mri: 1.2.0
-
safe-buffer@5.1.2: {}
safe-buffer@5.2.1: {}
@@ -14034,8 +15183,14 @@ snapshots:
dependencies:
compute-scroll-into-view: 3.1.0
+ semver@5.7.2: {}
+
semver@6.3.1: {}
+ semver@7.5.4:
+ dependencies:
+ lru-cache: 6.0.0
+
semver@7.6.3: {}
send@0.19.0:
@@ -14176,18 +15331,6 @@ snapshots:
signal-exit@4.1.0: {}
- simple-peer@9.11.1:
- dependencies:
- buffer: 6.0.3
- debug: 4.4.0
- err-code: 3.0.1
- get-browser-rtc: 1.1.0
- queue-microtask: 1.2.3
- randombytes: 2.1.0
- readable-stream: 3.6.2
- transitivePeerDependencies:
- - supports-color
-
simple-swizzle@0.2.2:
dependencies:
is-arrayish: 0.3.2
@@ -14196,6 +15339,11 @@ snapshots:
slash@3.0.0: {}
+ slice-ansi@5.0.0:
+ dependencies:
+ ansi-styles: 6.2.1
+ is-fullwidth-code-point: 4.0.0
+
slugify@1.6.6: {}
snake-case@3.0.4:
@@ -14255,8 +15403,26 @@ snapshots:
spawn-command@0.0.2: {}
+ spdx-correct@3.2.0:
+ dependencies:
+ spdx-expression-parse: 3.0.1
+ spdx-license-ids: 3.0.21
+
+ spdx-exceptions@2.5.0: {}
+
+ spdx-expression-parse@3.0.1:
+ dependencies:
+ spdx-exceptions: 2.5.0
+ spdx-license-ids: 3.0.21
+
+ spdx-license-ids@3.0.21: {}
+
split-on-first@1.1.0: {}
+ split2@3.2.2:
+ dependencies:
+ readable-stream: 3.6.2
+
sprintf-js@1.0.3: {}
stack-utils@2.0.6:
@@ -14277,6 +15443,8 @@ snapshots:
strict-uri-encode@2.0.0: {}
+ string-argv@0.3.2: {}
+
string-convert@0.2.1: {}
string-length@4.0.2:
@@ -14334,6 +15502,12 @@ snapshots:
strip-final-newline@2.0.0: {}
+ strip-final-newline@3.0.0: {}
+
+ strip-indent@3.0.0:
+ dependencies:
+ min-indent: 1.0.1
+
strip-json-comments@3.1.1: {}
strnum@1.0.5: {}
@@ -14403,7 +15577,7 @@ snapshots:
tailwind-merge@2.6.0: {}
- tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)):
+ tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -14422,7 +15596,7 @@ snapshots:
postcss: 8.4.49
postcss-import: 15.1.0(postcss@8.4.49)
postcss-js: 4.0.1(postcss@8.4.49)
- postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
postcss-nested: 6.2.0(postcss@8.4.49)
postcss-selector-parser: 6.1.2
resolve: 1.22.10
@@ -14430,8 +15604,6 @@ snapshots:
transitivePeerDependencies:
- ts-node
- tapable@0.2.9: {}
-
tapable@2.2.1: {}
tar-stream@2.2.0:
@@ -14442,24 +15614,14 @@ snapshots:
inherits: 2.0.4
readable-stream: 3.6.2
- tern@0.24.3:
- dependencies:
- acorn: 6.4.2
- acorn-loose: 6.1.0
- acorn-walk: 6.2.0
- enhanced-resolve: 2.3.0
- glob: 7.2.3
- minimatch: 3.1.2
- resolve-from: 2.0.0
-
- terser-webpack-plugin@5.3.11(@swc/core@1.10.6)(webpack@5.97.1(@swc/core@1.10.6)):
+ terser-webpack-plugin@5.3.11(@swc/core@1.10.6(@swc/helpers@0.5.15))(webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))):
dependencies:
'@jridgewell/trace-mapping': 0.3.25
jest-worker: 27.5.1
schema-utils: 4.3.0
serialize-javascript: 6.0.2
terser: 5.37.0
- webpack: 5.97.1(@swc/core@1.10.6)
+ webpack: 5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))
optionalDependencies:
'@swc/core': 1.10.6(@swc/helpers@0.5.15)
@@ -14476,6 +15638,8 @@ snapshots:
glob: 7.2.3
minimatch: 3.1.2
+ text-extensions@1.9.0: {}
+
text-table@0.2.0: {}
thenify-all@1.6.0:
@@ -14535,6 +15699,8 @@ snapshots:
tree-kill@1.2.2: {}
+ trim-newlines@3.0.1: {}
+
ts-api-utils@1.4.3(typescript@5.7.2):
dependencies:
typescript: 5.7.2
@@ -14545,12 +15711,12 @@ snapshots:
ts-interface-checker@0.1.13: {}
- ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2)))(typescript@5.7.2):
+ ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2)))(typescript@5.7.2):
dependencies:
bs-logger: 0.2.6
ejs: 3.1.10
fast-json-stable-stringify: 2.1.0
- jest: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2))
+ jest: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2))
jest-util: 29.7.0
json5: 2.2.3
lodash.memoize: 4.1.2
@@ -14564,7 +15730,7 @@ snapshots:
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.26.0)
- ts-loader@9.5.1(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6)):
+ ts-loader@9.5.1(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))):
dependencies:
chalk: 4.1.2
enhanced-resolve: 5.18.0
@@ -14572,9 +15738,9 @@ snapshots:
semver: 7.6.3
source-map: 0.7.4
typescript: 5.7.2
- webpack: 5.97.1(@swc/core@1.10.6)
+ webpack: 5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15))
- ts-node@10.9.2(@swc/core@1.10.6)(@types/node@20.17.12)(typescript@5.7.2):
+ ts-node@10.9.2(@swc/core@1.10.6(@swc/helpers@0.5.15))(@types/node@20.17.12)(typescript@5.7.2):
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.11
@@ -14611,7 +15777,7 @@ snapshots:
tslib@2.8.1: {}
- tsup@8.3.5(@swc/core@1.10.6)(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0):
+ tsup@8.3.5(@microsoft/api-extractor@7.49.2(@types/node@20.17.12))(@swc/core@1.10.6(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.7.0):
dependencies:
bundle-require: 5.1.0(esbuild@0.24.2)
cac: 6.7.14
@@ -14630,6 +15796,7 @@ snapshots:
tinyglobby: 0.2.10
tree-kill: 1.2.2
optionalDependencies:
+ '@microsoft/api-extractor': 7.49.2(@types/node@20.17.12)
'@swc/core': 1.10.6(@swc/helpers@0.5.15)
postcss: 8.4.49
typescript: 5.7.2
@@ -14639,6 +15806,11 @@ snapshots:
- tsx
- yaml
+ tsutils@3.21.0(typescript@5.7.2):
+ dependencies:
+ tslib: 1.14.1
+ typescript: 5.7.2
+
tus-js-client@4.2.3:
dependencies:
buffer-from: 1.1.2
@@ -14655,10 +15827,18 @@ snapshots:
type-detect@4.0.8: {}
+ type-fest@0.18.1: {}
+
type-fest@0.20.2: {}
type-fest@0.21.3: {}
+ type-fest@0.6.0: {}
+
+ type-fest@0.8.1: {}
+
+ type-fest@1.4.0: {}
+
type-is@1.6.18:
dependencies:
media-typer: 0.3.0
@@ -14684,10 +15864,6 @@ snapshots:
undici-types@6.19.8: {}
- unist-util-stringify-position@3.0.3:
- dependencies:
- '@types/unist': 2.0.11
-
universalify@2.0.1: {}
unpipe@1.0.0: {}
@@ -14748,13 +15924,6 @@ snapshots:
uuid@9.0.1: {}
- uvu@0.5.6:
- dependencies:
- dequal: 2.0.3
- diff: 5.2.0
- kleur: 4.1.5
- sade: 1.8.1
-
uzip@0.20201231.0: {}
v8-compile-cache-lib@3.0.1: {}
@@ -14765,20 +15934,40 @@ snapshots:
'@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0
+ validate-npm-package-license@3.0.4:
+ dependencies:
+ spdx-correct: 3.2.0
+ spdx-expression-parse: 3.0.1
+
vary@1.1.2: {}
- vite-plugin-svgr@4.3.0(rollup@4.30.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.12)(terser@5.37.0)):
+ vite-plugin-css-injected-by-js@3.5.2(vite@4.5.9(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)):
+ dependencies:
+ vite: 4.5.9(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
+
+ vite-plugin-svgr@4.3.0(rollup@4.30.1)(typescript@5.7.2)(vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)):
dependencies:
'@rollup/pluginutils': 5.1.4(rollup@4.30.1)
'@svgr/core': 8.1.0(typescript@5.7.2)
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.7.2))
- vite: 5.4.11(@types/node@20.17.12)(terser@5.37.0)
+ vite: 5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0)
transitivePeerDependencies:
- rollup
- supports-color
- typescript
- vite@5.4.11(@types/node@20.17.12)(terser@5.37.0):
+ vite@4.5.9(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0):
+ dependencies:
+ esbuild: 0.18.20
+ postcss: 8.4.49
+ rollup: 3.29.5
+ optionalDependencies:
+ '@types/node': 20.17.12
+ fsevents: 2.3.3
+ less: 4.2.2
+ terser: 5.37.0
+
+ vite@5.4.11(@types/node@20.17.12)(less@4.2.2)(terser@5.37.0):
dependencies:
esbuild: 0.21.5
postcss: 8.4.49
@@ -14786,6 +15975,7 @@ snapshots:
optionalDependencies:
'@types/node': 20.17.12
fsevents: 2.3.3
+ less: 4.2.2
terser: 5.37.0
walker@1.0.8:
@@ -14815,7 +16005,7 @@ snapshots:
webpack-sources@3.2.3: {}
- webpack@5.97.1(@swc/core@1.10.6):
+ webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15)):
dependencies:
'@types/eslint-scope': 3.7.7
'@types/estree': 1.0.6
@@ -14837,7 +16027,7 @@ snapshots:
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
- terser-webpack-plugin: 5.3.11(@swc/core@1.10.6)(webpack@5.97.1(@swc/core@1.10.6))
+ terser-webpack-plugin: 5.3.11(@swc/core@1.10.6(@swc/helpers@0.5.15))(webpack@5.97.1(@swc/core@1.10.6(@swc/helpers@0.5.15)))
watchpack: 2.4.2
webpack-sources: 3.2.3
transitivePeerDependencies:
@@ -14908,16 +16098,10 @@ snapshots:
imurmurhash: 0.1.4
signal-exit: 3.0.7
- ws@7.5.10: {}
-
ws@8.17.1: {}
ws@8.18.0: {}
- xml-js@1.6.11:
- dependencies:
- sax: 1.4.1
-
xml2js@0.6.2:
dependencies:
sax: 1.4.1
@@ -14935,24 +16119,6 @@ snapshots:
lib0: 0.2.99
yjs: 13.6.21
- y-protocols@1.0.6(yjs@13.6.21):
- dependencies:
- lib0: 0.2.99
- yjs: 13.6.21
-
- y-webrtc@10.3.0(yjs@13.6.21):
- dependencies:
- lib0: 0.2.99
- simple-peer: 9.11.1
- y-protocols: 1.0.6(yjs@13.6.21)
- yjs: 13.6.21
- optionalDependencies:
- ws: 8.18.0
- transitivePeerDependencies:
- - bufferutil
- - supports-color
- - utf-8-validate
-
y18n@4.0.3: {}
y18n@5.0.8: {}
@@ -14961,6 +16127,8 @@ snapshots:
yallist@4.0.0: {}
+ yaml@2.3.1: {}
+
yaml@2.7.0: {}
yargs-parser@13.1.2:
@@ -14968,6 +16136,8 @@ snapshots:
camelcase: 5.3.1
decamelize: 1.2.0
+ yargs-parser@20.2.9: {}
+
yargs-parser@21.1.1: {}
yargs@13.3.2:
From b6fce36b860e5a6d12f73ee001e81301a0f288d1 Mon Sep 17 00:00:00 2001
From: longdayi <13477510+longdayilongdayi@user.noreply.gitee.com>
Date: Wed, 5 Feb 2025 09:36:53 +0800
Subject: [PATCH 2/4] 02050936
---
packages/mind-elixir-core | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/mind-elixir-core b/packages/mind-elixir-core
index 57cbbc2..b911b4b 160000
--- a/packages/mind-elixir-core
+++ b/packages/mind-elixir-core
@@ -1 +1 @@
-Subproject commit 57cbbc27f9a04cf11bded6a88cf62ede3a1760ce
+Subproject commit b911b4ba7629da9d6c622abe241fd25299baf1a5
From 43ca9881d82880827c77998620d81add32a505d8 Mon Sep 17 00:00:00 2001
From: longdayi <13477510+longdayilongdayi@user.noreply.gitee.com>
Date: Wed, 5 Feb 2025 15:10:40 +0800
Subject: [PATCH 3/4] 02051510
---
.continue/prompts/coder.prompt | 19 +++
.continue/prompts/comment.prompt | 5 -
apps/web/package.json | 181 ++++++++++-----------
apps/web/src/hooks/useTusUpload.ts | 7 -
packages/common/src/index.ts | 5 +-
packages/common/src/models/course.ts | 7 +
packages/common/src/models/department.ts | 15 ++
packages/common/src/models/index.ts | 9 +
packages/common/src/models/message.ts | 7 +
packages/common/src/models/post.ts | 35 ++++
packages/common/src/models/rbac.ts | 22 +++
packages/common/src/models/section.ts | 5 +
packages/common/src/{ => models}/select.ts | 0
packages/common/src/models/staff.ts | 38 +++++
packages/common/src/models/term.ts | 8 +
packages/common/src/types.ts | 138 ----------------
packages/common/src/utils.ts | 4 +-
packages/utils/src/array-utils.ts | 0
packages/utils/src/browser-utils.ts | 0
packages/utils/src/crypto-utils.ts | 0
packages/utils/src/date-utils.ts | 0
packages/utils/src/dom-utils.ts | 0
packages/utils/src/file-utils.ts | 0
packages/utils/src/index.ts | 2 +-
packages/utils/src/math-utils.ts | 99 +++++++++++
packages/utils/src/object-utils.ts | 59 +++++++
packages/utils/src/random-utils.ts | 85 ++++++++++
packages/utils/src/string-utils.ts | 80 +++++++++
packages/utils/src/type-utils.ts | 94 +++++++++++
packages/utils/src/types.ts | 1 -
packages/utils/src/validation-utils.ts | 0
pnpm-lock.yaml | 146 -----------------
32 files changed, 677 insertions(+), 394 deletions(-)
create mode 100644 .continue/prompts/coder.prompt
create mode 100644 packages/common/src/models/course.ts
create mode 100644 packages/common/src/models/department.ts
create mode 100644 packages/common/src/models/index.ts
create mode 100644 packages/common/src/models/message.ts
create mode 100644 packages/common/src/models/post.ts
create mode 100644 packages/common/src/models/rbac.ts
create mode 100644 packages/common/src/models/section.ts
rename packages/common/src/{ => models}/select.ts (100%)
create mode 100644 packages/common/src/models/staff.ts
create mode 100644 packages/common/src/models/term.ts
create mode 100644 packages/utils/src/array-utils.ts
create mode 100644 packages/utils/src/browser-utils.ts
create mode 100644 packages/utils/src/crypto-utils.ts
create mode 100644 packages/utils/src/date-utils.ts
create mode 100644 packages/utils/src/dom-utils.ts
create mode 100644 packages/utils/src/file-utils.ts
create mode 100644 packages/utils/src/math-utils.ts
create mode 100644 packages/utils/src/object-utils.ts
create mode 100644 packages/utils/src/random-utils.ts
create mode 100644 packages/utils/src/string-utils.ts
create mode 100644 packages/utils/src/type-utils.ts
delete mode 100644 packages/utils/src/types.ts
create mode 100644 packages/utils/src/validation-utils.ts
diff --git a/.continue/prompts/coder.prompt b/.continue/prompts/coder.prompt
new file mode 100644
index 0000000..dce8ee7
--- /dev/null
+++ b/.continue/prompts/coder.prompt
@@ -0,0 +1,19 @@
+temperature: 0.5
+maxTokens: 8192
+---
+
+请扮演一名经验丰富的高级软件开发工程师,根据用户提供的指令创建、改进或扩展代码功能。
+输入要求:
+1. 用户将提供目标文件名或需要实现的功能描述。
+2. 输入中可能包括文件路径、代码风格要求,以及与功能相关的具体业务逻辑或技术细节。
+任务描述:
+1. 根据提供的文件名或功能需求,编写符合规范的代码文件或代码片段。
+2. 如果已有文件,检查并基于现有实现完善功能或修复问题。
+3. 遵循约定的开发框架、语言标准和最佳实践。
+4. 注重代码可维护性,添加适当的注释,确保逻辑清晰。
+输出要求:
+1. 仅返回生成的代码或文件内容。
+2. 全程使用中文注释
+3. 尽量避免硬编码和不必要的复杂性,以提高代码的可重用性和效率。
+4. 如功能涉及外部接口或工具调用,请确保通过注释给出清晰的说明和依赖。
+
\ No newline at end of file
diff --git a/.continue/prompts/comment.prompt b/.continue/prompts/comment.prompt
index 68cb798..37fbee4 100755
--- a/.continue/prompts/comment.prompt
+++ b/.continue/prompts/comment.prompt
@@ -4,11 +4,9 @@ maxTokens: 8192
角色定位:
- 高级软件开发工程师
-- 代码文档化与知识传播专家
注释目标:
1. 顶部注释
- 模块/文件整体功能描述
- - 使用场景
2. 类注释
- 核心功能概述
- 设计模式解析
@@ -22,12 +20,9 @@ maxTokens: 8192
- 逐行解释代码意图
- 关键语句原理阐述
- 高级语言特性解读
- - 潜在的设计考量
注释风格要求:
- 全程使用中文
- 专业、清晰、通俗易懂
-- 面向初学者的知识传递
-- 保持技术严谨性
输出约束:
- 仅返回添加注释后的代码
- 注释与代码完美融合
diff --git a/apps/web/package.json b/apps/web/package.json
index f17956d..0eff085 100755
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -1,92 +1,91 @@
{
- "name": "web",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "tsc -b && vite build",
- "lint": "eslint .",
- "preview": "vite preview"
- },
- "dependencies": {
- "@ag-grid-community/client-side-row-model": "~32.3.2",
- "@ag-grid-community/core": "~32.3.2",
- "@ag-grid-community/react": "~32.3.2",
- "@ag-grid-enterprise/clipboard": "~32.3.2",
- "@ag-grid-enterprise/column-tool-panel": "~32.3.2",
- "@ag-grid-enterprise/core": "~32.3.2",
- "@ag-grid-enterprise/filter-tool-panel": "~32.3.2",
- "@ag-grid-enterprise/master-detail": "~32.3.2",
- "@ag-grid-enterprise/menu": "~32.3.2",
- "@ag-grid-enterprise/range-selection": "~32.3.2",
- "@ag-grid-enterprise/server-side-row-model": "~32.3.2",
- "@ag-grid-enterprise/set-filter": "~32.3.2",
- "@ag-grid-enterprise/status-bar": "~32.3.2",
- "@ant-design/icons": "^5.4.0",
- "@dnd-kit/core": "^6.3.1",
- "@dnd-kit/sortable": "^10.0.0",
- "@dnd-kit/utilities": "^3.2.2",
- "@floating-ui/react": "^0.26.25",
- "@heroicons/react": "^2.2.0",
- "@hookform/resolvers": "^3.9.1",
- "@nice/client": "workspace:^",
- "@nice/common": "workspace:^",
- "@nice/iconer": "workspace:^",
- "mind-elixir": "workspace:^",
- "@nice/ui": "workspace:^",
- "@tanstack/query-async-storage-persister": "^5.51.9",
- "@tanstack/react-query": "^5.51.21",
- "@tanstack/react-query-persist-client": "^5.51.9",
- "@trpc/client": "11.0.0-rc.456",
- "@trpc/react-query": "11.0.0-rc.456",
- "@trpc/server": "11.0.0-rc.456",
- "@xyflow/react": "^12.3.6",
- "ag-grid-community": "~32.3.2",
- "ag-grid-enterprise": "~32.3.2",
- "ag-grid-react": "~32.3.2",
- "antd": "^5.19.3",
- "axios": "^1.7.2",
- "browser-image-compression": "^2.0.2",
- "class-variance-authority": "^0.7.1",
- "clsx": "^2.1.1",
- "d3-dag": "^1.1.0",
- "d3-hierarchy": "^3.1.2",
- "dayjs": "^1.11.12",
- "elkjs": "^0.9.3",
- "framer-motion": "^11.15.0",
- "hls.js": "^1.5.18",
- "idb-keyval": "^6.2.1",
- "mitt": "^3.0.1",
- "quill": "2.0.3",
- "react": "18.2.0",
- "react-beautiful-dnd": "^13.1.1",
- "react-dom": "18.2.0",
- "react-dropzone": "^14.3.5",
- "react-hook-form": "^7.54.2",
- "react-hot-toast": "^2.4.1",
- "react-resizable": "^3.0.5",
- "react-router-dom": "^6.24.1",
- "superjson": "^2.2.1",
- "tailwind-merge": "^2.6.0",
- "uuid": "^10.0.0",
- "yjs": "^13.6.20",
- "zod": "^3.23.8"
- },
- "devDependencies": {
- "@eslint/js": "^9.9.0",
- "@types/react": "18.2.38",
- "@types/react-dom": "18.2.15",
- "@vitejs/plugin-react-swc": "^3.5.0",
- "autoprefixer": "^10.4.20",
- "eslint": "^9.9.0",
- "eslint-plugin-react-hooks": "^5.1.0-rc.0",
- "eslint-plugin-react-refresh": "^0.4.9",
- "globals": "^15.9.0",
- "postcss": "^8.4.41",
- "tailwindcss": "^3.4.10",
- "typescript": "^5.5.4",
- "typescript-eslint": "^8.0.1",
- "vite": "^5.4.1"
- }
-}
+ "name": "web",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@ag-grid-community/client-side-row-model": "~32.3.2",
+ "@ag-grid-community/core": "~32.3.2",
+ "@ag-grid-community/react": "~32.3.2",
+ "@ag-grid-enterprise/clipboard": "~32.3.2",
+ "@ag-grid-enterprise/column-tool-panel": "~32.3.2",
+ "@ag-grid-enterprise/core": "~32.3.2",
+ "@ag-grid-enterprise/filter-tool-panel": "~32.3.2",
+ "@ag-grid-enterprise/master-detail": "~32.3.2",
+ "@ag-grid-enterprise/menu": "~32.3.2",
+ "@ag-grid-enterprise/range-selection": "~32.3.2",
+ "@ag-grid-enterprise/server-side-row-model": "~32.3.2",
+ "@ag-grid-enterprise/set-filter": "~32.3.2",
+ "@ag-grid-enterprise/status-bar": "~32.3.2",
+ "@ant-design/icons": "^5.4.0",
+ "@dnd-kit/core": "^6.3.1",
+ "@dnd-kit/sortable": "^10.0.0",
+ "@dnd-kit/utilities": "^3.2.2",
+ "@floating-ui/react": "^0.26.25",
+ "@heroicons/react": "^2.2.0",
+ "@hookform/resolvers": "^3.9.1",
+ "@nice/client": "workspace:^",
+ "@nice/common": "workspace:^",
+ "@nice/iconer": "workspace:^",
+ "@nice/utils": "workspace:^",
+ "mind-elixir": "workspace:^",
+ "@nice/ui": "workspace:^",
+ "@tanstack/query-async-storage-persister": "^5.51.9",
+ "@tanstack/react-query": "^5.51.21",
+ "@tanstack/react-query-persist-client": "^5.51.9",
+ "@trpc/client": "11.0.0-rc.456",
+ "@trpc/react-query": "11.0.0-rc.456",
+ "@trpc/server": "11.0.0-rc.456",
+ "@xyflow/react": "^12.3.6",
+ "ag-grid-community": "~32.3.2",
+ "ag-grid-enterprise": "~32.3.2",
+ "ag-grid-react": "~32.3.2",
+ "antd": "^5.19.3",
+ "axios": "^1.7.2",
+ "browser-image-compression": "^2.0.2",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "d3-dag": "^1.1.0",
+ "d3-hierarchy": "^3.1.2",
+ "dayjs": "^1.11.12",
+ "elkjs": "^0.9.3",
+ "framer-motion": "^11.15.0",
+ "hls.js": "^1.5.18",
+ "idb-keyval": "^6.2.1",
+ "mitt": "^3.0.1",
+ "quill": "2.0.3",
+ "react": "18.2.0",
+ "react-dom": "18.2.0",
+ "react-hook-form": "^7.54.2",
+ "react-hot-toast": "^2.4.1",
+ "react-resizable": "^3.0.5",
+ "react-router-dom": "^6.24.1",
+ "superjson": "^2.2.1",
+ "tailwind-merge": "^2.6.0",
+ "uuid": "^10.0.0",
+ "yjs": "^13.6.20",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.9.0",
+ "@types/react": "18.2.38",
+ "@types/react-dom": "18.2.15",
+ "@vitejs/plugin-react-swc": "^3.5.0",
+ "autoprefixer": "^10.4.20",
+ "eslint": "^9.9.0",
+ "eslint-plugin-react-hooks": "^5.1.0-rc.0",
+ "eslint-plugin-react-refresh": "^0.4.9",
+ "globals": "^15.9.0",
+ "postcss": "^8.4.41",
+ "tailwindcss": "^3.4.10",
+ "typescript": "^5.5.4",
+ "typescript-eslint": "^8.0.1",
+ "vite": "^5.4.1"
+ }
+}
\ No newline at end of file
diff --git a/apps/web/src/hooks/useTusUpload.ts b/apps/web/src/hooks/useTusUpload.ts
index 695d5a4..a890d6e 100644
--- a/apps/web/src/hooks/useTusUpload.ts
+++ b/apps/web/src/hooks/useTusUpload.ts
@@ -45,13 +45,6 @@ export function useTusUpload() {
onError: (error: Error) => void,
fileKey: string // 添加文件唯一标识
) => {
- // if (!file || !file.name || !file.type) {
- // const error = new Error("不可上传该类型文件");
- // setUploadError(error.message);
- // onError(error);
- // return;
- // }
-
setIsUploading(true);
setUploadProgress((prev) => ({ ...prev, [fileKey]: 0 }));
setUploadError(null);
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 033625d..ea8d9a7 100755
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -3,10 +3,9 @@ export * from "./enum"
export * from "./types"
export * from "./utils"
export * from "./constants"
-export * from "./select"
export * from "./collaboration"
export * from "./db"
-// export * from "./generated"
export * from "@prisma/client"
export * from "./upload"
-export * from "./tool"
\ No newline at end of file
+export * from "./tool"
+export * from "./models"
\ No newline at end of file
diff --git a/packages/common/src/models/course.ts b/packages/common/src/models/course.ts
new file mode 100644
index 0000000..94f7c17
--- /dev/null
+++ b/packages/common/src/models/course.ts
@@ -0,0 +1,7 @@
+import { Course, Enrollment } from "@prisma/client";
+import { SectionDto } from "./section";
+
+export type CourseDto = Course & {
+ enrollments: Enrollment[];
+ sections: SectionDto[];
+};
\ No newline at end of file
diff --git a/packages/common/src/models/department.ts b/packages/common/src/models/department.ts
new file mode 100644
index 0000000..c013723
--- /dev/null
+++ b/packages/common/src/models/department.ts
@@ -0,0 +1,15 @@
+import { Department } from "@prisma/client";
+import { TreeDataNode} from "../types";
+import { StaffDto } from "./staff";
+import { TermDto } from "./term";
+
+export interface DeptSimpleTreeNode extends TreeDataNode {
+ hasStaff?: boolean;
+}
+export type DepartmentDto = Department & {
+ parent: DepartmentDto;
+ children: DepartmentDto[];
+ hasChildren: boolean;
+ staffs: StaffDto[];
+ terms: TermDto[];
+};
\ No newline at end of file
diff --git a/packages/common/src/models/index.ts b/packages/common/src/models/index.ts
new file mode 100644
index 0000000..1febb05
--- /dev/null
+++ b/packages/common/src/models/index.ts
@@ -0,0 +1,9 @@
+export * from "./course"
+export * from "./department"
+export * from "./message"
+export * from "./staff"
+export * from "./term"
+export * from "./post"
+export * from "./rbac"
+export * from "./section"
+export * from "./select"
\ No newline at end of file
diff --git a/packages/common/src/models/message.ts b/packages/common/src/models/message.ts
new file mode 100644
index 0000000..6e9d0be
--- /dev/null
+++ b/packages/common/src/models/message.ts
@@ -0,0 +1,7 @@
+import { Message, Staff } from "@prisma/client";
+
+export type MessageDto = Message & {
+ readed: boolean;
+ receivers: Staff[];
+ sender: Staff;
+};
diff --git a/packages/common/src/models/post.ts b/packages/common/src/models/post.ts
new file mode 100644
index 0000000..7d6ebd9
--- /dev/null
+++ b/packages/common/src/models/post.ts
@@ -0,0 +1,35 @@
+import { Post, Department, Staff } from "@prisma/client";
+import { StaffDto } from "./staff";
+
+export type PostComment = {
+ id: string;
+ type: string;
+ title: string;
+ content: string;
+ authorId: string;
+ domainId: string;
+ referenceId: string;
+ resources: string[];
+ createdAt: Date;
+ updatedAt: Date;
+ parentId: string;
+ author: {
+ id: string;
+ showname: string;
+ username: string;
+ avatar: string;
+ };
+};
+export type PostDto = Post & {
+ readed: boolean;
+ readedCount: number;
+ author: StaffDto;
+ limitedComments: PostComment[];
+ commentsCount: number;
+ perms?: {
+ delete: boolean;
+ // edit: boolean;
+ };
+ watchableDepts: Department[];
+ watchableStaffs: Staff[];
+};
diff --git a/packages/common/src/models/rbac.ts b/packages/common/src/models/rbac.ts
new file mode 100644
index 0000000..01e2bb3
--- /dev/null
+++ b/packages/common/src/models/rbac.ts
@@ -0,0 +1,22 @@
+import { RoleMap } from "@prisma/client";
+import { StaffDto } from "./staff";
+
+export interface ResPerm {
+ instruction?: boolean;
+ createProgress?: boolean;
+ requestCancel?: boolean;
+ acceptCancel?: boolean;
+
+ conclude?: boolean;
+ createRisk?: boolean;
+ editIndicator?: boolean;
+ editMethod?: boolean;
+ editOrg?: boolean;
+
+ edit?: boolean;
+ delete?: boolean;
+ read?: boolean;
+}
+export type RoleMapDto = RoleMap & {
+ staff: StaffDto;
+};
\ No newline at end of file
diff --git a/packages/common/src/models/section.ts b/packages/common/src/models/section.ts
new file mode 100644
index 0000000..0824441
--- /dev/null
+++ b/packages/common/src/models/section.ts
@@ -0,0 +1,5 @@
+import { Lecture, Section } from "@prisma/client";
+
+export type SectionDto = Section & {
+ lectures: Lecture[];
+};
\ No newline at end of file
diff --git a/packages/common/src/select.ts b/packages/common/src/models/select.ts
similarity index 100%
rename from packages/common/src/select.ts
rename to packages/common/src/models/select.ts
diff --git a/packages/common/src/models/staff.ts b/packages/common/src/models/staff.ts
new file mode 100644
index 0000000..a6ace02
--- /dev/null
+++ b/packages/common/src/models/staff.ts
@@ -0,0 +1,38 @@
+import { Staff, Department } from "@prisma/client";
+import { RolePerms } from "../enum";
+
+export type StaffRowModel = {
+ avatar: string;
+ dept_name: string;
+ officer_id: string;
+ phone_number: string;
+ showname: string;
+ username: string;
+};
+export type UserProfile = Staff & {
+ permissions: RolePerms[];
+ deptIds: string[];
+ parentDeptIds: string[];
+ domain: Department;
+ department: Department;
+};
+
+export type StaffDto = Staff & {
+ domain?: Department;
+ department?: Department;
+};
+export interface AuthDto {
+ token: string;
+ staff: StaffDto;
+ refreshToken: string;
+ perms: string[];
+}
+export interface JwtPayload {
+ sub: string;
+ username: string;
+}
+export interface TokenPayload {
+ id: string;
+ phoneNumber: string;
+ name: string;
+}
\ No newline at end of file
diff --git a/packages/common/src/models/term.ts b/packages/common/src/models/term.ts
new file mode 100644
index 0000000..cef8b61
--- /dev/null
+++ b/packages/common/src/models/term.ts
@@ -0,0 +1,8 @@
+import { Term } from "@prisma/client";
+import { ResPerm } from "./rbac";
+
+export type TermDto = Term & {
+ permissions: ResPerm;
+ children: TermDto[];
+ hasChildren: boolean;
+};
\ No newline at end of file
diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts
index 41c1783..02ff9c9 100755
--- a/packages/common/src/types.ts
+++ b/packages/common/src/types.ts
@@ -1,15 +1,3 @@
-import type {
- Staff,
- Department,
- Term,
- Message,
- Post,
- RoleMap,
- Section,
- Lecture,
- Course,
- Enrollment,
-} from "@prisma/client";
import { SocketMsgType, RolePerms } from "./enum";
import { RowRequestSchema } from "./schema";
import { z } from "zod";
@@ -18,44 +6,11 @@ export interface SocketMessage {
type: SocketMsgType;
payload?: T;
}
-
-export interface DataNode {
- title: any;
- key: string;
- hasChildren?: boolean;
- children?: DataNode[];
- value: string;
- data?: any;
- isLeaf?: boolean;
-}
-
-export interface JwtPayload {
- sub: string;
- username: string;
-}
export type AppLocalSettings = {
urgent?: number;
important?: number;
exploreTime?: Date;
};
-export type StaffDto = Staff & {
- domain?: Department;
- department?: Department;
-};
-export interface AuthDto {
- token: string;
- staff: StaffDto;
- refreshToken: string;
- perms: string[];
-}
-export type UserProfile = Staff & {
- permissions: RolePerms[];
- deptIds: string[];
- parentDeptIds: string[];
- domain: Department;
- department: Department;
-};
-
export interface DataNode {
title: any;
key: string;
@@ -70,99 +25,6 @@ export interface TreeDataNode extends DataNode {
isLeaf?: boolean;
pId?: string;
}
-export interface DeptSimpleTreeNode extends TreeDataNode {
- hasStaff?: boolean;
-}
-export type StaffRowModel = {
- avatar: string;
- dept_name: string;
- officer_id: string;
- phone_number: string;
- showname: string;
- username: string;
-};
-export interface TokenPayload {
- id: string;
- phoneNumber: string;
- name: string;
-}
-export interface ResPerm {
- instruction?: boolean;
- createProgress?: boolean;
- requestCancel?: boolean;
- acceptCancel?: boolean;
-
- conclude?: boolean;
- createRisk?: boolean;
- editIndicator?: boolean;
- editMethod?: boolean;
- editOrg?: boolean;
-
- edit?: boolean;
- delete?: boolean;
- read?: boolean;
-}
-
-export type MessageDto = Message & {
- readed: boolean;
- receivers: Staff[];
- sender: Staff;
-};
-export type PostComment = {
- id: string;
- type: string;
- title: string;
- content: string;
- authorId: string;
- domainId: string;
- referenceId: string;
- resources: string[];
- createdAt: Date;
- updatedAt: Date;
- parentId: string;
- author: {
- id: string;
- showname: string;
- username: string;
- avatar: string;
- };
-};
-export type PostDto = Post & {
- readed: boolean;
- readedCount: number;
- author: StaffDto;
- limitedComments: PostComment[];
- commentsCount: number;
- perms?: {
- delete: boolean;
- // edit: boolean;
- };
- watchableDepts: Department[];
- watchableStaffs: Staff[];
-};
-
-export type TermDto = Term & {
- permissions: ResPerm;
- children: TermDto[];
- hasChildren: boolean;
-};
-export type DepartmentDto = Department & {
- parent: DepartmentDto;
- children: DepartmentDto[];
- hasChildren: boolean;
- staffs: StaffDto[];
- terms: TermDto[];
-};
-export type RoleMapDto = RoleMap & {
- staff: StaffDto;
-};
-export type SectionDto = Section & {
- lectures: Lecture[];
-};
-export type CourseDto = Course & {
- enrollments: Enrollment[];
- sections: SectionDto[];
-};
export interface BaseSetting {
appConfig?: {
splashScreen?: string;
diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts
index ee1e16d..083b229 100755
--- a/packages/common/src/utils.ts
+++ b/packages/common/src/utils.ts
@@ -1,5 +1,5 @@
import { Staff } from "@prisma/client";
-import { TermDto, TreeDataNode } from "./types";
+import { TreeDataNode } from "./types";
export function findNodeByKey(
nodes: TreeDataNode[],
targetKey: string
@@ -318,7 +318,7 @@ export const mapPropertiesToObjects = (array: T[], key: K)
* @returns {Array>} 映射后的对象数组
*/
export const mapArrayToObjectArray = (
- array: T[],
+ array: T[],
key: string = 'id'
): Array> => {
return array.map(item => ({ [key]: item }));
diff --git a/packages/utils/src/array-utils.ts b/packages/utils/src/array-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/packages/utils/src/browser-utils.ts b/packages/utils/src/browser-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/packages/utils/src/crypto-utils.ts b/packages/utils/src/crypto-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/packages/utils/src/date-utils.ts b/packages/utils/src/date-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/packages/utils/src/dom-utils.ts b/packages/utils/src/dom-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/packages/utils/src/file-utils.ts b/packages/utils/src/file-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index 77aa06e..b2ba304 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -38,4 +38,4 @@ export const getCompressedImageUrl = (originalUrl: string): string => {
const lastSlashIndex = cleanUrl.lastIndexOf("/");
return `${cleanUrl.slice(0, lastSlashIndex)}/compressed/${cleanUrl.slice(lastSlashIndex + 1).replace(/\.[^.]+$/, ".webp")}`;
};
-export * from "./types";
+export * from "./type-utils";
diff --git a/packages/utils/src/math-utils.ts b/packages/utils/src/math-utils.ts
new file mode 100644
index 0000000..7e7dfb8
--- /dev/null
+++ b/packages/utils/src/math-utils.ts
@@ -0,0 +1,99 @@
+/*** 数学计算工具函数
+ */
+
+/*** 将数值限制在指定范围内
+ * @paramvalue 要限制的值
+ * @parammin 最小值
+ * @parammax 最大值
+ */export const clamp = (value: number, min: number, max: number): number => {
+ return Math.min(Math.max(value, min), max);
+};
+
+/**
+ * 将数值四舍五入到指定小数位
+ * @param value要四舍五入的值* @param decimals 保留的小数位数
+ */export const round = (value: number, decimals: number = 0): number => {
+ const multiplier = Math.pow(10, decimals);
+ return Math.round(value * multiplier) / multiplier;
+};/**
+ * 生成指定范围内的随机数* @param min 最小值* @param max 最大值* @param isInteger 是否为整数,默认false
+ */
+export const random = (min: number, max: number, isInteger: boolean = false): number => {
+ const value = Math.random() * (max - min) + min;
+ return isInteger ? Math.floor(value) : value;
+};
+
+/*** 计算数组的平均值* @param numbers 数字数组
+ */export const average = (numbers: number[]): number => {
+ if (numbers.length === 0) return 0;
+ return numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
+};
+
+/**
+ * 计算数组的总和
+ * @param numbers 数字数组
+ */export const sum = (numbers: number[]): number => {
+ return numbers.reduce((sum, num) => sum + num, 0);
+};
+
+/**
+ *角度转弧度
+ * @paramdegrees 角度
+ */
+export const degreesToRadians = (degrees: number): number => {
+ return degrees * (Math.PI / 180);
+};/**
+ * 弧度转角度
+ * @param radians弧度
+ */
+export const radiansToDegrees = (radians: number): number => {
+ return radians * (180 / Math.PI);
+};/**
+ * 格式化数字为千分位表示
+ * @param value 要格式化的数值*/
+export const formatThousands = (value: number): string => {
+ return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+};
+
+/*** 计算百分比* @param value 当前值
+ *@param total 总值
+ *@param decimals 保留小数位数
+ */
+export const percentage = (value: number, total: number, decimals: number = 2): number => {
+ if (total === 0) return 0; return round((value / total) * 100, decimals);
+};
+
+/*** 判断两个数值是否近似相等
+ * @param a第一个数值
+ * @paramb 第二个数值
+ *@param epsilon 误差范围,默认0.000001
+ */
+export const approximatelyEqual = (a: number, b: number, epsilon: number = 0.000001): boolean => {
+ return Math.abs(a - b) < epsilon;
+};
+
+/**
+ * 将数值转换为带单位的字符串(K, M, B等)
+ * @param value 要转换的数值
+ */
+export const formatUnit = (value: number): string => {
+ const units = ["", "K", "M", "B", "T"];
+ const order = Math.floor(Math.log10(Math.abs(value)) / 3); if (order < 0) return value.toString();
+ const unit = units[order]; const scaled = value / Math.pow(10, order * 3);
+ return `${round(scaled, 1)}${unit}`;
+};
+
+/**
+ * 计算两点之间的距离* @param x1 第一个点的x坐标
+ *@param y1 第一个点的y坐标
+ * @param x2 第二个点的x坐标
+ * @param y2 第二个点的y坐标*/
+export const distance = (x1: number, y1: number, x2: number, y2: number): number => {
+ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
+};/**
+ * 线性插值* @param start 起始值
+ * @param end 结束值
+ * @param t 插值系数(0-1)*/
+export const lerp = (start: number, end: number, t: number): number => {
+ return start + (end - start) * clamp(t, 0, 1);
+};
\ No newline at end of file
diff --git a/packages/utils/src/object-utils.ts b/packages/utils/src/object-utils.ts
new file mode 100644
index 0000000..77a44ab
--- /dev/null
+++ b/packages/utils/src/object-utils.ts
@@ -0,0 +1,59 @@
+// 优雅实现对象操作工具函数集合
+
+/**
+ * 深拷贝对象或数组
+ * @param input 需要深拷贝的对象或数组
+ * @returns 深拷贝后的新对象/数组
+ */
+export function deepClone(input: T): T {
+ if (input === null || typeof input !== 'object') return input;
+ if (Array.isArray(input)) return input.map(deepClone) as unknown as T;
+
+ const result = {} as T;
+ for (const key in input) {
+ if (Object.prototype.hasOwnProperty.call(input, key)) {
+ result[key] = deepClone(input[key]);
+ }
+ }
+ return result;
+}
+
+/**
+ * 合并多个对象
+ * @param objects 需要合并的对象列表
+ * @returns 合并后的对象
+ */
+export function mergeObjects(...objects: Partial[]): T {
+ return objects.reduce((acc: Partial, obj) => {
+ for (const key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ if (typeof acc[key] === 'object' && typeof obj[key] === 'object') {
+ acc[key] = mergeObjects(acc[key], obj[key]);
+ } else {
+ acc[key] = obj[key];
+ }
+ }
+ }
+ return acc;
+ }, {} as Partial) as T;
+}
+
+/**
+ * 获取嵌套对象的属性值
+ * @param obj 待操作对象
+ * @param path 属性路径(以点分隔)
+ * @param defaultValue 默认值
+ * @returns 属性值或默认值
+ */
+export function getNestedValue(obj: T, path: string, defaultValue: U): U | unknown {
+ return path.split('.').reduce((acc: any, key: string) => acc && acc[key], obj) ?? defaultValue;
+}
+
+/**
+ * 判断对象是否为空
+ * @param obj 待检查对象
+ * @returns 是否为空对象
+ */
+export function isEmptyObject(obj: Record): boolean {
+ return Object.keys(obj).length === 0;
+}
diff --git a/packages/utils/src/random-utils.ts b/packages/utils/src/random-utils.ts
new file mode 100644
index 0000000..a763060
--- /dev/null
+++ b/packages/utils/src/random-utils.ts
@@ -0,0 +1,85 @@
+/**
+ * 随机工具函数库
+ * 提供生成随机数、随机字符串、随机数组等功能。
+ */
+
+/**
+ * 生成一个指定范围内的随机整数 (包含 min 和 max)
+ * @param min 最小值 (包含)
+ * @param max 最大值 (包含)
+ */
+export const getRandomInt = (min: number, max: number): number => {
+ const minimum = Math.ceil(min);
+ const maximum = Math.floor(max);
+ return Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
+};
+
+/**
+ * 生成一个指定长度的随机字符串
+ * @param length 随机字符串的长度
+ * @param chars 可选,使用的字符集,默认是字母 (大小写) 和数字
+ */
+export const getRandomString = (length: number, chars: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'): string => {
+ let result = '';
+ const charsLength = chars.length;
+ for (let i = 0; i < length; i++) {
+ result += chars.charAt(Math.floor(Math.random() * charsLength));
+ }
+ return result;
+};
+
+/**
+ * 生成一个随机布尔值 (true 或 false)
+ */
+export const getRandomBoolean = (): boolean => {
+ return Math.random() >= 0.5;
+};
+
+/**
+ * 从数组中随机选取一个值
+ * @param array 要随机提取的数组
+ */
+export const getRandomFromArray = (array: T[]): T => {
+ return array[Math.floor(Math.random() * array.length)];
+};
+
+/**
+ * 打乱一个数组
+ * @param array 要打乱的数组
+ */
+export const shuffleArray = (array: T[]): T[] => {
+ const shuffled = [...array]; // 创建一个副本以免修改原数组
+ for (let i = shuffled.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
+ }
+ return shuffled;
+};
+
+/**
+ * 生成一个随机的十六进制颜色代码 (如 "#a1b2c3")
+ */
+export const getRandomHexColor = (): string => {
+ return `#${Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0')}`;
+};
+
+/**
+ * 生成一个随机RGBA颜色
+ * @param alpha 可选,透明度 (范围 0-1)
+ */
+export const getRandomRGBAColor = (alpha: number = 1): string => {
+ const r = getRandomInt(0, 255);
+ const g = getRandomInt(0, 255);
+ const b = getRandomInt(0, 255);
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
+};
+
+/**
+ * 随机延迟一段时间 (返回一个 Promise,在随机时间后 resolve)
+ * @param min 最小延迟时间 (毫秒)
+ * @param max 最大延迟时间 (毫秒)
+ */
+export const randomDelay = (min: number, max: number): Promise => {
+ const delay = getRandomInt(min, max);
+ return new Promise(resolve => setTimeout(resolve, delay));
+};
\ No newline at end of file
diff --git a/packages/utils/src/string-utils.ts b/packages/utils/src/string-utils.ts
new file mode 100644
index 0000000..71d2494
--- /dev/null
+++ b/packages/utils/src/string-utils.ts
@@ -0,0 +1,80 @@
+/**
+ * 字符串工具函数库
+ * 提供对字符串常见处理的常用工具函数。
+ */
+
+/**
+ * 检查字符串是否为空或仅包含空格
+ */
+export const isEmptyOrWhitespace = (str: string): boolean => {
+ return !str || str.trim().length === 0;
+};
+
+/**
+ * 将字符串的首字母大写
+ */
+export const capitalize = (str: string): string => {
+ if (!str) return '';
+ return str.charAt(0).toUpperCase() + str.slice(1);
+};
+
+/**
+ * 转换成驼峰命名法 (camelCase)
+ */
+export const toCamelCase = (str: string): string => {
+ return str
+ .toLowerCase()
+ .replace(/[-_ ]+(\w)/g, (_, group: string) => group.toUpperCase());
+};
+
+/**
+ * 转换成蛇形命名法 (snake_case)
+ */
+export const toSnakeCase = (str: string): string => {
+ return str
+ .replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
+ .replace(/[\s\-]+/g, '_')
+ .replace(/^_/, '')
+ .toLowerCase();
+};
+
+/**
+ * 转换成烤串命名法 (kebab-case)
+ */
+export const toKebabCase = (str: string): string => {
+ return str
+ .replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)
+ .replace(/[\s_]+/g, '-')
+ .replace(/^-/, '')
+ .toLowerCase();
+};
+
+/**
+ * 截断字符串到指定长度,超出部分使用 "..." 表示
+ */
+export const truncate = (str: string, length: number): string => {
+ if (str.length <= length) return str;
+ return str.slice(0, length) + '...';
+};
+
+/**
+ * 统计字符串中每个字符的出现次数
+ */
+export const charFrequency = (str: string): Record => {
+ return str.split('').reduce((acc: Record, char: string) => {
+ acc[char] = (acc[char] || 0) + 1;
+ return acc;
+ }, {});
+};
+
+/**
+ * 检查字符串是否是有效的 JSON
+ */
+export const isValidJSON = (str: string): boolean => {
+ try {
+ JSON.parse(str);
+ return true;
+ } catch {
+ return false;
+ }
+};
\ No newline at end of file
diff --git a/packages/utils/src/type-utils.ts b/packages/utils/src/type-utils.ts
new file mode 100644
index 0000000..ec3d76b
--- /dev/null
+++ b/packages/utils/src/type-utils.ts
@@ -0,0 +1,94 @@
+/**
+ * 类型工具函数库
+ * 提供对 TypeScript 类型的常见操作工具。
+ */
+
+// --------------------------- 类型工具 ---------------------------
+
+/**
+ * 从某个对象类型中挑选出指定的键。
+ */
+export type PickKeys = {
+ [P in K]: T[P];
+};
+
+/**
+ * 从某个对象类型中排除指定的键。
+ */
+export type OmitKeys = Pick>;
+
+/**
+ * 将某些字段设置为可选。
+ */
+export type PartialByKeys = Omit & Partial>;
+
+/**
+ * 将某些字段设置为必填。
+ */
+export type RequiredByKeys = Omit & Required>;
+
+/**
+ * 可为空的类型。
+ */
+export type Nullable = T | null;
+
+/**
+ * 可为 undefined 的类型。
+ */
+export type Optional = T | undefined;
+
+/**
+ * 确保某个变量类型的检查 (主要用于类型推断辅助)。
+ */
+export const assertType = (value: T): T => value;
+
+/**
+ * 获取数组元素的类型。
+ */
+export type ArrayElement = A extends readonly (infer T)[] ? T : never;
+
+/**
+ * 获取某个对象中字段的值组成的联合类型。
+ */
+export type ValueOf = T[keyof T];
+
+/**
+ * 深部分可选:将嵌套对象所有字段设置为可选。
+ */
+export type DeepPartial = {
+ [K in keyof T]?: T[K] extends object ? DeepPartial : T[K];
+};
+
+/**
+ * 深部分必填:将嵌套对象所有字段设置为必填。
+ */
+export type DeepRequired = {
+ [K in keyof T]-?: T[K] extends object ? DeepRequired : T[K];
+};
+
+// --------------------------- 工具函数 ---------------------------
+
+/**
+ * 检查一个值是否为空 (null 或 undefined)
+ * @param val 要检查的值
+ */
+export const isNullOrUndefined = (val: unknown): val is null | undefined => {
+ return val === null || val === undefined;
+};
+
+/**
+ * 检查一个值是否为对象。
+ * @param val 要检查的值
+ */
+export const isObject = (val: unknown): val is Record => {
+ return typeof val === 'object' && val !== null && !Array.isArray(val);
+};
+
+/**
+ * 检查一个对象是否为空 (没有属性)。
+ * @param obj 要检查的对象
+ */
+export const isEmptyObject = (obj: Record): boolean => {
+ return Object.keys(obj).length === 0;
+};
+export type NonVoid = T extends void ? never : T;
\ No newline at end of file
diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts
deleted file mode 100644
index d3ed883..0000000
--- a/packages/utils/src/types.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type NonVoid = T extends void ? never : T;
\ No newline at end of file
diff --git a/packages/utils/src/validation-utils.ts b/packages/utils/src/validation-utils.ts
new file mode 100644
index 0000000..e69de29
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 90950c6..d020b0d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -377,15 +377,9 @@ importers:
react:
specifier: 18.2.0
version: 18.2.0
- react-beautiful-dnd:
- specifier: ^13.1.1
- version: 13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react-dom:
specifier: 18.2.0
version: 18.2.0(react@18.2.0)
- react-dropzone:
- specifier: ^14.3.5
- version: 14.3.5(react@18.2.0)
react-hook-form:
specifier: ^7.54.2
version: 7.54.2(react@18.2.0)
@@ -3077,9 +3071,6 @@ packages:
'@types/graceful-fs@4.1.9':
resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
- '@types/hoist-non-react-statics@3.3.6':
- resolution: {integrity: sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==}
-
'@types/http-errors@2.0.4':
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
@@ -3155,9 +3146,6 @@ packages:
'@types/react-dom@18.2.15':
resolution: {integrity: sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==}
- '@types/react-redux@7.1.34':
- resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==}
-
'@types/react@18.2.38':
resolution: {integrity: sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==}
@@ -3710,10 +3698,6 @@ packages:
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- attr-accept@2.2.5:
- resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==}
- engines: {node: '>=4'}
-
autoprefixer@10.4.20:
resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==}
engines: {node: ^10 || ^12 || >=14}
@@ -4192,9 +4176,6 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
- css-box-model@1.2.1:
- resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==}
-
cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@@ -4764,10 +4745,6 @@ packages:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
- file-selector@2.1.2:
- resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==}
- engines: {node: '>= 12'}
-
filelist@1.0.4:
resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
@@ -5037,9 +5014,6 @@ packages:
hls.js@1.5.18:
resolution: {integrity: sha512-znxR+2jecWluu/0KOBqUcvVyAB5tLff10vjMGrpAlz1eFY+ZhF1bY3r82V+Bk7WJdk03iTjtja9KFFz5BrqjSA==}
- hoist-non-react-statics@3.3.2:
- resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
-
hosted-git-info@2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
@@ -5848,9 +5822,6 @@ packages:
resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==}
engines: {node: '>= 4.0.0'}
- memoize-one@5.2.1:
- resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
-
meow@8.1.2:
resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==}
engines: {node: '>=10'}
@@ -6423,9 +6394,6 @@ packages:
resolution: {integrity: sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==}
engines: {npm: '>=8.2.3'}
- raf-schd@4.0.3:
- resolution: {integrity: sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==}
-
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -6665,13 +6633,6 @@ packages:
react: '>=16.9.0'
react-dom: '>=16.9.0'
- react-beautiful-dnd@13.1.1:
- resolution: {integrity: sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==}
- deprecated: 'react-beautiful-dnd is now deprecated. Context and options: https://github.com/atlassian/react-beautiful-dnd/issues/2672'
- peerDependencies:
- react: ^16.8.5 || ^17.0.0 || ^18.0.0
- react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0
-
react-dom@18.2.0:
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
peerDependencies:
@@ -6688,12 +6649,6 @@ packages:
react: '>= 16.3.0'
react-dom: '>= 16.3.0'
- react-dropzone@14.3.5:
- resolution: {integrity: sha512-9nDUaEEpqZLOz5v5SUcFA0CjM4vq8YbqO0WRls+EYT7+DvxUdzDPKNCPLqGfj3YL9MsniCLCD4RFA6M95V6KMQ==}
- engines: {node: '>= 10.13'}
- peerDependencies:
- react: '>= 16.8 || 18.0.0'
-
react-hook-form@7.54.2:
resolution: {integrity: sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==}
engines: {node: '>=18.0.0'}
@@ -6716,24 +6671,9 @@ packages:
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
- react-is@17.0.2:
- resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
-
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
- react-redux@7.2.9:
- resolution: {integrity: sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==}
- peerDependencies:
- react: ^16.8.3 || ^17 || ^18
- react-dom: '*'
- react-native: '*'
- peerDependenciesMeta:
- react-dom:
- optional: true
- react-native:
- optional: true
-
react-refresh@0.14.2:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
@@ -6801,9 +6741,6 @@ packages:
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
engines: {node: '>=4'}
- redux@4.2.1:
- resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==}
-
reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
@@ -7339,9 +7276,6 @@ packages:
through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
- tiny-invariant@1.3.3:
- resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
-
tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
@@ -7580,11 +7514,6 @@ packages:
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
- use-memo-one@1.1.3:
- resolution: {integrity: sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
-
use-sync-external-store@1.4.0:
resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==}
peerDependencies:
@@ -10687,11 +10616,6 @@ snapshots:
dependencies:
'@types/node': 20.17.12
- '@types/hoist-non-react-statics@3.3.6':
- dependencies:
- '@types/react': 18.2.38
- hoist-non-react-statics: 3.3.2
-
'@types/http-errors@2.0.4': {}
'@types/istanbul-lib-coverage@2.0.6': {}
@@ -10761,13 +10685,6 @@ snapshots:
dependencies:
'@types/react': 18.3.18
- '@types/react-redux@7.1.34':
- dependencies:
- '@types/hoist-non-react-statics': 3.3.6
- '@types/react': 18.2.38
- hoist-non-react-statics: 3.3.2
- redux: 4.2.1
-
'@types/react@18.2.38':
dependencies:
'@types/prop-types': 15.7.14
@@ -11553,8 +11470,6 @@ snapshots:
asynckit@0.4.0: {}
- attr-accept@2.2.5: {}
-
autoprefixer@10.4.20(postcss@8.4.49):
dependencies:
browserslist: 4.24.3
@@ -12088,10 +12003,6 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
- css-box-model@1.2.1:
- dependencies:
- tiny-invariant: 1.3.3
-
cssesc@3.0.0: {}
csstype@3.1.3: {}
@@ -12762,10 +12673,6 @@ snapshots:
dependencies:
flat-cache: 4.0.1
- file-selector@2.1.2:
- dependencies:
- tslib: 2.8.1
-
filelist@1.0.4:
dependencies:
minimatch: 5.1.6
@@ -13045,10 +12952,6 @@ snapshots:
hls.js@1.5.18: {}
- hoist-non-react-statics@3.3.2:
- dependencies:
- react-is: 16.13.1
-
hosted-git-info@2.8.9: {}
hosted-git-info@4.1.0:
@@ -14023,8 +13926,6 @@ snapshots:
dependencies:
fs-monkey: 1.0.6
- memoize-one@5.2.1: {}
-
meow@8.1.2:
dependencies:
'@types/minimist': 1.2.5
@@ -14548,8 +14449,6 @@ snapshots:
parchment: 3.0.0
quill-delta: 5.1.0
- raf-schd@4.0.3: {}
-
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -14883,20 +14782,6 @@ snapshots:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- react-beautiful-dnd@13.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
- dependencies:
- '@babel/runtime': 7.26.0
- css-box-model: 1.2.1
- memoize-one: 5.2.1
- raf-schd: 4.0.3
- react: 18.2.0
- react-dom: 18.2.0(react@18.2.0)
- react-redux: 7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
- redux: 4.2.1
- use-memo-one: 1.1.3(react@18.2.0)
- transitivePeerDependencies:
- - react-native
-
react-dom@18.2.0(react@18.2.0):
dependencies:
loose-envify: 1.4.0
@@ -14916,13 +14801,6 @@ snapshots:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- react-dropzone@14.3.5(react@18.2.0):
- dependencies:
- attr-accept: 2.2.5
- file-selector: 2.1.2
- prop-types: 15.8.1
- react: 18.2.0
-
react-hook-form@7.54.2(react@18.2.0):
dependencies:
react: 18.2.0
@@ -14941,22 +14819,8 @@ snapshots:
react-is@16.13.1: {}
- react-is@17.0.2: {}
-
react-is@18.3.1: {}
- react-redux@7.2.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
- dependencies:
- '@babel/runtime': 7.26.0
- '@types/react-redux': 7.1.34
- hoist-non-react-statics: 3.3.2
- loose-envify: 1.4.0
- prop-types: 15.8.1
- react: 18.2.0
- react-is: 17.0.2
- optionalDependencies:
- react-dom: 18.2.0(react@18.2.0)
-
react-refresh@0.14.2: {}
react-resizable@3.0.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
@@ -15037,10 +14901,6 @@ snapshots:
dependencies:
redis-errors: 1.2.0
- redux@4.2.1:
- dependencies:
- '@babel/runtime': 7.26.0
-
reflect-metadata@0.2.2: {}
regenerator-runtime@0.14.1: {}
@@ -15661,8 +15521,6 @@ snapshots:
through@2.3.8: {}
- tiny-invariant@1.3.3: {}
-
tinycolor2@1.6.0: {}
tinyexec@0.3.2: {}
@@ -15899,10 +15757,6 @@ snapshots:
querystringify: 2.2.0
requires-port: 1.0.0
- use-memo-one@1.1.3(react@18.2.0):
- dependencies:
- react: 18.2.0
-
use-sync-external-store@1.4.0(react@18.2.0):
dependencies:
react: 18.2.0
From 4fb0fa49e7987fb6232983c1f35afa503fcf687b Mon Sep 17 00:00:00 2001
From: longdayi <13477510+longdayilongdayi@user.noreply.gitee.com>
Date: Thu, 6 Feb 2025 16:32:31 +0800
Subject: [PATCH 4/4] 02061632
---
apps/web/package.json | 1 +
apps/web/src/App.tsx | 2 +-
.../main/courses/components/CourseCard.tsx | 48 ++++
.../main/courses/components/CourseList.tsx | 44 ++++
.../main/courses/components/FilterSection.tsx | 54 +++++
apps/web/src/app/main/courses/mockData.ts | 44 ++++
apps/web/src/app/main/courses/page.tsx | 73 ++++++
.../main/home/components/CategorySection.tsx | 162 +++++++++++++
.../main/home/components/CoursesSection.tsx | 206 ++++++++++++++++
.../components/FeaturedTeachersSection.tsx | 222 ++++++++++++++++++
.../app/main/home/components/HeroSection.tsx | 157 +++++++++++++
apps/web/src/app/main/home/page.tsx | 144 ++++++++++--
apps/web/src/app/main/layout/MainFooter.tsx | 68 ++++++
apps/web/src/app/main/layout/MainHeader.tsx | 65 +++++
apps/web/src/app/main/layout/MainLayout.tsx | 18 ++
.../src/app/main/layout/NavigationMenu.tsx | 31 +++
apps/web/src/app/main/layout/UserMenu.tsx | 49 ++++
apps/web/src/app/main/paths/page.tsx | 3 +
apps/web/src/app/main/self/courses/page.tsx | 7 +
apps/web/src/app/main/self/profiles/page.tsx | 3 +
.../src/components/layout/main/MainLayout.tsx | 40 ----
.../src/components/layout/main/nav-data.tsx | 43 ----
.../layout/main/notifications-dropdown.tsx | 40 ----
.../layout/main/notifications-panel.tsx | 64 -----
.../src/components/layout/main/search-bar.tsx | 55 -----
.../layout/main/search-dropdown.tsx | 58 -----
.../src/components/layout/main/side-bar.tsx | 44 ----
.../components/layout/main/top-nav-bar.tsx | 47 ----
.../layout/main/usermenu-dropdown.tsx | 68 ------
apps/web/src/index.css | 6 +-
apps/web/src/routes/index.tsx | 13 +-
apps/web/tailwind.config.js | 53 -----
apps/web/tailwind.config.ts | 2 +
packages/common/src/utils.ts | 40 ++--
packages/config/package.json | 35 +++
packages/config/src/colors.ts | 24 ++
packages/config/src/constants.ts | 19 ++
packages/config/src/context.tsx | 50 ++++
packages/config/src/generator.ts | 99 ++++++++
packages/config/src/index.ts | 6 +
packages/config/src/styles.ts | 89 +++++++
packages/config/src/tailwind.ts | 132 +++++++++++
packages/config/src/types.ts | 112 +++++++++
packages/config/src/utils.ts | 26 ++
packages/config/tsconfig.json | 43 ++++
packages/config/tsup.config.ts | 13 +
pnpm-lock.yaml | 71 ++++++
47 files changed, 2132 insertions(+), 561 deletions(-)
create mode 100644 apps/web/src/app/main/courses/components/CourseCard.tsx
create mode 100644 apps/web/src/app/main/courses/components/CourseList.tsx
create mode 100644 apps/web/src/app/main/courses/components/FilterSection.tsx
create mode 100644 apps/web/src/app/main/courses/mockData.ts
create mode 100644 apps/web/src/app/main/courses/page.tsx
create mode 100644 apps/web/src/app/main/home/components/CategorySection.tsx
create mode 100644 apps/web/src/app/main/home/components/CoursesSection.tsx
create mode 100644 apps/web/src/app/main/home/components/FeaturedTeachersSection.tsx
create mode 100644 apps/web/src/app/main/home/components/HeroSection.tsx
create mode 100644 apps/web/src/app/main/layout/MainFooter.tsx
create mode 100644 apps/web/src/app/main/layout/MainHeader.tsx
create mode 100644 apps/web/src/app/main/layout/MainLayout.tsx
create mode 100644 apps/web/src/app/main/layout/NavigationMenu.tsx
create mode 100644 apps/web/src/app/main/layout/UserMenu.tsx
create mode 100644 apps/web/src/app/main/paths/page.tsx
create mode 100644 apps/web/src/app/main/self/courses/page.tsx
create mode 100644 apps/web/src/app/main/self/profiles/page.tsx
delete mode 100644 apps/web/src/components/layout/main/MainLayout.tsx
delete mode 100644 apps/web/src/components/layout/main/nav-data.tsx
delete mode 100644 apps/web/src/components/layout/main/notifications-dropdown.tsx
delete mode 100644 apps/web/src/components/layout/main/notifications-panel.tsx
delete mode 100644 apps/web/src/components/layout/main/search-bar.tsx
delete mode 100644 apps/web/src/components/layout/main/search-dropdown.tsx
delete mode 100644 apps/web/src/components/layout/main/side-bar.tsx
delete mode 100644 apps/web/src/components/layout/main/top-nav-bar.tsx
delete mode 100644 apps/web/src/components/layout/main/usermenu-dropdown.tsx
delete mode 100755 apps/web/tailwind.config.js
create mode 100755 apps/web/tailwind.config.ts
create mode 100644 packages/config/package.json
create mode 100644 packages/config/src/colors.ts
create mode 100644 packages/config/src/constants.ts
create mode 100644 packages/config/src/context.tsx
create mode 100644 packages/config/src/generator.ts
create mode 100644 packages/config/src/index.ts
create mode 100644 packages/config/src/styles.ts
create mode 100644 packages/config/src/tailwind.ts
create mode 100644 packages/config/src/types.ts
create mode 100644 packages/config/src/utils.ts
create mode 100644 packages/config/tsconfig.json
create mode 100644 packages/config/tsup.config.ts
diff --git a/apps/web/package.json b/apps/web/package.json
index 0eff085..f10e338 100755
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -32,6 +32,7 @@
"@hookform/resolvers": "^3.9.1",
"@nice/client": "workspace:^",
"@nice/common": "workspace:^",
+ "@nice/config": "workspace:^",
"@nice/iconer": "workspace:^",
"@nice/utils": "workspace:^",
"mind-elixir": "workspace:^",
diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx
index 54a93a3..7f00070 100755
--- a/apps/web/src/App.tsx
+++ b/apps/web/src/App.tsx
@@ -24,7 +24,7 @@ function App() {
theme={{
algorithm: theme.defaultAlgorithm,
token: {
- colorPrimary: "#2e75b6",
+ colorPrimary: "#0088E8",
},
components: {},
}}>
diff --git a/apps/web/src/app/main/courses/components/CourseCard.tsx b/apps/web/src/app/main/courses/components/CourseCard.tsx
new file mode 100644
index 0000000..d549a1e
--- /dev/null
+++ b/apps/web/src/app/main/courses/components/CourseCard.tsx
@@ -0,0 +1,48 @@
+import { Card, Rate, Tag } from 'antd';
+import { Course } from '../mockData';
+import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons';
+
+interface CourseCardProps {
+ course: Course;
+}
+
+export default function CourseCard({ course }: CourseCardProps) {
+ return (
+
+ }
+ >
+
+
+ {course.title}
+
+
{course.instructor}
+
+
+ {course.rating}
+
+
+
+
+ {course.enrollments} 人在学
+
+
+
+ {course.duration}
+
+
+
+ {course.category}
+ {course.level}
+
+
+
+ );
+}
diff --git a/apps/web/src/app/main/courses/components/CourseList.tsx b/apps/web/src/app/main/courses/components/CourseList.tsx
new file mode 100644
index 0000000..3d67b1c
--- /dev/null
+++ b/apps/web/src/app/main/courses/components/CourseList.tsx
@@ -0,0 +1,44 @@
+import { Pagination, Empty } from 'antd';
+import { Course } from '../mockData';
+import CourseCard from './CourseCard';
+
+interface CourseListProps {
+ courses: Course[];
+ total: number;
+ pageSize: number;
+ currentPage: number;
+ onPageChange: (page: number) => void;
+}
+
+export default function CourseList({
+ courses,
+ total,
+ pageSize,
+ currentPage,
+ onPageChange,
+}: CourseListProps) {
+ return (
+
+ {courses.length > 0 ? (
+ <>
+
+ {courses.map(course => (
+
+ ))}
+
+
+ >
+ ) : (
+
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/apps/web/src/app/main/courses/components/FilterSection.tsx b/apps/web/src/app/main/courses/components/FilterSection.tsx
new file mode 100644
index 0000000..93e0e6f
--- /dev/null
+++ b/apps/web/src/app/main/courses/components/FilterSection.tsx
@@ -0,0 +1,54 @@
+import { Checkbox, Divider, Radio, Space } from 'antd';
+import { categories, levels } from '../mockData';
+
+interface FilterSectionProps {
+ selectedCategory: string;
+ selectedLevel: string;
+ onCategoryChange: (category: string) => void;
+ onLevelChange: (level: string) => void;
+}
+
+export default function FilterSection({
+ selectedCategory,
+ selectedLevel,
+ onCategoryChange,
+ onLevelChange,
+}: FilterSectionProps) {
+ return (
+
+
+
课程分类
+ onCategoryChange(e.target.value)}
+ className="flex flex-col space-y-3"
+ >
+ 全部课程
+ {categories.map(category => (
+
+ {category}
+
+ ))}
+
+
+
+
+
+
+
难度等级
+ onLevelChange(e.target.value)}
+ className="flex flex-col space-y-3"
+ >
+ 全部难度
+ {levels.map(level => (
+
+ {level}
+
+ ))}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/web/src/app/main/courses/mockData.ts b/apps/web/src/app/main/courses/mockData.ts
new file mode 100644
index 0000000..096d174
--- /dev/null
+++ b/apps/web/src/app/main/courses/mockData.ts
@@ -0,0 +1,44 @@
+export interface Course {
+ id: string;
+ title: string;
+ description: string;
+ instructor: string;
+ price: number;
+ originalPrice: number;
+ category: string;
+ level: string;
+ thumbnail: string;
+ rating: number;
+ enrollments: number;
+ duration: string;
+}
+
+export const categories = [
+ "计算机科学",
+ "数据科学",
+ "商业管理",
+ "人工智能",
+ "软件开发",
+ "网络安全",
+ "云计算",
+ "前端开发",
+ "后端开发",
+ "移动开发"
+];
+
+export const levels = ["入门", "初级", "中级", "高级"];
+
+export const mockCourses: Course[] = Array.from({ length: 50 }, (_, i) => ({
+ id: `course-${i + 1}`,
+ title: `${categories[i % categories.length]}课程 ${i + 1}`,
+ description: "本课程将带你深入了解该领域的核心概念和实践应用,通过实战项目提升你的专业技能。",
+ instructor: `讲师 ${i + 1}`,
+ price: Math.floor(Math.random() * 500 + 99),
+ originalPrice: Math.floor(Math.random() * 1000 + 299),
+ category: categories[i % categories.length],
+ level: levels[i % levels.length],
+ thumbnail: `/api/placeholder/280/160`,
+ rating: Number((Math.random() * 2 + 3).toFixed(1)),
+ enrollments: Math.floor(Math.random() * 10000),
+ duration: `${Math.floor(Math.random() * 20 + 10)}小时`
+}));
\ No newline at end of file
diff --git a/apps/web/src/app/main/courses/page.tsx b/apps/web/src/app/main/courses/page.tsx
new file mode 100644
index 0000000..f852e00
--- /dev/null
+++ b/apps/web/src/app/main/courses/page.tsx
@@ -0,0 +1,73 @@
+import { useState, useMemo } from 'react';
+import { mockCourses } from './mockData';
+import FilterSection from './components/FilterSection';
+import CourseList from './components/CourseList';
+
+export default function CoursesPage() {
+ const [currentPage, setCurrentPage] = useState(1);
+ const [selectedCategory, setSelectedCategory] = useState('');
+ const [selectedLevel, setSelectedLevel] = useState('');
+ const pageSize = 12;
+
+ const filteredCourses = useMemo(() => {
+ return mockCourses.filter(course => {
+ const matchCategory = !selectedCategory || course.category === selectedCategory;
+ const matchLevel = !selectedLevel || course.level === selectedLevel;
+ return matchCategory && matchLevel;
+ });
+ }, [selectedCategory, selectedLevel]);
+
+ const paginatedCourses = useMemo(() => {
+ const startIndex = (currentPage - 1) * pageSize;
+ return filteredCourses.slice(startIndex, startIndex + pageSize);
+ }, [filteredCourses, currentPage]);
+
+ const handlePageChange = (page: number) => {
+ setCurrentPage(page);
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ };
+
+ return (
+
+
+
+ {/* 左侧筛选区域 */}
+
+
+ {
+ setSelectedCategory(category);
+ setCurrentPage(1);
+ }}
+ onLevelChange={level => {
+ setSelectedLevel(level);
+ setCurrentPage(1);
+ }}
+ />
+
+
+
+ {/* 右侧课程列表区域 */}
+
+
+
+
+ 共找到 {filteredCourses.length} 门课程
+
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/web/src/app/main/home/components/CategorySection.tsx b/apps/web/src/app/main/home/components/CategorySection.tsx
new file mode 100644
index 0000000..638e429
--- /dev/null
+++ b/apps/web/src/app/main/home/components/CategorySection.tsx
@@ -0,0 +1,162 @@
+import React, { useState, useCallback } from 'react';
+import { Typography, Button } from 'antd';
+import { stringToColor } from '@nice/common';
+
+const { Title, Text } = Typography;
+
+interface CourseCategory {
+ name: string;
+ count: number;
+ description: string;
+}
+
+const courseCategories: CourseCategory[] = [
+ {
+ name: '计算机基础',
+ count: 120,
+ description: '计算机组成原理、操作系统、网络等基础知识'
+ },
+ {
+ name: '编程语言',
+ count: 85,
+ description: 'Python、Java、JavaScript等主流编程语言'
+ },
+ {
+ name: '人工智能',
+ count: 65,
+ description: '机器学习、深度学习、自然语言处理等前沿技术'
+ },
+ {
+ name: '数据科学',
+ count: 45,
+ description: '数据分析、数据可视化、商业智能等'
+ },
+ {
+ name: '云计算',
+ count: 38,
+ description: '云服务、容器化、微服务架构等'
+ },
+ {
+ name: '网络安全',
+ count: 42,
+ description: '网络安全基础、渗透测试、安全防护等'
+ }
+];
+
+const CategorySection = () => {
+ const [hoveredIndex, setHoveredIndex] = useState(null);
+ const [showAll, setShowAll] = useState(false);
+
+ const handleMouseEnter = useCallback((index: number) => {
+ setHoveredIndex(index);
+ }, []);
+
+ const handleMouseLeave = useCallback(() => {
+ setHoveredIndex(null);
+ }, []);
+
+ const displayedCategories = showAll
+ ? courseCategories
+ : courseCategories.slice(0, 8);
+
+ return (
+
+
+
+
+ 探索课程分类
+
+
+ 选择你感兴趣的方向,开启学习之旅
+
+
+
+ {displayedCategories.map((category, index) => {
+ const categoryColor = stringToColor(category.name);
+ const isHovered = hoveredIndex === index;
+
+ return (
+
handleMouseEnter(index)}
+ onMouseLeave={handleMouseLeave}
+ role="button"
+ tabIndex={0}
+ aria-label={`查看${category.name}课程类别`}
+ >
+
+
+
+
+
+
+
+ {category.name}
+
+
+ {category.count} 门课程
+
+
+
+ {category.description}
+
+
+ 了解更多
+
+ →
+
+
+
+
+ );
+ })}
+
+ {courseCategories.length > 8 && (
+
+
+
+ )}
+
+
+ );
+};
+
+export default CategorySection;
\ No newline at end of file
diff --git a/apps/web/src/app/main/home/components/CoursesSection.tsx b/apps/web/src/app/main/home/components/CoursesSection.tsx
new file mode 100644
index 0000000..4818e00
--- /dev/null
+++ b/apps/web/src/app/main/home/components/CoursesSection.tsx
@@ -0,0 +1,206 @@
+import React, { useState, useMemo } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { Button, Card, Typography, Tag, Progress } from 'antd';
+import {
+ PlayCircleOutlined,
+ UserOutlined,
+ ClockCircleOutlined,
+ TeamOutlined,
+ StarOutlined,
+ ArrowRightOutlined,
+} from '@ant-design/icons';
+
+const { Title, Text } = Typography;
+
+interface Course {
+ id: number;
+ title: string;
+ instructor: string;
+ students: number;
+ rating: number;
+ level: string;
+ duration: string;
+ category: string;
+ progress: number;
+ thumbnail: string;
+}
+
+interface CoursesSectionProps {
+ title: string;
+ description: string;
+ courses: Course[];
+ initialVisibleCoursesCount?: number;
+}
+
+const CoursesSection: React.FC = ({
+ title,
+ description,
+ courses,
+ initialVisibleCoursesCount = 8,
+}) => {
+ const navigate = useNavigate();
+ const [selectedCategory, setSelectedCategory] = useState('全部');
+ const [visibleCourses, setVisibleCourses] = useState(initialVisibleCoursesCount);
+
+ const categories = useMemo(() => {
+ const allCategories = courses.map((course) => course.category);
+ return ['全部', ...Array.from(new Set(allCategories))];
+ }, [courses]);
+
+ const filteredCourses = useMemo(() => {
+ return selectedCategory === '全部'
+ ? courses
+ : courses.filter((course) => course.category === selectedCategory);
+ }, [selectedCategory, courses]);
+
+ const displayedCourses = filteredCourses.slice(0, visibleCourses);
+
+ return (
+
+
+
+
+
+ {title}
+
+
+ {description}
+
+
+
+
+
+ {categories.map((category) => (
+ setSelectedCategory(category)}
+ className={`px-4 py-2 text-base cursor-pointer hover:scale-105 transform transition-all duration-300 ${selectedCategory === category
+ ? 'shadow-[0_2px_8px_-4px_rgba(59,130,246,0.5)]'
+ : 'hover:shadow-md'
+ }`}
+ >
+ {category}
+
+ ))}
+
+
+
+ {displayedCourses.map((course) => (
+
+
+
+
+ {course.progress > 0 && (
+
+ )}
+
+ }
+ >
+
+
+
+ {course.category}
+
+
+ {course.level}
+
+
+
+ {course.title}
+
+
+
+
+ {course.instructor}
+
+
+
+
+
+ {course.duration}
+
+
+
+ {course.students.toLocaleString()}
+
+
+
+ {course.rating}
+
+
+
+
+
+
+
+ ))}
+
+
+ {filteredCourses.length >= visibleCourses && (
+
+
+
+
navigate('/courses')}
+ className="cursor-pointer tracking-widest text-gray-500 hover:text-primary font-medium flex items-center gap-2 transition-all duration-300 ease-in-out"
+ >
+ 查看更多
+
+
+
+
+
+
+ )}
+