@kungal/editor-core 0.37.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.
@@ -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
- /** DOM attrs for the rendered spoiler chip. The styling references KunUI CSS
11
- * variables so it inherits the host theme (the render layer ships the vars). */
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. */
@@ -49,7 +68,8 @@ declare const insertSpoilerInputRule: _milkdown_kit_utils.$InputRule;
49
68
  declare const remarkSpoilerPlugin: _milkdown_kit_utils.$Remark<"remarkSpoiler", unknown>;
50
69
  /**
51
70
  * The spoiler plugin bundle: schema attrs, node schema, the `||…||` input rule,
52
- * the insert command and the remark round-trip. Pure no adapter needed.
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.
53
73
  */
54
74
  declare const createSpoilerPlugin: () => MilkdownPlugin[];
55
75
 
@@ -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
- /** DOM attrs for the rendered spoiler chip. The styling references KunUI CSS
11
- * variables so it inherits the host theme (the render layer ships the vars). */
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. */
@@ -49,7 +68,8 @@ declare const insertSpoilerInputRule: _milkdown_kit_utils.$InputRule;
49
68
  declare const remarkSpoilerPlugin: _milkdown_kit_utils.$Remark<"remarkSpoiler", unknown>;
50
69
  /**
51
70
  * The spoiler plugin bundle: schema attrs, node schema, the `||…||` input rule,
52
- * the insert command and the remark round-trip. Pure no adapter needed.
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.
53
73
  */
54
74
  declare const createSpoilerPlugin: () => MilkdownPlugin[];
55
75
 
@@ -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-default-500); border-radius: var(--radius-sm); padding: 0 4px; cursor: pointer;"
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) => {
@@ -194,16 +201,17 @@ var remarkSpoilerPlugin = $remark("remarkSpoiler", () => () => {
194
201
  if (!node.value.includes("||")) {
195
202
  return;
196
203
  }
204
+ const value = node.value.replaceAll(CARET_ANCHOR, "");
197
205
  const regex = /\|\|(.*?)\|\|/g;
198
206
  const newNodes = [];
199
207
  let lastIndex = 0;
200
- for (const match of node.value.matchAll(regex)) {
208
+ for (const match of value.matchAll(regex)) {
201
209
  const [full, content] = match;
202
210
  const matchIndex = match.index ?? 0;
203
211
  if (matchIndex > lastIndex) {
204
212
  newNodes.push({
205
213
  type: "text",
206
- value: node.value.slice(lastIndex, matchIndex)
214
+ value: value.slice(lastIndex, matchIndex)
207
215
  });
208
216
  }
209
217
  if (content) {
@@ -211,11 +219,12 @@ var remarkSpoilerPlugin = $remark("remarkSpoiler", () => () => {
211
219
  type: "kun-spoiler",
212
220
  children: [{ type: "text", value: content }]
213
221
  });
222
+ newNodes.push({ type: "text", value: CARET_ANCHOR });
214
223
  }
215
224
  lastIndex = matchIndex + full.length;
216
225
  }
217
- if (lastIndex < node.value.length) {
218
- newNodes.push({ type: "text", value: node.value.slice(lastIndex) });
226
+ if (lastIndex < value.length) {
227
+ newNodes.push({ type: "text", value: value.slice(lastIndex) });
219
228
  }
220
229
  if (newNodes.length > 0 && typeof index === "number") {
221
230
  parent.children?.splice(index, 1, ...newNodes);
@@ -229,7 +238,8 @@ var createSpoilerPlugin = () => [
229
238
  spoilerSchema,
230
239
  insertSpoilerInputRule,
231
240
  insertKunSpoilerCommand,
232
- remarkSpoilerPlugin
241
+ remarkSpoilerPlugin,
242
+ stripCaretAnchors
233
243
  ].flat();
234
244
  var hasMark = (state, type) => {
235
245
  if (!type) {