@kungal/editor-core 0.36.0 → 0.38.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/CHANGELOG.md +47 -0
- package/dist/preset/index.cjs +21 -8
- package/dist/preset/index.cjs.map +1 -1
- package/dist/preset/index.d.cts +31 -8
- package/dist/preset/index.d.ts +31 -8
- package/dist/preset/index.js +21 -8
- package/dist/preset/index.js.map +1 -1
- package/package.json +1 -1
package/dist/preset/index.d.cts
CHANGED
|
@@ -7,8 +7,27 @@ import { Uploader } from '@milkdown/kit/plugin/upload';
|
|
|
7
7
|
import { Decoration, EditorView } from '@milkdown/kit/prose/view';
|
|
8
8
|
import { HighlightStyle } from '@codemirror/language';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
10
|
+
/**
|
|
11
|
+
* DOM attrs for the spoiler chip AS SEEN WHILE EDITING — a tinted chip, so you
|
|
12
|
+
* can tell hidden text from ordinary text while you write it. (The published
|
|
13
|
+
* page renders `||…||` itself; this styling never leaves the editor.)
|
|
14
|
+
*
|
|
15
|
+
* Self-sufficient on purpose: it used to be `background: var(--color-default-500)`
|
|
16
|
+
* with no fallback, so in any host that does not define that palette token — the
|
|
17
|
+
* headless editor being exactly such a host — the whole declaration was invalid
|
|
18
|
+
* and the chip computed to `rgba(0, 0, 0, 0)`. Hidden text looked like plain text.
|
|
19
|
+
*
|
|
20
|
+
* `--kun-spoiler-bg` is the theming hook: an INLINE style beats every selector a
|
|
21
|
+
* host stylesheet can write, so without a custom property the chip would be
|
|
22
|
+
* untouchable from CSS. Setting the property is not (a rule may set it on
|
|
23
|
+
* `.kun-spoiler` freely) — which is how @kungal/editor-nuxt paints it in KunUI
|
|
24
|
+
* colors, and how any host re-tints it in one line.
|
|
25
|
+
*
|
|
26
|
+
* The default is `currentColor`-derived rather than a fixed grey so it works on a
|
|
27
|
+
* light and a dark background alike; the plain rgba before it is what a browser
|
|
28
|
+
* without `color-mix()` keeps (an unknown function is dropped at parse time, so
|
|
29
|
+
* the earlier declaration survives — unlike a bad `var()`, which kills both).
|
|
30
|
+
*/
|
|
12
31
|
declare const spoilerAttr: _milkdown_kit_utils.$NodeAttr;
|
|
13
32
|
/** The `kun-spoiler` inline node: parses/serializes `||text||` and renders a
|
|
14
33
|
* `<span data-type="kun-spoiler">` the render layer toggles on click. */
|
|
@@ -21,7 +40,9 @@ declare const spoilerSchema: _milkdown_kit_utils.$NodeSchema<"kun-spoiler">;
|
|
|
21
40
|
* - a selection → its TEXT moves INSIDE the node. It has to be moved, not
|
|
22
41
|
* replaced: `replaceSelectionWith` on its own deletes what you selected. The
|
|
23
42
|
* schema is `marks: ''` (bold inside `||…||` cannot round-trip), so the
|
|
24
|
-
* formatting is what's dropped, never the words.
|
|
43
|
+
* formatting is what's dropped, never the words. Line breaks become spaces:
|
|
44
|
+
* `||…||` pairs within one line in every reader of the syntax, so a spoiler
|
|
45
|
+
* spanning lines would serialize to markdown that reads back as literal `||`.
|
|
25
46
|
* - an empty selection → an empty spoiler with the caret inside it: type, and
|
|
26
47
|
* what you type is hidden. "Empty" means holding a caret anchor — a caret
|
|
27
48
|
* cannot sit in an inline node with no text node in it — and a spoiler with
|
|
@@ -32,10 +53,11 @@ declare const spoilerSchema: _milkdown_kit_utils.$NodeSchema<"kun-spoiler">;
|
|
|
32
53
|
* all, so this button has to toggle.
|
|
33
54
|
*
|
|
34
55
|
* Returns false where there is nothing to hide or nowhere to put it — inside a
|
|
35
|
-
* code block,
|
|
36
|
-
* delete it) — so a host can grey the
|
|
37
|
-
*
|
|
38
|
-
* survive the move:
|
|
56
|
+
* code block, with a NODE selected, or over a selection holding no words at all
|
|
57
|
+
* (an image is not text; replacing it would delete it) — so a host can grey the
|
|
58
|
+
* button out. A spoiler holds text, so any other inline node caught in a text
|
|
59
|
+
* selection alongside words (an image, inline math) does not survive the move:
|
|
60
|
+
* `||…||` cannot carry one.
|
|
39
61
|
*/
|
|
40
62
|
declare const insertKunSpoilerCommand: _milkdown_kit_utils.$Command<unknown>;
|
|
41
63
|
/** Typing `||text||` in the editor turns it into a spoiler node in place. The
|
|
@@ -46,7 +68,8 @@ declare const insertSpoilerInputRule: _milkdown_kit_utils.$InputRule;
|
|
|
46
68
|
declare const remarkSpoilerPlugin: _milkdown_kit_utils.$Remark<"remarkSpoiler", unknown>;
|
|
47
69
|
/**
|
|
48
70
|
* The spoiler plugin bundle: schema attrs, node schema, the `||…||` input rule,
|
|
49
|
-
* the insert command
|
|
71
|
+
* the insert command, the remark round-trip and the serializer guard that keeps
|
|
72
|
+
* caret anchors out of the markdown. Pure — no adapter needed.
|
|
50
73
|
*/
|
|
51
74
|
declare const createSpoilerPlugin: () => MilkdownPlugin[];
|
|
52
75
|
|
package/dist/preset/index.d.ts
CHANGED
|
@@ -7,8 +7,27 @@ import { Uploader } from '@milkdown/kit/plugin/upload';
|
|
|
7
7
|
import { Decoration, EditorView } from '@milkdown/kit/prose/view';
|
|
8
8
|
import { HighlightStyle } from '@codemirror/language';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
10
|
+
/**
|
|
11
|
+
* DOM attrs for the spoiler chip AS SEEN WHILE EDITING — a tinted chip, so you
|
|
12
|
+
* can tell hidden text from ordinary text while you write it. (The published
|
|
13
|
+
* page renders `||…||` itself; this styling never leaves the editor.)
|
|
14
|
+
*
|
|
15
|
+
* Self-sufficient on purpose: it used to be `background: var(--color-default-500)`
|
|
16
|
+
* with no fallback, so in any host that does not define that palette token — the
|
|
17
|
+
* headless editor being exactly such a host — the whole declaration was invalid
|
|
18
|
+
* and the chip computed to `rgba(0, 0, 0, 0)`. Hidden text looked like plain text.
|
|
19
|
+
*
|
|
20
|
+
* `--kun-spoiler-bg` is the theming hook: an INLINE style beats every selector a
|
|
21
|
+
* host stylesheet can write, so without a custom property the chip would be
|
|
22
|
+
* untouchable from CSS. Setting the property is not (a rule may set it on
|
|
23
|
+
* `.kun-spoiler` freely) — which is how @kungal/editor-nuxt paints it in KunUI
|
|
24
|
+
* colors, and how any host re-tints it in one line.
|
|
25
|
+
*
|
|
26
|
+
* The default is `currentColor`-derived rather than a fixed grey so it works on a
|
|
27
|
+
* light and a dark background alike; the plain rgba before it is what a browser
|
|
28
|
+
* without `color-mix()` keeps (an unknown function is dropped at parse time, so
|
|
29
|
+
* the earlier declaration survives — unlike a bad `var()`, which kills both).
|
|
30
|
+
*/
|
|
12
31
|
declare const spoilerAttr: _milkdown_kit_utils.$NodeAttr;
|
|
13
32
|
/** The `kun-spoiler` inline node: parses/serializes `||text||` and renders a
|
|
14
33
|
* `<span data-type="kun-spoiler">` the render layer toggles on click. */
|
|
@@ -21,7 +40,9 @@ declare const spoilerSchema: _milkdown_kit_utils.$NodeSchema<"kun-spoiler">;
|
|
|
21
40
|
* - a selection → its TEXT moves INSIDE the node. It has to be moved, not
|
|
22
41
|
* replaced: `replaceSelectionWith` on its own deletes what you selected. The
|
|
23
42
|
* schema is `marks: ''` (bold inside `||…||` cannot round-trip), so the
|
|
24
|
-
* formatting is what's dropped, never the words.
|
|
43
|
+
* formatting is what's dropped, never the words. Line breaks become spaces:
|
|
44
|
+
* `||…||` pairs within one line in every reader of the syntax, so a spoiler
|
|
45
|
+
* spanning lines would serialize to markdown that reads back as literal `||`.
|
|
25
46
|
* - an empty selection → an empty spoiler with the caret inside it: type, and
|
|
26
47
|
* what you type is hidden. "Empty" means holding a caret anchor — a caret
|
|
27
48
|
* cannot sit in an inline node with no text node in it — and a spoiler with
|
|
@@ -32,10 +53,11 @@ declare const spoilerSchema: _milkdown_kit_utils.$NodeSchema<"kun-spoiler">;
|
|
|
32
53
|
* all, so this button has to toggle.
|
|
33
54
|
*
|
|
34
55
|
* Returns false where there is nothing to hide or nowhere to put it — inside a
|
|
35
|
-
* code block,
|
|
36
|
-
* delete it) — so a host can grey the
|
|
37
|
-
*
|
|
38
|
-
* survive the move:
|
|
56
|
+
* code block, with a NODE selected, or over a selection holding no words at all
|
|
57
|
+
* (an image is not text; replacing it would delete it) — so a host can grey the
|
|
58
|
+
* button out. A spoiler holds text, so any other inline node caught in a text
|
|
59
|
+
* selection alongside words (an image, inline math) does not survive the move:
|
|
60
|
+
* `||…||` cannot carry one.
|
|
39
61
|
*/
|
|
40
62
|
declare const insertKunSpoilerCommand: _milkdown_kit_utils.$Command<unknown>;
|
|
41
63
|
/** Typing `||text||` in the editor turns it into a spoiler node in place. The
|
|
@@ -46,7 +68,8 @@ declare const insertSpoilerInputRule: _milkdown_kit_utils.$InputRule;
|
|
|
46
68
|
declare const remarkSpoilerPlugin: _milkdown_kit_utils.$Remark<"remarkSpoiler", unknown>;
|
|
47
69
|
/**
|
|
48
70
|
* The spoiler plugin bundle: schema attrs, node schema, the `||…||` input rule,
|
|
49
|
-
* the insert command
|
|
71
|
+
* the insert command, the remark round-trip and the serializer guard that keeps
|
|
72
|
+
* caret anchors out of the markdown. Pure — no adapter needed.
|
|
50
73
|
*/
|
|
51
74
|
declare const createSpoilerPlugin: () => MilkdownPlugin[];
|
|
52
75
|
|
package/dist/preset/index.js
CHANGED
|
@@ -6,13 +6,13 @@ import { listener } from '@milkdown/kit/plugin/listener';
|
|
|
6
6
|
import { clipboard } from '@milkdown/kit/plugin/clipboard';
|
|
7
7
|
import { indent } from '@milkdown/kit/plugin/indent';
|
|
8
8
|
import { trailing } from '@milkdown/kit/plugin/trailing';
|
|
9
|
+
import { commandsCtx, editorViewOptionsCtx, SerializerReady, serializerCtx } from '@milkdown/kit/core';
|
|
9
10
|
import { Fragment } from '@milkdown/kit/prose/model';
|
|
10
11
|
import { expectDomTypeError } from '@milkdown/kit/exception';
|
|
11
12
|
import { InputRule, textblockTypeInputRule } from '@milkdown/kit/prose/inputrules';
|
|
12
13
|
import { TextSelection, NodeSelection, PluginKey, Plugin } from '@milkdown/kit/prose/state';
|
|
13
14
|
import { $nodeAttr, $nodeSchema, $command, $inputRule, $remark, $useKeymap, $prose } from '@milkdown/kit/utils';
|
|
14
15
|
import { visit } from 'unist-util-visit';
|
|
15
|
-
import { commandsCtx, editorViewOptionsCtx } from '@milkdown/kit/core';
|
|
16
16
|
import { setBlockType } from '@milkdown/kit/prose/commands';
|
|
17
17
|
import { findNodeInSelection, nodeRule } from '@milkdown/kit/prose';
|
|
18
18
|
import katex from 'katex';
|
|
@@ -30,10 +30,17 @@ import { DecorationSet, Decoration } from '@milkdown/kit/prose/view';
|
|
|
30
30
|
var spoilerAttr = $nodeAttr("kun-spoiler", () => ({
|
|
31
31
|
container: {
|
|
32
32
|
class: "kun-spoiler",
|
|
33
|
-
style: "background: var(--color-
|
|
33
|
+
style: "background: rgba(127, 127, 127, 0.3); background: var(--kun-spoiler-bg, color-mix(in oklab, currentColor 22%, transparent)); border-radius: var(--radius-sm, 0.25rem); padding: 0 4px; cursor: pointer;"
|
|
34
34
|
}
|
|
35
35
|
}));
|
|
36
36
|
var CARET_ANCHOR = "\u200B";
|
|
37
|
+
var stripCaretAnchors = (ctx) => async () => {
|
|
38
|
+
await ctx.wait(SerializerReady);
|
|
39
|
+
ctx.update(
|
|
40
|
+
serializerCtx,
|
|
41
|
+
(serialize) => (doc) => serialize(doc).replaceAll(CARET_ANCHOR, "")
|
|
42
|
+
);
|
|
43
|
+
};
|
|
37
44
|
var withoutAnchors = (content) => {
|
|
38
45
|
const kept = [];
|
|
39
46
|
content.forEach((child) => {
|
|
@@ -144,10 +151,13 @@ var insertKunSpoilerCommand = $command(
|
|
|
144
151
|
if ($from.parent.isTextblock && !$from.parent.canReplaceWith($from.index(), $from.index(), type)) {
|
|
145
152
|
return false;
|
|
146
153
|
}
|
|
154
|
+
const text = state.doc.textBetween(from, to, " ", " ").replaceAll(CARET_ANCHOR, "");
|
|
155
|
+
if (!empty && !text.trim()) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
147
158
|
if (!dispatch) {
|
|
148
159
|
return true;
|
|
149
160
|
}
|
|
150
|
-
const text = state.doc.textBetween(from, to, " ").replaceAll(CARET_ANCHOR, "");
|
|
151
161
|
const node = type.create(null, state.schema.text(text || CARET_ANCHOR));
|
|
152
162
|
const tr = state.tr.replaceSelectionWith(node, false);
|
|
153
163
|
const after = tr.selection.to;
|
|
@@ -191,16 +201,17 @@ var remarkSpoilerPlugin = $remark("remarkSpoiler", () => () => {
|
|
|
191
201
|
if (!node.value.includes("||")) {
|
|
192
202
|
return;
|
|
193
203
|
}
|
|
204
|
+
const value = node.value.replaceAll(CARET_ANCHOR, "");
|
|
194
205
|
const regex = /\|\|(.*?)\|\|/g;
|
|
195
206
|
const newNodes = [];
|
|
196
207
|
let lastIndex = 0;
|
|
197
|
-
for (const match of
|
|
208
|
+
for (const match of value.matchAll(regex)) {
|
|
198
209
|
const [full, content] = match;
|
|
199
210
|
const matchIndex = match.index ?? 0;
|
|
200
211
|
if (matchIndex > lastIndex) {
|
|
201
212
|
newNodes.push({
|
|
202
213
|
type: "text",
|
|
203
|
-
value:
|
|
214
|
+
value: value.slice(lastIndex, matchIndex)
|
|
204
215
|
});
|
|
205
216
|
}
|
|
206
217
|
if (content) {
|
|
@@ -208,11 +219,12 @@ var remarkSpoilerPlugin = $remark("remarkSpoiler", () => () => {
|
|
|
208
219
|
type: "kun-spoiler",
|
|
209
220
|
children: [{ type: "text", value: content }]
|
|
210
221
|
});
|
|
222
|
+
newNodes.push({ type: "text", value: CARET_ANCHOR });
|
|
211
223
|
}
|
|
212
224
|
lastIndex = matchIndex + full.length;
|
|
213
225
|
}
|
|
214
|
-
if (lastIndex <
|
|
215
|
-
newNodes.push({ type: "text", value:
|
|
226
|
+
if (lastIndex < value.length) {
|
|
227
|
+
newNodes.push({ type: "text", value: value.slice(lastIndex) });
|
|
216
228
|
}
|
|
217
229
|
if (newNodes.length > 0 && typeof index === "number") {
|
|
218
230
|
parent.children?.splice(index, 1, ...newNodes);
|
|
@@ -226,7 +238,8 @@ var createSpoilerPlugin = () => [
|
|
|
226
238
|
spoilerSchema,
|
|
227
239
|
insertSpoilerInputRule,
|
|
228
240
|
insertKunSpoilerCommand,
|
|
229
|
-
remarkSpoilerPlugin
|
|
241
|
+
remarkSpoilerPlugin,
|
|
242
|
+
stripCaretAnchors
|
|
230
243
|
].flat();
|
|
231
244
|
var hasMark = (state, type) => {
|
|
232
245
|
if (!type) {
|