tiptap-extension-code-block-shiki 1.1.0 → 1.2.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.
@@ -1,8 +1,8 @@
1
- import { Node as R, textblockTypeInputRule as M, mergeAttributes as W, findChildren as v } from "@tiptap/core";
2
- import { Plugin as $, PluginKey as E, TextSelection as z, Selection as F } from "@tiptap/pm/state";
3
- import { DecorationSet as j, Decoration as A } from "@tiptap/pm/view";
4
- import { bundledThemes as H, bundledLanguages as O, createHighlighter as K } from "shiki";
5
- var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create({
1
+ import { Node as O, textblockTypeInputRule as M, mergeAttributes as R, findChildren as L } from "@tiptap/core";
2
+ import { Plugin as z, PluginKey as I, TextSelection as $, Selection as j } from "@tiptap/pm/state";
3
+ import { DecorationSet as F, Decoration as P } from "@tiptap/pm/view";
4
+ import { bundledThemes as E, bundledLanguages as W, createHighlighter as K } from "shiki";
5
+ var A = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = O.create({
6
6
  name: "codeBlock",
7
7
  addOptions() {
8
8
  return {
@@ -11,7 +11,7 @@ var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create(
11
11
  exitOnArrowDown: !0,
12
12
  defaultLanguage: null,
13
13
  enableTabIndentation: !1,
14
- tabSize: B,
14
+ tabSize: A,
15
15
  HTMLAttributes: {}
16
16
  };
17
17
  },
@@ -25,12 +25,12 @@ var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create(
25
25
  language: {
26
26
  default: this.options.defaultLanguage,
27
27
  parseHTML: (e) => {
28
- var o;
29
- const { languageClassPrefix: c } = this.options;
30
- if (!c)
28
+ var t;
29
+ const { languageClassPrefix: i } = this.options;
30
+ if (!i)
31
31
  return null;
32
- const l = [...((o = e.firstElementChild) == null ? void 0 : o.classList) || []].filter((s) => s.startsWith(c)).map((s) => s.replace(c, ""))[0];
33
- return l || null;
32
+ const c = [...((t = e.firstElementChild) == null ? void 0 : t.classList) || []].filter((r) => r.startsWith(i)).map((r) => r.replace(i, ""))[0];
33
+ return c || null;
34
34
  },
35
35
  rendered: !1
36
36
  }
@@ -44,10 +44,10 @@ var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create(
44
44
  }
45
45
  ];
46
46
  },
47
- renderHTML({ node: e, HTMLAttributes: o }) {
47
+ renderHTML({ node: e, HTMLAttributes: t }) {
48
48
  return [
49
49
  "pre",
50
- W(this.options.HTMLAttributes, o),
50
+ R(this.options.HTMLAttributes, t),
51
51
  [
52
52
  "code",
53
53
  {
@@ -57,10 +57,28 @@ var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create(
57
57
  ]
58
58
  ];
59
59
  },
60
+ markdownTokenName: "code",
61
+ parseMarkdown: (e, t) => {
62
+ var i, o;
63
+ return ((i = e.raw) == null ? void 0 : i.startsWith("```")) === !1 && ((o = e.raw) == null ? void 0 : o.startsWith("~~~")) === !1 && e.codeBlockStyle !== "indented" ? [] : t.createNode(
64
+ "codeBlock",
65
+ { language: e.lang || null },
66
+ e.text ? [t.createTextNode(e.text)] : []
67
+ );
68
+ },
69
+ renderMarkdown: (e, t) => {
70
+ var i;
71
+ let o = "";
72
+ const n = ((i = e.attrs) == null ? void 0 : i.language) || "";
73
+ return e.content ? o = [`\`\`\`${n}`, t.renderChildren(e.content), "```"].join(`
74
+ `) : o = `\`\`\`${n}
75
+
76
+ \`\`\``, o;
77
+ },
60
78
  addCommands() {
61
79
  return {
62
- setCodeBlock: (e) => ({ commands: o }) => o.setNode(this.name, e),
63
- toggleCodeBlock: (e) => ({ commands: o }) => o.toggleNode(this.name, "paragraph", e)
80
+ setCodeBlock: (e) => ({ commands: t }) => t.setNode(this.name, e),
81
+ toggleCodeBlock: (e) => ({ commands: t }) => t.toggleNode(this.name, "paragraph", e)
64
82
  };
65
83
  },
66
84
  addKeyboardShortcuts() {
@@ -68,89 +86,89 @@ var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create(
68
86
  "Mod-Alt-c": () => this.editor.commands.toggleCodeBlock(),
69
87
  // remove code block when at start of document or code block is empty
70
88
  Backspace: () => {
71
- const { empty: e, $anchor: o } = this.editor.state.selection, c = o.pos === 1;
72
- return !e || o.parent.type.name !== this.name ? !1 : c || !o.parent.textContent.length ? this.editor.commands.clearNodes() : !1;
89
+ const { empty: e, $anchor: t } = this.editor.state.selection, i = t.pos === 1;
90
+ return !e || t.parent.type.name !== this.name ? !1 : i || !t.parent.textContent.length ? this.editor.commands.clearNodes() : !1;
73
91
  },
74
92
  // handle tab indentation
75
93
  Tab: ({ editor: e }) => {
76
- var o;
94
+ var t;
77
95
  if (!this.options.enableTabIndentation)
78
96
  return !1;
79
- const c = (o = this.options.tabSize) != null ? o : B, { state: a } = e, { selection: t } = a, { $from: l, empty: s } = t;
80
- if (l.parent.type !== this.type)
97
+ const i = (t = this.options.tabSize) != null ? t : A, { state: o } = e, { selection: n } = o, { $from: c, empty: r } = n;
98
+ if (c.parent.type !== this.type)
81
99
  return !1;
82
- const n = " ".repeat(c);
83
- return s ? e.commands.insertContent(n) : e.commands.command(({ tr: d }) => {
84
- const { from: r, to: p } = t, i = a.doc.textBetween(r, p, `
100
+ const s = " ".repeat(i);
101
+ return r ? e.commands.insertContent(s) : e.commands.command(({ tr: d }) => {
102
+ const { from: a, to: g } = n, l = o.doc.textBetween(a, g, `
85
103
  `, `
86
104
  `).split(`
87
- `).map((h) => n + h).join(`
105
+ `).map((h) => s + h).join(`
88
106
  `);
89
- return d.replaceWith(r, p, a.schema.text(i)), !0;
107
+ return d.replaceWith(a, g, o.schema.text(l)), !0;
90
108
  });
91
109
  },
92
110
  // handle shift+tab reverse indentation
93
111
  "Shift-Tab": ({ editor: e }) => {
94
- var o;
112
+ var t;
95
113
  if (!this.options.enableTabIndentation)
96
114
  return !1;
97
- const c = (o = this.options.tabSize) != null ? o : B, { state: a } = e, { selection: t } = a, { $from: l, empty: s } = t;
98
- return l.parent.type !== this.type ? !1 : s ? e.commands.command(({ tr: n }) => {
115
+ const i = (t = this.options.tabSize) != null ? t : A, { state: o } = e, { selection: n } = o, { $from: c, empty: r } = n;
116
+ return c.parent.type !== this.type ? !1 : r ? e.commands.command(({ tr: s }) => {
99
117
  var d;
100
- const { pos: r } = l, p = l.start(), y = l.end(), i = a.doc.textBetween(p, y, `
118
+ const { pos: a } = c, g = c.start(), y = c.end(), l = o.doc.textBetween(g, y, `
101
119
  `, `
102
120
  `).split(`
103
121
  `);
104
122
  let h = 0, u = 0;
105
- const g = r - p;
106
- for (let T = 0; T < i.length; T += 1) {
107
- if (u + i[T].length >= g) {
123
+ const p = a - g;
124
+ for (let T = 0; T < l.length; T += 1) {
125
+ if (u + l[T].length >= p) {
108
126
  h = T;
109
127
  break;
110
128
  }
111
- u += i[T].length + 1;
129
+ u += l[T].length + 1;
112
130
  }
113
- const b = ((d = i[h].match(/^ */)) == null ? void 0 : d[0]) || "", x = Math.min(b.length, c);
131
+ const v = ((d = l[h].match(/^ */)) == null ? void 0 : d[0]) || "", x = Math.min(v.length, i);
114
132
  if (x === 0)
115
133
  return !0;
116
- let k = p;
134
+ let k = g;
117
135
  for (let T = 0; T < h; T += 1)
118
- k += i[T].length + 1;
119
- return n.delete(k, k + x), r - k <= x && n.setSelection(z.create(n.doc, k)), !0;
120
- }) : e.commands.command(({ tr: n }) => {
121
- const { from: d, to: r } = t, m = a.doc.textBetween(d, r, `
136
+ k += l[T].length + 1;
137
+ return s.delete(k, k + x), a - k <= x && s.setSelection($.create(s.doc, k)), !0;
138
+ }) : e.commands.command(({ tr: s }) => {
139
+ const { from: d, to: a } = n, m = o.doc.textBetween(d, a, `
122
140
  `, `
123
141
  `).split(`
124
- `).map((i) => {
142
+ `).map((l) => {
125
143
  var h;
126
- const u = ((h = i.match(/^ */)) == null ? void 0 : h[0]) || "", g = Math.min(u.length, c);
127
- return i.slice(g);
144
+ const u = ((h = l.match(/^ */)) == null ? void 0 : h[0]) || "", p = Math.min(u.length, i);
145
+ return l.slice(p);
128
146
  }).join(`
129
147
  `);
130
- return n.replaceWith(d, r, a.schema.text(m)), !0;
148
+ return s.replaceWith(d, a, o.schema.text(m)), !0;
131
149
  });
132
150
  },
133
151
  // exit node on triple enter
134
152
  Enter: ({ editor: e }) => {
135
153
  if (!this.options.exitOnTripleEnter)
136
154
  return !1;
137
- const { state: o } = e, { selection: c } = o, { $from: a, empty: t } = c;
138
- if (!t || a.parent.type !== this.type)
155
+ const { state: t } = e, { selection: i } = t, { $from: o, empty: n } = i;
156
+ if (!n || o.parent.type !== this.type)
139
157
  return !1;
140
- const l = a.parentOffset === a.parent.nodeSize - 2, s = a.parent.textContent.endsWith(`
158
+ const c = o.parentOffset === o.parent.nodeSize - 2, r = o.parent.textContent.endsWith(`
141
159
 
142
160
  `);
143
- return !l || !s ? !1 : e.chain().command(({ tr: n }) => (n.delete(a.pos - 2, a.pos), !0)).exitCode().run();
161
+ return !c || !r ? !1 : e.chain().command(({ tr: s }) => (s.delete(o.pos - 2, o.pos), !0)).exitCode().run();
144
162
  },
145
163
  // exit node on arrow down
146
164
  ArrowDown: ({ editor: e }) => {
147
165
  if (!this.options.exitOnArrowDown)
148
166
  return !1;
149
- const { state: o } = e, { selection: c, doc: a } = o, { $from: t, empty: l } = c;
150
- if (!l || t.parent.type !== this.type || !(t.parentOffset === t.parent.nodeSize - 2))
167
+ const { state: t } = e, { selection: i, doc: o } = t, { $from: n, empty: c } = i;
168
+ if (!c || n.parent.type !== this.type || !(n.parentOffset === n.parent.nodeSize - 2))
151
169
  return !1;
152
- const n = t.after();
153
- return n === void 0 ? !1 : a.nodeAt(n) ? e.commands.command(({ tr: r }) => (r.setSelection(F.near(a.resolve(n))), !0)) : e.commands.exitCode();
170
+ const s = n.after();
171
+ return s === void 0 ? !1 : o.nodeAt(s) ? e.commands.command(({ tr: a }) => (a.setSelection(j.near(o.resolve(s))), !0)) : e.commands.exitCode();
154
172
  }
155
173
  };
156
174
  },
@@ -176,159 +194,159 @@ var B = 4, U = /^```([a-z]+)?[\s\n]$/, V = /^~~~([a-z]+)?[\s\n]$/, J = R.create(
176
194
  return [
177
195
  // this plugin creates a code block for pasted content from VS Code
178
196
  // we can also detect the copied code language
179
- new $({
180
- key: new E("codeBlockVSCodeHandler"),
197
+ new z({
198
+ key: new I("codeBlockVSCodeHandler"),
181
199
  props: {
182
- handlePaste: (e, o) => {
183
- if (!o.clipboardData || this.editor.isActive(this.type.name))
200
+ handlePaste: (e, t) => {
201
+ if (!t.clipboardData || this.editor.isActive(this.type.name))
184
202
  return !1;
185
- const c = o.clipboardData.getData("text/plain"), a = o.clipboardData.getData("vscode-editor-data"), t = a ? JSON.parse(a) : void 0, l = t?.mode;
186
- if (!c || !l)
203
+ const i = t.clipboardData.getData("text/plain"), o = t.clipboardData.getData("vscode-editor-data"), n = o ? JSON.parse(o) : void 0, c = n?.mode;
204
+ if (!i || !c)
187
205
  return !1;
188
- const { tr: s, schema: n } = e.state, d = n.text(c.replace(/\r\n?/g, `
206
+ const { tr: r, schema: s } = e.state, d = s.text(i.replace(/\r\n?/g, `
189
207
  `));
190
- return s.replaceSelectionWith(this.type.create({ language: l }, d)), s.selection.$from.parent.type !== this.type && s.setSelection(z.near(s.doc.resolve(Math.max(0, s.selection.from - 2)))), s.setMeta("paste", !0), e.dispatch(s), !0;
208
+ return r.replaceSelectionWith(this.type.create({ language: c }, d)), r.selection.$from.parent.type !== this.type && r.setSelection($.near(r.doc.resolve(Math.max(0, r.selection.from - 2)))), r.setMeta("paste", !0), e.dispatch(r), !0;
191
209
  }
192
210
  }
193
211
  })
194
212
  ];
195
213
  }
196
214
  }), Z = J;
197
- let f, L;
198
- const D = /* @__PURE__ */ new Set(), N = /* @__PURE__ */ new Set(), w = /* @__PURE__ */ new Map();
215
+ let f, w;
216
+ const N = /* @__PURE__ */ new Set(), D = /* @__PURE__ */ new Set(), B = /* @__PURE__ */ new Map();
199
217
  function q(e) {
200
- return e in H || w.has(e);
218
+ return e in E || B.has(e);
201
219
  }
202
220
  function G() {
203
221
  return f;
204
222
  }
205
223
  function Q(e) {
206
- if (!f && !L) {
224
+ if (!f && !w) {
207
225
  if (e.customThemes)
208
- for (const t of e.customThemes)
209
- t.name && w.set(t.name, t);
210
- const o = e.themes.filter(
211
- (t) => !!t && t in H
212
- ), c = e.languages.filter(
213
- (t) => !!t && t in O
214
- ), a = [...o, ...w.values()];
215
- return L = K({ themes: a, langs: c }).then((t) => {
216
- f = t;
217
- }), L;
226
+ for (const n of e.customThemes)
227
+ n.name && B.set(n.name, n);
228
+ const t = e.themes.filter(
229
+ (n) => !!n && n in E
230
+ ), i = e.languages.filter(
231
+ (n) => !!n && n in W
232
+ ), o = [...t, ...B.values()];
233
+ return w = K({ themes: o, langs: i }).then((n) => {
234
+ f = n;
235
+ }), w;
218
236
  }
219
- if (L)
220
- return L;
237
+ if (w)
238
+ return w;
221
239
  }
222
- async function P(e) {
223
- if (f && !f.getLoadedThemes().includes(e) && !N.has(e) && q(e)) {
224
- N.add(e);
225
- const o = w.get(e) ?? e;
226
- return await f.loadTheme(o), N.delete(e), !0;
240
+ async function b(e) {
241
+ if (f && !f.getLoadedThemes().includes(e) && !D.has(e) && q(e)) {
242
+ D.add(e);
243
+ const t = B.get(e) ?? e;
244
+ return await f.loadTheme(t), D.delete(e), !0;
227
245
  }
228
246
  return !1;
229
247
  }
230
- async function _(e) {
231
- return f && !f.getLoadedLanguages().includes(e) && !D.has(e) && e in O ? (D.add(e), await f.loadLanguage(e), D.delete(e), !0) : !1;
248
+ async function H(e) {
249
+ return f && !f.getLoadedLanguages().includes(e) && !N.has(e) && e in W ? (N.add(e), await f.loadLanguage(e), N.delete(e), !0) : !1;
232
250
  }
233
251
  async function X({
234
252
  doc: e,
235
- name: o,
236
- defaultTheme: c,
237
- defaultLanguage: a,
238
- themeModes: t,
239
- customThemes: l
253
+ name: t,
254
+ defaultTheme: i,
255
+ defaultLanguage: o,
256
+ themeModes: n,
257
+ customThemes: c
240
258
  }) {
241
- const s = v(e, (r) => r.type.name === o), n = [
242
- ...s.map((r) => r.node.attrs.theme),
243
- c
259
+ const r = L(e, (a) => a.type.name === t), s = [
260
+ ...r.map((a) => a.node.attrs.theme),
261
+ i
244
262
  ], d = [
245
- ...s.map((r) => r.node.attrs.language),
246
- a
263
+ ...r.map((a) => a.node.attrs.language),
264
+ o
247
265
  ];
248
266
  if (f)
249
267
  await Promise.all([
250
- ...n.flatMap((r) => P(r)),
251
- ...d.flatMap((r) => !!r && _(r))
268
+ ...s.flatMap((a) => b(a)),
269
+ ...d.flatMap((a) => !!a && H(a))
252
270
  ]);
253
271
  else {
254
- const r = [...n];
255
- t && (t.light && !r.includes(t.light) && r.push(t.light), t.dark && !r.includes(t.dark) && r.push(t.dark)), await Q({
272
+ const a = [...s];
273
+ n && (n.light && !a.includes(n.light) && a.push(n.light), n.dark && !a.includes(n.dark) && a.push(n.dark)), await Q({
256
274
  languages: d,
257
- themes: r,
258
- customThemes: l
275
+ themes: a,
276
+ customThemes: c
259
277
  });
260
278
  }
261
279
  }
262
280
  function C(e) {
263
- return Object.entries(e).map(([o, c]) => `${o}:${c}`).join(";");
281
+ return Object.entries(e).map(([t, i]) => `${t}:${i}`).join(";");
264
282
  }
265
- function I({
283
+ function _({
266
284
  doc: e,
267
- name: o,
268
- defaultTheme: c,
269
- defaultLanguage: a,
270
- themes: t
285
+ name: t,
286
+ defaultTheme: i,
287
+ defaultLanguage: o,
288
+ themes: n
271
289
  }) {
272
- const l = [];
273
- return v(e, (n) => n.type.name === o).forEach((n) => {
274
- let d = n.pos + 1, r = n.node.attrs.language || a;
275
- const p = n.node.attrs.theme || c, y = n.node.attrs.themes?.light || t?.light, m = n.node.attrs.themes?.dark || t?.dark, i = G();
276
- if (!i) return;
277
- i.getLoadedLanguages().includes(r) || (r = "plaintext");
278
- const h = (g) => i.getLoadedThemes().includes(g) ? g : i.getLoadedThemes()[0];
290
+ const c = [];
291
+ return L(e, (s) => s.type.name === t).forEach((s) => {
292
+ let d = s.pos + 1, a = s.node.attrs.language || o;
293
+ const g = s.node.attrs.theme || i, y = s.node.attrs.themes?.light || n?.light, m = s.node.attrs.themes?.dark || n?.dark, l = G();
294
+ if (!l) return;
295
+ l.getLoadedLanguages().includes(a) || (a = "plaintext");
296
+ const h = (p) => l.getLoadedThemes().includes(p) ? p : l.getLoadedThemes()[0];
279
297
  let u;
280
- if (t) {
281
- u = i.codeToTokens(n.node.textContent, {
282
- lang: r,
298
+ if (n) {
299
+ u = l.codeToTokens(s.node.textContent, {
300
+ lang: a,
283
301
  themes: {
284
302
  light: h(y),
285
303
  dark: h(m)
286
304
  }
287
305
  });
288
- const g = {};
289
- u.bg && (g["background-color"] = u.bg), u.fg && (g.color = u.fg), l.push(
290
- A.node(n.pos, n.pos + n.node.nodeSize, {
291
- style: C(g),
306
+ const p = {};
307
+ u.bg && (p["background-color"] = u.bg), u.fg && (p.color = u.fg), c.push(
308
+ P.node(s.pos, s.pos + s.node.nodeSize, {
309
+ style: C(p),
292
310
  class: "shiki"
293
311
  })
294
312
  );
295
313
  } else {
296
- u = i.codeToTokens(n.node.textContent, {
297
- lang: r,
298
- theme: h(p)
314
+ u = l.codeToTokens(s.node.textContent, {
315
+ lang: a,
316
+ theme: h(g)
299
317
  });
300
- const g = i.getLoadedThemes().includes(p) ? p : i.getLoadedThemes()[0], S = i.getTheme(g);
301
- l.push(
302
- A.node(n.pos, n.pos + n.node.nodeSize, {
318
+ const p = l.getLoadedThemes().includes(g) ? g : l.getLoadedThemes()[0], S = l.getTheme(p);
319
+ c.push(
320
+ P.node(s.pos, s.pos + s.node.nodeSize, {
303
321
  style: C({ "background-color": S.bg })
304
322
  })
305
323
  );
306
324
  }
307
- for (const g of u.tokens) {
308
- for (const S of g) {
309
- const b = d + S.content.length;
325
+ for (const p of u.tokens) {
326
+ for (const S of p) {
327
+ const v = d + S.content.length;
310
328
  let x = "";
311
- t ? x = C(S.htmlStyle || {}) : x = C({ color: S.color || "inherit" });
312
- const k = A.inline(d, b, {
329
+ n ? x = C(S.htmlStyle || {}) : x = C({ color: S.color || "inherit" });
330
+ const k = P.inline(d, v, {
313
331
  style: x
314
332
  });
315
- l.push(k), d = b;
333
+ c.push(k), d = v;
316
334
  }
317
335
  d += 1;
318
336
  }
319
- }), j.create(e, l);
337
+ }), F.create(e, c);
320
338
  }
321
339
  function Y({
322
340
  name: e,
323
- defaultLanguage: o,
324
- defaultTheme: c,
325
- themes: a,
326
- customThemes: t
341
+ defaultLanguage: t,
342
+ defaultTheme: i,
343
+ themes: o,
344
+ customThemes: n
327
345
  }) {
328
- const l = new $({
329
- key: new E("shiki"),
330
- view(s) {
331
- class n {
346
+ const c = new z({
347
+ key: new I("shiki"),
348
+ view(r) {
349
+ class s {
332
350
  constructor() {
333
351
  this.initDecorations();
334
352
  }
@@ -339,86 +357,86 @@ function Y({
339
357
  }
340
358
  // Initialize shiki async, and then highlight initial document
341
359
  async initDecorations() {
342
- const r = s.state.doc;
360
+ const a = r.state.doc;
343
361
  await X({
344
- doc: r,
362
+ doc: a,
345
363
  name: e,
346
- defaultLanguage: o,
347
- defaultTheme: c,
348
- themeModes: a,
349
- customThemes: t ?? void 0
364
+ defaultLanguage: t,
365
+ defaultTheme: i,
366
+ themeModes: o,
367
+ customThemes: n ?? void 0
350
368
  });
351
- const p = s.state.tr.setMeta("shikiPluginForceDecoration", !0);
352
- s.dispatch(p);
369
+ const g = r.state.tr.setMeta("shikiPluginForceDecoration", !0);
370
+ r.dispatch(g);
353
371
  }
354
372
  // When new codeblocks were added and they have missing themes or
355
373
  // languages, load those and then add code decorations once again.
356
374
  async checkUndecoratedBlocks() {
357
- const r = v(
358
- s.state.doc,
359
- (i) => i.type.name === e
360
- ), p = (i) => {
361
- const h = [_(i.node.attrs.language)];
362
- return a ? (h.push(
363
- P(i.node.attrs.themes?.light || a.light)
364
- ), h.push(P(i.node.attrs.themes?.dark || a.dark))) : h.push(P(i.node.attrs.theme)), h;
375
+ const a = L(
376
+ r.state.doc,
377
+ (l) => l.type.name === e
378
+ ), g = (l) => {
379
+ const h = [H(l.node.attrs.language)];
380
+ return o ? (h.push(
381
+ b(l.node.attrs.themes?.light || o.light)
382
+ ), h.push(b(l.node.attrs.themes?.dark || o.dark))) : h.push(b(l.node.attrs.theme)), h;
365
383
  };
366
384
  if ((await Promise.all(
367
- r.flatMap((i) => p(i))
385
+ a.flatMap((l) => g(l))
368
386
  )).includes(!0)) {
369
- const i = s.state.tr.setMeta("shikiPluginForceDecoration", !0);
370
- s.dispatch(i);
387
+ const l = r.state.tr.setMeta("shikiPluginForceDecoration", !0);
388
+ r.dispatch(l);
371
389
  }
372
390
  }
373
391
  }
374
- return new n();
392
+ return new s();
375
393
  },
376
394
  state: {
377
- init: (s, { doc: n }) => I({
378
- doc: n,
395
+ init: (r, { doc: s }) => _({
396
+ doc: s,
379
397
  name: e,
380
- defaultLanguage: o,
381
- defaultTheme: c,
382
- themes: a
398
+ defaultLanguage: t,
399
+ defaultTheme: i,
400
+ themes: o
383
401
  }),
384
- apply: (s, n, d, r) => {
385
- const p = d.selection.$head.parent.type.name, y = r.selection.$head.parent.type.name, m = v(
402
+ apply: (r, s, d, a) => {
403
+ const g = d.selection.$head.parent.type.name, y = a.selection.$head.parent.type.name, m = L(
386
404
  d.doc,
387
405
  (u) => u.type.name === e
388
- ), i = v(
389
- r.doc,
406
+ ), l = L(
407
+ a.doc,
390
408
  (u) => u.type.name === e
391
- ), h = s.docChanged && // Apply decorations if:
409
+ ), h = r.docChanged && // Apply decorations if:
392
410
  // selection includes named node,
393
- ([p, y].includes(e) || // OR transaction adds/removes named node,
394
- i.length !== m.length || // OR transaction has changes that completely encapsulte a node
411
+ ([g, y].includes(e) || // OR transaction adds/removes named node,
412
+ l.length !== m.length || // OR transaction has changes that completely encapsulte a node
395
413
  // (for example, a transaction that affects the entire document).
396
414
  // Such transactions can happen during collab syncing via y-prosemirror, for example.
397
- s.steps.some((u) => (
415
+ r.steps.some((u) => (
398
416
  // @ts-expect-error
399
417
  u.from !== void 0 && // @ts-expect-error
400
- u.to !== void 0 && m.some((g) => (
418
+ u.to !== void 0 && m.some((p) => (
401
419
  // @ts-expect-error
402
- g.pos >= u.from && // @ts-expect-error
403
- g.pos + g.node.nodeSize <= u.to
420
+ p.pos >= u.from && // @ts-expect-error
421
+ p.pos + p.node.nodeSize <= u.to
404
422
  ))
405
423
  )));
406
- return s.getMeta("shikiPluginForceDecoration") || h ? I({
407
- doc: s.doc,
424
+ return r.getMeta("shikiPluginForceDecoration") || h ? _({
425
+ doc: r.doc,
408
426
  name: e,
409
- defaultLanguage: o,
410
- defaultTheme: c,
411
- themes: a
412
- }) : n.map(s.mapping, s.doc);
427
+ defaultLanguage: t,
428
+ defaultTheme: i,
429
+ themes: o
430
+ }) : s.map(r.mapping, r.doc);
413
431
  }
414
432
  },
415
433
  props: {
416
- decorations(s) {
417
- return l.getState(s);
434
+ decorations(r) {
435
+ return c.getState(r);
418
436
  }
419
437
  }
420
438
  });
421
- return l;
439
+ return c;
422
440
  }
423
441
  /* v8 ignore start -- @preserve */
424
442
  /* v8 ignore stop -- @preserve */
@@ -432,6 +450,23 @@ const re = Z.extend({
432
450
  customThemes: null
433
451
  };
434
452
  },
453
+ markdownTokenName: "code",
454
+ parseMarkdown(e, t) {
455
+ return e.raw?.startsWith("```") === !1 && e.raw?.startsWith("~~~") === !1 && e.codeBlockStyle !== "indented" ? [] : t.createNode(
456
+ "codeBlock",
457
+ { language: e.lang || null },
458
+ e.text ? [t.createTextNode(e.text)] : []
459
+ );
460
+ },
461
+ renderMarkdown(e, t, i) {
462
+ const o = e.attrs?.language || "";
463
+ return e.content ? [`\`\`\`${o}`, t.renderChildren(e.content), "```"].join(
464
+ `
465
+ `
466
+ ) : `\`\`\`${o}
467
+
468
+ \`\`\``;
469
+ },
435
470
  addProseMirrorPlugins() {
436
471
  return [
437
472
  ...this.parent?.() || [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiptap-extension-code-block-shiki",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Use Shiki syntax highlighting for codeblocks in TipTap.",
5
5
  "repository": "timomeh/tiptap-extension-code-block-shiki",
6
6
  "author": {
@@ -32,13 +32,14 @@
32
32
  "@biomejs/biome": "2.2.6",
33
33
  "@codecov/vite-plugin": "^1.9.1",
34
34
  "@microsoft/api-extractor": "^7.53.1",
35
- "@tiptap/core": "^3.6.6",
36
- "@tiptap/extension-code-block": "^3.6.6",
37
- "@tiptap/pm": "^3.6.6",
38
- "@tiptap/starter-kit": "^3.6.6",
35
+ "@tiptap/core": "^3.21.0",
36
+ "@tiptap/extension-code-block": "^3.21.0",
37
+ "@tiptap/markdown": "^3.21.0",
38
+ "@tiptap/pm": "^3.21.0",
39
+ "@tiptap/starter-kit": "^3.21.0",
39
40
  "@vitest/coverage-v8": "^3.2.4",
40
41
  "happy-dom": "^20.0.0",
41
- "shiki": "^3.13.0",
42
+ "shiki": "^4.0.0",
42
43
  "typescript": "^5.9.3",
43
44
  "unplugin-dts": "1.0.0-beta.0",
44
45
  "vite": "^7.1.9",
@@ -47,7 +48,7 @@
47
48
  "peerDependencies": {
48
49
  "@tiptap/core": "^2.3.0 || ^3.0.0",
49
50
  "@tiptap/pm": "^2.3.0 || ^3.0.0",
50
- "shiki": "^3.0.0"
51
+ "shiki": "^3.0.0 || ^4.0.0"
51
52
  },
52
53
  "keywords": [
53
54
  "tiptap",