@flatbiz/antd
Version:
557 lines (539 loc) • 19.7 kB
JavaScript
/*! @flatjs/forge MIT @flatbiz/antd */
import { _ as _objectWithoutProperties, a as _slicedToArray, b as _objectSpread2 } from './_rollupPluginBabelHelpers-BspM60Sw.js';
import _CloseCircleFilled from '@ant-design/icons/es/icons/CloseCircleFilled.js';
import { useRef, useState, useEffect, useCallback, useMemo } from 'react';
import { Button, InputNumber, message, Spin } from 'antd';
import { openNewWindow, getUuid, loadScripts, loadStyles } from '@flatbiz/utils';
import { classNames } from '@dimjs/utils/class-names/class-names';
import { useMemoizedFn, useSize } from 'ahooks';
import { C as CardLayout } from './card-layout-P-Qb5pCT.js';
import { C as CodeRender } from './code-Dbu2QlhZ.js';
import { d as dialogModal } from './dialog-modal-CGMNBSgq.js';
import { jsx, jsxs } from 'react/jsx-runtime';
import { getCodeString } from 'rehype-rewrite';
import { isObject } from '@dimjs/lang/is-object';
import { isString } from '@dimjs/lang/is-string';
import { A as AlertWrapper } from './alert-DGRFbqqK.js';
import { E as EasyForm } from './form-ByFljQr9.js';
import { F as FormItemHidden } from './form-item-hidden-BtQvJEx7.js';
import { F as FormItemWrapper } from './form-item-wrapper-Ci7-5IKi.js';
import { G as Gap } from './gap-5v_ndf2v.js';
import { U as UploadMultiType } from './content-CXmBn9B0.js';
var MermaidViewBtn = function MermaidViewBtn() {
var handeClick = function handeClick() {
dialogModal.open({
title: 'Mermaid图形示例',
content: function content() {
return /*#__PURE__*/jsxs("div", {
children: [/*#__PURE__*/jsx(CardLayout, {
title: '示例',
subTitle: '在Markdown中使用Mermaid图形',
layoutType: "tight",
children: /*#__PURE__*/jsx(CodeRender, {
code: "```mermaid\nsequenceDiagram\n native->>haipay\u670D\u52A1\u7AEF:\u83B7\u53D6accessToken\n haipay\u670D\u52A1\u7AEF->>tc\u670D\u52A1\u7AEF: \u8C03\u7528tc\u7684\u63A5\u53E3\u83B7\u53D6accessToken\n tc\u670D\u52A1\u7AEF->>haipay\u670D\u52A1\u7AEF: \u8FD4\u56DEaccessToken\n haipay\u670D\u52A1\u7AEF-->>native: \u5C06accessToken\u8FD4\u56DEnative\n native->>tch5: \u5C06accessToken\u8FD4\u56DE\u7ED9tch5\uFF0C\u8FDB\u884C\u767B\u5F55"
})
}), /*#__PURE__*/jsx(Button, {
block: true,
type: "primary",
ghost: true,
style: {
marginTop: 20
},
onClick: function onClick() {
openNewWindow('https://docs.min2k.com/zh/mermaid/syntax/pie.html');
},
children: "\u67E5\u770B\u66F4\u591A\u793A\u4F8B"
})]
});
},
okHidden: true,
cancelHidden: true
});
};
return /*#__PURE__*/jsx(Button, {
type: "default",
size: "small",
style: {
fontSize: 12
},
onClick: handeClick,
children: "\u652F\u6301Mermaid\u56FE\u5F62"
}, "imageUpload");
};
var _excluded$1 = ["children", "className"];
var PluginMermaidCode = function PluginMermaidCode(_ref) {
var _ref$children = _ref.children,
children = _ref$children === void 0 ? [] : _ref$children,
className = _ref.className,
props = _objectWithoutProperties(_ref, _excluded$1);
var demoid = useRef(getUuid());
var _useState = useState(''),
_useState2 = _slicedToArray(_useState, 2),
svgContent = _useState2[0],
setSvgContent = _useState2[1];
var renderAbortRef = useRef(false);
var isMermaid = className && /^language-mermaid/.test(className.toLocaleLowerCase());
var code = children ? getCodeString(props.node.children) : children[0] || '';
useEffect(function () {
if (isMermaid && code) {
// 标记之前的渲染为已取消
renderAbortRef.current = true;
// 重置取消标志
renderAbortRef.current = false;
// 生成新的唯一 ID
var currentId = getUuid();
demoid.current = currentId;
// 创建一个临时的隐藏容器用于 Mermaid 渲染
var tempContainer = document.createElement('div');
tempContainer.style.position = 'absolute';
tempContainer.style.visibility = 'hidden';
tempContainer.style.width = '0';
tempContainer.style.height = '0';
tempContainer.style.top = '-9999px';
tempContainer.style.left = '-9999px';
tempContainer.id = currentId;
document.body.appendChild(tempContainer);
// 使用 requestAnimationFrame 确保在正确的时机渲染
var frameId = requestAnimationFrame(function () {
if (renderAbortRef.current) {
// 清理临时容器
try {
if (tempContainer.parentNode) {
document.body.removeChild(tempContainer);
}
} catch (_unused) {
// 忽略清理错误
}
return;
}
var mermaid = window['mermaid'];
// 在临时容器中渲染
mermaid.render(currentId, code).then(function (_ref2) {
var svg = _ref2.svg;
// 检查是否已被取消
if (renderAbortRef.current) {
return;
}
// 使用 React state 更新 SVG 内容,而不是直接操作 DOM
setSvgContent(svg);
}).catch(function (error) {
if (!renderAbortRef.current) {
console.log('Mermaid render error:', error);
setSvgContent('');
}
}).finally(function () {
// 清理临时容器
try {
if (tempContainer.parentNode) {
document.body.removeChild(tempContainer);
}
} catch (_unused2) {
// 忽略清理错误
}
});
});
// 清理函数:取消正在进行的渲染
return function () {
renderAbortRef.current = true;
cancelAnimationFrame(frameId);
// 清理临时容器
try {
if (tempContainer.parentNode) {
document.body.removeChild(tempContainer);
}
} catch (_unused3) {
// 忽略清理错误
}
};
} else {
setSvgContent('');
}
return undefined;
}, [isMermaid, code]);
if (isMermaid) {
return /*#__PURE__*/jsx("code", {
className: className,
"data-name": "mermaid",
dangerouslySetInnerHTML: {
__html: svgContent
}
});
}
return /*#__PURE__*/jsx("code", {
className: className,
children: children
});
};
function getImageDimensions(url) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.onload = function () {
resolve({
width: img.naturalWidth,
height: img.naturalHeight
});
};
img.onerror = function () {
reject(new Error('图片加载失败'));
};
img.src = url;
});
}
var UploadImageContent = function UploadImageContent(props) {
var onValuesChange = useCallback(function (changedFields) {
return new Promise(function ($return, $error) {
if (changedFields.imageUrls) {
var imageUrls = changedFields.imageUrls;
if (!(imageUrls !== null && imageUrls !== void 0 && imageUrls.length)) return $return();
var imageUrl = isString(imageUrls[0]) ? imageUrls[0] : imageUrls[0].url;
getImageDimensions(imageUrl).then(function (_ref) {
var width = _ref.width,
height = _ref.height;
props.form.setFieldsValue({
width: width,
height: height
});
}).catch(function () {});
}
return $return();
});
}, [props.form]);
var onUploadFile = useMemoizedFn(function (file) {
return new Promise(function ($return, $error) {
var _props$onUploadImage, formData, respData;
formData = new FormData();
formData.append('file', file);
return Promise.resolve((_props$onUploadImage = props.onUploadImage) === null || _props$onUploadImage === void 0 ? void 0 : _props$onUploadImage.call(props, file)).then(function ($await_1) {
try {
respData = $await_1;
return $return(respData);
} catch ($boundEx) {
return $error($boundEx);
}
}, $error);
});
});
return /*#__PURE__*/jsxs(EasyForm, {
form: props.form,
onValuesChange: onValuesChange,
initialValues: {
file: [{
url: 'https://file.40017.cn/jinfu/arbitrarily/umm4vdnm25z6kffm.png',
name: 'xxx1.png'
}, {
url: 'https://file.40017.cn/jinfu/arbitrarily/umm4vdnm25z6kffm.png',
name: 'xxx2.png'
}]
},
children: [/*#__PURE__*/jsx(FormItemHidden, {
name: "height"
}), /*#__PURE__*/jsx(FormItemWrapper, {
name: "imageUrls",
label: "\u56FE\u7247",
rules: [{
required: true,
message: '请选择或粘贴图片'
}],
noStyle: true,
children: /*#__PURE__*/jsx(UploadMultiType, {
onUploadFile: onUploadFile,
maxCount: 1
})
}), /*#__PURE__*/jsx(Gap, {
height: 12
}), /*#__PURE__*/jsx(FormItemWrapper, {
name: "width",
label: "\u5BBD\u5EA6",
children: /*#__PURE__*/jsx(InputNumber, {
placeholder: "\u8BF7\u8F93\u5165\u5BBD\u5EA6",
style: {
width: '200px'
},
addonAfter: "px"
})
}), /*#__PURE__*/jsx(AlertWrapper, {
size: "small",
description: "\u53EF\u4FEE\u6539\u5BBD\u5EA6\u8FDB\u884C\u7B49\u6BD4\u7F29\u653E\u663E\u793A"
})]
});
};
var UploadImageBtn = function UploadImageBtn(props) {
var handleImageClick = function handleImageClick() {
dialogModal.open({
title: '上传图片',
content: function content(form) {
return /*#__PURE__*/jsx(UploadImageContent, {
form: form,
onUploadImage: props.onUploadImage
});
},
okText: '确定',
onOk: function onOk(form) {
return new Promise(function ($return, $error) {
var values, imageUrls, imageItem, _props$onUploadResult, _props$onUploadResult2, name;
return Promise.resolve(form.validateFields()).then(function ($await_2) {
try {
values = $await_2;
try {
imageUrls = values.imageUrls;
if (!(imageUrls !== null && imageUrls !== void 0 && imageUrls.length)) return $return();
imageItem = imageUrls[0];
if (isObject(imageItem)) {
(_props$onUploadResult = props.onUploadResult) === null || _props$onUploadResult === void 0 || _props$onUploadResult.call(props, {
url: imageItem.url,
name: imageItem.name,
width: values.width
});
} else {
name = imageItem.split('/').pop();
(_props$onUploadResult2 = props.onUploadResult) === null || _props$onUploadResult2 === void 0 || _props$onUploadResult2.call(props, {
url: imageItem,
name: name,
width: values.width
});
}
} catch (error) {
message.error((error === null || error === void 0 ? void 0 : error['message']) || '上传图片失败');
return $return(Promise.reject());
}
return $return(Promise.resolve());
} catch ($boundEx) {
return $error($boundEx);
}
}, $error);
});
},
onCancel: function onCancel() {
console.log('onCancel');
}
});
};
return /*#__PURE__*/jsx(Button, {
type: "default",
size: "small",
style: {
fontSize: 12
},
onClick: handleImageClick,
children: "\u4E0A\u4F20\u56FE\u7247"
});
};
var _excluded = ["value", "onChange", "onUploadImage", "readonly", "isDarkMode", "className", "style", "readonlyHeightAuto", "height", "hideBorder"];
var ReactMdEditor = function ReactMdEditor(props) {
var value = props.value,
onChange = props.onChange,
onUploadImage = props.onUploadImage,
readonly = props.readonly,
isDarkMode = props.isDarkMode,
className = props.className,
style = props.style,
readonlyHeightAuto = props.readonlyHeightAuto,
height = props.height,
hideBorder = props.hideBorder,
restProps = _objectWithoutProperties(props, _excluded);
var _useState = useState(value),
_useState2 = _slicedToArray(_useState, 2),
innerValue = _useState2[0],
setInnerValue = _useState2[1];
var readonlyHeightAutoFt = readonlyHeightAuto !== null && readonlyHeightAuto !== void 0 ? readonlyHeightAuto : true;
useEffect(function () {
console.log('props.value', props.value);
setInnerValue(props.value);
}, [props.value]);
// 编辑器实例引用(用于操作内容)
var editorRef = useRef(null);
// 隐藏的文件选择器ref
useRef(null);
var onInnerChange = function onInnerChange(value) {
setInnerValue(value);
onChange === null || onChange === void 0 || onChange(value);
};
// 处理图片选择(核心:读取图片并插入)
var onUploadResult = function onUploadResult(respData) {
try {
var imageMarkdown = "\n<img src=\"".concat(respData.url, "\" width=\"").concat(respData.width, "\" alt=\"").concat(respData.name, "\">\n");
// 将图片Markdown插入到编辑器光标位置
if (editorRef.current) {
var _editorRef$current;
var textarea = (_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current['textarea'];
var cursorPosition = textarea.selectionStart;
var newContent = (innerValue === null || innerValue === void 0 ? void 0 : innerValue.slice(0, cursorPosition)) + imageMarkdown + (innerValue === null || innerValue === void 0 ? void 0 : innerValue.slice(cursorPosition));
onInnerChange(newContent);
}
} catch (error) {
message.error((error === null || error === void 0 ? void 0 : error['message']) || '添加图片失败');
}
};
var imageUploadCommand = onUploadImage ? {
name: 'imageUpload',
keyCommand: 'imageUpload',
render: function render() {
return /*#__PURE__*/jsx(UploadImageBtn, {
onUploadResult: onUploadResult,
onUploadImage: onUploadImage
// type="default"
// size="small"
// style={{ fontSize: 12 }}
// onClick={handleImageClick}
}, "imageUpload");
}
} : null;
// 支持 mermaid 语法
var mermaidCommand = {
name: 'mermaid',
keyCommand: 'mermaid',
render: function render() {
return /*#__PURE__*/jsx(MermaidViewBtn
// type="default"
, {}, "mermaid");
}
};
var MDEditor = window['@uiw/react-md-editor'].default;
var commands = window['@uiw/react-md-editor'].commands;
var extraCommands = [];
if (imageUploadCommand && !readonly) {
extraCommands = [imageUploadCommand, commands.divider, mermaidCommand, commands.divider, commands.fullscreen];
} else {
extraCommands = [mermaidCommand, commands.divider, commands.fullscreen];
}
var preview = readonly ? 'preview' : 'live';
var dataColorMode = isDarkMode ? 'dark' : 'light';
var commandsFt = useMemo(function () {
if (readonly) return [];
return undefined;
}, [readonly]);
var id = useMemo(function () {
return getUuid();
}, []);
var wmdeMarkdownSize = useSize(function () {
return document.querySelector("#".concat(id, " .wmde-markdown"));
});
var autoHeight = useMemo(function () {
return readonly && readonlyHeightAutoFt;
}, [readonly, readonlyHeightAutoFt]);
var heightFt = useMemo(function () {
if (autoHeight) {
var _wmdeMarkdownSize$hei;
return ((_wmdeMarkdownSize$hei = wmdeMarkdownSize === null || wmdeMarkdownSize === void 0 ? void 0 : wmdeMarkdownSize.height) !== null && _wmdeMarkdownSize$hei !== void 0 ? _wmdeMarkdownSize$hei : 0) + 25;
}
return height;
}, [autoHeight, wmdeMarkdownSize === null || wmdeMarkdownSize === void 0 ? void 0 : wmdeMarkdownSize.height, height]);
var visibleDragbarFt = useMemo(function () {
if (autoHeight) return false;
return restProps.visibleDragbar;
}, [autoHeight, restProps.visibleDragbar]);
return /*#__PURE__*/jsx("div", {
style: style,
className: classNames('v-markdown-editor', className),
id: id,
children: /*#__PURE__*/jsx(MDEditor, _objectSpread2(_objectSpread2({
highlightEnable: true
}, restProps), {}, {
style: {
boxShadow: hideBorder ? 'none' : undefined
},
height: heightFt,
ref: editorRef,
value: innerValue,
preview: preview,
onChange: onInnerChange,
visibleDragbar: visibleDragbarFt,
"data-color-mode": dataColorMode,
extraCommands: extraCommands,
commands: commandsFt,
previewOptions: {
components: {
code: PluginMermaidCode
}
}
}))
});
};
/**
* markdown编辑器
* ```
* 1. 使用@uiw/react-md-editor组件
* 2. 动态加载 mermaid.js 和 mdeditor.js 和 mdeditor.css
* //oss.ly.com/newpay/cdn/react-md-editor/mermaid.11.12.0.min.js
* //oss.ly.com/newpay/cdn/react-md-editor/4.0.11/mdeditor.min.js
* //oss.ly.com/newpay/cdn/react-md-editor/4.0.11/mdeditor.min.css
* ```
*/
var MarkdownEditor = function MarkdownEditor(props) {
var _useState = useState(false),
_useState2 = _slicedToArray(_useState, 2),
renderFlag = _useState2[0],
setRenderFlag = _useState2[1];
var _useState3 = useState(null),
_useState4 = _slicedToArray(_useState3, 2),
errorMsg = _useState4[0],
setErrorMsg = _useState4[1];
useEffect(function () {
Promise.all([loadScripts({
scriptUrls: ['//oss.ly.com/newpay/cdn/react-md-editor/mermaid.11.12.0.min.js', '//oss.ly.com/newpay/cdn/react-md-editor/4.0.11/mdeditor.min.js'],
checkFn: function checkFn() {
var isLoaded = window['@uiw/react-md-editor'] && window['mermaid'];
return isLoaded;
},
intervalMs: 20
}), loadStyles({
styleUrls: ['//oss.ly.com/newpay/cdn/react-md-editor/4.0.11/mdeditor.min.css']
})]).then(function () {
setRenderFlag(true);
}).catch(function (error) {
console.error(error);
setRenderFlag(true);
setErrorMsg((error === null || error === void 0 ? void 0 : error.message) || 'Markdown编辑器加载失败');
});
}, []);
if (!renderFlag) {
return /*#__PURE__*/jsx(Spin, {
tip: /*#__PURE__*/jsx("div", {
style: {
marginTop: 10
},
children: "Markdown\u7F16\u8F91\u5668\u52A0\u8F7D\u4E2D"
}),
size: "small",
children: /*#__PURE__*/jsx("div", {
style: {
padding: 50,
background: 'rgba(0, 0, 0, 0.05)',
borderRadius: 4
}
})
});
}
if (errorMsg) {
return /*#__PURE__*/jsxs("div", {
style: {
textAlign: 'center',
padding: 20,
background: '#fff'
},
children: [/*#__PURE__*/jsx(_CloseCircleFilled, {
style: {
color: '#f00',
fontSize: 30
}
}), /*#__PURE__*/jsx("div", {
style: {
color: '#f00',
marginTop: 10,
fontSize: 16
},
children: "Markdown\u7F16\u8F91\u5668\u52A0\u8F7D\u5931\u8D25"
}), /*#__PURE__*/jsx("div", {
style: {
color: '#898989',
marginTop: 5,
fontSize: 12
},
children: errorMsg
})]
});
}
return /*#__PURE__*/jsx(ReactMdEditor, _objectSpread2({}, props));
};
export { MarkdownEditor as M };
//# sourceMappingURL=content-DnpCk2LR.js.map