@blocklet/editor 2.5.5 → 2.5.7
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.
|
@@ -13,7 +13,13 @@ export declare const X_CODE_TRANSLATIONS: {
|
|
|
13
13
|
seeAllLines: string;
|
|
14
14
|
collapseCode: string;
|
|
15
15
|
};
|
|
16
|
+
ja: {
|
|
17
|
+
seeAllLines: string;
|
|
18
|
+
collapseCode: string;
|
|
19
|
+
};
|
|
16
20
|
};
|
|
21
|
+
export declare const QUOTE_MAP: Readonly<Map<string, string>>;
|
|
22
|
+
export declare function trimQuotes(raw: string): string;
|
|
17
23
|
export interface CodeProps {
|
|
18
24
|
editorTheme: EditorThemeClasses;
|
|
19
25
|
language: string;
|
|
@@ -22,4 +28,4 @@ export interface CodeProps {
|
|
|
22
28
|
foldable?: string;
|
|
23
29
|
foldthreshold?: string;
|
|
24
30
|
}
|
|
25
|
-
export default function Code({ editorTheme, language, title, body, foldable: _foldable, foldthreshold: _foldThreshold, }: CodeProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export default function Code({ editorTheme, language, title: rawTitle, body, foldable: _foldable, foldthreshold: _foldThreshold, }: CodeProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { codeToHtml } from 'shiki';
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
4
4
|
import { Box, IconButton, styled, useTheme, Typography, Stack } from '@mui/material';
|
|
5
5
|
import { Icon } from '@iconify/react';
|
|
6
6
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
@@ -346,7 +346,38 @@ export const X_CODE_TRANSLATIONS = {
|
|
|
346
346
|
seeAllLines: '查看所有 {lines} 行',
|
|
347
347
|
collapseCode: '折叠代码',
|
|
348
348
|
},
|
|
349
|
+
ja: {
|
|
350
|
+
seeAllLines: 'すべての {lines} 行を表示',
|
|
351
|
+
collapseCode: 'コードを折りたたむ',
|
|
352
|
+
},
|
|
349
353
|
};
|
|
354
|
+
// 引号集合
|
|
355
|
+
export const QUOTE_MAP = Object.freeze(new Map([
|
|
356
|
+
['"', '"'],
|
|
357
|
+
["'", "'"],
|
|
358
|
+
['`', '`'],
|
|
359
|
+
['”', '“'],
|
|
360
|
+
['‘', '’'],
|
|
361
|
+
['「', '」'],
|
|
362
|
+
['『', '』'],
|
|
363
|
+
]));
|
|
364
|
+
// 去除首尾成对的引号
|
|
365
|
+
export function trimQuotes(raw) {
|
|
366
|
+
if (!raw)
|
|
367
|
+
return '';
|
|
368
|
+
let s = raw.trim();
|
|
369
|
+
while (s.length > 1) {
|
|
370
|
+
const open = s[0];
|
|
371
|
+
const close = QUOTE_MAP.get(open);
|
|
372
|
+
if (close && s.endsWith(close)) {
|
|
373
|
+
s = s.slice(1, -1).trim();
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return s;
|
|
380
|
+
}
|
|
350
381
|
/** Header 组件 */
|
|
351
382
|
function CodeHeader({ title, icon, actions }) {
|
|
352
383
|
if (!title && !icon)
|
|
@@ -443,11 +474,17 @@ const XCode = styled('div')(({ theme }) => ({
|
|
|
443
474
|
},
|
|
444
475
|
},
|
|
445
476
|
}));
|
|
446
|
-
export default function Code({ editorTheme, language, title, body = '', foldable: _foldable = 'true', foldthreshold: _foldThreshold = '25', // ps: dataset 会强制将 key 小写
|
|
477
|
+
export default function Code({ editorTheme, language, title: rawTitle, body = '', foldable: _foldable = 'true', foldthreshold: _foldThreshold = '25', // ps: dataset 会强制将 key 小写
|
|
447
478
|
}) {
|
|
448
479
|
const [highlightedCode, setHighlightedCode] = useState('');
|
|
449
480
|
const [isLoading, setIsLoading] = useState(false);
|
|
450
481
|
const muiTheme = useTheme();
|
|
482
|
+
const title = useMemo(() => {
|
|
483
|
+
if (typeof rawTitle === 'string') {
|
|
484
|
+
return trimQuotes(rawTitle);
|
|
485
|
+
}
|
|
486
|
+
return '';
|
|
487
|
+
}, [rawTitle]);
|
|
451
488
|
// 参数类型转换(html dataset 只支持 string value)
|
|
452
489
|
const foldable = _foldable === 'true';
|
|
453
490
|
let foldThreshold = parseInt(_foldThreshold, 10);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { trimQuotes } from './Code';
|
|
3
|
+
describe('trimQuotes', () => {
|
|
4
|
+
describe('Basic single layer quotes', () => {
|
|
5
|
+
it('should trim double quotes', () => {
|
|
6
|
+
expect(trimQuotes('"hello"')).toBe('hello');
|
|
7
|
+
});
|
|
8
|
+
it('should trim single quotes', () => {
|
|
9
|
+
expect(trimQuotes("'hello'")).toBe('hello');
|
|
10
|
+
});
|
|
11
|
+
it('should trim backticks', () => {
|
|
12
|
+
expect(trimQuotes('`hello`')).toBe('hello');
|
|
13
|
+
});
|
|
14
|
+
it('should trim Chinese double quotes', () => {
|
|
15
|
+
expect(trimQuotes('”hello“')).toBe('hello');
|
|
16
|
+
});
|
|
17
|
+
it('should trim Chinese single quotes', () => {
|
|
18
|
+
expect(trimQuotes('‘hello’')).toBe('hello');
|
|
19
|
+
});
|
|
20
|
+
it('should trim Japanese square brackets', () => {
|
|
21
|
+
expect(trimQuotes('「hello」')).toBe('hello');
|
|
22
|
+
});
|
|
23
|
+
it('should trim Japanese double square brackets', () => {
|
|
24
|
+
expect(trimQuotes('『hello』')).toBe('hello');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
describe('Nested paired quotes', () => {
|
|
28
|
+
it('should trim nested single quotes inside double quotes', () => {
|
|
29
|
+
expect(trimQuotes('"\'hello\'"')).toBe('hello');
|
|
30
|
+
});
|
|
31
|
+
it('should trim nested Chinese double quotes', () => {
|
|
32
|
+
expect(trimQuotes('””hello““')).toBe('hello');
|
|
33
|
+
});
|
|
34
|
+
it('should trim nested Japanese brackets', () => {
|
|
35
|
+
expect(trimQuotes('「『hello』」')).toBe('hello');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('Unpaired quotes', () => {
|
|
39
|
+
it('should return original string when quote is only at start', () => {
|
|
40
|
+
expect(trimQuotes('"hello')).toBe('"hello');
|
|
41
|
+
});
|
|
42
|
+
it('should return original string when quote is only at end', () => {
|
|
43
|
+
expect(trimQuotes('hello"')).toBe('hello"');
|
|
44
|
+
});
|
|
45
|
+
it('should return original string when Chinese quote is only at start', () => {
|
|
46
|
+
expect(trimQuotes('”hello')).toBe('”hello');
|
|
47
|
+
});
|
|
48
|
+
it('should return original string when Chinese quote is only at end', () => {
|
|
49
|
+
expect(trimQuotes('hello”')).toBe('hello”');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('Internal quotes without outer wrapping', () => {
|
|
53
|
+
it('should not trim quotes in the middle of string', () => {
|
|
54
|
+
expect(trimQuotes('hello "world"')).toBe('hello "world"');
|
|
55
|
+
});
|
|
56
|
+
it('should not trim apostrophe in the middle of string', () => {
|
|
57
|
+
expect(trimQuotes("it's ok")).toBe("it's ok");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('Multiple layers (continuous peeling)', () => {
|
|
61
|
+
it('should trim multiple layers of Chinese double quotes', () => {
|
|
62
|
+
expect(trimQuotes('””hello““')).toBe('hello');
|
|
63
|
+
});
|
|
64
|
+
it('should trim multiple layers of nested quotes', () => {
|
|
65
|
+
expect(trimQuotes("'「『hi』」'")).toBe('hi');
|
|
66
|
+
});
|
|
67
|
+
it('should trim multiple layers of mixed quotes', () => {
|
|
68
|
+
expect(trimQuotes('"”「test」“"')).toBe('test');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('Whitespace and empty input', () => {
|
|
72
|
+
it('should trim quotes and surrounding spaces', () => {
|
|
73
|
+
expect(trimQuotes(' "trimmed" ')).toBe('trimmed');
|
|
74
|
+
});
|
|
75
|
+
it('should return empty string for empty input', () => {
|
|
76
|
+
expect(trimQuotes('')).toBe('');
|
|
77
|
+
});
|
|
78
|
+
it('should return empty string for whitespace only', () => {
|
|
79
|
+
expect(trimQuotes(' ')).toBe('');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('No quotes', () => {
|
|
83
|
+
it('should return original string when no quotes present', () => {
|
|
84
|
+
expect(trimQuotes('hello')).toBe('hello');
|
|
85
|
+
});
|
|
86
|
+
it('should trim spaces when no quotes present', () => {
|
|
87
|
+
expect(trimQuotes(' hello ')).toBe('hello');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/editor",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.7",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"ufo": "^1.5.4",
|
|
74
74
|
"url-join": "^4.0.1",
|
|
75
75
|
"zustand": "^4.5.5",
|
|
76
|
-
"@blocklet/pdf": "2.5.
|
|
76
|
+
"@blocklet/pdf": "2.5.7"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@babel/core": "^7.25.2",
|