@aleph-alpha/chat-kit 6.1.1 → 6.3.0
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/dist/{CkHistory.vue_vue_type_script_setup_true_lang-Cr8vF94e.js → CkHistory.vue_vue_type_script_setup_true_lang-gV-lp0ZB.js} +345 -164
- package/dist/adapters/responses-api.js +1 -1
- package/dist/chat-kit.css +111 -28
- package/dist/code-palette-DAJUTnR-.js +21598 -0
- package/dist/components/base/CkCodeEditor/CkCodeEditor.stories.d.ts +43 -0
- package/dist/components/base/CkCodeEditor/CkCodeEditor.stories.d.ts.map +1 -0
- package/dist/components/base/CkCodeEditor/CkCodeEditor.vue.d.ts +39 -0
- package/dist/components/base/CkCodeEditor/CkCodeEditor.vue.d.ts.map +1 -0
- package/dist/components/base/CkCodeEditor/createCodeMirror.d.ts +44 -0
- package/dist/components/base/CkCodeEditor/createCodeMirror.d.ts.map +1 -0
- package/dist/components/base/CkCodeEditor/index.d.ts +3 -0
- package/dist/components/base/CkCodeEditor/index.d.ts.map +1 -0
- package/dist/components/base/CkCodeEditor/types.d.ts +129 -0
- package/dist/components/base/CkCodeEditor/types.d.ts.map +1 -0
- package/dist/components/base/CkMilkdownEditor/CkMilkdownEditor.stories.d.ts +6 -0
- package/dist/components/base/CkMilkdownEditor/CkMilkdownEditor.stories.d.ts.map +1 -1
- package/dist/components/base/CkMilkdownEditor/CkMilkdownEditor.vue.d.ts +1 -0
- package/dist/components/base/CkMilkdownEditor/CkMilkdownEditor.vue.d.ts.map +1 -1
- package/dist/components/base/CkMilkdownEditor/createCrepeEditor.d.ts +1 -0
- package/dist/components/base/CkMilkdownEditor/createCrepeEditor.d.ts.map +1 -1
- package/dist/components/base/CkMilkdownEditor/types.d.ts +8 -0
- package/dist/components/base/CkMilkdownEditor/types.d.ts.map +1 -1
- package/dist/components/base/index.d.ts +2 -0
- package/dist/components/base/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +27 -26
- package/dist/composables/index.js +1 -1
- package/dist/createCodeMirror-BkV6FEPn.js +101 -0
- package/dist/{createCrepeEditor-CFbvSH3s.js → createCrepeEditor-Ci5FHHIV.js} +1434 -24739
- package/dist/handlers/index.js +2 -2
- package/dist/handlers/useChatKitLabels.d.ts +6 -0
- package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
- package/dist/{components/base/CkMilkdownEditor/codeMirrorTheme.d.ts → helpers/codemirror/theme.d.ts} +1 -1
- package/dist/helpers/codemirror/theme.d.ts.map +1 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.d.ts.map +1 -1
- package/dist/helpers/markdownToPlainText.d.ts +18 -0
- package/dist/helpers/markdownToPlainText.d.ts.map +1 -0
- package/dist/{index-BWvkps_G.js → index-B2tew8uf.js} +3 -3
- package/dist/{index-DhY_9bdS.js → index-BLVAx_f8.js} +2 -2
- package/dist/{index-B0ldhzaj.js → index-BUCqcTPA.js} +2 -2
- package/dist/{index-DdlzabmR.js → index-BhvbqYsK.js} +2 -2
- package/dist/{index-gzleljO6.js → index-BoUJGvvQ.js} +2 -2
- package/dist/{index-sKO1lHHC.js → index-BtY1uxn6.js} +3 -2
- package/dist/{index-BVOjyn3y.js → index-BvG6l44n.js} +3 -2
- package/dist/{index-BoqzHVNB.js → index-CB6xZVsf.js} +2 -2
- package/dist/{index-BaS8OW8V.js → index-CIF93PZF.js} +3 -3
- package/dist/index-CLdXUpL8.js +9560 -0
- package/dist/{index-DSq3gvqU.js → index-CN8d3yl1.js} +1 -1
- package/dist/{index-CRfGWVdQ.js → index-CYk7AB8M.js} +4 -4
- package/dist/{index-C72e57-5.js → index-CZFx44C7.js} +2 -2
- package/dist/{index-Tj3pzx-E.js → index-Cxs6kPho.js} +3 -3
- package/dist/index-D6ftdiLa.js +1825 -0
- package/dist/{index-CMJGuXap.js → index-DgCcFC3N.js} +3 -3
- package/dist/{index-DSU7cBGz.js → index-DhwsowEf.js} +2 -2
- package/dist/{index-C_gTb50u.js → index-Dl24CCB3.js} +4 -4
- package/dist/{index-BlHHEbV-.js → index-DqGDenO9.js} +2 -2
- package/dist/{index-naWlQpaL.js → index-DufAP1JF.js} +3 -2
- package/dist/{index-Dm6C1blN.js → index-DxTzaHLr.js} +4 -4
- package/dist/{index-A5rWjRtZ.js → index-MfXW4ZyN.js} +3 -2
- package/dist/{index-C6zYjwIQ.js → index-ZHg2R9iD.js} +3 -2
- package/dist/{index-ZeRS5rER.js → index-gYt3E3Cp.js} +2 -2
- package/dist/{index-Da3777l2.js → index-w2yzH7vs.js} +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -30
- package/dist/markdownToPlainText-BOtlQ_BY.js +34 -0
- package/dist/{useChatKitLabels-Ww1Q7xUr.js → useChatKitLabels-CatQSpfL.js} +881 -10428
- package/dist/{useMessageHandler-Tellov3w.js → useMessageHandler-nnsort0-.js} +1 -1
- package/package.json +5 -3
- package/src/components/base/CkCodeEditor/CkCodeEditor.spec.ts +223 -0
- package/src/components/base/CkCodeEditor/CkCodeEditor.stories.ts +311 -0
- package/src/components/base/CkCodeEditor/CkCodeEditor.vue +238 -0
- package/src/components/base/CkCodeEditor/createCodeMirror.ts +188 -0
- package/src/components/base/CkCodeEditor/index.ts +2 -0
- package/src/components/base/CkCodeEditor/types.ts +128 -0
- package/src/components/base/CkMilkdownEditor/CkMilkdownEditor.spec.ts +13 -0
- package/src/components/base/CkMilkdownEditor/CkMilkdownEditor.stories.ts +34 -0
- package/src/components/base/CkMilkdownEditor/CkMilkdownEditor.vue +3 -1
- package/src/components/base/CkMilkdownEditor/createCrepeEditor.ts +2 -1
- package/src/components/base/CkMilkdownEditor/milkdown-theme.css +39 -26
- package/src/components/base/CkMilkdownEditor/types.ts +8 -0
- package/src/components/base/index.ts +6 -0
- package/src/components/index.ts +4 -0
- package/src/handlers/useChatKitLabels.ts +6 -0
- package/src/helpers/codemirror/code-palette.css +49 -0
- package/src/{components/base/CkMilkdownEditor/codeMirrorTheme.ts → helpers/codemirror/theme.ts} +23 -12
- package/src/helpers/index.ts +1 -0
- package/src/helpers/markdownToPlainText.spec.ts +107 -0
- package/src/helpers/markdownToPlainText.ts +69 -0
- package/src/index.ts +5 -1
- package/dist/components/base/CkMilkdownEditor/codeMirrorTheme.d.ts.map +0 -1
- package/dist/generateId-BHf0W4Rq.js +0 -6
|
@@ -49,36 +49,12 @@
|
|
|
49
49
|
--crepe-shadow-1: var(--shadow-md);
|
|
50
50
|
--crepe-shadow-2: var(--shadow-lg);
|
|
51
51
|
|
|
52
|
-
/*
|
|
53
|
-
|
|
54
|
-
--ck-cm-foreground: #24292f;
|
|
55
|
-
--ck-cm-keyword: #cf222e;
|
|
56
|
-
--ck-cm-string: #0a3069;
|
|
57
|
-
--ck-cm-comment: #6e7781;
|
|
58
|
-
--ck-cm-function: #8250df;
|
|
59
|
-
--ck-cm-constant: #0550ae;
|
|
60
|
-
/* UiCodeBlock rewrites Shiki's orange entity colour to the primary text token. */
|
|
61
|
-
--ck-cm-entity: oklch(var(--content-on-surface-primary));
|
|
62
|
-
--ck-cm-tag: #116329;
|
|
63
|
-
--ck-cm-error: #82071e;
|
|
64
|
-
--ck-cm-selection: oklch(var(--background-accent-soft));
|
|
52
|
+
/* The `--ck-cm-*` syntax palette comes from the shared `code-palette.css`
|
|
53
|
+
* via the `ck-code-surface` class on this same root. */
|
|
65
54
|
|
|
66
55
|
position: relative;
|
|
67
56
|
}
|
|
68
57
|
|
|
69
|
-
/* CodeMirror palette ≈ Shiki `github-dark`. */
|
|
70
|
-
html.dark .ck-milkdown {
|
|
71
|
-
--ck-cm-bg: #24292e;
|
|
72
|
-
--ck-cm-foreground: #c9d1d9;
|
|
73
|
-
--ck-cm-keyword: #ff7b72;
|
|
74
|
-
--ck-cm-string: #a5d6ff;
|
|
75
|
-
--ck-cm-comment: #8b949e;
|
|
76
|
-
--ck-cm-function: #d2a8ff;
|
|
77
|
-
--ck-cm-constant: #79c0ff;
|
|
78
|
-
--ck-cm-tag: #7ee787;
|
|
79
|
-
--ck-cm-error: #ffa198;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
58
|
/* ------------------------------------------------------------------------ */
|
|
83
59
|
/* Minimal reset (replaces Crepe's reset.css) */
|
|
84
60
|
/* ------------------------------------------------------------------------ */
|
|
@@ -407,10 +383,47 @@ html.dark .ck-milkdown {
|
|
|
407
383
|
color: var(--ck-cm-foreground);
|
|
408
384
|
}
|
|
409
385
|
|
|
386
|
+
/* Line-number gutter. CodeMirror's `basicSetup` (which Crepe always loads)
|
|
387
|
+
* always renders it, so `showLineNumbers` only toggles this class — no
|
|
388
|
+
* reconfiguration, and the change applies to code blocks already on screen.
|
|
389
|
+
* Hidden by default to match `UiCodeBlock`, whose `showLineNumbers` is also
|
|
390
|
+
* false by default, so a document reads the same in the editor and in
|
|
391
|
+
* `CkMarkdownRenderer`. */
|
|
410
392
|
.ck-milkdown .milkdown .milkdown-code-block .cm-gutters {
|
|
411
393
|
display: none;
|
|
412
394
|
}
|
|
413
395
|
|
|
396
|
+
.ck-milkdown--line-numbers .milkdown .milkdown-code-block .cm-gutters {
|
|
397
|
+
display: flex;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* `basicSetup` also installs a code-folding gutter. Its chevrons are noise in
|
|
401
|
+
* a prose editor and have no counterpart in `UiCodeBlock`, so only the numbers
|
|
402
|
+
* are ever shown. `!important` is required because CodeMirror's own base theme
|
|
403
|
+
* declares `.cm-gutter { display: flex !important }`, which no amount of
|
|
404
|
+
* specificity can outrank. Crepe always passes `basicSetup`, so the extension
|
|
405
|
+
* cannot simply be left out. */
|
|
406
|
+
.ck-milkdown .milkdown .milkdown-code-block .cm-foldGutter {
|
|
407
|
+
display: none !important;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.ck-milkdown--line-numbers
|
|
411
|
+
.milkdown
|
|
412
|
+
.milkdown-code-block
|
|
413
|
+
.cm-lineNumbers
|
|
414
|
+
.cm-gutterElement {
|
|
415
|
+
min-width: 2.25rem;
|
|
416
|
+
padding: 0 0.75rem 0 1rem;
|
|
417
|
+
color: oklch(var(--content-on-surface-muted));
|
|
418
|
+
text-align: right;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* The gutter supplies the left inset once it is visible, so the code itself
|
|
422
|
+
* should not pay for it twice. */
|
|
423
|
+
.ck-milkdown--line-numbers .milkdown .milkdown-code-block .cm-content {
|
|
424
|
+
padding-left: 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
414
427
|
/* Shown while the CodeMirror instance is still mounting. */
|
|
415
428
|
.ck-milkdown .milkdown .milkdown-code-block .milkdown-code-block-placeholder {
|
|
416
429
|
margin: 0;
|
|
@@ -71,6 +71,14 @@ export interface CkMilkdownEditorProps {
|
|
|
71
71
|
* @default false
|
|
72
72
|
*/
|
|
73
73
|
autofocus?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Show a line-number gutter on fenced code blocks. Matches the prop of the
|
|
76
|
+
* same name on `UiCodeBlock`, so one flag can drive the editor and the
|
|
77
|
+
* rendered message alike. Applies to code blocks already on screen.
|
|
78
|
+
*
|
|
79
|
+
* @default false
|
|
80
|
+
*/
|
|
81
|
+
showLineNumbers?: boolean;
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
/** Events emitted by {@link CkMilkdownEditor}. */
|
|
@@ -86,3 +86,9 @@ export type {
|
|
|
86
86
|
CkMilkdownEditorExposed,
|
|
87
87
|
CkMilkdownEditorProps,
|
|
88
88
|
} from './CkMilkdownEditor';
|
|
89
|
+
export { CkCodeEditor } from './CkCodeEditor';
|
|
90
|
+
export type {
|
|
91
|
+
CkCodeEditorEmits,
|
|
92
|
+
CkCodeEditorExposed,
|
|
93
|
+
CkCodeEditorProps,
|
|
94
|
+
} from './CkCodeEditor';
|
package/src/components/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ export {
|
|
|
28
28
|
CkUserMessage,
|
|
29
29
|
CkEditableUserMessage,
|
|
30
30
|
CkMilkdownEditor,
|
|
31
|
+
CkCodeEditor,
|
|
31
32
|
} from './base';
|
|
32
33
|
export type {
|
|
33
34
|
CkAgentMessageHeaderProps,
|
|
@@ -70,6 +71,9 @@ export type {
|
|
|
70
71
|
CkMilkdownEditorEmits,
|
|
71
72
|
CkMilkdownEditorExposed,
|
|
72
73
|
CkMilkdownEditorProps,
|
|
74
|
+
CkCodeEditorEmits,
|
|
75
|
+
CkCodeEditorExposed,
|
|
76
|
+
CkCodeEditorProps,
|
|
73
77
|
} from './base';
|
|
74
78
|
|
|
75
79
|
// Composed (pattern) components
|
|
@@ -111,6 +111,10 @@ export type ChatKitLabels = {
|
|
|
111
111
|
* set and more conversations exist than the limit.
|
|
112
112
|
*/
|
|
113
113
|
historyShowAll?: string;
|
|
114
|
+
/** Accessible name of the copy button in the `CkCodeEditor` header. */
|
|
115
|
+
codeEditorCopy?: string;
|
|
116
|
+
/** Accessible name of the `CkCodeEditor` copy button just after a copy. */
|
|
117
|
+
codeEditorCopied?: string;
|
|
114
118
|
/** Accessible name of the "Bold" button in the `CkMilkdownEditor` toolbar. */
|
|
115
119
|
markdownEditorBold?: string;
|
|
116
120
|
/** Accessible name of the "Italic" button in the `CkMilkdownEditor` toolbar. */
|
|
@@ -168,6 +172,8 @@ export const defaultChatKitLabels = {
|
|
|
168
172
|
historyItemEditAction: 'Edit',
|
|
169
173
|
historyItemDeleteAction: 'Delete',
|
|
170
174
|
historyShowAll: 'Show all',
|
|
175
|
+
codeEditorCopy: 'Copy code',
|
|
176
|
+
codeEditorCopied: 'Copied',
|
|
171
177
|
markdownEditorBold: 'Bold',
|
|
172
178
|
markdownEditorItalic: 'Italic',
|
|
173
179
|
markdownEditorStrikethrough: 'Strikethrough',
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Syntax palette shared by every CodeMirror surface in chat-kit — the code
|
|
3
|
+
* blocks inside `CkMilkdownEditor` and the standalone `CkCodeEditor`.
|
|
4
|
+
*
|
|
5
|
+
* The values are Shiki's `github-light` and `github-dark`, which is what
|
|
6
|
+
* `UiCodeBlock` renders inside `CkMarkdownRenderer`, read off a rendered block
|
|
7
|
+
* rather than copied from memory. A snippet therefore keeps its colours whether
|
|
8
|
+
* it is being read or edited. `theme.ts` maps CodeMirror's syntax tags onto
|
|
9
|
+
* these variables; nothing else should hardcode a code colour.
|
|
10
|
+
*
|
|
11
|
+
* Apply `.ck-code-surface` to the root of any component hosting a CodeMirror
|
|
12
|
+
* instance. The dark values follow `html.dark`, matching how `UiCodeBlock`
|
|
13
|
+
* switches its own Shiki theme.
|
|
14
|
+
*
|
|
15
|
+
* Exact parity is not achievable for every token: Shiki classifies with
|
|
16
|
+
* TextMate grammars and CodeMirror with Lezer, and the two disagree at the
|
|
17
|
+
* edges. The mapping in `theme.ts` targets the classes that actually occur in
|
|
18
|
+
* everyday code.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
.ck-code-surface {
|
|
22
|
+
--ck-cm-bg: #ffffff;
|
|
23
|
+
--ck-cm-foreground: #24292e;
|
|
24
|
+
--ck-cm-keyword: #d73a49;
|
|
25
|
+
--ck-cm-string: #032f62;
|
|
26
|
+
--ck-cm-comment: #6a737d;
|
|
27
|
+
/* Declared functions, classes and interfaces. */
|
|
28
|
+
--ck-cm-function: #6f42c1;
|
|
29
|
+
/* Built-in types, literals and plain variables. */
|
|
30
|
+
--ck-cm-constant: #005cc5;
|
|
31
|
+
/* `UiCodeBlock` rewrites Shiki's orange (#e36209 / #ffab70) to the primary
|
|
32
|
+
* text token, which is what declared property names end up as. */
|
|
33
|
+
--ck-cm-property: oklch(var(--content-on-surface-primary));
|
|
34
|
+
--ck-cm-tag: #22863a;
|
|
35
|
+
--ck-cm-error: #b31d28;
|
|
36
|
+
--ck-cm-selection: oklch(var(--background-accent-soft));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
html.dark .ck-code-surface {
|
|
40
|
+
--ck-cm-bg: #24292e;
|
|
41
|
+
--ck-cm-foreground: #e1e4e8;
|
|
42
|
+
--ck-cm-keyword: #f97583;
|
|
43
|
+
--ck-cm-string: #9ecbff;
|
|
44
|
+
--ck-cm-comment: #6a737d;
|
|
45
|
+
--ck-cm-function: #b392f0;
|
|
46
|
+
--ck-cm-constant: #79b8ff;
|
|
47
|
+
--ck-cm-tag: #85e89d;
|
|
48
|
+
--ck-cm-error: #fdaeb7;
|
|
49
|
+
}
|
package/src/{components/base/CkMilkdownEditor/codeMirrorTheme.ts → helpers/codemirror/theme.ts}
RENAMED
|
@@ -21,6 +21,7 @@ const cssVar = (name: string): string => `var(--ck-cm-${name})`;
|
|
|
21
21
|
* editor and in `CkMarkdownRenderer`.
|
|
22
22
|
*/
|
|
23
23
|
export const ckHighlightStyle = HighlightStyle.define([
|
|
24
|
+
// Keywords, and the operators GitHub colours like keywords (`=`, `:`).
|
|
24
25
|
{
|
|
25
26
|
tag: [
|
|
26
27
|
t.keyword,
|
|
@@ -29,6 +30,7 @@ export const ckHighlightStyle = HighlightStyle.define([
|
|
|
29
30
|
t.definitionKeyword,
|
|
30
31
|
t.moduleKeyword,
|
|
31
32
|
t.operatorKeyword,
|
|
33
|
+
t.operator,
|
|
32
34
|
],
|
|
33
35
|
color: cssVar('keyword'),
|
|
34
36
|
},
|
|
@@ -40,14 +42,20 @@ export const ckHighlightStyle = HighlightStyle.define([
|
|
|
40
42
|
tag: [t.comment, t.lineComment, t.blockComment, t.docComment],
|
|
41
43
|
color: cssVar('comment'),
|
|
42
44
|
},
|
|
45
|
+
// Things being declared: functions, classes, interfaces.
|
|
43
46
|
{
|
|
44
47
|
tag: [
|
|
45
48
|
t.function(t.variableName),
|
|
46
49
|
t.function(t.propertyName),
|
|
47
50
|
t.definition(t.function(t.variableName)),
|
|
51
|
+
t.definition(t.typeName),
|
|
52
|
+
t.className,
|
|
53
|
+
t.namespace,
|
|
54
|
+
t.self,
|
|
48
55
|
],
|
|
49
56
|
color: cssVar('function'),
|
|
50
57
|
},
|
|
58
|
+
// Built-in types, literals and ordinary variables.
|
|
51
59
|
{
|
|
52
60
|
tag: [
|
|
53
61
|
t.number,
|
|
@@ -56,25 +64,20 @@ export const ckHighlightStyle = HighlightStyle.define([
|
|
|
56
64
|
t.atom,
|
|
57
65
|
t.constant(t.name),
|
|
58
66
|
t.constant(t.variableName),
|
|
67
|
+
t.definition(t.variableName),
|
|
68
|
+
t.typeName,
|
|
69
|
+
t.standard(t.typeName),
|
|
59
70
|
t.propertyName,
|
|
60
71
|
t.attributeName,
|
|
61
72
|
t.attributeValue,
|
|
62
73
|
],
|
|
63
74
|
color: cssVar('constant'),
|
|
64
75
|
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
t.typeName,
|
|
68
|
-
t.className,
|
|
69
|
-
t.namespace,
|
|
70
|
-
t.definition(t.variableName),
|
|
71
|
-
t.self,
|
|
72
|
-
],
|
|
73
|
-
color: cssVar('entity'),
|
|
74
|
-
},
|
|
76
|
+
// A declared property name, which UiCodeBlock renders in the text token.
|
|
77
|
+
{ tag: t.definition(t.propertyName), color: cssVar('property') },
|
|
75
78
|
{ tag: [t.tagName, t.angleBracket], color: cssVar('tag') },
|
|
76
79
|
{
|
|
77
|
-
tag: [t.variableName, t.
|
|
80
|
+
tag: [t.variableName, t.punctuation, t.bracket, t.separator],
|
|
78
81
|
color: cssVar('foreground'),
|
|
79
82
|
},
|
|
80
83
|
{ tag: t.heading, fontWeight: 'bold' },
|
|
@@ -107,8 +110,16 @@ export const ckCodeMirrorTheme: Extension = [
|
|
|
107
110
|
'.cm-line': {
|
|
108
111
|
padding: '0',
|
|
109
112
|
},
|
|
113
|
+
// Gutter visibility is driven by the `showLineNumbers` prop through a root
|
|
114
|
+
// class in `milkdown-theme.css`, not from here, so it can toggle without
|
|
115
|
+
// reconfiguring CodeMirror. Only the chrome is set here.
|
|
110
116
|
'.cm-gutters': {
|
|
111
|
-
|
|
117
|
+
backgroundColor: 'transparent',
|
|
118
|
+
borderRight: 'none',
|
|
119
|
+
color: cssVar('comment'),
|
|
120
|
+
},
|
|
121
|
+
'.cm-activeLineGutter': {
|
|
122
|
+
backgroundColor: 'transparent',
|
|
112
123
|
},
|
|
113
124
|
'.cm-cursor, .cm-dropCursor': {
|
|
114
125
|
borderLeftColor: cssVar('foreground'),
|
package/src/helpers/index.ts
CHANGED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { markdownToPlainText } from './markdownToPlainText';
|
|
4
|
+
|
|
5
|
+
describe('markdownToPlainText', () => {
|
|
6
|
+
it('returns text without markdown unchanged', () => {
|
|
7
|
+
expect(markdownToPlainText('A plain excerpt from a page.')).toBe(
|
|
8
|
+
'A plain excerpt from a page.',
|
|
9
|
+
);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('keeps a link label and drops its url', () => {
|
|
13
|
+
expect(
|
|
14
|
+
markdownToPlainText(
|
|
15
|
+
'See the [annual report](https://example.com/r.pdf).',
|
|
16
|
+
),
|
|
17
|
+
).toBe('See the annual report.');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('strips emphasis markers', () => {
|
|
21
|
+
expect(markdownToPlainText('Revenue **rose** by _12%_ and ~~fell~~.')).toBe(
|
|
22
|
+
'Revenue rose by 12% and fell.',
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('separates a heading from the paragraph that follows it', () => {
|
|
27
|
+
expect(markdownToPlainText('## Cost\n\n12 EUR per seat.')).toBe(
|
|
28
|
+
'Cost 12 EUR per seat.',
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('flattens a GFM table without its pipes', () => {
|
|
33
|
+
const table = ['| Plan | Cost |', '| --- | --- |', '| Pro | 12 |'].join(
|
|
34
|
+
'\n',
|
|
35
|
+
);
|
|
36
|
+
expect(markdownToPlainText(table)).toBe('Plan Cost Pro 12');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('separates list items', () => {
|
|
40
|
+
expect(markdownToPlainText('- first\n- second\n- third')).toBe(
|
|
41
|
+
'first second third',
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('keeps code content but not its fence', () => {
|
|
46
|
+
expect(markdownToPlainText('Run `pnpm build` first.')).toBe(
|
|
47
|
+
'Run pnpm build first.',
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('drops an image rather than reading its alt text as prose', () => {
|
|
52
|
+
expect(markdownToPlainText(' Revenue rose.')).toBe(
|
|
53
|
+
'Revenue rose.',
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('removes inline html tags without joining the words around them', () => {
|
|
58
|
+
expect(markdownToPlainText('Revenue rose.<br>Costs fell.')).toBe(
|
|
59
|
+
'Revenue rose. Costs fell.',
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('keeps the prose inside a raw html block', () => {
|
|
64
|
+
expect(
|
|
65
|
+
markdownToPlainText('<div class="x">Revenue rose.</div>\nCosts fell.'),
|
|
66
|
+
).toBe('Revenue rose. Costs fell.');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('keeps a hard line break as a word separator', () => {
|
|
70
|
+
expect(markdownToPlainText('Revenue rose. \nCosts fell.')).toBe(
|
|
71
|
+
'Revenue rose. Costs fell.',
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('leaves a literal comparison inside a raw html block alone', () => {
|
|
76
|
+
expect(markdownToPlainText('<div>2 < 3 and 4 > 1</div>')).toBe(
|
|
77
|
+
'2 < 3 and 4 > 1',
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('removes an html comment', () => {
|
|
82
|
+
expect(markdownToPlainText('<div>Hi</div>\n<!-- hidden -->\nText.')).toBe(
|
|
83
|
+
'Hi Text.',
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('collapses the newlines a multi-paragraph excerpt carries', () => {
|
|
88
|
+
expect(markdownToPlainText('First line.\n\n\nSecond line.')).toBe(
|
|
89
|
+
'First line. Second line.',
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('leaves an unbalanced emphasis marker as literal text', () => {
|
|
94
|
+
expect(markdownToPlainText('Revenue **rose sharply in')).toBe(
|
|
95
|
+
'Revenue **rose sharply in',
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('is idempotent', () => {
|
|
100
|
+
const once = markdownToPlainText('A [linked](https://example.com) claim.');
|
|
101
|
+
expect(markdownToPlainText(once)).toBe(once);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('returns an empty string for empty input', () => {
|
|
105
|
+
expect(markdownToPlainText('')).toBe('');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { unified } from 'unified';
|
|
2
|
+
import remarkParse from 'remark-parse';
|
|
3
|
+
import remarkGfm from 'remark-gfm';
|
|
4
|
+
import type { Nodes } from 'mdast';
|
|
5
|
+
|
|
6
|
+
const parser = unified().use(remarkParse).use(remarkGfm);
|
|
7
|
+
|
|
8
|
+
const DROPPED_NODES = new Set(['image', 'imageReference']);
|
|
9
|
+
|
|
10
|
+
// A hard line break is a childless, valueless leaf, so it has to yield its
|
|
11
|
+
// separator explicitly or `first<br>second` flattens to `firstsecond`.
|
|
12
|
+
const SEPARATOR_NODES = new Set(['break']);
|
|
13
|
+
|
|
14
|
+
// An `html` node cannot be dropped whole: a line starting with a block tag
|
|
15
|
+
// makes markdown's HTML-block rule run to the next blank line, so the node
|
|
16
|
+
// holds the following prose too. Its tags are stripped instead, replaced by a
|
|
17
|
+
// space so `rose.<br>Costs` doesn't come out as one word. A tag has to start
|
|
18
|
+
// like one (`<p`, `</p`, `<!--`) so a literal comparison inside the block —
|
|
19
|
+
// `2 < 3 and 4 > 1` — isn't mistaken for one and deleted. The repetition is
|
|
20
|
+
// bounded because an unbounded `[^>]*` scans quadratically over a run of `<`
|
|
21
|
+
// with no closing `>` (`sonarjs/slow-regex`).
|
|
22
|
+
const HTML_TAG_RE = /<[!/]?[a-zA-Z-][^>]{0,512}>/g;
|
|
23
|
+
|
|
24
|
+
// Children of these need a separator, or a heading runs straight into the
|
|
25
|
+
// paragraph below it (`## Cost` + `12 EUR` → `Cost12 EUR`).
|
|
26
|
+
const BLOCK_CONTAINERS = new Set([
|
|
27
|
+
'root',
|
|
28
|
+
'blockquote',
|
|
29
|
+
'list',
|
|
30
|
+
'listItem',
|
|
31
|
+
'table',
|
|
32
|
+
'tableRow',
|
|
33
|
+
'footnoteDefinition',
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
function flatten(node: Nodes): string {
|
|
37
|
+
if (DROPPED_NODES.has(node.type)) return '';
|
|
38
|
+
if (SEPARATOR_NODES.has(node.type)) return ' ';
|
|
39
|
+
if ('value' in node) {
|
|
40
|
+
return node.type === 'html'
|
|
41
|
+
? node.value.replace(HTML_TAG_RE, ' ')
|
|
42
|
+
: node.value;
|
|
43
|
+
}
|
|
44
|
+
if (!('children' in node)) return '';
|
|
45
|
+
return node.children
|
|
46
|
+
.map(flatten)
|
|
47
|
+
.join(BLOCK_CONTAINERS.has(node.type) ? ' ' : '');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Flatten markdown to the prose inside it: `[label](url)` becomes `label`,
|
|
52
|
+
* headings lose their `#`, emphasis markers and table pipes go.
|
|
53
|
+
*
|
|
54
|
+
* For excerpt text that is *displayed as plain text* — a citation snippet
|
|
55
|
+
* preview, say — where the markdown is an artefact of how the source was
|
|
56
|
+
* extracted rather than something the UI intends to render. Reads the parsed
|
|
57
|
+
* tree instead of pattern-matching the string, so it is structurally exact for
|
|
58
|
+
* well-formed markdown where a regex would guess. Idempotent on text carrying
|
|
59
|
+
* no markdown, so it is a no-op once a producer starts sending plain text.
|
|
60
|
+
*
|
|
61
|
+
* Two artefacts survive. A truncated excerpt can end mid-syntax (`**bold` with
|
|
62
|
+
* no closing pair), which the parser reads as literal text — the correct
|
|
63
|
+
* reading, at the cost of a visible `**`. And markdown inside a raw HTML block
|
|
64
|
+
* is never parsed as markdown, so it is flattened as the literal text it is.
|
|
65
|
+
*/
|
|
66
|
+
export function markdownToPlainText(markdown: string): string {
|
|
67
|
+
if (!markdown) return '';
|
|
68
|
+
return flatten(parser.parse(markdown)).replace(/\s+/g, ' ').trim();
|
|
69
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -100,6 +100,7 @@ export {
|
|
|
100
100
|
CkUserMessage,
|
|
101
101
|
CkEditableUserMessage,
|
|
102
102
|
CkMilkdownEditor,
|
|
103
|
+
CkCodeEditor,
|
|
103
104
|
} from './components';
|
|
104
105
|
export type {
|
|
105
106
|
CkAgentMessageHeaderProps,
|
|
@@ -145,10 +146,13 @@ export type {
|
|
|
145
146
|
CkMilkdownEditorEmits,
|
|
146
147
|
CkMilkdownEditorExposed,
|
|
147
148
|
CkMilkdownEditorProps,
|
|
149
|
+
CkCodeEditorEmits,
|
|
150
|
+
CkCodeEditorExposed,
|
|
151
|
+
CkCodeEditorProps,
|
|
148
152
|
} from './components';
|
|
149
153
|
|
|
150
154
|
// Helpers
|
|
151
|
-
export { formatRelativeTime } from './helpers';
|
|
155
|
+
export { formatRelativeTime, markdownToPlainText } from './helpers';
|
|
152
156
|
|
|
153
157
|
// Shared Types
|
|
154
158
|
export type {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codeMirrorTheme.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkMilkdownEditor/codeMirrorTheme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAsB,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,2FAC6D,CAAC;AAO3F;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,gBA8D3B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAwC/B,CAAC"}
|