@blue-patterns/richtext 0.0.0-stage → 0.7.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +275 -0
- package/LICENSE +22 -0
- package/README.md +88 -2
- package/astryx.integration.mjs +11 -0
- package/blocks/RichTextEditorShowcase.template.mjs +13 -0
- package/blocks/RichTextEditorShowcase.tsx +19 -0
- package/dist/RichTextEditor.d.ts +282 -0
- package/dist/RichTextEditor.d.ts.map +1 -0
- package/dist/RichTextEditor.js +657 -0
- package/dist/RichTextEditorAutoLinkPlugin.d.ts +83 -0
- package/dist/RichTextEditorAutoLinkPlugin.d.ts.map +1 -0
- package/dist/RichTextEditorAutoLinkPlugin.js +99 -0
- package/dist/RichTextEditorToolbar.d.ts +186 -0
- package/dist/RichTextEditorToolbar.d.ts.map +1 -0
- package/dist/RichTextEditorToolbar.js +688 -0
- package/dist/RichTextView.d.ts +92 -0
- package/dist/RichTextView.d.ts.map +1 -0
- package/dist/RichTextView.js +267 -0
- package/dist/codeLanguages.d.ts +14 -0
- package/dist/codeLanguages.d.ts.map +1 -0
- package/dist/codeLanguages.js +34 -0
- package/dist/codeLineTokens.d.ts +53 -0
- package/dist/codeLineTokens.d.ts.map +1 -0
- package/dist/codeLineTokens.js +188 -0
- package/dist/editorNodes.d.ts +8 -0
- package/dist/editorNodes.d.ts.map +1 -0
- package/dist/editorNodes.js +30 -0
- package/dist/editorTheme.d.ts +7 -0
- package/dist/editorTheme.d.ts.map +1 -0
- package/dist/editorTheme.js +328 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/internal/CodeBackspacePlugin.d.ts +2 -0
- package/dist/internal/CodeBackspacePlugin.d.ts.map +1 -0
- package/dist/internal/CodeBackspacePlugin.js +70 -0
- package/dist/internal/CodeBlockHeaderPlugin.d.ts +11 -0
- package/dist/internal/CodeBlockHeaderPlugin.d.ts.map +1 -0
- package/dist/internal/CodeBlockHeaderPlugin.js +204 -0
- package/dist/internal/CodePastePlugin.d.ts +5 -0
- package/dist/internal/CodePastePlugin.d.ts.map +1 -0
- package/dist/internal/CodePastePlugin.js +104 -0
- package/dist/internal/CodeSyntaxPlugin.d.ts +8 -0
- package/dist/internal/CodeSyntaxPlugin.d.ts.map +1 -0
- package/dist/internal/CodeSyntaxPlugin.js +397 -0
- package/dist/internal/CodeTabPlugin.d.ts +2 -0
- package/dist/internal/CodeTabPlugin.d.ts.map +1 -0
- package/dist/internal/CodeTabPlugin.js +256 -0
- package/dist/internal/DisabledLinkGuardPlugin.d.ts +4 -0
- package/dist/internal/DisabledLinkGuardPlugin.d.ts.map +1 -0
- package/dist/internal/DisabledLinkGuardPlugin.js +93 -0
- package/dist/internal/ImageSourceCaretPlugin.d.ts +3 -0
- package/dist/internal/ImageSourceCaretPlugin.d.ts.map +1 -0
- package/dist/internal/ImageSourceCaretPlugin.js +105 -0
- package/dist/internal/ListItemShortcutsPlugin.d.ts +6 -0
- package/dist/internal/ListItemShortcutsPlugin.d.ts.map +1 -0
- package/dist/internal/ListItemShortcutsPlugin.js +314 -0
- package/dist/internal/MarkdownExtensionsPlugin.d.ts +17 -0
- package/dist/internal/MarkdownExtensionsPlugin.d.ts.map +1 -0
- package/dist/internal/MarkdownExtensionsPlugin.js +185 -0
- package/dist/internal/SelectAllScopePlugin.d.ts +2 -0
- package/dist/internal/SelectAllScopePlugin.d.ts.map +1 -0
- package/dist/internal/SelectAllScopePlugin.js +67 -0
- package/dist/internal/TableColumnFloorPlugin.d.ts +12 -0
- package/dist/internal/TableColumnFloorPlugin.d.ts.map +1 -0
- package/dist/internal/TableColumnFloorPlugin.js +84 -0
- package/dist/internal/TablePastePlugin.d.ts +9 -0
- package/dist/internal/TablePastePlugin.d.ts.map +1 -0
- package/dist/internal/TablePastePlugin.js +183 -0
- package/dist/internal/TableScrollRegionPlugin.d.ts +9 -0
- package/dist/internal/TableScrollRegionPlugin.d.ts.map +1 -0
- package/dist/internal/TableScrollRegionPlugin.js +95 -0
- package/dist/internal/TaskCheckboxPlugin.d.ts +7 -0
- package/dist/internal/TaskCheckboxPlugin.d.ts.map +1 -0
- package/dist/internal/TaskCheckboxPlugin.js +193 -0
- package/dist/internal/ToolbarLinkPopover.d.ts +74 -0
- package/dist/internal/ToolbarLinkPopover.d.ts.map +1 -0
- package/dist/internal/ToolbarLinkPopover.js +292 -0
- package/dist/linkEditing.d.ts +6 -0
- package/dist/linkEditing.d.ts.map +1 -0
- package/dist/linkEditing.js +20 -0
- package/dist/linkForm.d.ts +28 -0
- package/dist/linkForm.d.ts.map +1 -0
- package/dist/linkForm.js +137 -0
- package/dist/linkUtils.d.ts +27 -0
- package/dist/linkUtils.d.ts.map +1 -0
- package/dist/linkUtils.js +101 -0
- package/dist/markdown.d.ts +17 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +17 -0
- package/dist/markdownCharacterReferences.d.ts +135 -0
- package/dist/markdownCharacterReferences.d.ts.map +1 -0
- package/dist/markdownCharacterReferences.js +1127 -0
- package/dist/markdownCodeFence.d.ts +4 -0
- package/dist/markdownCodeFence.d.ts.map +1 -0
- package/dist/markdownCodeFence.js +167 -0
- package/dist/markdownExtensionNode.d.ts +88 -0
- package/dist/markdownExtensionNode.d.ts.map +1 -0
- package/dist/markdownExtensionNode.js +248 -0
- package/dist/markdownExtensions.d.ts +115 -0
- package/dist/markdownExtensions.d.ts.map +1 -0
- package/dist/markdownExtensions.js +392 -0
- package/dist/markdownHardLineBreak.d.ts +25 -0
- package/dist/markdownHardLineBreak.d.ts.map +1 -0
- package/dist/markdownHardLineBreak.js +59 -0
- package/dist/markdownHeading.d.ts +20 -0
- package/dist/markdownHeading.d.ts.map +1 -0
- package/dist/markdownHeading.js +30 -0
- package/dist/markdownLink.d.ts +5 -0
- package/dist/markdownLink.d.ts.map +1 -0
- package/dist/markdownLink.js +80 -0
- package/dist/markdownListExport.d.ts +3 -0
- package/dist/markdownListExport.d.ts.map +1 -0
- package/dist/markdownListExport.js +68 -0
- package/dist/markdownListIndentation.d.ts +8 -0
- package/dist/markdownListIndentation.d.ts.map +1 -0
- package/dist/markdownListIndentation.js +101 -0
- package/dist/markdownOrderedList.d.ts +3 -0
- package/dist/markdownOrderedList.d.ts.map +1 -0
- package/dist/markdownOrderedList.js +51 -0
- package/dist/markdownQuote.d.ts +22 -0
- package/dist/markdownQuote.d.ts.map +1 -0
- package/dist/markdownQuote.js +32 -0
- package/dist/markdownSerializers.d.ts +49 -0
- package/dist/markdownSerializers.d.ts.map +1 -0
- package/dist/markdownSerializers.js +83 -0
- package/dist/markdownSource.d.ts +71 -0
- package/dist/markdownSource.d.ts.map +1 -0
- package/dist/markdownSource.js +804 -0
- package/dist/markdownSpaceRuns.d.ts +24 -0
- package/dist/markdownSpaceRuns.d.ts.map +1 -0
- package/dist/markdownSpaceRuns.js +147 -0
- package/dist/markdownTable.d.ts +35 -0
- package/dist/markdownTable.d.ts.map +1 -0
- package/dist/markdownTable.js +227 -0
- package/dist/markdownTaskList.d.ts +48 -0
- package/dist/markdownTaskList.d.ts.map +1 -0
- package/dist/markdownTaskList.js +166 -0
- package/dist/markdownThematicBreak.d.ts +3 -0
- package/dist/markdownThematicBreak.d.ts.map +1 -0
- package/dist/markdownThematicBreak.js +55 -0
- package/dist/privateAttributes/layerPortalBoundary.stylex.d.ts +12 -0
- package/dist/privateAttributes/layerPortalBoundary.stylex.d.ts.map +1 -0
- package/dist/privateAttributes/layerPortalBoundary.stylex.js +16 -0
- package/dist/richtext.css +213 -0
- package/dist/textSemantics.d.ts +3 -0
- package/dist/textSemantics.d.ts.map +1 -0
- package/dist/textSemantics.js +87 -0
- package/package.json +158 -3
- package/src/RichTextEditor.doc.mjs +308 -0
- package/src/RichTextEditor.tsx +1109 -0
- package/src/RichTextEditorAutoLinkPlugin.doc.mjs +43 -0
- package/src/RichTextEditorAutoLinkPlugin.tsx +126 -0
- package/src/RichTextEditorToolbar.doc.mjs +92 -0
- package/src/RichTextEditorToolbar.tsx +871 -0
- package/src/RichTextView.doc.mjs +101 -0
- package/src/RichTextView.tsx +351 -0
- package/src/codeLanguages.ts +42 -0
- package/src/codeLineTokens.ts +241 -0
- package/src/doc-mjs.d.ts +23 -0
- package/src/editorNodes.ts +44 -0
- package/src/editorTheme.ts +550 -0
- package/src/index.ts +59 -0
- package/src/internal/CodeBackspacePlugin.tsx +96 -0
- package/src/internal/CodeBlockHeaderPlugin.tsx +282 -0
- package/src/internal/CodePastePlugin.tsx +144 -0
- package/src/internal/CodeSyntaxPlugin.tsx +493 -0
- package/src/internal/CodeTabPlugin.tsx +298 -0
- package/src/internal/DisabledLinkGuardPlugin.tsx +93 -0
- package/src/internal/ImageSourceCaretPlugin.tsx +159 -0
- package/src/internal/ListItemShortcutsPlugin.tsx +404 -0
- package/src/internal/MarkdownExtensionsPlugin.tsx +289 -0
- package/src/internal/SelectAllScopePlugin.tsx +86 -0
- package/src/internal/TableColumnFloorPlugin.tsx +99 -0
- package/src/internal/TablePastePlugin.tsx +223 -0
- package/src/internal/TableScrollRegionPlugin.tsx +107 -0
- package/src/internal/TaskCheckboxPlugin.tsx +246 -0
- package/src/internal/ToolbarLinkPopover.tsx +392 -0
- package/src/linkEditing.ts +20 -0
- package/src/linkForm.tsx +156 -0
- package/src/linkUtils.ts +106 -0
- package/src/markdown.ts +25 -0
- package/src/markdownCharacterReferences.ts +1137 -0
- package/src/markdownCodeFence.ts +216 -0
- package/src/markdownExtensionNode.ts +339 -0
- package/src/markdownExtensions.ts +496 -0
- package/src/markdownHardLineBreak.ts +73 -0
- package/src/markdownHeading.ts +33 -0
- package/src/markdownLink.ts +86 -0
- package/src/markdownListExport.ts +85 -0
- package/src/markdownListIndentation.ts +105 -0
- package/src/markdownOrderedList.ts +60 -0
- package/src/markdownQuote.ts +35 -0
- package/src/markdownSerializers.ts +108 -0
- package/src/markdownSource.ts +1045 -0
- package/src/markdownSpaceRuns.ts +164 -0
- package/src/markdownTable.ts +309 -0
- package/src/markdownTaskList.ts +222 -0
- package/src/markdownThematicBreak.ts +66 -0
- package/src/privateAttributes/layerPortalBoundary.stylex.ts +18 -0
- package/src/textSemantics.ts +104 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownListExport.ts
|
|
5
|
+
* @input Uses @lexical/list (ListNode, ListItemNode) and @lexical/markdown
|
|
6
|
+
* (ElementTransformer).
|
|
7
|
+
* @output Exports LIST_EXPORT, which writes lists the way Lexical's list
|
|
8
|
+
* transformers do except for nesting: a nested list is indented to its
|
|
9
|
+
* parent item's content column instead of four spaces per level, and each
|
|
10
|
+
* task item writes `[ ]` or `[x]` (markdownTaskList.ts).
|
|
11
|
+
* @position Part of DEFAULT_TRANSFORMERS (markdownTable.ts), ahead of
|
|
12
|
+
* Lexical's list transformers, which still import. Import reads nesting the
|
|
13
|
+
* CommonMark way (markdownListIndentation.ts), so a child written four
|
|
14
|
+
* spaces under `100. parent` (content column five) would read back at the
|
|
15
|
+
* parent's level; indenting to the content column keeps an edited list's
|
|
16
|
+
* structure when it is read again (spec:AST-062 FR3).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { $isListItemNode, $isListNode, ListItemNode, ListNode } from '@lexical/list';
|
|
20
|
+
import { $getTaskState } from "./markdownTaskList.js";
|
|
21
|
+
|
|
22
|
+
/** The bullet Lexical recorded for a list on import (`-`, `*`, or `+`). */
|
|
23
|
+
function bulletOf(list) {
|
|
24
|
+
// The export may hand over a view of the list (an object inheriting from
|
|
25
|
+
// the node, see markdownSource.ts); Lexical validates the fields of the
|
|
26
|
+
// node it serializes, so read the recorded state from the node itself.
|
|
27
|
+
const serialized = list.getLatest().exportJSON();
|
|
28
|
+
const marker = serialized.$?.mdListMarker;
|
|
29
|
+
return marker === '*' || marker === '+' ? marker : '-';
|
|
30
|
+
}
|
|
31
|
+
function exportList(list, exportChildren, indent) {
|
|
32
|
+
const lines = [];
|
|
33
|
+
const type = list.getListType();
|
|
34
|
+
let index = 0;
|
|
35
|
+
// Where a nested list goes: the content column of the item before it.
|
|
36
|
+
let childIndent = `${indent} `;
|
|
37
|
+
for (const item of list.getChildren()) {
|
|
38
|
+
if (!$isListItemNode(item)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const first = item.getFirstChild();
|
|
42
|
+
if (item.getChildrenSize() === 1 && $isListNode(first)) {
|
|
43
|
+
lines.push(exportList(first, exportChildren, childIndent));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const marker = type === 'number' ? `${list.getStart() + index}. ` : `${bulletOf(list)} `;
|
|
47
|
+
// A task item, in any bulleted list, writes its box.
|
|
48
|
+
const task = type === 'number' ? null : $getTaskState(item);
|
|
49
|
+
const checkbox = task == null ? '' : `[${task === 'checked' ? 'x' : ' '}] `;
|
|
50
|
+
let text = exportChildren(item);
|
|
51
|
+
if (type !== 'number') {
|
|
52
|
+
// As Lexical does: keep `1. ` at the start of a bullet item literal.
|
|
53
|
+
text = text.replace(/^(\s{0,3}\d+)(\.\s)/, '$1\\$2');
|
|
54
|
+
}
|
|
55
|
+
lines.push(indent + marker + checkbox + text);
|
|
56
|
+
childIndent = indent + ' '.repeat(marker.length);
|
|
57
|
+
index++;
|
|
58
|
+
}
|
|
59
|
+
return lines.join('\n');
|
|
60
|
+
}
|
|
61
|
+
export const LIST_EXPORT = {
|
|
62
|
+
dependencies: [ListNode, ListItemNode],
|
|
63
|
+
export: (node, exportChildren) => $isListNode(node) ? exportList(node, exportChildren, '') : null,
|
|
64
|
+
// Export only: Lexical's list transformers import.
|
|
65
|
+
regExp: /(?!)/,
|
|
66
|
+
replace: () => false,
|
|
67
|
+
type: 'element'
|
|
68
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rewrites each list item line's indentation as four spaces per CommonMark
|
|
3
|
+
* nesting level, leaving every other line, and every line inside fenced code,
|
|
4
|
+
* as it is. The line count and every line's content after its indentation
|
|
5
|
+
* are unchanged.
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeListIndentation(markdown: string): string;
|
|
8
|
+
//# sourceMappingURL=markdownListIndentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownListIndentation.d.ts","sourceRoot":"","sources":["../src/markdownListIndentation.ts"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAmEjE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownListIndentation.ts
|
|
5
|
+
* @input Markdown source text.
|
|
6
|
+
* @output Exports normalizeListIndentation, which rewrites the indentation of
|
|
7
|
+
* every list item line so its nesting reads the same to Lexical as it does
|
|
8
|
+
* to CommonMark.
|
|
9
|
+
* @position Used by markdownSource.ts on the text it imports (never on the
|
|
10
|
+
* bytes it records). Lexical nests a list item one level per four spaces or
|
|
11
|
+
* one tab; CommonMark nests an item under the item whose content it is
|
|
12
|
+
* indented to, so `- a` / ` - b` (two spaces) and `1. a` / ` 1. b`
|
|
13
|
+
* (three) are nested lists that Lexical would flatten (spec:AST-061 FR5).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** A list item line: indentation, marker, and the spaces after it. */
|
|
17
|
+
const LIST_ITEM = /^([ \t]*)([-+*]|\d{1,9}[.)])( {1,4}|\t|$)/;
|
|
18
|
+
const FENCE_OPEN = /^[ \t]*(`{3,}|~{3,})/;
|
|
19
|
+
const BLANK_LINE = /^[ \t]*\r?$/;
|
|
20
|
+
/** A thematic break after its indentation: three or more of one marker. */
|
|
21
|
+
const THEMATIC_BREAK_CONTENT = /^([-*_])(?:[ \t]*\1){2,}[ \t]*\r?$/;
|
|
22
|
+
|
|
23
|
+
/** Columns of leading whitespace, with tabs stopping every four columns. */
|
|
24
|
+
function columnsOf(whitespace) {
|
|
25
|
+
let columns = 0;
|
|
26
|
+
for (const character of whitespace) {
|
|
27
|
+
columns = character === '\t' ? columns + 4 - columns % 4 : columns + 1;
|
|
28
|
+
}
|
|
29
|
+
return columns;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Rewrites each list item line's indentation as four spaces per CommonMark
|
|
34
|
+
* nesting level, leaving every other line, and every line inside fenced code,
|
|
35
|
+
* as it is. The line count and every line's content after its indentation
|
|
36
|
+
* are unchanged.
|
|
37
|
+
*/
|
|
38
|
+
export function normalizeListIndentation(markdown) {
|
|
39
|
+
const lines = markdown.split('\n');
|
|
40
|
+
// The content column of each open list item, outermost first.
|
|
41
|
+
const open = [];
|
|
42
|
+
let fence = null;
|
|
43
|
+
let afterBlankLine = false;
|
|
44
|
+
for (let index = 0; index < lines.length; index++) {
|
|
45
|
+
const line = lines[index];
|
|
46
|
+
if (fence != null) {
|
|
47
|
+
if (new RegExp(`^[ \\t]*${fence[0]}{${fence.length},}[ \\t]*\\r?$`).test(line)) {
|
|
48
|
+
fence = null;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (BLANK_LINE.test(line)) {
|
|
53
|
+
afterBlankLine = true;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const leading = /^[ \t]*/.exec(line)?.[0] ?? '';
|
|
57
|
+
const indent = columnsOf(leading);
|
|
58
|
+
if (THEMATIC_BREAK_CONTENT.test(line.slice(leading.length))) {
|
|
59
|
+
// A thematic break, never an item, even where an item could start
|
|
60
|
+
// (CommonMark 0.31 §4.1). Lexical shows it only as a block of its own,
|
|
61
|
+
// so a break inside an item loses its indentation and reads as one.
|
|
62
|
+
while (open.length > 0 && indent < open[open.length - 1]) {
|
|
63
|
+
open.pop();
|
|
64
|
+
}
|
|
65
|
+
if (open.length > 0) {
|
|
66
|
+
lines[index] = line.slice(leading.length);
|
|
67
|
+
}
|
|
68
|
+
afterBlankLine = false;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const item = LIST_ITEM.exec(line);
|
|
72
|
+
if (item == null) {
|
|
73
|
+
const opening = FENCE_OPEN.exec(line);
|
|
74
|
+
if (opening != null) {
|
|
75
|
+
fence = opening[1];
|
|
76
|
+
}
|
|
77
|
+
// A line after a blank line belongs to the items it is indented into;
|
|
78
|
+
// without a blank line it continues the last item's paragraph lazily.
|
|
79
|
+
if (afterBlankLine) {
|
|
80
|
+
while (open.length > 0 && indent < open[open.length - 1]) {
|
|
81
|
+
open.pop();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
afterBlankLine = false;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
afterBlankLine = false;
|
|
88
|
+
// An item nests under every open item whose content it reaches.
|
|
89
|
+
while (open.length > 0 && indent < open[open.length - 1]) {
|
|
90
|
+
open.pop();
|
|
91
|
+
}
|
|
92
|
+
const depth = open.length;
|
|
93
|
+
// The content column, counted across the whole prefix so a tab after
|
|
94
|
+
// the marker stops at the right column; a marker that ends the line has
|
|
95
|
+
// its content one column after it.
|
|
96
|
+
const markerEnd = columnsOf(item[0]) + (item[3] === '' ? 1 : 0);
|
|
97
|
+
open.push(markerEnd);
|
|
98
|
+
lines[index] = ' '.repeat(depth * 4) + line.slice(item[1].length);
|
|
99
|
+
}
|
|
100
|
+
return lines.join('\n');
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownOrderedList.d.ts","sourceRoot":"","sources":["../src/markdownOrderedList.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAe,KAAK,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAsBxE,eAAO,MAAM,0BAA0B,EAAE,kBAkBxC,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownOrderedList.ts
|
|
5
|
+
* @input Uses @lexical/list (ListNode, ListItemNode) and @lexical/markdown
|
|
6
|
+
* (ORDERED_LIST).
|
|
7
|
+
* @output Exports ORDERED_LIST_KEEPING_START, Lexical's ordered list
|
|
8
|
+
* transformer with one change: a nested numbered list starts at the number
|
|
9
|
+
* its first item was written with.
|
|
10
|
+
* @position Replaces Lexical's ORDERED_LIST in DEFAULT_TRANSFORMERS
|
|
11
|
+
* (markdownTable.ts). Lexical nests an indented item under a numbered list
|
|
12
|
+
* by indenting it into a new list that starts at 1, so `27.` written as the
|
|
13
|
+
* first item of a nested list read as `1.` (or `a.` under spec:AST-061
|
|
14
|
+
* DEC-6). Markdown keeps every list's start, nested or not (DEC-6), so this
|
|
15
|
+
* sets the new nested list's start from the marker. A later item in the same
|
|
16
|
+
* nested list continues its sequence, as Lexical's does.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { $isListItemNode, $isListNode } from '@lexical/list';
|
|
20
|
+
import { ORDERED_LIST } from '@lexical/markdown';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The list `item` was indented into: the last item under `list`, followed
|
|
24
|
+
* down through the wrapper items Lexical nests lists in.
|
|
25
|
+
*/
|
|
26
|
+
function nestedListOfLastItem(list) {
|
|
27
|
+
let current = list;
|
|
28
|
+
for (;;) {
|
|
29
|
+
const last = current.getLastChild();
|
|
30
|
+
const nested = $isListItemNode(last) ? last.getFirstChild() : null;
|
|
31
|
+
if (!$isListItemNode(last) || last.getChildrenSize() !== 1 || !$isListNode(nested)) {
|
|
32
|
+
return current;
|
|
33
|
+
}
|
|
34
|
+
current = nested;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export const ORDERED_LIST_KEEPING_START = {
|
|
38
|
+
...ORDERED_LIST,
|
|
39
|
+
replace: (parentNode, children, match, isImport) => {
|
|
40
|
+
const previous = parentNode.getPreviousSibling();
|
|
41
|
+
const result = ORDERED_LIST.replace(parentNode, children, match, isImport);
|
|
42
|
+
if ($isListNode(previous) && previous.getListType() === 'number') {
|
|
43
|
+
const nested = nestedListOfLastItem(previous);
|
|
44
|
+
// The new item opened this nested list: start it at its own number.
|
|
45
|
+
if (nested !== previous && nested.getListType() === 'number' && nested.getChildrenSize() === 1) {
|
|
46
|
+
nested.setStart(Number(match[2]));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file markdownQuote.ts
|
|
3
|
+
* @input Uses @lexical/markdown (Lexical's QUOTE element transformer).
|
|
4
|
+
* @output Exports QUOTE_MARKERS, Lexical's quote transformer reading a block
|
|
5
|
+
* quote marker as CommonMark does.
|
|
6
|
+
* @position Part of DEFAULT_TRANSFORMERS (markdownTable.ts) in place of
|
|
7
|
+
* Lexical's QUOTE, whose pattern needs a space after `>` and no indentation.
|
|
8
|
+
* Matches core Markdown's block quote marker (CommonMark 0.31 §5.1). Typing
|
|
9
|
+
* shortcuts keep Lexical's own trigger: `> ` makes a quote. Text that starts
|
|
10
|
+
* like a marker is escaped on export by markdownSource.ts.
|
|
11
|
+
*/
|
|
12
|
+
import { type ElementTransformer } from '@lexical/markdown';
|
|
13
|
+
/**
|
|
14
|
+
* A block quote marker: up to three spaces of indentation, then `>` and the
|
|
15
|
+
* one space or tab that may follow it, so `>a` and ` > a` import as quotes,
|
|
16
|
+
* as in core Markdown. A typed line becomes a quote only at Lexical's own
|
|
17
|
+
* `> `, so typing `>` and Enter, or ` > `, changes nothing new. RichText
|
|
18
|
+
* quotes do not nest: the marker of a quote inside a quote stays in the
|
|
19
|
+
* outer quote's text.
|
|
20
|
+
*/
|
|
21
|
+
export declare const QUOTE_MARKERS: ElementTransformer;
|
|
22
|
+
//# sourceMappingURL=markdownQuote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownQuote.d.ts","sourceRoot":"","sources":["../src/markdownQuote.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH,OAAO,EAAQ,KAAK,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAKjE;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,kBAO3B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownQuote.ts
|
|
5
|
+
* @input Uses @lexical/markdown (Lexical's QUOTE element transformer).
|
|
6
|
+
* @output Exports QUOTE_MARKERS, Lexical's quote transformer reading a block
|
|
7
|
+
* quote marker as CommonMark does.
|
|
8
|
+
* @position Part of DEFAULT_TRANSFORMERS (markdownTable.ts) in place of
|
|
9
|
+
* Lexical's QUOTE, whose pattern needs a space after `>` and no indentation.
|
|
10
|
+
* Matches core Markdown's block quote marker (CommonMark 0.31 §5.1). Typing
|
|
11
|
+
* shortcuts keep Lexical's own trigger: `> ` makes a quote. Text that starts
|
|
12
|
+
* like a marker is escaped on export by markdownSource.ts.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { QUOTE } from '@lexical/markdown';
|
|
16
|
+
|
|
17
|
+
/** Lexical's own quote marker, which the typing shortcut keeps using. */
|
|
18
|
+
const SHORTCUT_MARKER = /^>\s/;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A block quote marker: up to three spaces of indentation, then `>` and the
|
|
22
|
+
* one space or tab that may follow it, so `>a` and ` > a` import as quotes,
|
|
23
|
+
* as in core Markdown. A typed line becomes a quote only at Lexical's own
|
|
24
|
+
* `> `, so typing `>` and Enter, or ` > `, changes nothing new. RichText
|
|
25
|
+
* quotes do not nest: the marker of a quote inside a quote stays in the
|
|
26
|
+
* outer quote's text.
|
|
27
|
+
*/
|
|
28
|
+
export const QUOTE_MARKERS = {
|
|
29
|
+
...QUOTE,
|
|
30
|
+
regExp: /^ {0,3}>[ \t]?/,
|
|
31
|
+
replace: (parentNode, children, match, isImport) => isImport || SHORTCUT_MARKER.test(match[0]) ? QUOTE.replace(parentNode, children, match, isImport) : false
|
|
32
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Transformer } from '@lexical/markdown';
|
|
2
|
+
import { type RichTextMarkdownExtension } from './markdownExtensions.js';
|
|
3
|
+
import type { Klass, LexicalNode } from 'lexical';
|
|
4
|
+
/** Options shared by the Markdown serializer helpers. */
|
|
5
|
+
export interface MarkdownSerializerOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Markdown transformers to use. Defaults to the editor's default set: the
|
|
8
|
+
* standard `@lexical/markdown` `TRANSFORMERS` plus GFM tables. Pass the same
|
|
9
|
+
* array you give `RichTextEditor`'s `transformers` prop so content
|
|
10
|
+
* round-trips consistently.
|
|
11
|
+
*/
|
|
12
|
+
transformers?: ReadonlyArray<Transformer>;
|
|
13
|
+
/**
|
|
14
|
+
* Extra Lexical nodes to register beyond the default OSS set, mirroring the
|
|
15
|
+
* editor's `nodes` prop. Required for custom node types to serialize.
|
|
16
|
+
*/
|
|
17
|
+
nodes?: ReadonlyArray<Klass<LexicalNode>>;
|
|
18
|
+
/**
|
|
19
|
+
* Markdown plugins to recognize, each adopted with `createRichTextExtension`
|
|
20
|
+
* (spec:AST-064). Their syntax becomes extension nodes holding its exact
|
|
21
|
+
* source; without them, plugin syntax stays text. Pass the same extensions
|
|
22
|
+
* the surfaces that show the document use.
|
|
23
|
+
*/
|
|
24
|
+
extensions?: ReadonlyArray<RichTextMarkdownExtension>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert a Markdown string to a serialized Lexical `EditorState` JSON string
|
|
28
|
+
* — the same shape `RichTextEditor`'s `defaultValue` expects. Runs headless
|
|
29
|
+
* (no DOM), so it is safe in Node / SSR.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```
|
|
33
|
+
* const value = markdownToEditorStateJSON('# Title\n\nHello');
|
|
34
|
+
* <RichTextEditor label="Notes" defaultValue={value} />
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function markdownToEditorStateJSON(markdown: string, options?: MarkdownSerializerOptions): string;
|
|
38
|
+
/**
|
|
39
|
+
* Convert a serialized Lexical `EditorState` JSON string (e.g. the value
|
|
40
|
+
* produced by `RichTextEditor`'s `onChange` or `defaultValue`) to a Markdown
|
|
41
|
+
* string. Runs headless (no DOM), so it is safe in Node / SSR.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```
|
|
45
|
+
* const md = editorStateJSONToMarkdown(savedJson);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function editorStateJSONToMarkdown(editorStateJSON: string, options?: MarkdownSerializerOptions): string;
|
|
49
|
+
//# sourceMappingURL=markdownSerializers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownSerializers.d.ts","sourceRoot":"","sources":["../src/markdownSerializers.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAOnD,OAAO,EAAY,KAAK,yBAAyB,EAAC,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAC,KAAK,EAAE,WAAW,EAAC,MAAM,SAAS,CAAC;AAEhD,yDAAyD;AACzD,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC1C;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC,yBAAyB,CAAC,CAAC;CACvD;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,MAAM,CAMR;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,yBAA8B,GACtC,MAAM,CAKR"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file markdownSerializers.ts
|
|
5
|
+
* @input Uses @lexical/headless (createHeadlessEditor), @lexical/markdown
|
|
6
|
+
* (transformer types), the shared DEFAULT_NODES set, DEFAULT_TRANSFORMERS,
|
|
7
|
+
* and the source-preserving import and export in markdownSource.ts.
|
|
8
|
+
* @output Standalone Markdown <-> serialized EditorState helpers:
|
|
9
|
+
* markdownToEditorStateJSON, editorStateJSONToMarkdown.
|
|
10
|
+
* @position Exported from the server-safe `@blue-patterns/richtext/markdown`
|
|
11
|
+
* entry and re-exported from the @blue-patterns/richtext barrel. Complements the ref's getMarkdown() by working WITHOUT a mounted
|
|
12
|
+
* editor (e.g. to produce a `defaultValue` from Markdown on the server).
|
|
13
|
+
*
|
|
14
|
+
* SYNC: When modified, update:
|
|
15
|
+
* - /packages/richtext/src/index.ts (exports)
|
|
16
|
+
* - /packages/richtext/src/RichTextEditor.doc.mjs (usage notes)
|
|
17
|
+
* - /packages/richtext/src/RichTextEditor.test.tsx (tests)
|
|
18
|
+
*
|
|
19
|
+
* NOTE: `@lexical/headless`, `@lexical/markdown`, and `lexical` are OPTIONAL
|
|
20
|
+
* peer dependencies. Install them to use these helpers. `@lexical/headless`
|
|
21
|
+
* runs Lexical without a DOM, so these work in Node / SSR contexts.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { createHeadlessEditor } from '@lexical/headless';
|
|
25
|
+
import { DEFAULT_NODES } from "./editorNodes.js";
|
|
26
|
+
import { $exportMarkdownKeepingSource, importMarkdownKeepingSource } from "./markdownSource.js";
|
|
27
|
+
import { DEFAULT_TRANSFORMERS } from "./markdownTable.js";
|
|
28
|
+
import { pluginsOf } from "./markdownExtensions.js";
|
|
29
|
+
|
|
30
|
+
/** Options shared by the Markdown serializer helpers. */
|
|
31
|
+
|
|
32
|
+
function createSerializerEditor(nodes) {
|
|
33
|
+
return createHeadlessEditor({
|
|
34
|
+
namespace: 'astryx-editor-serializer',
|
|
35
|
+
nodes: nodes ? [...DEFAULT_NODES, ...nodes] : [...DEFAULT_NODES],
|
|
36
|
+
onError(error) {
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Convert a Markdown string to a serialized Lexical `EditorState` JSON string
|
|
44
|
+
* — the same shape `RichTextEditor`'s `defaultValue` expects. Runs headless
|
|
45
|
+
* (no DOM), so it is safe in Node / SSR.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```
|
|
49
|
+
* const value = markdownToEditorStateJSON('# Title\n\nHello');
|
|
50
|
+
* <RichTextEditor label="Notes" defaultValue={value} />
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function markdownToEditorStateJSON(markdown, options = {}) {
|
|
54
|
+
const {
|
|
55
|
+
transformers = DEFAULT_TRANSFORMERS,
|
|
56
|
+
nodes,
|
|
57
|
+
extensions = []
|
|
58
|
+
} = options;
|
|
59
|
+
const plugins = pluginsOf(extensions, transformers);
|
|
60
|
+
const editor = createSerializerEditor(nodes);
|
|
61
|
+
importMarkdownKeepingSource(editor, markdown, [...transformers], plugins);
|
|
62
|
+
return JSON.stringify(editor.getEditorState().toJSON());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Convert a serialized Lexical `EditorState` JSON string (e.g. the value
|
|
67
|
+
* produced by `RichTextEditor`'s `onChange` or `defaultValue`) to a Markdown
|
|
68
|
+
* string. Runs headless (no DOM), so it is safe in Node / SSR.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```
|
|
72
|
+
* const md = editorStateJSONToMarkdown(savedJson);
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function editorStateJSONToMarkdown(editorStateJSON, options = {}) {
|
|
76
|
+
const {
|
|
77
|
+
transformers = DEFAULT_TRANSFORMERS,
|
|
78
|
+
nodes
|
|
79
|
+
} = options;
|
|
80
|
+
const editor = createSerializerEditor(nodes);
|
|
81
|
+
const state = editor.parseEditorState(editorStateJSON);
|
|
82
|
+
return state.read(() => $exportMarkdownKeepingSource([...transformers]));
|
|
83
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file markdownSource.ts
|
|
3
|
+
* @input Uses lexical (node state, root, node classes), @lexical/markdown
|
|
4
|
+
* ($convertFromMarkdownString / $convertToMarkdownString), @lexical/code,
|
|
5
|
+
* and the plugin node shielding and export in markdownExtensions.ts.
|
|
6
|
+
* @output Exports importMarkdownKeepingSource and $exportMarkdownKeepingSource,
|
|
7
|
+
* the source-preserving Markdown import and export behind
|
|
8
|
+
* markdownToEditorStateJSON, editorStateJSONToMarkdown, and getMarkdown().
|
|
9
|
+
* @position Internal to @blue-patterns/richtext. Implements spec:AST-062: an
|
|
10
|
+
* untouched top-level block exports exactly as authored, and an edit
|
|
11
|
+
* regenerates only the blocks it changed.
|
|
12
|
+
*
|
|
13
|
+
* Import splits the source into chunks (runs of non-blank lines; a fenced code
|
|
14
|
+
* block is one chunk even across blank lines) and imports each chunk on its
|
|
15
|
+
* own. Once node transforms settle the tree, the top-level nodes from one or
|
|
16
|
+
* more consecutive chunks form a group, and the group's first node records the
|
|
17
|
+
* exact bytes it came from and its canonical Markdown at import. Facts about
|
|
18
|
+
* the whole document — its byte order mark, the bytes before the first block
|
|
19
|
+
* and after the last, its line ending — live on the root, so moving, copying,
|
|
20
|
+
* or deleting blocks never moves or duplicates them.
|
|
21
|
+
*
|
|
22
|
+
* Export reads the tree without changing it. Each group's canonical Markdown
|
|
23
|
+
* is regenerated (and cached per node, so an unchanged tree costs a lookup per
|
|
24
|
+
* group); when it still matches the recorded one, the recorded bytes are
|
|
25
|
+
* written instead.
|
|
26
|
+
*/
|
|
27
|
+
import { type Transformer } from '@lexical/markdown';
|
|
28
|
+
import { type ElementNode, type LexicalEditor } from 'lexical';
|
|
29
|
+
import type { MarkdownPluginEntry } from '@blue-patterns/core/Markdown/plugins';
|
|
30
|
+
/** The whitespace and content one chunk of Markdown source was split into. */
|
|
31
|
+
export interface MarkdownChunk {
|
|
32
|
+
/** Blank lines before the chunk; only the first chunk has any. */
|
|
33
|
+
readonly leading: string;
|
|
34
|
+
/** The chunk's lines, without the line ending that ends the last one. */
|
|
35
|
+
readonly content: string;
|
|
36
|
+
/** Everything after the content up to the next chunk, or to the end. */
|
|
37
|
+
readonly trailing: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function splitMarkdownChunks(markdown: string): Array<MarkdownChunk>;
|
|
40
|
+
/**
|
|
41
|
+
* Imports Markdown into the editor's root and records its authored bytes. Runs
|
|
42
|
+
* two discrete updates: the first imports every chunk and stamps its nodes
|
|
43
|
+
* with the chunk's group id; the second runs after node transforms have
|
|
44
|
+
* settled the tree (adjacent lists merge, for example), so each group covers
|
|
45
|
+
* exactly the chunks that ended up in its nodes.
|
|
46
|
+
*/
|
|
47
|
+
export declare function importMarkdownKeepingSource(editor: LexicalEditor, markdown: string, transformers: Array<Transformer>, plugins?: ReadonlyArray<MarkdownPluginEntry>): void;
|
|
48
|
+
/**
|
|
49
|
+
* Joins the lines of a paragraph, list item, or block quote across soft line
|
|
50
|
+
* breaks: a line ending without two trailing spaces or a backslash continues
|
|
51
|
+
* the block, as one space (CommonMark, soft line breaks; spec:AST-061 FR5).
|
|
52
|
+
* Lexical imports every line ending as a line break and marks the hard ones,
|
|
53
|
+
* so the unmarked ones outside code are the soft breaks.
|
|
54
|
+
*/
|
|
55
|
+
export declare function $joinSoftLineBreaks(element: ElementNode): void;
|
|
56
|
+
/**
|
|
57
|
+
* Moves a list that begins nested right after another list into that list's
|
|
58
|
+
* last item. Lexical starts a new top-level list for an item of a different
|
|
59
|
+
* type (a bullet under `1. item`) and nests it there, while CommonMark nests
|
|
60
|
+
* it inside the item above; without this, writing it back would lose the
|
|
61
|
+
* nesting (spec:AST-061 FR5, spec:AST-062 FR3).
|
|
62
|
+
*/
|
|
63
|
+
export declare function $nestFollowingLists(root: ElementNode): void;
|
|
64
|
+
/**
|
|
65
|
+
* A token that appears nowhere in `text`. There are 137,468 private-use code
|
|
66
|
+
* points, so a text shorter than that always misses one of them; a longer
|
|
67
|
+
* text cannot contain every one of the 137,468² ordered pairs.
|
|
68
|
+
*/
|
|
69
|
+
export declare function absentToken(text: string): string;
|
|
70
|
+
export declare function $exportMarkdownKeepingSource(transformers: ReadonlyArray<Transformer>): string;
|
|
71
|
+
//# sourceMappingURL=markdownSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdownSource.d.ts","sourceRoot":"","sources":["../src/markdownSource.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAA6B,KAAK,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAI/E,OAAO,EAUL,KAAK,WAAW,EAChB,KAAK,aAAa,EAGnB,MAAM,SAAS,CAAC;AAyBjB,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,sCAAsC,CAAC;AAE9E,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AA0JD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,CA4E1E;AA8CD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,EAChC,OAAO,GAAE,aAAa,CAAC,mBAAmB,CAAM,GAC/C,IAAI,CAgGN;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA6B9D;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAoB3D;AAsLD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBhD;AAmOD,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,aAAa,CAAC,WAAW,CAAC,GACvC,MAAM,CA0ER"}
|