@kungal/editor-core 0.35.0 → 0.36.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 +34 -0
- package/dist/preset/index.cjs +77 -8
- package/dist/preset/index.cjs.map +1 -1
- package/dist/preset/index.d.cts +24 -2
- package/dist/preset/index.d.ts +24 -2
- package/dist/preset/index.js +76 -7
- package/dist/preset/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @kungal/editor-core
|
|
2
2
|
|
|
3
|
+
## 0.36.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f7c65c2: fix(editor): the spoiler toolbar button hides the selection instead of deleting it
|
|
8
|
+
|
|
9
|
+
`insertKunSpoilerCommand` built an EMPTY `kun-spoiler` node and dropped it over
|
|
10
|
+
the selection with `replaceSelectionWith`, so clicking 隐藏文本 with text selected
|
|
11
|
+
deleted the text and left a bare `||||` — and the next thing typed landed
|
|
12
|
+
outside the node, so nothing was hidden either. The JSDoc said "wraps the
|
|
13
|
+
current selection"; the code never wrapped anything.
|
|
14
|
+
|
|
15
|
+
The command now covers the three cases the `||…||` syntax does:
|
|
16
|
+
|
|
17
|
+
- **a selection** → its text moves inside the node. The schema is `marks: ''`
|
|
18
|
+
(inline formatting cannot round-trip through `||…||`), so bold is what's
|
|
19
|
+
dropped, never the words. Selections spanning paragraphs collapse into one
|
|
20
|
+
spoiler; select-all (an `AllSelection`) works too.
|
|
21
|
+
- **an empty selection** → a new spoiler with the caret INSIDE it: type and it
|
|
22
|
+
is hidden. It holds a zero-width caret anchor, because a caret cannot sit in
|
|
23
|
+
an inline node with no text node in it — the serializer strips anchors, and a
|
|
24
|
+
spoiler holding nothing else serializes to nothing, so a stray click cannot
|
|
25
|
+
leave `||||` behind.
|
|
26
|
+
- **the caret already inside a spoiler** → reveal it, leaving the text selected.
|
|
27
|
+
Nesting would have produced `||||text||||`, which reads back as nothing.
|
|
28
|
+
|
|
29
|
+
The button is therefore a toggle, and both toolbars (the headless one and the
|
|
30
|
+
KunUI one in `@kungal/editor-nuxt`) now show it pressed while the caret is
|
|
31
|
+
inside a spoiler — `KunToggleMark` gains a `'spoiler'` member for that, so
|
|
32
|
+
`activeMarks` carries one more key.
|
|
33
|
+
|
|
34
|
+
It returns `false` — no document change — inside a code block and with a node
|
|
35
|
+
selected (an image is not text; replacing it would delete it).
|
|
36
|
+
|
|
3
37
|
## 0.35.0
|
|
4
38
|
|
|
5
39
|
### Minor Changes
|
package/dist/preset/index.cjs
CHANGED
|
@@ -7,12 +7,13 @@ var listener = require('@milkdown/kit/plugin/listener');
|
|
|
7
7
|
var clipboard = require('@milkdown/kit/plugin/clipboard');
|
|
8
8
|
var indent = require('@milkdown/kit/plugin/indent');
|
|
9
9
|
var trailing = require('@milkdown/kit/plugin/trailing');
|
|
10
|
+
var model = require('@milkdown/kit/prose/model');
|
|
10
11
|
var exception = require('@milkdown/kit/exception');
|
|
11
12
|
var inputrules = require('@milkdown/kit/prose/inputrules');
|
|
13
|
+
var state = require('@milkdown/kit/prose/state');
|
|
12
14
|
var utils = require('@milkdown/kit/utils');
|
|
13
15
|
var unistUtilVisit = require('unist-util-visit');
|
|
14
16
|
var core = require('@milkdown/kit/core');
|
|
15
|
-
var state = require('@milkdown/kit/prose/state');
|
|
16
17
|
var commands = require('@milkdown/kit/prose/commands');
|
|
17
18
|
var prose = require('@milkdown/kit/prose');
|
|
18
19
|
var katex = require('katex');
|
|
@@ -39,6 +40,21 @@ var spoilerAttr = utils.$nodeAttr("kun-spoiler", () => ({
|
|
|
39
40
|
style: "background: var(--color-default-500); border-radius: var(--radius-sm); padding: 0 4px; cursor: pointer;"
|
|
40
41
|
}
|
|
41
42
|
}));
|
|
43
|
+
var CARET_ANCHOR = "\u200B";
|
|
44
|
+
var withoutAnchors = (content) => {
|
|
45
|
+
const kept = [];
|
|
46
|
+
content.forEach((child) => {
|
|
47
|
+
if (!child.isText) {
|
|
48
|
+
kept.push(child);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const text = (child.text ?? "").replaceAll(CARET_ANCHOR, "");
|
|
52
|
+
if (text) {
|
|
53
|
+
kept.push(child.type.schema.text(text, child.marks));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return model.Fragment.fromArray(kept);
|
|
57
|
+
};
|
|
42
58
|
var spoilerSchema = utils.$nodeSchema("kun-spoiler", (ctx) => ({
|
|
43
59
|
group: "inline",
|
|
44
60
|
inline: true,
|
|
@@ -83,23 +99,76 @@ var spoilerSchema = utils.$nodeSchema("kun-spoiler", (ctx) => ({
|
|
|
83
99
|
toMarkdown: {
|
|
84
100
|
match: (node) => node.type.name === "kun-spoiler",
|
|
85
101
|
runner: (state, node) => {
|
|
102
|
+
const content = withoutAnchors(node.content);
|
|
103
|
+
if (!content.size) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
86
106
|
state.addNode("text", void 0, "||");
|
|
87
|
-
state.next(
|
|
107
|
+
state.next(content);
|
|
88
108
|
state.addNode("text", void 0, "||");
|
|
89
109
|
}
|
|
90
110
|
}
|
|
91
111
|
}));
|
|
112
|
+
var enclosingSpoiler = ($pos, type) => {
|
|
113
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
114
|
+
const node = $pos.node(depth);
|
|
115
|
+
if (node.type === type) {
|
|
116
|
+
return { pos: $pos.before(depth), node };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
};
|
|
92
121
|
var insertKunSpoilerCommand = utils.$command(
|
|
93
122
|
"InsertKunSpoiler",
|
|
94
|
-
(ctx) => () => (state, dispatch) => {
|
|
95
|
-
|
|
123
|
+
(ctx) => () => (state$1, dispatch) => {
|
|
124
|
+
const type = spoilerSchema.type(ctx);
|
|
125
|
+
const { $from, from, to, empty } = state$1.selection;
|
|
126
|
+
const open = enclosingSpoiler($from, type);
|
|
127
|
+
if (open) {
|
|
128
|
+
if (dispatch) {
|
|
129
|
+
const { pos, node: node2 } = open;
|
|
130
|
+
const revealed = withoutAnchors(node2.content);
|
|
131
|
+
const end = pos + node2.nodeSize;
|
|
132
|
+
const trailing2 = state$1.doc.textBetween(
|
|
133
|
+
end,
|
|
134
|
+
Math.min(end + CARET_ANCHOR.length, state$1.doc.content.size)
|
|
135
|
+
);
|
|
136
|
+
const tr2 = state$1.tr.replaceWith(
|
|
137
|
+
pos,
|
|
138
|
+
trailing2 === CARET_ANCHOR ? end + CARET_ANCHOR.length : end,
|
|
139
|
+
revealed
|
|
140
|
+
);
|
|
141
|
+
if (revealed.size) {
|
|
142
|
+
tr2.setSelection(state.TextSelection.create(tr2.doc, pos, pos + revealed.size));
|
|
143
|
+
}
|
|
144
|
+
dispatch(tr2.scrollIntoView());
|
|
145
|
+
}
|
|
96
146
|
return true;
|
|
97
147
|
}
|
|
98
|
-
|
|
99
|
-
|
|
148
|
+
if (state$1.selection instanceof state.NodeSelection) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
if ($from.parent.isTextblock && !$from.parent.canReplaceWith($from.index(), $from.index(), type)) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
if (!dispatch) {
|
|
100
155
|
return true;
|
|
101
156
|
}
|
|
102
|
-
|
|
157
|
+
const text = state$1.doc.textBetween(from, to, " ").replaceAll(CARET_ANCHOR, "");
|
|
158
|
+
const node = type.create(null, state$1.schema.text(text || CARET_ANCHOR));
|
|
159
|
+
const tr = state$1.tr.replaceSelectionWith(node, false);
|
|
160
|
+
const after = tr.selection.to;
|
|
161
|
+
tr.insertText(CARET_ANCHOR, after);
|
|
162
|
+
dispatch(
|
|
163
|
+
tr.setSelection(
|
|
164
|
+
state.TextSelection.create(
|
|
165
|
+
tr.doc,
|
|
166
|
+
// On the anchor inside the empty node (type and it is hidden), or
|
|
167
|
+
// past the one after a wrap (type and it is not).
|
|
168
|
+
empty ? after - node.nodeSize + 1 + CARET_ANCHOR.length : after + 1
|
|
169
|
+
)
|
|
170
|
+
).scrollIntoView()
|
|
171
|
+
);
|
|
103
172
|
return true;
|
|
104
173
|
}
|
|
105
174
|
);
|
|
@@ -116,7 +185,7 @@ var insertSpoilerInputRule = utils.$inputRule(
|
|
|
116
185
|
{ revealed: false },
|
|
117
186
|
schema.text(content)
|
|
118
187
|
);
|
|
119
|
-
const zeroWidthSpace = schema.text(
|
|
188
|
+
const zeroWidthSpace = schema.text(CARET_ANCHOR);
|
|
120
189
|
return tr.replaceWith(startPos, end, [spoilerNode, zeroWidthSpace]).setStoredMarks([]).scrollIntoView();
|
|
121
190
|
})
|
|
122
191
|
);
|