@lobehub/ui 2.11.9 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/Image/Image.js +2 -8
- package/es/Image/style.js +3 -3
- package/es/Markdown/Markdown.js +72 -76
- package/es/Markdown/Typography.js +4 -1
- package/es/{mdx/mdxComponents → Markdown/components}/Footnotes.d.ts +2 -2
- package/es/Markdown/components/Footnotes.js +120 -0
- package/es/Markdown/components/{SearchResultCard/index.js → SearchResultCards/SearchResultCard.js} +4 -2
- package/es/Markdown/components/SearchResultCards/index.js +7 -3
- package/es/Markdown/components/useDelayedAnimated.d.ts +1 -0
- package/es/Markdown/components/useDelayedAnimated.js +31 -0
- package/es/Markdown/markdown.style.js +12 -11
- package/es/Markdown/plugins/rehypeCustomFootnotes.d.ts +1 -0
- package/es/Markdown/plugins/{footnote.js → rehypeCustomFootnotes.js} +2 -34
- package/es/Markdown/plugins/rehypeStreamAnimated.d.ts +2 -0
- package/es/Markdown/plugins/{animated.js → rehypeStreamAnimated.js} +1 -1
- package/es/Markdown/plugins/remarkColor.d.ts +17 -0
- package/es/Markdown/plugins/remarkColor.js +188 -0
- package/es/Markdown/plugins/remarkCustomFootnotes.d.ts +6 -0
- package/es/Markdown/plugins/remarkCustomFootnotes.js +32 -0
- package/es/Markdown/plugins/remarkGfmPlus.d.ts +5 -0
- package/es/Markdown/plugins/remarkGfmPlus.js +140 -0
- package/es/Markdown/plugins/remarkVideo.d.ts +17 -0
- package/es/Markdown/plugins/remarkVideo.js +186 -0
- package/es/Markdown/style.d.ts +1 -0
- package/es/Markdown/style.js +5 -4
- package/es/Markdown/type.d.ts +1 -0
- package/es/Mermaid/SyntaxMermaid/index.js +4 -2
- package/es/Video/index.js +1 -1
- package/es/hooks/useMarkdown/useMarkdownComponents.js +65 -13
- package/es/hooks/useMarkdown/useMarkdownRehypePlugins.js +4 -4
- package/es/hooks/useMarkdown/useMarkdownRemarkPlugins.js +7 -3
- package/es/mdx/mdxComponents/Section.js +4 -2
- package/package.json +2 -1
- package/es/Markdown/plugins/animated.d.ts +0 -2
- package/es/Markdown/plugins/footnote.d.ts +0 -2
- package/es/hooks/useMarkdown/fixMarkdownEmphasisSpacing.d.ts +0 -1
- package/es/hooks/useMarkdown/fixMarkdownEmphasisSpacing.js +0 -189
- package/es/mdx/mdxComponents/Footnotes.js +0 -44
- /package/es/Markdown/components/{SearchResultCard/index.d.ts → SearchResultCards/SearchResultCard.d.ts} +0 -0
- /package/es/Markdown/components/{SearchResultCard → SearchResultCards}/style.d.ts +0 -0
- /package/es/Markdown/components/{SearchResultCard → SearchResultCards}/style.js +0 -0
- /package/es/Markdown/plugins/{katexDir.d.ts → rehypeKatexDir.d.ts} +0 -0
- /package/es/Markdown/plugins/{katexDir.js → rehypeKatexDir.js} +0 -0
|
@@ -9,7 +9,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
|
|
|
9
9
|
// SPDX-License-Identifier: MIT
|
|
10
10
|
|
|
11
11
|
import { visit } from 'unist-util-visit';
|
|
12
|
-
export var
|
|
12
|
+
export var rehypeStreamAnimated = function rehypeStreamAnimated() {
|
|
13
13
|
return function (tree) {
|
|
14
14
|
visit(tree, 'element', function (node) {
|
|
15
15
|
if (['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'strong'].includes(node.tagName) && node.children) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface RemarkColorOptions {
|
|
2
|
+
/**
|
|
3
|
+
* 自定义颜色验证函数
|
|
4
|
+
*/
|
|
5
|
+
colorValidator?: (colorString: string) => boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Remark plugin to handle color syntax in markdown code spans
|
|
9
|
+
* Supports GitHub-style color visualization for HEX, RGB, and HSL colors
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* `#FF0000` -> renders with red color preview
|
|
13
|
+
* `rgb(255, 0, 0)` -> renders with red color preview
|
|
14
|
+
* `hsl(0, 100%, 50%)` -> renders with red color preview
|
|
15
|
+
*/
|
|
16
|
+
export declare const remarkColor: (options?: RemarkColorOptions) => (tree: any) => void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
+
import { visit } from 'unist-util-visit';
|
|
8
|
+
/**
|
|
9
|
+
* Remark plugin to handle color syntax in markdown code spans
|
|
10
|
+
* Supports GitHub-style color visualization for HEX, RGB, and HSL colors
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* `#FF0000` -> renders with red color preview
|
|
14
|
+
* `rgb(255, 0, 0)` -> renders with red color preview
|
|
15
|
+
* `hsl(0, 100%, 50%)` -> renders with red color preview
|
|
16
|
+
*/
|
|
17
|
+
export var remarkColor = function remarkColor() {
|
|
18
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
19
|
+
var colorValidator = options.colorValidator;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 验证并标准化颜色值
|
|
23
|
+
*/
|
|
24
|
+
var validateAndNormalizeColor = function validateAndNormalizeColor(colorString) {
|
|
25
|
+
var trimmed = colorString.trim();
|
|
26
|
+
|
|
27
|
+
// 如果有自定义验证函数,使用它
|
|
28
|
+
if (colorValidator && !colorValidator(trimmed)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// HEX 颜色: #RRGGBB 或 #RGB
|
|
33
|
+
var hexPattern = /^#([\dA-Fa-f]{6}|[\dA-Fa-f]{3})$/;
|
|
34
|
+
if (hexPattern.test(trimmed)) {
|
|
35
|
+
// 标准化为 6 位 HEX
|
|
36
|
+
if (trimmed.length === 4) {
|
|
37
|
+
var _trimmed = _slicedToArray(trimmed, 4),
|
|
38
|
+
r = _trimmed[1],
|
|
39
|
+
g = _trimmed[2],
|
|
40
|
+
b = _trimmed[3];
|
|
41
|
+
return "#".concat(r).concat(r).concat(g).concat(g).concat(b).concat(b);
|
|
42
|
+
}
|
|
43
|
+
return trimmed.toUpperCase();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// RGB 颜色: rgb(r, g, b)
|
|
47
|
+
var rgbPattern = /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
|
|
48
|
+
var rgbMatch = trimmed.match(rgbPattern);
|
|
49
|
+
if (rgbMatch) {
|
|
50
|
+
var _rgbMatch = _slicedToArray(rgbMatch, 4),
|
|
51
|
+
_r = _rgbMatch[1],
|
|
52
|
+
_g = _rgbMatch[2],
|
|
53
|
+
_b = _rgbMatch[3];
|
|
54
|
+
var rNum = parseInt(_r, 10);
|
|
55
|
+
var gNum = parseInt(_g, 10);
|
|
56
|
+
var bNum = parseInt(_b, 10);
|
|
57
|
+
|
|
58
|
+
// 验证 RGB 值范围
|
|
59
|
+
if (rNum >= 0 && rNum <= 255 && gNum >= 0 && gNum <= 255 && bNum >= 0 && bNum <= 255) {
|
|
60
|
+
return "rgb(".concat(rNum, ", ").concat(gNum, ", ").concat(bNum, ")");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// HSL 颜色: hsl(h, s%, l%)
|
|
65
|
+
var hslPattern = /^hsl\s*\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$/i;
|
|
66
|
+
var hslMatch = trimmed.match(hslPattern);
|
|
67
|
+
if (hslMatch) {
|
|
68
|
+
var _hslMatch = _slicedToArray(hslMatch, 4),
|
|
69
|
+
h = _hslMatch[1],
|
|
70
|
+
s = _hslMatch[2],
|
|
71
|
+
l = _hslMatch[3];
|
|
72
|
+
var hNum = parseInt(h, 10);
|
|
73
|
+
var sNum = parseInt(s, 10);
|
|
74
|
+
var lNum = parseInt(l, 10);
|
|
75
|
+
|
|
76
|
+
// 验证 HSL 值范围
|
|
77
|
+
if (hNum >= 0 && hNum <= 360 && sNum >= 0 && sNum <= 100 && lNum >= 0 && lNum <= 100) {
|
|
78
|
+
return "hsl(".concat(hNum, ", ").concat(sNum, "%, ").concat(lNum, "%)");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
83
|
+
return function (tree) {
|
|
84
|
+
// 处理 inlineCode 节点(反引号包围的代码)
|
|
85
|
+
visit(tree, 'inlineCode', function (node) {
|
|
86
|
+
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
87
|
+
var parent = arguments.length > 2 ? arguments[2] : undefined;
|
|
88
|
+
if (!node.value || typeof node.value !== 'string') return;
|
|
89
|
+
var colorValue = validateAndNormalizeColor(node.value);
|
|
90
|
+
if (colorValue) {
|
|
91
|
+
// 创建自定义颜色节点
|
|
92
|
+
var colorNode = {
|
|
93
|
+
children: [{
|
|
94
|
+
type: 'text',
|
|
95
|
+
value: node.value
|
|
96
|
+
}],
|
|
97
|
+
color: colorValue,
|
|
98
|
+
data: {
|
|
99
|
+
hName: 'code',
|
|
100
|
+
hProperties: {
|
|
101
|
+
'className': 'color-preview',
|
|
102
|
+
'data-color': colorValue,
|
|
103
|
+
'data-original': node.value,
|
|
104
|
+
'style': "--color-preview-color: ".concat(colorValue)
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
type: 'colorPreview',
|
|
108
|
+
value: node.value
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// 替换 inlineCode 节点
|
|
112
|
+
parent.children.splice(index, 1, colorNode);
|
|
113
|
+
return index;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// 处理文本节点中的颜色语法(作为备用,处理可能的边缘情况)
|
|
118
|
+
visit(tree, 'text', function (node) {
|
|
119
|
+
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
120
|
+
var parent = arguments.length > 2 ? arguments[2] : undefined;
|
|
121
|
+
if (!node.value || typeof node.value !== 'string') return;
|
|
122
|
+
|
|
123
|
+
// 查找反引号包围的颜色值
|
|
124
|
+
var colorPattern = /`([^`]+)`/g;
|
|
125
|
+
var text = node.value;
|
|
126
|
+
var hasColorMatch = false;
|
|
127
|
+
var newNodes = [];
|
|
128
|
+
var lastIndex = 0;
|
|
129
|
+
var match;
|
|
130
|
+
while ((match = colorPattern.exec(text)) !== null) {
|
|
131
|
+
var _match = match,
|
|
132
|
+
_match2 = _slicedToArray(_match, 2),
|
|
133
|
+
fullMatch = _match2[0],
|
|
134
|
+
colorCandidate = _match2[1];
|
|
135
|
+
var colorValue = validateAndNormalizeColor(colorCandidate);
|
|
136
|
+
if (colorValue) {
|
|
137
|
+
hasColorMatch = true;
|
|
138
|
+
var startIndex = match.index;
|
|
139
|
+
|
|
140
|
+
// 添加匹配前的文本
|
|
141
|
+
if (startIndex > lastIndex) {
|
|
142
|
+
newNodes.push({
|
|
143
|
+
type: 'text',
|
|
144
|
+
value: text.slice(lastIndex, startIndex)
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 添加颜色节点
|
|
149
|
+
newNodes.push({
|
|
150
|
+
children: [{
|
|
151
|
+
type: 'text',
|
|
152
|
+
value: colorCandidate
|
|
153
|
+
}],
|
|
154
|
+
color: colorValue,
|
|
155
|
+
data: {
|
|
156
|
+
hName: 'code',
|
|
157
|
+
hProperties: {
|
|
158
|
+
'className': 'color-preview',
|
|
159
|
+
'data-color': colorValue,
|
|
160
|
+
'data-original': colorCandidate,
|
|
161
|
+
'style': "--color-preview-color: ".concat(colorValue)
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
type: 'colorPreview',
|
|
165
|
+
value: colorCandidate
|
|
166
|
+
});
|
|
167
|
+
lastIndex = startIndex + fullMatch.length;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (hasColorMatch) {
|
|
171
|
+
// 添加剩余文本
|
|
172
|
+
if (lastIndex < text.length) {
|
|
173
|
+
newNodes.push({
|
|
174
|
+
type: 'text',
|
|
175
|
+
value: text.slice(lastIndex)
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 替换当前节点
|
|
180
|
+
if (newNodes.length > 0 && parent) {
|
|
181
|
+
var _parent$children;
|
|
182
|
+
(_parent$children = parent.children).splice.apply(_parent$children, [index, 1].concat(newNodes));
|
|
183
|
+
return index + newNodes.length - 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SKIP, visit } from 'unist-util-visit';
|
|
2
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
3
|
+
export var remarkCustomFootnotes = function remarkCustomFootnotes() {
|
|
4
|
+
return function (tree, file) {
|
|
5
|
+
var footnoteLinks = new Map();
|
|
6
|
+
visit(tree, 'footnoteDefinition', function (node) {
|
|
7
|
+
var linkData = null;
|
|
8
|
+
|
|
9
|
+
// 查找第一个link类型的子节点
|
|
10
|
+
visit(node, 'link', function (linkNode) {
|
|
11
|
+
if (linkData) return SKIP; // 只取第一个链接
|
|
12
|
+
|
|
13
|
+
// 提取链接文本
|
|
14
|
+
var textNode = linkNode.children.find(function (n) {
|
|
15
|
+
return n.type === 'text';
|
|
16
|
+
});
|
|
17
|
+
linkData = {
|
|
18
|
+
alt: (textNode === null || textNode === void 0 ? void 0 : textNode.value) || '',
|
|
19
|
+
title: (textNode === null || textNode === void 0 ? void 0 : textNode.value) || '',
|
|
20
|
+
url: linkNode.url // 或者根据需求处理
|
|
21
|
+
};
|
|
22
|
+
return SKIP; // 找到后停止遍历
|
|
23
|
+
});
|
|
24
|
+
if (linkData) {
|
|
25
|
+
footnoteLinks.set(node.identifier, linkData);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// 将数据存入文件上下文
|
|
30
|
+
file.data.footnoteLinks = Object.fromEntries(footnoteLinks);
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
+
import { visit } from 'unist-util-visit';
|
|
8
|
+
export var remarkGfmPlus = function remarkGfmPlus() {
|
|
9
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
10
|
+
var _options$allowHtmlTag = options.allowHtmlTags,
|
|
11
|
+
allowHtmlTags = _options$allowHtmlTag === void 0 ? ['sub', 'sup', 'ins', 'kbd'] : _options$allowHtmlTag;
|
|
12
|
+
return function (tree) {
|
|
13
|
+
// 遍历所有父节点,查找分离的HTML标签模式
|
|
14
|
+
visit(tree, function (node) {
|
|
15
|
+
if (!node.children || !Array.isArray(node.children)) return;
|
|
16
|
+
var children = node.children;
|
|
17
|
+
var i = 0;
|
|
18
|
+
while (i < children.length) {
|
|
19
|
+
var currentNode = children[i];
|
|
20
|
+
|
|
21
|
+
// 查找开始标签
|
|
22
|
+
if (currentNode.type === 'html' && currentNode.value) {
|
|
23
|
+
var tagPattern = "^<(".concat(allowHtmlTags.join('|'), ")>$");
|
|
24
|
+
var startTagMatch = currentNode.value.match(new RegExp(tagPattern));
|
|
25
|
+
if (startTagMatch) {
|
|
26
|
+
var tagName = startTagMatch[1];
|
|
27
|
+
|
|
28
|
+
// 查找对应的结束标签
|
|
29
|
+
var endIndex = -1;
|
|
30
|
+
var textNodes = [];
|
|
31
|
+
for (var j = i + 1; j < children.length; j++) {
|
|
32
|
+
var nextNode = children[j];
|
|
33
|
+
if (nextNode.type === 'html' && nextNode.value === "</".concat(tagName, ">")) {
|
|
34
|
+
endIndex = j;
|
|
35
|
+
break;
|
|
36
|
+
} else if (nextNode.type === 'text') {
|
|
37
|
+
textNodes.push(nextNode);
|
|
38
|
+
} else {
|
|
39
|
+
// 如果遇到其他类型的节点,停止查找
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (endIndex !== -1) {
|
|
44
|
+
// 收集所有文本内容
|
|
45
|
+
var textContent = textNodes.map(function (node) {
|
|
46
|
+
return node.value;
|
|
47
|
+
}).join('');
|
|
48
|
+
|
|
49
|
+
// 创建新的自定义节点
|
|
50
|
+
var newNode = {
|
|
51
|
+
children: [{
|
|
52
|
+
type: 'text',
|
|
53
|
+
value: textContent
|
|
54
|
+
}],
|
|
55
|
+
data: {
|
|
56
|
+
hName: tagName,
|
|
57
|
+
hProperties: {}
|
|
58
|
+
},
|
|
59
|
+
type: tagName
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// 替换从开始标签到结束标签的所有节点
|
|
63
|
+
var removeCount = endIndex - i + 1;
|
|
64
|
+
children.splice(i, removeCount, newNode);
|
|
65
|
+
|
|
66
|
+
// 继续处理下一个节点
|
|
67
|
+
i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
i++;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// 保留对文本节点中完整HTML标签的处理(作为备用)
|
|
77
|
+
visit(tree, 'text', function (node) {
|
|
78
|
+
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
79
|
+
var parent = arguments.length > 2 ? arguments[2] : undefined;
|
|
80
|
+
if (!node.value || typeof node.value !== 'string') return;
|
|
81
|
+
|
|
82
|
+
// 处理HTML实体编码的标签
|
|
83
|
+
var encodedTagPattern = "<(".concat(allowHtmlTags.join('|'), ")>(.*?)<\\/\\1>");
|
|
84
|
+
var encodedTagRegex = new RegExp(encodedTagPattern, 'gi');
|
|
85
|
+
var text = node.value;
|
|
86
|
+
if (!encodedTagRegex.test(text)) return;
|
|
87
|
+
|
|
88
|
+
// 重置正则表达式的 lastIndex
|
|
89
|
+
encodedTagRegex.lastIndex = 0;
|
|
90
|
+
var newNodes = [];
|
|
91
|
+
var lastIndex = 0;
|
|
92
|
+
var match;
|
|
93
|
+
while ((match = encodedTagRegex.exec(text)) !== null) {
|
|
94
|
+
var _match = match,
|
|
95
|
+
_match2 = _slicedToArray(_match, 3),
|
|
96
|
+
fullMatch = _match2[0],
|
|
97
|
+
tagName = _match2[1],
|
|
98
|
+
content = _match2[2];
|
|
99
|
+
var startIndex = match.index;
|
|
100
|
+
|
|
101
|
+
// 添加匹配前的文本
|
|
102
|
+
if (startIndex > lastIndex) {
|
|
103
|
+
newNodes.push({
|
|
104
|
+
type: 'text',
|
|
105
|
+
value: text.slice(lastIndex, startIndex)
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 添加特殊标签节点
|
|
110
|
+
newNodes.push({
|
|
111
|
+
children: [{
|
|
112
|
+
type: 'text',
|
|
113
|
+
value: content
|
|
114
|
+
}],
|
|
115
|
+
data: {
|
|
116
|
+
hName: tagName,
|
|
117
|
+
hProperties: {}
|
|
118
|
+
},
|
|
119
|
+
type: tagName
|
|
120
|
+
});
|
|
121
|
+
lastIndex = startIndex + fullMatch.length;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 添加剩余文本
|
|
125
|
+
if (lastIndex < text.length) {
|
|
126
|
+
newNodes.push({
|
|
127
|
+
type: 'text',
|
|
128
|
+
value: text.slice(lastIndex)
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 替换当前节点
|
|
133
|
+
if (newNodes.length > 0 && parent) {
|
|
134
|
+
var _parent$children;
|
|
135
|
+
(_parent$children = parent.children).splice.apply(_parent$children, [index, 1].concat(newNodes));
|
|
136
|
+
return index + newNodes.length - 1;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface RemarkVideoOptions {
|
|
2
|
+
/**
|
|
3
|
+
* 支持的视频标签名,默认为 ['video']
|
|
4
|
+
*/
|
|
5
|
+
videoTags?: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Remark plugin to handle <video> tags in markdown text
|
|
9
|
+
* This plugin converts <video> tags to proper video elements
|
|
10
|
+
* without requiring allowHtml to be enabled
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <video src="https://example.com/video.mp4" />
|
|
14
|
+
* <video src="https://example.com/video.mp4" controls width="400" height="300" />
|
|
15
|
+
*/
|
|
16
|
+
export declare const remarkVideo: (options?: RemarkVideoOptions) => (tree: any) => void;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
4
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
5
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
6
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
7
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
8
|
+
import { visit } from 'unist-util-visit';
|
|
9
|
+
/**
|
|
10
|
+
* Remark plugin to handle <video> tags in markdown text
|
|
11
|
+
* This plugin converts <video> tags to proper video elements
|
|
12
|
+
* without requiring allowHtml to be enabled
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <video src="https://example.com/video.mp4" />
|
|
16
|
+
* <video src="https://example.com/video.mp4" controls width="400" height="300" />
|
|
17
|
+
*/
|
|
18
|
+
export var remarkVideo = function remarkVideo() {
|
|
19
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
20
|
+
var _options$videoTags = options.videoTags,
|
|
21
|
+
videoTags = _options$videoTags === void 0 ? ['video'] : _options$videoTags;
|
|
22
|
+
return function (tree) {
|
|
23
|
+
// 处理HTML节点中的video标签
|
|
24
|
+
visit(tree, 'html', function (node) {
|
|
25
|
+
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
26
|
+
var parent = arguments.length > 2 ? arguments[2] : undefined;
|
|
27
|
+
if (!node.value || typeof node.value !== 'string') return;
|
|
28
|
+
var _iterator = _createForOfIteratorHelper(videoTags),
|
|
29
|
+
_step;
|
|
30
|
+
try {
|
|
31
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
32
|
+
var tagName = _step.value;
|
|
33
|
+
// 匹配自闭合的video标签,支持属性
|
|
34
|
+
var selfClosingPattern = "^<".concat(tagName, "([^>]*?)\\s*\\/?\\s*>$");
|
|
35
|
+
var selfClosingMatch = node.value.trim().match(new RegExp(selfClosingPattern, 'i'));
|
|
36
|
+
if (selfClosingMatch) {
|
|
37
|
+
var _selfClosingMatch$;
|
|
38
|
+
var attributesStr = ((_selfClosingMatch$ = selfClosingMatch[1]) === null || _selfClosingMatch$ === void 0 ? void 0 : _selfClosingMatch$.trim()) || '';
|
|
39
|
+
|
|
40
|
+
// 解析属性
|
|
41
|
+
var properties = {};
|
|
42
|
+
var attrRegex = /(\w+)=["']([^"']*?)["']/g;
|
|
43
|
+
var attrMatch = void 0;
|
|
44
|
+
while ((attrMatch = attrRegex.exec(attributesStr)) !== null) {
|
|
45
|
+
properties[attrMatch[1]] = attrMatch[2];
|
|
46
|
+
}
|
|
47
|
+
console.log('remarkVideo: Found video tag:', tagName, properties);
|
|
48
|
+
|
|
49
|
+
// 创建video节点
|
|
50
|
+
var newNode = {
|
|
51
|
+
children: [],
|
|
52
|
+
data: {
|
|
53
|
+
hName: tagName,
|
|
54
|
+
hProperties: properties
|
|
55
|
+
},
|
|
56
|
+
type: tagName
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// 替换html节点为video节点
|
|
60
|
+
parent.children.splice(index, 1, newNode);
|
|
61
|
+
return index;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 匹配成对的video标签(虽然不太常见,但也支持)
|
|
65
|
+
var pairedPattern = "^<".concat(tagName, "([^>]*?)>(.*?)<\\/").concat(tagName, ">$");
|
|
66
|
+
var pairedMatch = node.value.trim().match(new RegExp(pairedPattern, 'is'));
|
|
67
|
+
if (pairedMatch) {
|
|
68
|
+
var _pairedMatch$;
|
|
69
|
+
var _attributesStr = ((_pairedMatch$ = pairedMatch[1]) === null || _pairedMatch$ === void 0 ? void 0 : _pairedMatch$.trim()) || '';
|
|
70
|
+
var content = pairedMatch[2] || '';
|
|
71
|
+
|
|
72
|
+
// 解析属性
|
|
73
|
+
var _properties = {};
|
|
74
|
+
var _attrRegex = /(\w+)=["']([^"']*?)["']/g;
|
|
75
|
+
var _attrMatch = void 0;
|
|
76
|
+
while ((_attrMatch = _attrRegex.exec(_attributesStr)) !== null) {
|
|
77
|
+
_properties[_attrMatch[1]] = _attrMatch[2];
|
|
78
|
+
}
|
|
79
|
+
console.log('remarkVideo: Found paired video tag:', tagName, _properties);
|
|
80
|
+
|
|
81
|
+
// 创建video节点
|
|
82
|
+
var _newNode = {
|
|
83
|
+
children: content ? [{
|
|
84
|
+
type: 'text',
|
|
85
|
+
value: content
|
|
86
|
+
}] : [],
|
|
87
|
+
data: {
|
|
88
|
+
hName: tagName,
|
|
89
|
+
hProperties: _properties
|
|
90
|
+
},
|
|
91
|
+
type: tagName
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// 替换html节点为video节点
|
|
95
|
+
parent.children.splice(index, 1, _newNode);
|
|
96
|
+
return index;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
_iterator.e(err);
|
|
101
|
+
} finally {
|
|
102
|
+
_iterator.f();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 处理文本节点中的video标签(HTML实体编码形式)
|
|
107
|
+
visit(tree, 'text', function (node) {
|
|
108
|
+
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
109
|
+
var parent = arguments.length > 2 ? arguments[2] : undefined;
|
|
110
|
+
if (!node.value || typeof node.value !== 'string') return;
|
|
111
|
+
var _iterator2 = _createForOfIteratorHelper(videoTags),
|
|
112
|
+
_step2;
|
|
113
|
+
try {
|
|
114
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
115
|
+
var tagName = _step2.value;
|
|
116
|
+
// 处理HTML实体编码的自闭合video标签
|
|
117
|
+
var encodedSelfClosingPattern = "<".concat(tagName, "([^&]*?)\\s*\\/?\\s*>");
|
|
118
|
+
var encodedSelfClosingRegex = new RegExp(encodedSelfClosingPattern, 'gi');
|
|
119
|
+
if (!encodedSelfClosingRegex.test(node.value)) continue;
|
|
120
|
+
|
|
121
|
+
// 重置正则表达式的 lastIndex
|
|
122
|
+
encodedSelfClosingRegex.lastIndex = 0;
|
|
123
|
+
var text = node.value;
|
|
124
|
+
var newNodes = [];
|
|
125
|
+
var lastIndex = 0;
|
|
126
|
+
var match = void 0;
|
|
127
|
+
while ((match = encodedSelfClosingRegex.exec(text)) !== null) {
|
|
128
|
+
var _match = match,
|
|
129
|
+
_match2 = _slicedToArray(_match, 2),
|
|
130
|
+
fullMatch = _match2[0],
|
|
131
|
+
attributesStr = _match2[1];
|
|
132
|
+
var startIndex = match.index;
|
|
133
|
+
|
|
134
|
+
// 添加匹配前的文本
|
|
135
|
+
if (startIndex > lastIndex) {
|
|
136
|
+
newNodes.push({
|
|
137
|
+
type: 'text',
|
|
138
|
+
value: text.slice(lastIndex, startIndex)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 解析属性(需要解码HTML实体)
|
|
143
|
+
var decodedAttrs = attributesStr.replaceAll('"', '"').replaceAll(''', "'").replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');
|
|
144
|
+
var properties = {};
|
|
145
|
+
var attrRegex = /(\w+)=["']([^"']*?)["']/g;
|
|
146
|
+
var attrMatch = void 0;
|
|
147
|
+
while ((attrMatch = attrRegex.exec(decodedAttrs)) !== null) {
|
|
148
|
+
properties[attrMatch[1]] = attrMatch[2];
|
|
149
|
+
}
|
|
150
|
+
console.log('remarkVideo: Found encoded video tag:', tagName, properties);
|
|
151
|
+
|
|
152
|
+
// 添加video节点
|
|
153
|
+
newNodes.push({
|
|
154
|
+
children: [],
|
|
155
|
+
data: {
|
|
156
|
+
hName: tagName,
|
|
157
|
+
hProperties: properties
|
|
158
|
+
},
|
|
159
|
+
type: tagName
|
|
160
|
+
});
|
|
161
|
+
lastIndex = startIndex + fullMatch.length;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 添加剩余文本
|
|
165
|
+
if (lastIndex < text.length) {
|
|
166
|
+
newNodes.push({
|
|
167
|
+
type: 'text',
|
|
168
|
+
value: text.slice(lastIndex)
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 替换当前节点
|
|
173
|
+
if (newNodes.length > 0 && parent) {
|
|
174
|
+
var _parent$children;
|
|
175
|
+
(_parent$children = parent.children).splice.apply(_parent$children, [index, 1].concat(newNodes));
|
|
176
|
+
return index + newNodes.length - 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} catch (err) {
|
|
180
|
+
_iterator2.e(err);
|
|
181
|
+
} finally {
|
|
182
|
+
_iterator2.f();
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
};
|
package/es/Markdown/style.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const useStyles: (props?: unknown) => import("antd-style").ReturnStyles<{
|
|
2
2
|
chat: import("antd-style").SerializedStyles;
|
|
3
|
+
gfm: import("antd-style").SerializedStyles;
|
|
3
4
|
latex: import("antd-style").SerializedStyles;
|
|
4
5
|
root: import("antd-style").SerializedStyles;
|
|
5
6
|
}>;
|
package/es/Markdown/style.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var _templateObject, _templateObject2, _templateObject3;
|
|
1
|
+
var _templateObject, _templateObject2, _templateObject3, _templateObject4;
|
|
2
2
|
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
|
|
3
3
|
import { createStyles } from 'antd-style';
|
|
4
4
|
export var useStyles = createStyles(function (_ref) {
|
|
@@ -7,8 +7,9 @@ export var useStyles = createStyles(function (_ref) {
|
|
|
7
7
|
isDarkMode = _ref.isDarkMode;
|
|
8
8
|
var cyanColor = isDarkMode ? token.cyan9A : token.cyan11A;
|
|
9
9
|
return {
|
|
10
|
-
chat: css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
chat: css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n ol,\n ul {\n > li {\n &::marker {\n color: ", " !important;\n }\n\n > li {\n &::marker {\n color: ", " !important;\n }\n }\n }\n }\n\n ul {\n list-style: unset;\n\n > li {\n &::before {\n content: unset;\n display: unset;\n }\n }\n }\n "])), cyanColor, token.colorTextSecondary),
|
|
11
|
+
gfm: css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n .markdown-alert {\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n padding-inline-start: 1em;\n border-inline-start: solid 4px ", ";\n\n > p {\n margin-block-start: 0 !important;\n }\n }\n\n .markdown-alert > :first-child {\n margin-block-start: 0;\n }\n\n .markdown-alert > :last-child {\n margin-block-end: 0;\n }\n\n .markdown-alert-note {\n border-inline-start-color: ", ";\n }\n\n .markdown-alert-tip {\n border-inline-start-color: ", ";\n }\n\n .markdown-alert-important {\n border-inline-start-color: ", ";\n }\n\n .markdown-alert-warning {\n border-inline-start-color: ", ";\n }\n\n .markdown-alert-caution {\n border-inline-start-color: ", ";\n }\n\n .markdown-alert-title {\n display: flex;\n align-items: center;\n margin-block-end: 0.5em !important;\n font-weight: 500;\n }\n\n .markdown-alert-note .markdown-alert-title {\n color: ", ";\n fill: ", ";\n }\n\n .markdown-alert-tip .markdown-alert-title {\n color: ", ";\n fill: ", ";\n }\n\n .markdown-alert-important .markdown-alert-title {\n color: ", ";\n fill: ", ";\n }\n\n .markdown-alert-warning .markdown-alert-title {\n color: ", ";\n fill: ", ";\n }\n\n .markdown-alert-caution .markdown-alert-title {\n color: ", ";\n fill: ", ";\n }\n\n /* Style the footnotes section. */\n\n .octicon {\n overflow: visible !important;\n display: inline-block;\n margin-inline-end: 0.5em;\n vertical-align: text-bottom;\n }\n\n .sr-only {\n position: absolute;\n\n overflow: hidden;\n\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n\n word-wrap: normal;\n\n clip: rect(0, 0, 0, 0);\n }\n\n sup:has(*[aria-describedby='footnote-label']) {\n margin-inline: 2px;\n vertical-align: super !important;\n\n [data-footnote-ref] {\n display: inline-block;\n\n width: 16px;\n height: 16px;\n border-radius: 4px;\n\n font-family: ", ";\n font-size: 10px;\n color: ", " !important;\n text-align: center;\n\n background: ", ";\n }\n }\n\n code.color-preview {\n position: relative;\n display: inline-flex !important;\n gap: 0.4em;\n\n &::after {\n content: '';\n\n width: 0.66em;\n height: 0.66em;\n border: 1px solid ", ";\n border-radius: 50%;\n\n background-color: attr(data-color);\n\n /* Fallback for browsers that don't support attr() in background */\n background-color: var(--color-preview-color, #000);\n }\n }\n "])), token.colorBorder, token.colorInfo, token.colorSuccess, token.purple, token.colorWarning, token.colorError, token.colorInfo, token.colorInfo, token.colorSuccess, token.colorSuccess, token.purple, token.purple, token.colorWarning, token.colorWarning, token.colorError, token.colorError, token.fontFamilyCode, token.colorTextSecondary, token.colorFillSecondary, token.colorFill),
|
|
12
|
+
latex: css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n .katex-error {\n color: ", " !important;\n }\n\n .katex-html {\n overflow: auto hidden;\n padding: 3px;\n\n .base {\n margin-block: 0;\n margin-inline: auto;\n }\n\n .tag {\n position: relative !important;\n display: inline-block;\n padding-inline-start: 0.5rem;\n }\n }\n "])), token.colorTextDescription),
|
|
13
|
+
root: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n position: relative;\n overflow: hidden;\n max-width: 100%;\n "])))
|
|
13
14
|
};
|
|
14
15
|
});
|
package/es/Markdown/type.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { ImageProps, PreProps, VideoProps } from "../mdx";
|
|
|
9
9
|
import type { AProps, DivProps } from "../types";
|
|
10
10
|
import type { CitationItem } from "../types/citation";
|
|
11
11
|
export interface TypographyProps extends DivProps {
|
|
12
|
+
borderRadius?: number;
|
|
12
13
|
fontSize?: number;
|
|
13
14
|
headerMultiple?: number;
|
|
14
15
|
lineHeight?: number;
|