@lofcz/platejs-code-block 52.0.11

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/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Ziad Beyens, Dylan Schiemann, Joe Anderson, Felix Feng
4
+
5
+ Unless otherwise specified in a LICENSE file within an individual package directory,
6
+ this license applies to all files in this repository outside of those package directories.
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # Plate code block plugin
2
+
3
+ This package implements the code block plugin for Plate.
4
+
5
+ ## Documentation
6
+
7
+ Check out
8
+ [Basic Elements](https://platejs.org/docs/basic-blocks).
9
+
10
+ ## License
11
+
12
+ [MIT](../../LICENSE)
@@ -0,0 +1,465 @@
1
+ import { ElementApi, KEYS, NodeApi, createSlatePlugin, createTSlatePlugin } from "platejs";
2
+
3
+ //#region src/lib/deserializer/htmlDeserializerCodeBlock.ts
4
+ const htmlDeserializerCodeBlock = {
5
+ rules: [{ validNodeName: "PRE" }, {
6
+ validNodeName: "P",
7
+ validStyle: { fontFamily: "Consolas" }
8
+ }],
9
+ parse: ({ element }) => {
10
+ const languageSelectorText = [...element.childNodes].find((node) => node.nodeName === "SELECT")?.textContent || "";
11
+ const textContent = element.textContent?.replace(languageSelectorText, "") || "";
12
+ let lines = textContent.split("\n");
13
+ if (!lines?.length) lines = [textContent];
14
+ return {
15
+ children: lines.map((line) => ({
16
+ children: [{ text: line }],
17
+ type: KEYS.codeLine
18
+ })),
19
+ type: KEYS.codeBlock
20
+ };
21
+ }
22
+ };
23
+
24
+ //#endregion
25
+ //#region src/lib/queries/getCodeLineEntry.ts
26
+ /** If at (default = selection) is in ul>li>p, return li and ul node entries. */
27
+ const getCodeLineEntry = (editor, { at = editor.selection } = {}) => {
28
+ if (at && editor.api.some({
29
+ at,
30
+ match: { type: editor.getType(KEYS.codeLine) }
31
+ })) {
32
+ const selectionParent = editor.api.parent(at);
33
+ if (!selectionParent) return;
34
+ const [, parentPath] = selectionParent;
35
+ const codeLine = editor.api.above({
36
+ at,
37
+ match: { type: editor.getType(KEYS.codeLine) }
38
+ }) || editor.api.parent(parentPath);
39
+ if (!codeLine) return;
40
+ const [codeLineNode, codeLinePath] = codeLine;
41
+ if (ElementApi.isElement(codeLineNode) && codeLineNode.type !== editor.getType(KEYS.codeLine)) return;
42
+ const codeBlock = editor.api.parent(codeLinePath);
43
+ if (!codeBlock) return;
44
+ return {
45
+ codeBlock,
46
+ codeLine
47
+ };
48
+ }
49
+ };
50
+
51
+ //#endregion
52
+ //#region src/lib/queries/getIndentDepth.ts
53
+ const nonWhitespaceOrEndRegex = /\S|$/;
54
+ const getIndentDepth = (editor, { codeLine }) => {
55
+ const [, codeLinePath] = codeLine;
56
+ return editor.api.string(codeLinePath).search(nonWhitespaceOrEndRegex);
57
+ };
58
+
59
+ //#endregion
60
+ //#region src/lib/queries/isCodeBlockEmpty.ts
61
+ /** Is the selection inside an empty code block */
62
+ const isCodeBlockEmpty = (editor) => {
63
+ const { codeBlock } = getCodeLineEntry(editor) ?? {};
64
+ if (!codeBlock) return false;
65
+ const codeLines = Array.from(NodeApi.children(editor, codeBlock[1]));
66
+ if (codeLines.length === 0) return true;
67
+ if (codeLines.length > 1) return false;
68
+ const firstCodeLineNode = codeLines[0][0];
69
+ return !NodeApi.string(firstCodeLineNode);
70
+ };
71
+
72
+ //#endregion
73
+ //#region src/lib/setCodeBlockToDecorations.ts
74
+ const CODE_LINE_TO_DECORATIONS = /* @__PURE__ */ new WeakMap();
75
+ function getHighlightNodes(result) {
76
+ return result.value || result.children || [];
77
+ }
78
+ function parseNodes(nodes, className = []) {
79
+ return nodes.flatMap((node) => {
80
+ const classes = [...className, ...node.properties ? node.properties.className : []];
81
+ if (node.children) return parseNodes(node.children, classes);
82
+ return {
83
+ classes,
84
+ text: node.value
85
+ };
86
+ });
87
+ }
88
+ function normalizeTokens(tokens) {
89
+ const lines = [[]];
90
+ let currentLine = lines[0];
91
+ for (const token of tokens) {
92
+ const tokenLines = token.text.split("\n");
93
+ for (let i = 0; i < tokenLines.length; i++) {
94
+ const content = tokenLines[i];
95
+ if (content) currentLine.push({
96
+ classes: token.classes,
97
+ content
98
+ });
99
+ if (i < tokenLines.length - 1) {
100
+ lines.push([]);
101
+ currentLine = lines.at(-1);
102
+ }
103
+ }
104
+ }
105
+ return lines;
106
+ }
107
+ function codeBlockToDecorations(editor, [block, blockPath]) {
108
+ const { defaultLanguage, ...options } = editor.getOptions(BaseCodeBlockPlugin);
109
+ const lowlight = options.lowlight;
110
+ const text = block.children.map((line) => NodeApi.string(line)).join("\n");
111
+ const effectiveLanguage = block.lang || defaultLanguage;
112
+ let highlighted;
113
+ try {
114
+ if (!effectiveLanguage || effectiveLanguage === "plaintext") highlighted = { value: [] };
115
+ else if (effectiveLanguage === "auto") highlighted = lowlight.highlightAuto(text);
116
+ else highlighted = lowlight.highlight(effectiveLanguage, text);
117
+ } catch (error) {
118
+ const availableLanguages = lowlight.listLanguages();
119
+ if (effectiveLanguage && availableLanguages.includes(effectiveLanguage)) {
120
+ editor.api.debug.error(error, "CODE_HIGHLIGHT");
121
+ highlighted = { value: [] };
122
+ } else {
123
+ editor.api.debug.warn(`Language "${effectiveLanguage}" is not registered. Falling back to plaintext`);
124
+ highlighted = { value: [] };
125
+ }
126
+ }
127
+ const normalizedTokens = normalizeTokens(parseNodes(getHighlightNodes(highlighted)));
128
+ const blockChildren = block.children;
129
+ const nodeToDecorations = /* @__PURE__ */ new Map();
130
+ const numLines = Math.min(normalizedTokens.length, blockChildren.length);
131
+ for (let index = 0; index < numLines; index++) {
132
+ const lineTokens = normalizedTokens[index];
133
+ const element = blockChildren[index];
134
+ if (!nodeToDecorations.has(element)) nodeToDecorations.set(element, []);
135
+ let start = 0;
136
+ for (const token of lineTokens) {
137
+ const length = token.content.length;
138
+ if (!length) continue;
139
+ const end = start + length;
140
+ const decoration = {
141
+ anchor: {
142
+ offset: start,
143
+ path: [
144
+ ...blockPath,
145
+ index,
146
+ 0
147
+ ]
148
+ },
149
+ className: token.classes.join(" "),
150
+ focus: {
151
+ offset: end,
152
+ path: [
153
+ ...blockPath,
154
+ index,
155
+ 0
156
+ ]
157
+ },
158
+ [KEYS.codeSyntax]: true
159
+ };
160
+ nodeToDecorations.get(element).push(decoration);
161
+ start = end;
162
+ }
163
+ }
164
+ return nodeToDecorations;
165
+ }
166
+ function setCodeBlockToDecorations(editor, [block, blockPath]) {
167
+ const decorations = codeBlockToDecorations(editor, [block, blockPath]);
168
+ for (const [node, decs] of decorations.entries()) CODE_LINE_TO_DECORATIONS.set(node, decs);
169
+ }
170
+ function resetCodeBlockDecorations(codeBlock) {
171
+ codeBlock.children.forEach((line) => {
172
+ CODE_LINE_TO_DECORATIONS.delete(line);
173
+ });
174
+ }
175
+
176
+ //#endregion
177
+ //#region src/lib/transforms/deleteStartSpace.ts
178
+ const whitespaceRegex = /\s/;
179
+ /** If there is a whitespace character at the start of the code line, delete it. */
180
+ const deleteStartSpace = (editor, { codeLine }) => {
181
+ const [, codeLinePath] = codeLine;
182
+ const codeLineStart = editor.api.start(codeLinePath);
183
+ const codeLineEnd = codeLineStart && editor.api.after(codeLineStart);
184
+ const spaceRange = codeLineEnd && editor.api.range(codeLineStart, codeLineEnd);
185
+ const spaceText = editor.api.string(spaceRange);
186
+ if (whitespaceRegex.test(spaceText)) {
187
+ editor.tf.delete({ at: spaceRange });
188
+ return true;
189
+ }
190
+ return false;
191
+ };
192
+
193
+ //#endregion
194
+ //#region src/lib/transforms/indentCodeLine.ts
195
+ const nonWhitespaceRegex = /\S/;
196
+ /**
197
+ * Indent if:
198
+ *
199
+ * - The selection is expanded OR
200
+ * - There are no non-whitespace characters left of the cursor Indentation = 2
201
+ * spaces.
202
+ */
203
+ const indentCodeLine = (editor, { codeLine, indentDepth = 2 }) => {
204
+ const [, codeLinePath] = codeLine;
205
+ const codeLineStart = editor.api.start(codeLinePath);
206
+ const indent = " ".repeat(indentDepth);
207
+ if (!editor.api.isExpanded()) {
208
+ const cursor = editor.selection?.anchor;
209
+ const range = editor.api.range(codeLineStart, cursor);
210
+ const text = editor.api.string(range);
211
+ if (nonWhitespaceRegex.test(text)) {
212
+ editor.tf.insertText(indent, { at: editor.selection });
213
+ return;
214
+ }
215
+ }
216
+ editor.tf.insertText(indent, { at: codeLineStart });
217
+ };
218
+
219
+ //#endregion
220
+ //#region src/lib/transforms/outdentCodeLine.ts
221
+ /** Outdent the code line. Remove 2 whitespace characters if any. */
222
+ const outdentCodeLine = (editor, { codeBlock, codeLine }) => {
223
+ if (deleteStartSpace(editor, {
224
+ codeBlock,
225
+ codeLine
226
+ })) deleteStartSpace(editor, {
227
+ codeBlock,
228
+ codeLine
229
+ });
230
+ };
231
+
232
+ //#endregion
233
+ //#region src/lib/transforms/unwrapCodeBlock.ts
234
+ const unwrapCodeBlock = (editor) => {
235
+ if (!editor.selection) return;
236
+ const codeBlockType = editor.getType(KEYS.codeBlock);
237
+ const defaultType = editor.getType(KEYS.p);
238
+ editor.tf.withoutNormalizing(() => {
239
+ const codeBlockEntries = editor.api.nodes({
240
+ at: editor.selection,
241
+ match: { type: codeBlockType }
242
+ });
243
+ const reversedCodeBlockEntries = Array.from(codeBlockEntries).reverse();
244
+ for (const codeBlockEntry of reversedCodeBlockEntries) {
245
+ const codeLineEntries = NodeApi.children(editor, codeBlockEntry[1]);
246
+ for (const [, path] of codeLineEntries) editor.tf.setNodes({ type: defaultType }, { at: path });
247
+ editor.tf.unwrapNodes({
248
+ at: codeBlockEntry[1],
249
+ match: { type: codeBlockType },
250
+ split: true
251
+ });
252
+ }
253
+ });
254
+ };
255
+
256
+ //#endregion
257
+ //#region src/lib/withInsertDataCodeBlock.ts
258
+ const withInsertDataCodeBlock = ({ editor, tf: { insertData }, type: codeBlockType }) => ({ transforms: { insertData(data) {
259
+ const text = data.getData("text/plain");
260
+ const vscodeDataString = data.getData("vscode-editor-data");
261
+ const codeLineType = editor.getType(KEYS.codeLine);
262
+ if (vscodeDataString) try {
263
+ const vscodeData = JSON.parse(vscodeDataString);
264
+ const lines = text.split("\n");
265
+ const [blockAbove$1] = editor.api.block() ?? [];
266
+ if (blockAbove$1 && [codeBlockType, codeLineType].includes(blockAbove$1?.type)) {
267
+ if (lines[0]) editor.tf.insertText(lines[0]);
268
+ if (lines.length > 1) {
269
+ const nodes = lines.slice(1).map((line) => ({
270
+ children: [{ text: line }],
271
+ type: codeLineType
272
+ }));
273
+ editor.tf.insertNodes(nodes);
274
+ }
275
+ } else {
276
+ const node = {
277
+ children: lines.map((line) => ({
278
+ children: [{ text: line }],
279
+ type: codeLineType
280
+ })),
281
+ lang: vscodeData?.mode,
282
+ type: codeBlockType
283
+ };
284
+ editor.tf.insertNodes(node, { select: true });
285
+ }
286
+ return;
287
+ } catch (_error) {}
288
+ const [blockAbove] = editor.api.block() ?? [];
289
+ if (blockAbove && [codeBlockType, codeLineType].includes(blockAbove?.type) && text?.includes("\n")) {
290
+ const lines = text.split("\n");
291
+ if (lines[0]) editor.tf.insertText(lines[0]);
292
+ if (lines.length > 1) {
293
+ const nodes = lines.slice(1).map((line) => ({
294
+ children: [{ text: line }],
295
+ type: codeLineType
296
+ }));
297
+ editor.tf.insertNodes(nodes);
298
+ }
299
+ return;
300
+ }
301
+ insertData(data);
302
+ } } });
303
+
304
+ //#endregion
305
+ //#region src/lib/withInsertFragmentCodeBlock.ts
306
+ function extractCodeLinesFromCodeBlock(node) {
307
+ return node.children;
308
+ }
309
+ const withInsertFragmentCodeBlock = ({ editor, tf: { insertFragment }, type: codeBlockType }) => ({ transforms: { insertFragment(fragment) {
310
+ const [blockAbove] = editor.api.block() ?? [];
311
+ const codeLineType = editor.getType(KEYS.codeLine);
312
+ function convertNodeToCodeLine(node) {
313
+ return {
314
+ children: [{ text: NodeApi.string(node) }],
315
+ type: codeLineType
316
+ };
317
+ }
318
+ if (blockAbove && [codeBlockType, codeLineType].includes(blockAbove?.type)) return insertFragment(fragment.flatMap((node) => {
319
+ const element = node;
320
+ return element.type === codeBlockType ? extractCodeLinesFromCodeBlock(element) : convertNodeToCodeLine(element);
321
+ }));
322
+ return insertFragment(fragment);
323
+ } } });
324
+
325
+ //#endregion
326
+ //#region src/lib/withNormalizeCodeBlock.tsx
327
+ /** Normalize code block node to force the pre>code>div.codeline structure. */
328
+ const withNormalizeCodeBlock = ({ editor, getOptions, tf: { normalizeNode }, type }) => ({ transforms: { normalizeNode([node, path]) {
329
+ if (node.type === type && getOptions().lowlight) setCodeBlockToDecorations(editor, [node, path]);
330
+ normalizeNode([node, path]);
331
+ if (!ElementApi.isElement(node)) return;
332
+ const codeBlockType = editor.getType(KEYS.codeBlock);
333
+ const codeLineType = editor.getType(KEYS.codeLine);
334
+ if (node.type === codeBlockType) {
335
+ const nonCodeLine = Array.from(NodeApi.children(editor, path)).find(([child]) => child.type !== codeLineType);
336
+ if (nonCodeLine) editor.tf.setNodes({ type: codeLineType }, { at: nonCodeLine[1] });
337
+ }
338
+ } } });
339
+
340
+ //#endregion
341
+ //#region src/lib/withCodeBlock.ts
342
+ const withCodeBlock = (ctx) => {
343
+ const { editor, getOptions, tf: { apply, insertBreak, resetBlock, selectAll, tab }, type } = ctx;
344
+ return { transforms: {
345
+ apply(operation) {
346
+ if (getOptions().lowlight && operation.type === "set_node") {
347
+ const entry = editor.api.node(operation.path);
348
+ if (entry?.[0].type === type && operation.newProperties?.lang) resetCodeBlockDecorations(entry[0]);
349
+ }
350
+ apply(operation);
351
+ },
352
+ insertBreak() {
353
+ const apply$1 = () => {
354
+ if (!editor.selection) return;
355
+ const res = getCodeLineEntry(editor, {});
356
+ if (!res) return;
357
+ const { codeBlock, codeLine } = res;
358
+ const indentDepth = getIndentDepth(editor, {
359
+ codeBlock,
360
+ codeLine
361
+ });
362
+ insertBreak();
363
+ indentCodeLine(editor, {
364
+ codeBlock,
365
+ codeLine,
366
+ indentDepth
367
+ });
368
+ return true;
369
+ };
370
+ if (apply$1()) return;
371
+ insertBreak();
372
+ },
373
+ resetBlock(options) {
374
+ if (editor.api.block({
375
+ at: options?.at,
376
+ match: { type }
377
+ })) {
378
+ unwrapCodeBlock(editor);
379
+ return;
380
+ }
381
+ return resetBlock(options);
382
+ },
383
+ selectAll: () => {
384
+ const apply$1 = () => {
385
+ const codeBlock = editor.api.above({ match: { type } });
386
+ if (!codeBlock) return;
387
+ if (editor.api.isAt({ end: true }) && editor.api.isAt({ start: true })) return;
388
+ editor.tf.select(codeBlock[1]);
389
+ return true;
390
+ };
391
+ if (apply$1()) return true;
392
+ return selectAll();
393
+ },
394
+ tab: (options) => {
395
+ const apply$1 = () => {
396
+ const _codeLines = editor.api.nodes({ match: { type } });
397
+ const codeLines = Array.from(_codeLines);
398
+ if (codeLines.length > 0) {
399
+ const [, firstLinePath] = codeLines[0];
400
+ const codeBlock = editor.api.parent(firstLinePath);
401
+ if (!codeBlock) return;
402
+ editor.tf.withoutNormalizing(() => {
403
+ for (const codeLine of codeLines) if (options.reverse) outdentCodeLine(editor, {
404
+ codeBlock,
405
+ codeLine
406
+ });
407
+ else indentCodeLine(editor, {
408
+ codeBlock,
409
+ codeLine
410
+ });
411
+ });
412
+ return true;
413
+ }
414
+ };
415
+ if (apply$1()) return true;
416
+ return tab(options);
417
+ },
418
+ ...withInsertDataCodeBlock(ctx).transforms,
419
+ ...withInsertFragmentCodeBlock(ctx).transforms,
420
+ ...withNormalizeCodeBlock(ctx).transforms
421
+ } };
422
+ };
423
+
424
+ //#endregion
425
+ //#region src/lib/BaseCodeBlockPlugin.ts
426
+ const BaseCodeLinePlugin = createTSlatePlugin({
427
+ key: KEYS.codeLine,
428
+ node: {
429
+ isElement: true,
430
+ isStrictSiblings: true
431
+ }
432
+ });
433
+ const BaseCodeSyntaxPlugin = createSlatePlugin({
434
+ key: KEYS.codeSyntax,
435
+ node: { isLeaf: true }
436
+ });
437
+ const BaseCodeBlockPlugin = createTSlatePlugin({
438
+ key: KEYS.codeBlock,
439
+ inject: { plugins: { [KEYS.html]: { parser: { query: ({ editor }) => !editor.api.some({ match: { type: editor.getType(KEYS.codeLine) } }) } } } },
440
+ node: { isElement: true },
441
+ options: {
442
+ defaultLanguage: null,
443
+ lowlight: null
444
+ },
445
+ parsers: { html: { deserializer: htmlDeserializerCodeBlock } },
446
+ plugins: [BaseCodeLinePlugin, BaseCodeSyntaxPlugin],
447
+ render: { as: "pre" },
448
+ rules: {
449
+ delete: { empty: "reset" },
450
+ match: ({ editor, rule }) => ["break.empty", "delete.empty"].includes(rule) && isCodeBlockEmpty(editor)
451
+ },
452
+ decorate: ({ editor, entry: [node, path], getOptions, type }) => {
453
+ if (!getOptions().lowlight) return [];
454
+ const codeLineType = editor.getType(KEYS.codeLine);
455
+ if (node.type === type && !CODE_LINE_TO_DECORATIONS.get(node.children[0])) setCodeBlockToDecorations(editor, [node, path]);
456
+ if (node.type === codeLineType) return CODE_LINE_TO_DECORATIONS.get(node) || [];
457
+ return [];
458
+ }
459
+ }).overrideEditor(withCodeBlock).extendTransforms(({ editor }) => ({ toggle: () => {
460
+ editor.tf.toggleBlock(editor.getType(KEYS.codeBlock));
461
+ } }));
462
+
463
+ //#endregion
464
+ export { getIndentDepth as _, withNormalizeCodeBlock as a, unwrapCodeBlock as c, deleteStartSpace as d, CODE_LINE_TO_DECORATIONS as f, isCodeBlockEmpty as g, setCodeBlockToDecorations as h, withCodeBlock as i, outdentCodeLine as l, resetCodeBlockDecorations as m, BaseCodeLinePlugin as n, withInsertFragmentCodeBlock as o, codeBlockToDecorations as p, BaseCodeSyntaxPlugin as r, withInsertDataCodeBlock as s, BaseCodeBlockPlugin as t, indentCodeLine as u, getCodeLineEntry as v, htmlDeserializerCodeBlock as y };
465
+ //# sourceMappingURL=BaseCodeBlockPlugin-BntJ075t.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseCodeBlockPlugin-BntJ075t.js","names":["HtmlDeserializer","KEYS","htmlDeserializerCodeBlock","rules","validNodeName","validStyle","fontFamily","parse","element","languageSelectorText","childNodes","find","node","ChildNode","nodeName","textContent","replace","lines","split","length","codeLines","map","line","children","text","type","codeLine","codeBlock","ElementOf","NodeEntry","SlateEditor","TElement","TLocation","ElementApi","KEYS","getCodeLineEntry","E","editor","at","selection","api","some","match","type","getType","codeLine","selectionParent","parent","parentPath","above","N","codeLineNode","codeLinePath","isElement","codeBlock","Editor","IndentCodeLineOptions","nonWhitespaceOrEndRegex","getIndentDepth","editor","codeLine","codeLinePath","text","api","string","search","SlateEditor","NodeApi","getCodeLineEntry","isCodeBlockEmpty","editor","codeBlock","codeLines","Array","from","children","length","firstCodeLineNode","string","DecoratedRange","NodeEntry","SlateEditor","TCodeBlockElement","TElement","KEYS","NodeApi","BaseCodeBlockPlugin","CODE_LINE_TO_DECORATIONS","WeakMap","getHighlightNodes","result","value","children","parseNodes","nodes","className","classes","text","flatMap","node","properties","normalizeTokens","tokens","lines","content","currentLine","token","tokenLines","split","i","length","push","at","codeBlockToDecorations","editor","block","blockPath","Map","defaultLanguage","options","getOptions","lowlight","map","line","string","join","language","lang","effectiveLanguage","highlighted","highlightAuto","highlight","error","availableLanguages","listLanguages","isLanguageRegistered","includes","api","debug","warn","normalizedTokens","blockChildren","nodeToDecorations","numLines","Math","min","index","lineTokens","element","has","set","start","end","decoration","anchor","offset","path","focus","codeSyntax","get","setCodeBlockToDecorations","decorations","decs","entries","resetCodeBlockDecorations","codeBlock","forEach","delete","Editor","OutdentCodeLineOptions","whitespaceRegex","deleteStartSpace","editor","codeLine","codeLinePath","codeLineStart","api","start","codeLineEnd","after","spaceRange","range","spaceText","string","test","tf","delete","at","Editor","ElementEntry","nonWhitespaceRegex","IndentCodeLineOptions","codeBlock","codeLine","indentDepth","indentCodeLine","editor","codeLinePath","codeLineStart","api","start","indent","repeat","isExpanded","cursor","selection","anchor","range","text","string","test","tf","insertText","at","Editor","ElementEntry","deleteStartSpace","OutdentCodeLineOptions","codeBlock","codeLine","outdentCodeLine","editor","deleted","SlateEditor","TLocation","KEYS","NodeApi","unwrapCodeBlock","editor","selection","codeBlockType","getType","codeBlock","defaultType","p","tf","withoutNormalizing","codeBlockEntries","api","nodes","at","match","type","reversedCodeBlockEntries","Array","from","reverse","codeBlockEntry","codeLineEntries","children","path","setNodes","unwrapNodes","split","OverrideEditor","TElement","KEYS","withInsertDataCodeBlock","editor","tf","insertData","type","codeBlockType","transforms","data","text","getData","vscodeDataString","codeLineType","getType","codeLine","vscodeData","JSON","parse","lines","split","blockAbove","api","block","isInCodeBlock","includes","insertText","length","nodes","slice","map","line","children","insertNodes","node","lang","mode","select","_error","OverrideEditor","TElement","KEYS","NodeApi","extractCodeLinesFromCodeBlock","node","children","withInsertFragmentCodeBlock","editor","tf","insertFragment","type","codeBlockType","transforms","fragment","blockAbove","api","block","codeLineType","getType","codeLine","convertNodeToCodeLine","text","string","includes","flatMap","element","NodeEntry","OverrideEditor","TCodeBlockElement","ElementApi","KEYS","NodeApi","CodeBlockConfig","setCodeBlockToDecorations","withNormalizeCodeBlock","editor","getOptions","tf","normalizeNode","type","transforms","node","path","lowlight","isElement","codeBlockType","getType","codeBlock","codeLineType","codeLine","isCodeBlockRoot","nonCodeLine","Array","from","children","find","child","setNodes","at","OverrideEditor","TCodeBlockElement","TElement","CodeBlockConfig","getCodeLineEntry","getIndentDepth","resetCodeBlockDecorations","indentCodeLine","outdentCodeLine","unwrapCodeBlock","withInsertDataCodeBlock","withInsertFragmentCodeBlock","withNormalizeCodeBlock","withCodeBlock","ctx","editor","getOptions","tf","apply","insertBreak","resetBlock","selectAll","tab","type","transforms","operation","lowlight","entry","api","node","path","newProperties","lang","selection","res","codeBlock","codeLine","indentDepth","options","block","at","match","above","isAt","end","start","select","_codeLines","nodes","codeLines","Array","from","length","firstLinePath","parent","withoutNormalizing","reverse","createLowlight","PluginConfig","TCodeBlockElement","TElement","createSlatePlugin","createTSlatePlugin","KEYS","htmlDeserializerCodeBlock","isCodeBlockEmpty","CODE_LINE_TO_DECORATIONS","setCodeBlockToDecorations","withCodeBlock","CodeBlockConfig","defaultLanguage","lowlight","ReturnType","BaseCodeLinePlugin","key","codeLine","node","isElement","isStrictSiblings","BaseCodeSyntaxPlugin","codeSyntax","isLeaf","BaseCodeBlockPlugin","codeBlock","inject","plugins","html","parser","query","editor","api","some","match","type","getType","options","parsers","deserializer","render","as","rules","delete","empty","rule","includes","decorate","entry","path","getOptions","codeLineType","get","children","overrideEditor","extendTransforms","toggle","tf","toggleBlock"],"sources":["../src/lib/deserializer/htmlDeserializerCodeBlock.ts","../src/lib/queries/getCodeLineEntry.ts","../src/lib/queries/getIndentDepth.ts","../src/lib/queries/isCodeBlockEmpty.ts","../src/lib/setCodeBlockToDecorations.ts","../src/lib/transforms/deleteStartSpace.ts","../src/lib/transforms/indentCodeLine.ts","../src/lib/transforms/outdentCodeLine.ts","../src/lib/transforms/unwrapCodeBlock.ts","../src/lib/withInsertDataCodeBlock.ts","../src/lib/withInsertFragmentCodeBlock.ts","../src/lib/withNormalizeCodeBlock.tsx","../src/lib/withCodeBlock.ts","../src/lib/BaseCodeBlockPlugin.ts"],"sourcesContent":["import type { HtmlDeserializer } from 'platejs';\n\nimport { KEYS } from 'platejs';\n\nexport const htmlDeserializerCodeBlock: HtmlDeserializer = {\n rules: [\n {\n validNodeName: 'PRE',\n },\n {\n validNodeName: 'P',\n validStyle: {\n fontFamily: 'Consolas',\n },\n },\n ],\n parse: ({ element }) => {\n const languageSelectorText =\n [...element.childNodes].find(\n (node: ChildNode) => node.nodeName === 'SELECT'\n )?.textContent || '';\n\n const textContent =\n element.textContent?.replace(languageSelectorText, '') || '';\n\n let lines = textContent.split('\\n');\n\n if (!lines?.length) {\n lines = [textContent];\n }\n\n const codeLines = lines.map((line) => ({\n children: [{ text: line }],\n type: KEYS.codeLine,\n }));\n\n return {\n children: codeLines,\n type: KEYS.codeBlock,\n };\n },\n};\n","import {\n type ElementOf,\n type NodeEntry,\n type SlateEditor,\n type TElement,\n type TLocation,\n ElementApi,\n KEYS,\n} from 'platejs';\n\n/** If at (default = selection) is in ul>li>p, return li and ul node entries. */\nexport const getCodeLineEntry = <N extends ElementOf<E>, E extends SlateEditor>(\n editor: E,\n { at = editor.selection }: { at?: TLocation | null } = {}\n) => {\n if (\n at &&\n editor.api.some({\n at,\n match: { type: editor.getType(KEYS.codeLine) },\n })\n ) {\n const selectionParent = editor.api.parent(at);\n\n if (!selectionParent) return;\n\n const [, parentPath] = selectionParent;\n\n const codeLine =\n editor.api.above<TElement>({\n at,\n match: { type: editor.getType(KEYS.codeLine) },\n }) || editor.api.parent<N>(parentPath);\n\n if (!codeLine) return;\n\n const [codeLineNode, codeLinePath] = codeLine;\n\n if (\n ElementApi.isElement(codeLineNode) &&\n codeLineNode.type !== editor.getType(KEYS.codeLine)\n )\n return;\n\n const codeBlock = editor.api.parent<N>(codeLinePath);\n\n if (!codeBlock) return;\n\n return {\n codeBlock,\n codeLine: codeLine as NodeEntry<N>,\n };\n }\n};\n","import type { Editor } from 'platejs';\n\nimport type { IndentCodeLineOptions } from '../transforms/indentCodeLine';\n\nconst nonWhitespaceOrEndRegex = /\\S|$/;\n\nexport const getIndentDepth = (\n editor: Editor,\n { codeLine }: IndentCodeLineOptions\n) => {\n const [, codeLinePath] = codeLine;\n const text = editor.api.string(codeLinePath);\n\n return text.search(nonWhitespaceOrEndRegex);\n};\n","import { type SlateEditor, NodeApi } from 'platejs';\n\nimport { getCodeLineEntry } from './getCodeLineEntry';\n\n/** Is the selection inside an empty code block */\nexport const isCodeBlockEmpty = (editor: SlateEditor) => {\n const { codeBlock } = getCodeLineEntry(editor) ?? {};\n\n if (!codeBlock) return false;\n\n const codeLines = Array.from(NodeApi.children(editor, codeBlock[1]));\n\n if (codeLines.length === 0) return true;\n if (codeLines.length > 1) return false;\n\n const firstCodeLineNode = codeLines[0][0];\n\n return !NodeApi.string(firstCodeLineNode);\n};\n","import {\n type DecoratedRange,\n type NodeEntry,\n type SlateEditor,\n type TCodeBlockElement,\n type TElement,\n KEYS,\n NodeApi,\n} from 'platejs';\n\nimport { BaseCodeBlockPlugin } from './BaseCodeBlockPlugin';\n\n// Cache for storing decorations per code line element\nexport const CODE_LINE_TO_DECORATIONS: WeakMap<TElement, DecoratedRange[]> =\n new WeakMap();\n\n// Helper function to get highlight nodes from Lowlight result\nfunction getHighlightNodes(result: any) {\n return result.value || result.children || [];\n}\n\n// Helper function to parse nodes from Lowlight's hast tree\nfunction parseNodes(\n nodes: any[],\n className: string[] = []\n): { classes: string[]; text: string }[] {\n return nodes.flatMap((node) => {\n const classes = [\n ...className,\n ...(node.properties ? node.properties.className : []),\n ];\n if (node.children) {\n return parseNodes(node.children, classes);\n }\n return { classes, text: node.value };\n });\n}\n\n// Helper function to normalize tokens by line\nfunction normalizeTokens(tokens: { classes: string[]; text: string }[]) {\n const lines: { classes: string[]; content: string }[][] = [[]];\n let currentLine = lines[0];\n\n for (const token of tokens) {\n const tokenLines = token.text.split('\\n');\n\n for (let i = 0; i < tokenLines.length; i++) {\n const content = tokenLines[i];\n\n if (content) {\n currentLine.push({ classes: token.classes, content });\n }\n\n // Create a new line unless we're on the last line\n if (i < tokenLines.length - 1) {\n lines.push([]);\n currentLine = lines.at(-1) as any;\n }\n }\n }\n\n return lines;\n}\n\n// Helper function to compute decorations for a code block\nexport function codeBlockToDecorations(\n editor: SlateEditor,\n [block, blockPath]: NodeEntry<TCodeBlockElement>\n): Map<TElement, DecoratedRange[]> {\n const { defaultLanguage, ...options } =\n editor.getOptions(BaseCodeBlockPlugin);\n const lowlight = options.lowlight!;\n\n // Get all code lines and combine their text\n const text = block.children.map((line) => NodeApi.string(line)).join('\\n');\n const language = block.lang;\n const effectiveLanguage = language || defaultLanguage;\n\n let highlighted: any;\n try {\n // Skip highlighting for plaintext or when no language is specified\n if (!effectiveLanguage || effectiveLanguage === 'plaintext') {\n highlighted = { value: [] }; // Empty result for plaintext\n } else if (effectiveLanguage === 'auto') {\n highlighted = lowlight.highlightAuto(text);\n } else {\n highlighted = lowlight.highlight(effectiveLanguage, text);\n }\n } catch (error) {\n // Verify if language is registered, fallback to plaintext if not\n const availableLanguages = lowlight.listLanguages();\n const isLanguageRegistered =\n effectiveLanguage && availableLanguages.includes(effectiveLanguage);\n if (isLanguageRegistered) {\n editor.api.debug.error(error, 'CODE_HIGHLIGHT');\n highlighted = { value: [] }; // Empty result on error\n } else {\n editor.api.debug.warn(\n `Language \"${effectiveLanguage}\" is not registered. Falling back to plaintext`\n );\n highlighted = { value: [] };\n }\n }\n\n // Parse and normalize tokens\n const tokens = parseNodes(getHighlightNodes(highlighted));\n const normalizedTokens = normalizeTokens(tokens);\n const blockChildren = block.children as TElement[];\n\n // Create decorations map\n const nodeToDecorations = new Map<TElement, DecoratedRange[]>();\n\n // Safety check: don't process more lines than we have children\n const numLines = Math.min(normalizedTokens.length, blockChildren.length);\n\n // Process each line's tokens\n for (let index = 0; index < numLines; index++) {\n const lineTokens = normalizedTokens[index];\n const element = blockChildren[index];\n\n if (!nodeToDecorations.has(element)) {\n nodeToDecorations.set(element, []);\n }\n\n let start = 0;\n for (const token of lineTokens) {\n const length = token.content.length;\n if (!length) continue;\n\n const end = start + length;\n\n const decoration: DecoratedRange = {\n anchor: {\n offset: start,\n path: [...blockPath, index, 0],\n },\n className: token.classes.join(' '),\n focus: {\n offset: end,\n path: [...blockPath, index, 0],\n },\n [KEYS.codeSyntax]: true,\n } as any;\n\n nodeToDecorations.get(element)!.push(decoration);\n start = end;\n }\n }\n\n return nodeToDecorations;\n}\n\nexport function setCodeBlockToDecorations(\n editor: SlateEditor,\n [block, blockPath]: NodeEntry<TCodeBlockElement>\n) {\n const decorations = codeBlockToDecorations(editor, [block, blockPath]);\n\n // Update the global cache with the new decorations\n for (const [node, decs] of decorations.entries()) {\n CODE_LINE_TO_DECORATIONS.set(node, decs);\n }\n}\n\nexport function resetCodeBlockDecorations(codeBlock: TCodeBlockElement) {\n codeBlock.children.forEach((line) => {\n CODE_LINE_TO_DECORATIONS.delete(line as TElement);\n });\n}\n","import type { Editor } from 'platejs';\n\nimport type { OutdentCodeLineOptions } from './outdentCodeLine';\n\nconst whitespaceRegex = /\\s/;\n\n/** If there is a whitespace character at the start of the code line, delete it. */\nexport const deleteStartSpace = (\n editor: Editor,\n { codeLine }: OutdentCodeLineOptions\n) => {\n const [, codeLinePath] = codeLine;\n const codeLineStart = editor.api.start(codeLinePath);\n const codeLineEnd = codeLineStart && editor.api.after(codeLineStart);\n const spaceRange =\n codeLineEnd && editor.api.range(codeLineStart, codeLineEnd);\n const spaceText = editor.api.string(spaceRange);\n\n if (whitespaceRegex.test(spaceText)) {\n editor.tf.delete({ at: spaceRange });\n\n return true;\n }\n\n return false;\n};\n","import type { Editor, ElementEntry } from 'platejs';\n\nconst nonWhitespaceRegex = /\\S/;\n\nexport type IndentCodeLineOptions = {\n codeBlock: ElementEntry;\n codeLine: ElementEntry;\n indentDepth?: number;\n};\n\n/**\n * Indent if:\n *\n * - The selection is expanded OR\n * - There are no non-whitespace characters left of the cursor Indentation = 2\n * spaces.\n */\nexport const indentCodeLine = (\n editor: Editor,\n { codeLine, indentDepth = 2 }: IndentCodeLineOptions\n) => {\n const [, codeLinePath] = codeLine;\n const codeLineStart = editor.api.start(codeLinePath)!;\n const indent = ' '.repeat(indentDepth);\n\n if (!editor.api.isExpanded()) {\n const cursor = editor.selection?.anchor;\n const range = editor.api.range(codeLineStart, cursor);\n const text = editor.api.string(range);\n\n if (nonWhitespaceRegex.test(text)) {\n editor.tf.insertText(indent, { at: editor.selection! });\n\n return;\n }\n }\n\n editor.tf.insertText(indent, { at: codeLineStart });\n};\n","import type { Editor, ElementEntry } from 'platejs';\n\nimport { deleteStartSpace } from './deleteStartSpace';\n\nexport type OutdentCodeLineOptions = {\n codeBlock: ElementEntry;\n codeLine: ElementEntry;\n};\n\n/** Outdent the code line. Remove 2 whitespace characters if any. */\nexport const outdentCodeLine = (\n editor: Editor,\n { codeBlock, codeLine }: OutdentCodeLineOptions\n) => {\n const deleted = deleteStartSpace(editor, { codeBlock, codeLine });\n if (deleted) {\n deleteStartSpace(editor, { codeBlock, codeLine });\n }\n};\n","import { type SlateEditor, type TLocation, KEYS, NodeApi } from 'platejs';\n\nexport const unwrapCodeBlock = (editor: SlateEditor) => {\n if (!editor.selection) return;\n\n const codeBlockType = editor.getType(KEYS.codeBlock);\n const defaultType = editor.getType(KEYS.p);\n\n editor.tf.withoutNormalizing(() => {\n const codeBlockEntries = editor.api.nodes({\n at: editor.selection as TLocation,\n match: { type: codeBlockType },\n });\n\n const reversedCodeBlockEntries = Array.from(codeBlockEntries).reverse();\n\n for (const codeBlockEntry of reversedCodeBlockEntries) {\n const codeLineEntries = NodeApi.children(editor, codeBlockEntry[1]);\n\n for (const [, path] of codeLineEntries) {\n editor.tf.setNodes({ type: defaultType }, { at: path });\n }\n\n editor.tf.unwrapNodes({\n at: codeBlockEntry[1],\n match: { type: codeBlockType },\n split: true,\n });\n }\n });\n};\n","import type { OverrideEditor, TElement } from 'platejs';\n\nimport { KEYS } from 'platejs';\n\nexport const withInsertDataCodeBlock: OverrideEditor = ({\n editor,\n tf: { insertData },\n type: codeBlockType,\n}) => ({\n transforms: {\n insertData(data) {\n const text = data.getData('text/plain');\n const vscodeDataString = data.getData('vscode-editor-data');\n const codeLineType = editor.getType(KEYS.codeLine);\n\n // Handle VSCode paste with language\n if (vscodeDataString) {\n try {\n const vscodeData = JSON.parse(vscodeDataString);\n const lines = text.split('\\n');\n\n // Check if we're in a code block\n const [blockAbove] = editor.api.block<TElement>() ?? [];\n const isInCodeBlock =\n blockAbove &&\n [codeBlockType, codeLineType].includes(blockAbove?.type);\n\n if (isInCodeBlock) {\n // If in code block, insert first line as text at cursor\n if (lines[0]) {\n editor.tf.insertText(lines[0]);\n }\n\n // Insert remaining lines as new code lines\n if (lines.length > 1) {\n const nodes = lines.slice(1).map((line) => ({\n children: [{ text: line }],\n type: codeLineType,\n }));\n editor.tf.insertNodes(nodes);\n }\n } else {\n // Create new code block\n const node = {\n children: lines.map((line) => ({\n children: [{ text: line }],\n type: codeLineType,\n })),\n lang: vscodeData?.mode,\n type: codeBlockType,\n };\n\n editor.tf.insertNodes(node, {\n select: true,\n });\n }\n\n return;\n } catch (_error) {}\n }\n\n // Handle plain text paste into code block only if there are line breaks\n const [blockAbove] = editor.api.block<TElement>() ?? [];\n if (\n blockAbove &&\n [codeBlockType, codeLineType].includes(blockAbove?.type) &&\n text?.includes('\\n')\n ) {\n const lines = text.split('\\n');\n\n // Insert first line as text at cursor\n if (lines[0]) {\n editor.tf.insertText(lines[0]);\n }\n\n // Insert remaining lines as new code lines\n if (lines.length > 1) {\n const nodes = lines.slice(1).map((line) => ({\n children: [{ text: line }],\n type: codeLineType,\n }));\n editor.tf.insertNodes(nodes);\n }\n return;\n }\n\n insertData(data);\n },\n },\n});\n","import { type OverrideEditor, type TElement, KEYS, NodeApi } from 'platejs';\n\nfunction extractCodeLinesFromCodeBlock(node: TElement) {\n return node.children as TElement[];\n}\n\nexport const withInsertFragmentCodeBlock: OverrideEditor = ({\n editor,\n tf: { insertFragment },\n type: codeBlockType,\n}) => ({\n transforms: {\n insertFragment(fragment) {\n const [blockAbove] = editor.api.block<TElement>() ?? [];\n const codeLineType = editor.getType(KEYS.codeLine);\n\n function convertNodeToCodeLine(node: TElement): TElement {\n return {\n children: [{ text: NodeApi.string(node) }],\n type: codeLineType,\n };\n }\n\n if (\n blockAbove &&\n [codeBlockType, codeLineType].includes(blockAbove?.type)\n ) {\n return insertFragment(\n fragment.flatMap((node) => {\n const element = node as TElement;\n\n return element.type === codeBlockType\n ? extractCodeLinesFromCodeBlock(element)\n : convertNodeToCodeLine(element);\n })\n );\n }\n\n return insertFragment(fragment);\n },\n },\n});\n","import {\n type NodeEntry,\n type OverrideEditor,\n type TCodeBlockElement,\n ElementApi,\n KEYS,\n NodeApi,\n} from 'platejs';\n\nimport type { CodeBlockConfig } from './BaseCodeBlockPlugin';\n\nimport { setCodeBlockToDecorations } from './setCodeBlockToDecorations';\n\n/** Normalize code block node to force the pre>code>div.codeline structure. */\nexport const withNormalizeCodeBlock: OverrideEditor<CodeBlockConfig> = ({\n editor,\n getOptions,\n tf: { normalizeNode },\n type,\n}) => ({\n transforms: {\n normalizeNode([node, path]) {\n // Decorate is called on selection change as well, so we prefer to only run this on code block changes.\n if (node.type === type && getOptions().lowlight) {\n setCodeBlockToDecorations(editor, [\n node,\n path,\n ] as NodeEntry<TCodeBlockElement>);\n }\n\n normalizeNode([node, path]);\n\n if (!ElementApi.isElement(node)) {\n return;\n }\n\n const codeBlockType = editor.getType(KEYS.codeBlock);\n const codeLineType = editor.getType(KEYS.codeLine);\n const isCodeBlockRoot = node.type === codeBlockType;\n\n if (isCodeBlockRoot) {\n // Children should all be code lines\n const nonCodeLine = Array.from(NodeApi.children(editor, path)).find(\n ([child]) => child.type !== codeLineType\n );\n\n if (nonCodeLine) {\n editor.tf.setNodes({ type: codeLineType }, { at: nonCodeLine[1] });\n }\n }\n },\n },\n});\n","import type { OverrideEditor, TCodeBlockElement, TElement } from 'platejs';\n\nimport type { CodeBlockConfig } from './BaseCodeBlockPlugin';\n\nimport { getCodeLineEntry, getIndentDepth } from './queries';\nimport { resetCodeBlockDecorations } from './setCodeBlockToDecorations';\nimport { indentCodeLine, outdentCodeLine, unwrapCodeBlock } from './transforms';\nimport { withInsertDataCodeBlock } from './withInsertDataCodeBlock';\nimport { withInsertFragmentCodeBlock } from './withInsertFragmentCodeBlock';\nimport { withNormalizeCodeBlock } from './withNormalizeCodeBlock';\n\nexport const withCodeBlock: OverrideEditor<CodeBlockConfig> = (ctx) => {\n const {\n editor,\n getOptions,\n tf: { apply, insertBreak, resetBlock, selectAll, tab },\n type,\n } = ctx;\n\n return {\n transforms: {\n apply(operation) {\n if (getOptions().lowlight && operation.type === 'set_node') {\n const entry = editor.api.node(operation.path);\n\n if (entry?.[0].type === type && operation.newProperties?.lang) {\n // Clear decorations for all code lines in this block\n resetCodeBlockDecorations(entry[0] as TCodeBlockElement);\n }\n }\n\n apply(operation);\n },\n insertBreak() {\n const apply = () => {\n if (!editor.selection) return;\n\n const res = getCodeLineEntry(editor, {});\n\n if (!res) return;\n\n const { codeBlock, codeLine } = res;\n const indentDepth = getIndentDepth(editor, {\n codeBlock,\n codeLine,\n });\n\n insertBreak();\n\n indentCodeLine(editor, {\n codeBlock,\n codeLine,\n indentDepth,\n });\n\n return true;\n };\n\n if (apply()) return;\n\n insertBreak();\n },\n resetBlock(options) {\n if (\n editor.api.block({\n at: options?.at,\n match: { type },\n })\n ) {\n unwrapCodeBlock(editor);\n return;\n }\n\n return resetBlock(options);\n },\n selectAll: () => {\n const apply = () => {\n const codeBlock = editor.api.above({\n match: { type },\n });\n\n if (!codeBlock) return;\n\n if (\n editor.api.isAt({ end: true }) &&\n editor.api.isAt({ start: true })\n ) {\n return;\n }\n\n // Select the whole code block\n editor.tf.select(codeBlock[1]);\n return true;\n };\n\n if (apply()) return true;\n\n return selectAll();\n },\n tab: (options) => {\n const apply = () => {\n const _codeLines = editor.api.nodes<TElement>({\n match: { type },\n });\n const codeLines = Array.from(_codeLines);\n\n if (codeLines.length > 0) {\n const [, firstLinePath] = codeLines[0];\n const codeBlock = editor.api.parent<TElement>(firstLinePath);\n\n if (!codeBlock) return;\n\n editor.tf.withoutNormalizing(() => {\n for (const codeLine of codeLines) {\n if (options.reverse) {\n outdentCodeLine(editor, { codeBlock, codeLine });\n } else {\n indentCodeLine(editor, { codeBlock, codeLine });\n }\n }\n });\n\n return true; // Prevent default\n }\n };\n\n if (apply()) return true;\n\n return tab(options);\n },\n ...withInsertDataCodeBlock(ctx).transforms,\n ...withInsertFragmentCodeBlock(ctx).transforms,\n ...withNormalizeCodeBlock(ctx).transforms,\n },\n };\n};\n","import type { createLowlight } from 'lowlight';\n\nimport {\n type PluginConfig,\n type TCodeBlockElement,\n type TElement,\n createSlatePlugin,\n createTSlatePlugin,\n KEYS,\n} from 'platejs';\n\nimport { htmlDeserializerCodeBlock } from './deserializer/htmlDeserializerCodeBlock';\nimport { isCodeBlockEmpty } from './queries';\nimport {\n CODE_LINE_TO_DECORATIONS,\n setCodeBlockToDecorations,\n} from './setCodeBlockToDecorations';\nimport { withCodeBlock } from './withCodeBlock';\n\nexport type CodeBlockConfig = PluginConfig<\n 'code_block',\n {\n /**\n * Default language to use when no language is specified. Set to null to\n * disable syntax highlighting by default.\n */\n defaultLanguage?: string | null;\n /**\n * Lowlight instance to use for highlighting. If not provided, syntax\n * highlighting will be disabled.\n */\n lowlight?: ReturnType<typeof createLowlight> | null;\n }\n>;\n\nexport const BaseCodeLinePlugin = createTSlatePlugin({\n key: KEYS.codeLine,\n node: { isElement: true, isStrictSiblings: true },\n});\n\nexport const BaseCodeSyntaxPlugin = createSlatePlugin({\n key: KEYS.codeSyntax,\n node: { isLeaf: true },\n});\n\nexport const BaseCodeBlockPlugin = createTSlatePlugin<CodeBlockConfig>({\n key: KEYS.codeBlock,\n inject: {\n plugins: {\n [KEYS.html]: {\n parser: {\n query: ({ editor }) =>\n !editor.api.some({\n match: { type: editor.getType(KEYS.codeLine) },\n }),\n },\n },\n },\n },\n node: {\n isElement: true,\n },\n options: {\n defaultLanguage: null,\n lowlight: null,\n },\n parsers: { html: { deserializer: htmlDeserializerCodeBlock } },\n plugins: [BaseCodeLinePlugin, BaseCodeSyntaxPlugin],\n render: { as: 'pre' },\n rules: {\n delete: {\n empty: 'reset',\n },\n match: ({ editor, rule }) =>\n ['break.empty', 'delete.empty'].includes(rule) &&\n isCodeBlockEmpty(editor),\n },\n decorate: ({ editor, entry: [node, path], getOptions, type }) => {\n if (!getOptions().lowlight) return [];\n\n const codeLineType = editor.getType(KEYS.codeLine);\n\n // Initialize decorations for the code block, we assume code line decorate will be called next.\n if (\n node.type === type &&\n !CODE_LINE_TO_DECORATIONS.get((node.children as TElement[])[0])\n ) {\n setCodeBlockToDecorations(editor, [node as TCodeBlockElement, path]);\n }\n\n if (node.type === codeLineType) {\n return CODE_LINE_TO_DECORATIONS.get(node as TElement) || [];\n }\n\n return [];\n },\n})\n .overrideEditor(withCodeBlock)\n .extendTransforms(({ editor }) => ({\n toggle: () => {\n editor.tf.toggleBlock(editor.getType(KEYS.codeBlock));\n },\n }));\n"],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ import { DecoratedRange, Editor, ElementEntry, ElementOf, HtmlDeserializer, InsertNodesOptions, NodeEntry, OverrideEditor, PluginConfig, SlateEditor, TCodeBlockElement, TElement, TLocation } from "platejs";
2
+ import { createLowlight } from "lowlight";
3
+
4
+ //#region src/lib/BaseCodeBlockPlugin.d.ts
5
+ type CodeBlockConfig = PluginConfig<'code_block', {
6
+ /**
7
+ * Default language to use when no language is specified. Set to null to
8
+ * disable syntax highlighting by default.
9
+ */
10
+ defaultLanguage?: string | null;
11
+ /**
12
+ * Lowlight instance to use for highlighting. If not provided, syntax
13
+ * highlighting will be disabled.
14
+ */
15
+ lowlight?: ReturnType<typeof createLowlight> | null;
16
+ }>;
17
+ declare const BaseCodeLinePlugin: any;
18
+ declare const BaseCodeSyntaxPlugin: any;
19
+ declare const BaseCodeBlockPlugin: any;
20
+ //#endregion
21
+ //#region src/lib/setCodeBlockToDecorations.d.ts
22
+ declare const CODE_LINE_TO_DECORATIONS: WeakMap<TElement, DecoratedRange[]>;
23
+ declare function codeBlockToDecorations(editor: SlateEditor, [block, blockPath]: NodeEntry<TCodeBlockElement>): Map<TElement, DecoratedRange[]>;
24
+ declare function setCodeBlockToDecorations(editor: SlateEditor, [block, blockPath]: NodeEntry<TCodeBlockElement>): void;
25
+ declare function resetCodeBlockDecorations(codeBlock: TCodeBlockElement): void;
26
+ //#endregion
27
+ //#region src/lib/withCodeBlock.d.ts
28
+ declare const withCodeBlock: OverrideEditor<CodeBlockConfig>;
29
+ //#endregion
30
+ //#region src/lib/withInsertDataCodeBlock.d.ts
31
+ declare const withInsertDataCodeBlock: OverrideEditor;
32
+ //#endregion
33
+ //#region src/lib/withInsertFragmentCodeBlock.d.ts
34
+ declare const withInsertFragmentCodeBlock: OverrideEditor;
35
+ //#endregion
36
+ //#region src/lib/withNormalizeCodeBlock.d.ts
37
+ /** Normalize code block node to force the pre>code>div.codeline structure. */
38
+ declare const withNormalizeCodeBlock: OverrideEditor<CodeBlockConfig>;
39
+ //#endregion
40
+ //#region src/lib/deserializer/htmlDeserializerCodeBlock.d.ts
41
+ declare const htmlDeserializerCodeBlock: HtmlDeserializer;
42
+ //#endregion
43
+ //#region src/lib/formatter/formatter.d.ts
44
+ declare const isLangSupported: (lang?: string) => boolean;
45
+ declare const isValidSyntax: (code: string, lang?: string) => boolean;
46
+ declare const formatCodeBlock: (editor: Editor, {
47
+ element
48
+ }: {
49
+ element: TCodeBlockElement;
50
+ }) => void;
51
+ //#endregion
52
+ //#region src/lib/formatter/jsonFormatter.d.ts
53
+ declare const formatJson: (code: string) => string;
54
+ declare const isValidJson: (code: string) => boolean;
55
+ //#endregion
56
+ //#region src/lib/queries/getCodeLineEntry.d.ts
57
+ /** If at (default = selection) is in ul>li>p, return li and ul node entries. */
58
+ declare const getCodeLineEntry: <N extends ElementOf<E>, E extends SlateEditor>(editor: E, {
59
+ at
60
+ }?: {
61
+ at?: TLocation | null;
62
+ }) => {
63
+ codeBlock: any;
64
+ codeLine: NodeEntry<N>;
65
+ } | undefined;
66
+ //#endregion
67
+ //#region src/lib/transforms/indentCodeLine.d.ts
68
+ type IndentCodeLineOptions = {
69
+ codeBlock: ElementEntry;
70
+ codeLine: ElementEntry;
71
+ indentDepth?: number;
72
+ };
73
+ /**
74
+ * Indent if:
75
+ *
76
+ * - The selection is expanded OR
77
+ * - There are no non-whitespace characters left of the cursor Indentation = 2
78
+ * spaces.
79
+ */
80
+ declare const indentCodeLine: (editor: Editor, {
81
+ codeLine,
82
+ indentDepth
83
+ }: IndentCodeLineOptions) => void;
84
+ //#endregion
85
+ //#region src/lib/queries/getIndentDepth.d.ts
86
+ declare const getIndentDepth: (editor: Editor, {
87
+ codeLine
88
+ }: IndentCodeLineOptions) => any;
89
+ //#endregion
90
+ //#region src/lib/queries/isCodeBlockEmpty.d.ts
91
+ /** Is the selection inside an empty code block */
92
+ declare const isCodeBlockEmpty: (editor: SlateEditor) => boolean;
93
+ //#endregion
94
+ //#region src/lib/queries/isSelectionAtCodeBlockStart.d.ts
95
+ /** Is the selection at the start of the first code line in a code block */
96
+ declare const isSelectionAtCodeBlockStart: (editor: SlateEditor) => any;
97
+ //#endregion
98
+ //#region src/lib/transforms/outdentCodeLine.d.ts
99
+ type OutdentCodeLineOptions = {
100
+ codeBlock: ElementEntry;
101
+ codeLine: ElementEntry;
102
+ };
103
+ /** Outdent the code line. Remove 2 whitespace characters if any. */
104
+ declare const outdentCodeLine: (editor: Editor, {
105
+ codeBlock,
106
+ codeLine
107
+ }: OutdentCodeLineOptions) => void;
108
+ //#endregion
109
+ //#region src/lib/transforms/deleteStartSpace.d.ts
110
+ /** If there is a whitespace character at the start of the code line, delete it. */
111
+ declare const deleteStartSpace: (editor: Editor, {
112
+ codeLine
113
+ }: OutdentCodeLineOptions) => boolean;
114
+ //#endregion
115
+ //#region src/lib/transforms/insertCodeBlock.d.ts
116
+ /**
117
+ * Insert a code block: set the node to code line and wrap it with a code block.
118
+ * If the cursor is not at the block start, insert break before.
119
+ */
120
+ declare const insertCodeBlock: (editor: SlateEditor, insertNodesOptions?: Omit<InsertNodesOptions, "match">) => void;
121
+ //#endregion
122
+ //#region src/lib/transforms/insertCodeLine.d.ts
123
+ /** Insert a code line starting with indentation. */
124
+ declare const insertCodeLine: (editor: SlateEditor, indentDepth?: number) => void;
125
+ //#endregion
126
+ //#region src/lib/transforms/insertEmptyCodeBlock.d.ts
127
+ type CodeBlockInsertOptions = {
128
+ defaultType?: string;
129
+ insertNodesOptions?: Omit<InsertNodesOptions, 'match'>;
130
+ };
131
+ /**
132
+ * Called by toolbars to make sure a code-block gets inserted below a paragraph
133
+ * rather than awkwardly splitting the current selection.
134
+ */
135
+ declare const insertEmptyCodeBlock: (editor: SlateEditor, {
136
+ defaultType,
137
+ insertNodesOptions
138
+ }?: CodeBlockInsertOptions) => void;
139
+ //#endregion
140
+ //#region src/lib/transforms/toggleCodeBlock.d.ts
141
+ declare const toggleCodeBlock: (editor: SlateEditor) => void;
142
+ //#endregion
143
+ //#region src/lib/transforms/unwrapCodeBlock.d.ts
144
+ declare const unwrapCodeBlock: (editor: SlateEditor) => void;
145
+ //#endregion
146
+ export { BaseCodeBlockPlugin, BaseCodeLinePlugin, BaseCodeSyntaxPlugin, CODE_LINE_TO_DECORATIONS, CodeBlockConfig, CodeBlockInsertOptions, IndentCodeLineOptions, OutdentCodeLineOptions, codeBlockToDecorations, deleteStartSpace, formatCodeBlock, formatJson, getCodeLineEntry, getIndentDepth, htmlDeserializerCodeBlock, indentCodeLine, insertCodeBlock, insertCodeLine, insertEmptyCodeBlock, isCodeBlockEmpty, isLangSupported, isSelectionAtCodeBlockStart, isValidJson, isValidSyntax, outdentCodeLine, resetCodeBlockDecorations, setCodeBlockToDecorations, toggleCodeBlock, unwrapCodeBlock, withCodeBlock, withInsertDataCodeBlock, withInsertFragmentCodeBlock, withNormalizeCodeBlock };
147
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/lib/BaseCodeBlockPlugin.ts","../src/lib/setCodeBlockToDecorations.ts","../src/lib/withCodeBlock.ts","../src/lib/withInsertDataCodeBlock.ts","../src/lib/withInsertFragmentCodeBlock.ts","../src/lib/withNormalizeCodeBlock.tsx","../src/lib/deserializer/htmlDeserializerCodeBlock.ts","../src/lib/formatter/formatter.ts","../src/lib/formatter/jsonFormatter.ts","../src/lib/queries/getCodeLineEntry.ts","../src/lib/transforms/indentCodeLine.ts","../src/lib/queries/getIndentDepth.ts","../src/lib/queries/isCodeBlockEmpty.ts","../src/lib/queries/isSelectionAtCodeBlockStart.ts","../src/lib/transforms/outdentCodeLine.ts","../src/lib/transforms/deleteStartSpace.ts","../src/lib/transforms/insertCodeBlock.ts","../src/lib/transforms/insertCodeLine.ts","../src/lib/transforms/insertEmptyCodeBlock.ts","../src/lib/transforms/toggleCodeBlock.ts","../src/lib/transforms/unwrapCodeBlock.ts"],"sourcesContent":[],"mappings":";;;;KAmBY,eAAA,GAAkB;;AAA9B;;;EAA8B,eAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAAY;AAgB1C;AAKA;AAKA;aAde,kBAAkB;;cAIpB;ACtBA,cD2BA,oBC1BE,EAAA,GAAA;AADgC,cDgClC,mBChCkC,EAAA,GAAA;;;cAAlC,0BAA0B,QAAQ,UAAU;iBAoDzC,sBAAA,SACN,iCACY,UAAU,qBAC7B,IAAI,UAAU;iBAoFD,yBAAA,SACN,iCACY,UAAU;ADvIpB,iBCiJI,yBAAA,CDjJW,SAAA,ECiJ0B,iBDjJ1B,CAAA,EAAA,IAAA;;;cERd,eAAe,eAAe;;;cCP9B,yBAAyB;;;cCEzB,6BAA6B;;;;cCQ7B,wBAAwB,eAAe;;;cCVvC,2BAA2B;;;cCE3B;cAGA;cAeA,0BACH;;;EPNE,OAAA,EOUC,iBPVc;CAYM,EAAA,GAAA,IAAA;;;cQ/BpB;cAQA;;;;cCGA,6BAA8B,UAAU,cAAc,qBACzD;;ATOV,CAAA;OSNoC;ATMpC,CAAA,EAAA,GAAY;EAYqB,SAAA,EAAA,GAAA;EAAlB,QAAA,ESmBa,STnBb,CSmBuB,CTnBvB,CAAA;CAZe,GAAA,SAAA;;;KUflB,qBAAA;aACC;YACD;EVaA,WAAA,CAAA,EAAA,MAAe;CAYM;;;;AAIjC;AAKA;AAKA;;cU5Ba,yBACH;;;GACuB;;;cCbpB,yBACH;;GACM;;;;cCHH,2BAA4B;;;;cCA5B,sCAAuC;;;KCDxC,sBAAA;aACC;YACD;AdaZ,CAAA;;AAYe,ccrBF,edqBE,EAAA,CAAA,MAAA,EcpBL,MdoBK,EAAA;EAAA,SAAA;EAAA;AAAA,CAAA,EcnBY,sBdmBZ,EAAA,GAAA,IAAA;;;;cexBF,2BACH;;GACM;;;;;;AfUhB;AAYiC,cgBvBpB,ehBuBoB,EAAA,CAAA,MAAA,EgBtBvB,WhBsBuB,EAAA,kBAAA,CAAA,EgBrBX,IhBqBW,CgBrBN,kBhBqBM,EAAA,OAAA,CAAA,EAAA,GAAA,IAAA;;;;ciB1BpB,yBAA0B;;;KCD3B,sBAAA;;uBAEW,KAAK;AlBa5B,CAAA;;;;;AAgBa,ckBtBA,oBlByBX,EAAA,CAAA,MAAA,EkBxBQ,WlBwBR,EAAA;EAAA,WAAA;EAAA;AAAA,CAAA,CAAA,EkBpBG,sBlBoBH,EAAA,GAAA,IAAA;;;cmBhCW,0BAA2B;;;cCJ3B,0BAA2B"}
package/dist/index.js ADDED
@@ -0,0 +1,134 @@
1
+ import { _ as getIndentDepth, a as withNormalizeCodeBlock, c as unwrapCodeBlock, d as deleteStartSpace, f as CODE_LINE_TO_DECORATIONS, g as isCodeBlockEmpty, h as setCodeBlockToDecorations, i as withCodeBlock, l as outdentCodeLine, m as resetCodeBlockDecorations, n as BaseCodeLinePlugin, o as withInsertFragmentCodeBlock, p as codeBlockToDecorations, r as BaseCodeSyntaxPlugin, s as withInsertDataCodeBlock, t as BaseCodeBlockPlugin, u as indentCodeLine, v as getCodeLineEntry, y as htmlDeserializerCodeBlock } from "./BaseCodeBlockPlugin-BntJ075t.js";
2
+ import { KEYS } from "platejs";
3
+
4
+ //#region src/lib/queries/isSelectionAtCodeBlockStart.ts
5
+ /** Is the selection at the start of the first code line in a code block */
6
+ const isSelectionAtCodeBlockStart = (editor) => {
7
+ const { selection } = editor;
8
+ if (!selection || editor.api.isExpanded()) return false;
9
+ const { codeBlock } = getCodeLineEntry(editor) ?? {};
10
+ if (!codeBlock) return false;
11
+ return editor.api.isStart(selection.anchor, codeBlock[1]);
12
+ };
13
+
14
+ //#endregion
15
+ //#region src/lib/transforms/insertCodeBlock.ts
16
+ /**
17
+ * Insert a code block: set the node to code line and wrap it with a code block.
18
+ * If the cursor is not at the block start, insert break before.
19
+ */
20
+ const insertCodeBlock = (editor, insertNodesOptions = {}) => {
21
+ if (!editor.selection || editor.api.isExpanded()) return;
22
+ const matchCodeElements = (node) => node.type === KEYS.codeBlock || node.type === KEYS.codeLine;
23
+ if (editor.api.some({ match: matchCodeElements })) return;
24
+ if (!editor.api.isAt({ start: true })) editor.tf.insertBreak();
25
+ editor.tf.setNodes({
26
+ children: [{ text: "" }],
27
+ type: KEYS.codeLine
28
+ }, insertNodesOptions);
29
+ editor.tf.wrapNodes({
30
+ children: [],
31
+ type: KEYS.codeBlock
32
+ }, insertNodesOptions);
33
+ };
34
+
35
+ //#endregion
36
+ //#region src/lib/transforms/insertCodeLine.ts
37
+ /** Insert a code line starting with indentation. */
38
+ const insertCodeLine = (editor, indentDepth = 0) => {
39
+ if (editor.selection) {
40
+ const indent = " ".repeat(indentDepth);
41
+ editor.tf.insertNodes({
42
+ children: [{ text: indent }],
43
+ type: editor.getType(KEYS.codeLine)
44
+ });
45
+ }
46
+ };
47
+
48
+ //#endregion
49
+ //#region src/lib/transforms/insertEmptyCodeBlock.ts
50
+ /**
51
+ * Called by toolbars to make sure a code-block gets inserted below a paragraph
52
+ * rather than awkwardly splitting the current selection.
53
+ */
54
+ const insertEmptyCodeBlock = (editor, { defaultType = editor.getType(KEYS.p), insertNodesOptions } = {}) => {
55
+ if (!editor.selection) return;
56
+ if (editor.api.isExpanded() || !editor.api.isEmpty(editor.selection, { block: true })) editor.tf.insertNodes(editor.api.create.block({
57
+ children: [{ text: "" }],
58
+ type: defaultType
59
+ }), {
60
+ nextBlock: true,
61
+ select: true,
62
+ ...insertNodesOptions
63
+ });
64
+ insertCodeBlock(editor, insertNodesOptions);
65
+ };
66
+
67
+ //#endregion
68
+ //#region src/lib/transforms/toggleCodeBlock.ts
69
+ const toggleCodeBlock = (editor) => {
70
+ if (!editor.selection) return;
71
+ const codeBlockType = editor.getType(KEYS.codeBlock);
72
+ const codeLineType = editor.getType(KEYS.codeLine);
73
+ const isActive = editor.api.some({ match: { type: codeBlockType } });
74
+ editor.tf.withoutNormalizing(() => {
75
+ unwrapCodeBlock(editor);
76
+ if (!isActive) {
77
+ editor.tf.setNodes({ type: codeLineType });
78
+ const codeBlock = {
79
+ children: [],
80
+ type: codeBlockType
81
+ };
82
+ editor.tf.wrapNodes(codeBlock);
83
+ }
84
+ });
85
+ };
86
+
87
+ //#endregion
88
+ //#region src/lib/formatter/jsonFormatter.ts
89
+ const formatJson = (code) => {
90
+ try {
91
+ return JSON.stringify(JSON.parse(code), null, 2);
92
+ } catch (_error) {
93
+ return code;
94
+ }
95
+ };
96
+ const isValidJson = (code) => {
97
+ try {
98
+ JSON.parse(code);
99
+ return true;
100
+ } catch (_error) {
101
+ return false;
102
+ }
103
+ };
104
+
105
+ //#endregion
106
+ //#region src/lib/formatter/formatter.ts
107
+ const supportedLanguages = new Set(["json"]);
108
+ const isLangSupported = (lang) => Boolean(lang && supportedLanguages.has(lang));
109
+ const isValidSyntax = (code, lang) => {
110
+ if (!isLangSupported(lang)) return false;
111
+ switch (lang) {
112
+ case "json": return isValidJson(code);
113
+ default: return false;
114
+ }
115
+ };
116
+ const formatCodeBlock = (editor, { element }) => {
117
+ const { lang } = element;
118
+ if (!lang || !isLangSupported(lang)) return;
119
+ const code = editor.api.string(element);
120
+ if (isValidSyntax(code, lang)) {
121
+ const formattedCode = formatCode(code, lang);
122
+ editor.tf.insertText(formattedCode, { at: element });
123
+ }
124
+ };
125
+ const formatCode = (code, lang) => {
126
+ switch (lang) {
127
+ case "json": return formatJson(code);
128
+ default: return code;
129
+ }
130
+ };
131
+
132
+ //#endregion
133
+ export { BaseCodeBlockPlugin, BaseCodeLinePlugin, BaseCodeSyntaxPlugin, CODE_LINE_TO_DECORATIONS, codeBlockToDecorations, deleteStartSpace, formatCodeBlock, formatJson, getCodeLineEntry, getIndentDepth, htmlDeserializerCodeBlock, indentCodeLine, insertCodeBlock, insertCodeLine, insertEmptyCodeBlock, isCodeBlockEmpty, isLangSupported, isSelectionAtCodeBlockStart, isValidJson, isValidSyntax, outdentCodeLine, resetCodeBlockDecorations, setCodeBlockToDecorations, toggleCodeBlock, unwrapCodeBlock, withCodeBlock, withInsertDataCodeBlock, withInsertFragmentCodeBlock, withNormalizeCodeBlock };
134
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["SlateEditor","getCodeLineEntry","isSelectionAtCodeBlockStart","editor","selection","api","isExpanded","codeBlock","isStart","anchor","InsertNodesOptions","SlateEditor","TElement","KEYS","insertCodeBlock","editor","insertNodesOptions","Omit","selection","api","isExpanded","matchCodeElements","node","type","codeBlock","codeLine","some","match","isAt","start","tf","insertBreak","setNodes","children","text","wrapNodes","SlateEditor","KEYS","insertCodeLine","editor","indentDepth","selection","indent","repeat","tf","insertNodes","children","text","type","getType","codeLine","InsertNodesOptions","SlateEditor","KEYS","insertCodeBlock","CodeBlockInsertOptions","defaultType","insertNodesOptions","Omit","insertEmptyCodeBlock","editor","getType","p","selection","api","isExpanded","isEmpty","block","tf","insertNodes","create","children","text","type","nextBlock","select","SlateEditor","TElement","KEYS","unwrapCodeBlock","toggleCodeBlock","editor","selection","codeBlockType","getType","codeBlock","codeLineType","codeLine","isActive","api","some","match","type","tf","withoutNormalizing","setNodes","children","wrapNodes","formatJson","code","JSON","stringify","parse","_error","isValidJson","Editor","TCodeBlockElement","formatJson","isValidJson","supportedLanguages","Set","isLangSupported","lang","Boolean","has","isValidSyntax","code","formatCodeBlock","editor","element","api","string","formattedCode","formatCode","tf","insertText","at"],"sources":["../src/lib/queries/isSelectionAtCodeBlockStart.ts","../src/lib/transforms/insertCodeBlock.ts","../src/lib/transforms/insertCodeLine.ts","../src/lib/transforms/insertEmptyCodeBlock.ts","../src/lib/transforms/toggleCodeBlock.ts","../src/lib/formatter/jsonFormatter.ts","../src/lib/formatter/formatter.ts"],"sourcesContent":["import type { SlateEditor } from 'platejs';\n\nimport { getCodeLineEntry } from './getCodeLineEntry';\n\n/** Is the selection at the start of the first code line in a code block */\nexport const isSelectionAtCodeBlockStart = (editor: SlateEditor) => {\n const { selection } = editor;\n\n if (!selection || editor.api.isExpanded()) return false;\n\n const { codeBlock } = getCodeLineEntry(editor) ?? {};\n\n if (!codeBlock) return false;\n\n return editor.api.isStart(selection.anchor, codeBlock[1]);\n};\n","import type { InsertNodesOptions, SlateEditor, TElement } from 'platejs';\n\nimport { KEYS } from 'platejs';\n\n/**\n * Insert a code block: set the node to code line and wrap it with a code block.\n * If the cursor is not at the block start, insert break before.\n */\nexport const insertCodeBlock = (\n editor: SlateEditor,\n insertNodesOptions: Omit<InsertNodesOptions, 'match'> = {}\n) => {\n if (!editor.selection || editor.api.isExpanded()) return;\n\n const matchCodeElements = (node: TElement) =>\n node.type === KEYS.codeBlock || node.type === KEYS.codeLine;\n\n if (\n editor.api.some({\n match: matchCodeElements,\n })\n ) {\n return;\n }\n if (!editor.api.isAt({ start: true })) {\n editor.tf.insertBreak();\n }\n\n editor.tf.setNodes(\n {\n children: [{ text: '' }],\n type: KEYS.codeLine,\n },\n insertNodesOptions\n );\n\n editor.tf.wrapNodes<TElement>(\n {\n children: [],\n type: KEYS.codeBlock,\n },\n insertNodesOptions\n );\n};\n","import type { SlateEditor } from 'platejs';\n\nimport { KEYS } from 'platejs';\n\n/** Insert a code line starting with indentation. */\nexport const insertCodeLine = (editor: SlateEditor, indentDepth = 0) => {\n if (editor.selection) {\n const indent = ' '.repeat(indentDepth);\n\n editor.tf.insertNodes({\n children: [{ text: indent }],\n type: editor.getType(KEYS.codeLine),\n });\n }\n};\n","import { type InsertNodesOptions, type SlateEditor, KEYS } from 'platejs';\n\nimport { insertCodeBlock } from './insertCodeBlock';\n\nexport type CodeBlockInsertOptions = {\n defaultType?: string;\n insertNodesOptions?: Omit<InsertNodesOptions, 'match'>;\n};\n\n/**\n * Called by toolbars to make sure a code-block gets inserted below a paragraph\n * rather than awkwardly splitting the current selection.\n */\nexport const insertEmptyCodeBlock = (\n editor: SlateEditor,\n {\n defaultType = editor.getType(KEYS.p),\n insertNodesOptions,\n }: CodeBlockInsertOptions = {}\n) => {\n if (!editor.selection) return;\n if (\n editor.api.isExpanded() ||\n !editor.api.isEmpty(editor.selection, { block: true })\n ) {\n editor.tf.insertNodes(\n editor.api.create.block({ children: [{ text: '' }], type: defaultType }),\n {\n nextBlock: true,\n select: true,\n ...insertNodesOptions,\n }\n );\n }\n\n insertCodeBlock(editor, insertNodesOptions);\n};\n","import type { SlateEditor, TElement } from 'platejs';\n\nimport { KEYS } from 'platejs';\n\nimport { unwrapCodeBlock } from './unwrapCodeBlock';\n\nexport const toggleCodeBlock = (editor: SlateEditor) => {\n if (!editor.selection) return;\n\n const codeBlockType = editor.getType(KEYS.codeBlock);\n const codeLineType = editor.getType(KEYS.codeLine);\n\n const isActive = editor.api.some({\n match: { type: codeBlockType },\n });\n\n editor.tf.withoutNormalizing(() => {\n unwrapCodeBlock(editor);\n\n if (!isActive) {\n editor.tf.setNodes({\n type: codeLineType,\n });\n\n const codeBlock = {\n children: [],\n type: codeBlockType,\n };\n\n editor.tf.wrapNodes<TElement>(codeBlock);\n }\n });\n};\n","export const formatJson = (code: string): string => {\n try {\n return JSON.stringify(JSON.parse(code), null, 2);\n } catch (_error) {\n return code;\n }\n};\n\nexport const isValidJson = (code: string): boolean => {\n try {\n JSON.parse(code);\n\n return true;\n } catch (_error) {\n return false;\n }\n};\n","import type { Editor, TCodeBlockElement } from 'platejs';\n\nimport { formatJson, isValidJson } from './jsonFormatter';\n\nconst supportedLanguages = new Set(['json']);\n\nexport const isLangSupported = (lang?: string): boolean =>\n Boolean(lang && supportedLanguages.has(lang));\n\nexport const isValidSyntax = (code: string, lang?: string): boolean => {\n if (!isLangSupported(lang)) {\n return false;\n }\n\n switch (lang) {\n case 'json': {\n return isValidJson(code);\n }\n default: {\n return false;\n }\n }\n};\n\nexport const formatCodeBlock = (\n editor: Editor,\n {\n element,\n }: {\n element: TCodeBlockElement;\n }\n) => {\n const { lang } = element;\n\n if (!lang || !isLangSupported(lang)) {\n return;\n }\n\n const code = editor.api.string(element);\n\n if (isValidSyntax(code, lang)) {\n const formattedCode = formatCode(code, lang);\n editor.tf.insertText(formattedCode, { at: element });\n }\n};\n\nconst formatCode = (code: string, lang?: string): string => {\n switch (lang) {\n case 'json': {\n return formatJson(code);\n }\n default: {\n return code;\n }\n }\n};\n"],"mappings":";;;;;AAKA,MAAaE,+BAA+BC,WAAwB;CAClE,MAAM,EAAEC,cAAcD;AAEtB,KAAI,CAACC,aAAaD,OAAOE,IAAIC,YAAY,CAAE,QAAO;CAElD,MAAM,EAAEC,cAAcN,iBAAiBE,OAAO,IAAI,EAAE;AAEpD,KAAI,CAACI,UAAW,QAAO;AAEvB,QAAOJ,OAAOE,IAAIG,QAAQJ,UAAUK,QAAQF,UAAU,GAAG;;;;;;;;;ACN3D,MAAaO,mBACXC,QACAC,qBAAwD,EAAE,KACvD;AACH,KAAI,CAACD,OAAOG,aAAaH,OAAOI,IAAIC,YAAY,CAAE;CAElD,MAAMC,qBAAqBC,SACzBA,KAAKC,SAASV,KAAKW,aAAaF,KAAKC,SAASV,KAAKY;AAErD,KACEV,OAAOI,IAAIO,KAAK,EACdC,OAAON,mBACR,CAAC,CAEF;AAEF,KAAI,CAACN,OAAOI,IAAIS,KAAK,EAAEC,OAAO,MAAM,CAAC,CACnCd,QAAOe,GAAGC,aAAa;AAGzBhB,QAAOe,GAAGE,SACR;EACEC,UAAU,CAAC,EAAEC,MAAM,IAAI,CAAC;EACxBX,MAAMV,KAAKY;EACZ,EACDT,mBACD;AAEDD,QAAOe,GAAGK,UACR;EACEF,UAAU,EAAE;EACZV,MAAMV,KAAKW;EACZ,EACDR,mBACD;;;;;;ACrCH,MAAasB,kBAAkBC,QAAqBC,cAAc,MAAM;AACtE,KAAID,OAAOE,WAAW;EACpB,MAAMC,SAAS,IAAIC,OAAOH,YAAY;AAEtCD,SAAOK,GAAGC,YAAY;GACpBC,UAAU,CAAC,EAAEC,MAAML,QAAQ,CAAC;GAC5BM,MAAMT,OAAOU,QAAQZ,KAAKa,SAAQ;GACnC,CAAC;;;;;;;;;;ACCN,MAAaS,wBACXC,QACA,EACEJ,cAAcI,OAAOC,QAAQR,KAAKS,EAAE,EACpCL,uBAC0B,EAAE,KAC3B;AACH,KAAI,CAACG,OAAOG,UAAW;AACvB,KACEH,OAAOI,IAAIC,YAAY,IACvB,CAACL,OAAOI,IAAIE,QAAQN,OAAOG,WAAW,EAAEI,OAAO,MAAM,CAAC,CAEtDP,QAAOQ,GAAGC,YACRT,OAAOI,IAAIM,OAAOH,MAAM;EAAEI,UAAU,CAAC,EAAEC,MAAM,IAAI,CAAC;EAAEC,MAAMjB;EAAa,CAAC,EACxE;EACEkB,WAAW;EACXC,QAAQ;EACR,GAAGlB;EAEP,CAAC;AAGHH,iBAAgBM,QAAQH,mBAAmB;;;;;AC7B7C,MAAauB,mBAAmBC,WAAwB;AACtD,KAAI,CAACA,OAAOC,UAAW;CAEvB,MAAMC,gBAAgBF,OAAOG,QAAQN,KAAKO,UAAU;CACpD,MAAMC,eAAeL,OAAOG,QAAQN,KAAKS,SAAS;CAElD,MAAMC,WAAWP,OAAOQ,IAAIC,KAAK,EAC/BC,OAAO,EAAEC,MAAMT,eAAc,EAC9B,CAAC;AAEFF,QAAOY,GAAGC,yBAAyB;AACjCf,kBAAgBE,OAAO;AAEvB,MAAI,CAACO,UAAU;AACbP,UAAOY,GAAGE,SAAS,EACjBH,MAAMN,cACP,CAAC;GAEF,MAAMD,YAAY;IAChBW,UAAU,EAAE;IACZJ,MAAMT;IACP;AAEDF,UAAOY,GAAGI,UAAoBZ,UAAU;;GAE1C;;;;;AC/BJ,MAAaa,cAAcC,SAAyB;AAClD,KAAI;AACF,SAAOC,KAAKC,UAAUD,KAAKE,MAAMH,KAAK,EAAE,MAAM,EAAE;UACzCI,QAAQ;AACf,SAAOJ;;;AAIX,MAAaK,eAAeL,SAA0B;AACpD,KAAI;AACFC,OAAKE,MAAMH,KAAK;AAEhB,SAAO;UACAI,QAAQ;AACf,SAAO;;;;;;ACVX,MAAMM,qBAAqB,IAAIC,IAAI,CAAC,OAAO,CAAC;AAE5C,MAAaC,mBAAmBC,SAC9BC,QAAQD,QAAQH,mBAAmBK,IAAIF,KAAK,CAAC;AAE/C,MAAaG,iBAAiBC,MAAcJ,SAA2B;AACrE,KAAI,CAACD,gBAAgBC,KAAK,CACxB,QAAO;AAGT,SAAQA,MAAR;EACE,KAAK,OACH,QAAOJ,YAAYQ,KAAK;EAE1B,QACE,QAAO;;;AAKb,MAAaC,mBACXC,QACA,EACEC,cAIC;CACH,MAAM,EAAEP,SAASO;AAEjB,KAAI,CAACP,QAAQ,CAACD,gBAAgBC,KAAK,CACjC;CAGF,MAAMI,OAAOE,OAAOE,IAAIC,OAAOF,QAAQ;AAEvC,KAAIJ,cAAcC,MAAMJ,KAAK,EAAE;EAC7B,MAAMU,gBAAgBC,WAAWP,MAAMJ,KAAK;AAC5CM,SAAOM,GAAGC,WAAWH,eAAe,EAAEI,IAAIP,SAAS,CAAC;;;AAIxD,MAAMI,cAAcP,MAAcJ,SAA0B;AAC1D,SAAQA,MAAR;EACE,KAAK,OACH,QAAOL,WAAWS,KAAK;EAEzB,QACE,QAAOA"}
@@ -0,0 +1,8 @@
1
+ //#region src/react/CodeBlockPlugin.d.ts
2
+ declare const CodeSyntaxPlugin: any;
3
+ declare const CodeLinePlugin: any;
4
+ /** Enables support for pre-formatted code blocks. */
5
+ declare const CodeBlockPlugin: any;
6
+ //#endregion
7
+ export { CodeBlockPlugin, CodeLinePlugin, CodeSyntaxPlugin };
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/react/CodeBlockPlugin.tsx"],"sourcesContent":[],"mappings":";cAQa;AAAA,cAEA,cAFsD,EAAA,GAAA;AAEnE;AAGa,cAAA,eAEX,EAAA,GAAA"}
@@ -0,0 +1,12 @@
1
+ import { n as BaseCodeLinePlugin, r as BaseCodeSyntaxPlugin, t as BaseCodeBlockPlugin } from "../BaseCodeBlockPlugin-BntJ075t.js";
2
+ import { toPlatePlugin } from "platejs/react";
3
+
4
+ //#region src/react/CodeBlockPlugin.tsx
5
+ const CodeSyntaxPlugin = toPlatePlugin(BaseCodeSyntaxPlugin);
6
+ const CodeLinePlugin = toPlatePlugin(BaseCodeLinePlugin);
7
+ /** Enables support for pre-formatted code blocks. */
8
+ const CodeBlockPlugin = toPlatePlugin(BaseCodeBlockPlugin, { plugins: [CodeLinePlugin, CodeSyntaxPlugin] });
9
+
10
+ //#endregion
11
+ export { CodeBlockPlugin, CodeLinePlugin, CodeSyntaxPlugin };
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["toPlatePlugin","BaseCodeBlockPlugin","BaseCodeLinePlugin","BaseCodeSyntaxPlugin","CodeSyntaxPlugin","CodeLinePlugin","CodeBlockPlugin","plugins"],"sources":["../../src/react/CodeBlockPlugin.tsx"],"sourcesContent":["import { toPlatePlugin } from 'platejs/react';\n\nimport {\n BaseCodeBlockPlugin,\n BaseCodeLinePlugin,\n BaseCodeSyntaxPlugin,\n} from '../lib/BaseCodeBlockPlugin';\n\nexport const CodeSyntaxPlugin = toPlatePlugin(BaseCodeSyntaxPlugin);\n\nexport const CodeLinePlugin = toPlatePlugin(BaseCodeLinePlugin);\n\n/** Enables support for pre-formatted code blocks. */\nexport const CodeBlockPlugin = toPlatePlugin(BaseCodeBlockPlugin, {\n plugins: [CodeLinePlugin, CodeSyntaxPlugin],\n});\n"],"mappings":";;;;AAQA,MAAaI,mBAAmBJ,cAAcG,qBAAqB;AAEnE,MAAaE,iBAAiBL,cAAcE,mBAAmB;;AAG/D,MAAaI,kBAAkBN,cAAcC,qBAAqB,EAChEM,SAAS,CAACF,gBAAgBD,iBAAgB,EAC3C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@lofcz/platejs-code-block",
3
+ "version": "52.0.11",
4
+ "description": "Code block plugin for Plate",
5
+ "keywords": [
6
+ "plate",
7
+ "plugin",
8
+ "slate"
9
+ ],
10
+ "homepage": "https://platejs.org",
11
+ "bugs": {
12
+ "url": "https://github.com/udecode/plate/issues"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/lofcz/plate.git",
17
+ "directory": "packages/code-block"
18
+ },
19
+ "license": "MIT",
20
+ "sideEffects": false,
21
+ "exports": {
22
+ ".": "./dist/index.js",
23
+ "./react": "./dist/react/index.js",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "files": [
29
+ "dist/**/*"
30
+ ],
31
+ "devDependencies": {
32
+ "lowlight": "^3.3.0",
33
+ "@plate/scripts": "1.0.0"
34
+ },
35
+ "peerDependencies": {
36
+ "platejs": ">=52.0.11",
37
+ "react": ">=18.0.0",
38
+ "react-dom": ">=18.0.0"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "type": "module",
44
+ "module": "./dist/index.js",
45
+ "dependencies": {
46
+ "react-compiler-runtime": "^1.0.0"
47
+ },
48
+ "scripts": {
49
+ "brl": "plate-pkg p:brl",
50
+ "build": "plate-pkg p:build",
51
+ "build:watch": "plate-pkg p:build:watch",
52
+ "clean": "plate-pkg p:clean",
53
+ "lint": "plate-pkg p:lint",
54
+ "lint:fix": "plate-pkg p:lint:fix",
55
+ "test": "plate-pkg p:test",
56
+ "test:watch": "plate-pkg p:test:watch",
57
+ "typecheck": "plate-pkg p:typecheck"
58
+ }
59
+ }