@astryxdesign/richtext 0.6.5-canary.24fe2cd → 0.6.5-canary.258ff02
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/README.md +3 -2
- package/dist/CodeBlockHeaderPlugin.d.ts +7 -0
- package/dist/CodeBlockHeaderPlugin.d.ts.map +1 -0
- package/dist/CodeBlockHeaderPlugin.js +196 -0
- package/dist/RichTextEditor.d.ts +15 -7
- package/dist/RichTextEditor.d.ts.map +1 -1
- package/dist/RichTextEditor.js +63 -10
- package/dist/RichTextEditorAutoLinkPlugin.d.ts +10 -11
- package/dist/RichTextEditorAutoLinkPlugin.d.ts.map +1 -1
- package/dist/RichTextEditorAutoLinkPlugin.js +10 -11
- package/dist/RichTextEditorToolbar.d.ts.map +1 -1
- package/dist/RichTextEditorToolbar.js +2 -3
- package/dist/RichTextView.d.ts +12 -4
- package/dist/RichTextView.d.ts.map +1 -1
- package/dist/RichTextView.js +80 -18
- package/dist/TableColumnFloorPlugin.d.ts +12 -0
- package/dist/TableColumnFloorPlugin.d.ts.map +1 -0
- package/dist/TableColumnFloorPlugin.js +84 -0
- package/dist/TableScrollRegionPlugin.d.ts +9 -0
- package/dist/TableScrollRegionPlugin.d.ts.map +1 -0
- package/dist/TableScrollRegionPlugin.js +95 -0
- package/dist/TaskCheckboxPlugin.d.ts +7 -0
- package/dist/TaskCheckboxPlugin.d.ts.map +1 -0
- package/dist/TaskCheckboxPlugin.js +193 -0
- package/dist/editorNodes.d.ts +2 -2
- package/dist/editorNodes.d.ts.map +1 -1
- package/dist/editorNodes.js +5 -3
- package/dist/editorTheme.d.ts.map +1 -1
- package/dist/editorTheme.js +256 -46
- package/dist/markdownCharacterReferences.d.ts +28 -0
- package/dist/markdownCharacterReferences.d.ts.map +1 -0
- package/dist/markdownCharacterReferences.js +314 -0
- package/dist/markdownHardLineBreak.d.ts +22 -0
- package/dist/markdownHardLineBreak.d.ts.map +1 -0
- package/dist/markdownHardLineBreak.js +38 -0
- package/dist/markdownListExport.d.ts +3 -0
- package/dist/markdownListExport.d.ts.map +1 -0
- package/dist/markdownListExport.js +65 -0
- package/dist/markdownListIndentation.d.ts +8 -0
- package/dist/markdownListIndentation.d.ts.map +1 -0
- package/dist/markdownListIndentation.js +85 -0
- package/dist/markdownSerializers.d.ts +4 -3
- package/dist/markdownSerializers.d.ts.map +1 -1
- package/dist/markdownSerializers.js +8 -11
- package/dist/markdownSource.d.ts +79 -0
- package/dist/markdownSource.d.ts.map +1 -0
- package/dist/markdownSource.js +577 -0
- package/dist/markdownTable.d.ts +32 -0
- package/dist/markdownTable.d.ts.map +1 -0
- package/dist/markdownTable.js +191 -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/richtext.css +95 -16
- package/package.json +14 -3
- package/src/CodeBlockHeaderPlugin.test.tsx +100 -0
- package/src/CodeBlockHeaderPlugin.tsx +261 -0
- package/src/RichTextEditor.doc.mjs +28 -7
- package/src/RichTextEditor.test.tsx +420 -18
- package/src/RichTextEditor.tsx +82 -19
- package/src/RichTextEditorAutoLinkPlugin.tsx +10 -11
- package/src/RichTextEditorToolbar.tsx +2 -3
- package/src/RichTextView.tsx +85 -26
- package/src/TableColumnFloorPlugin.test.tsx +49 -0
- package/src/TableColumnFloorPlugin.tsx +99 -0
- package/src/TableScrollRegionPlugin.test.tsx +138 -0
- package/src/TableScrollRegionPlugin.tsx +107 -0
- package/src/TaskCheckboxPlugin.tsx +242 -0
- package/src/__tests__/MarkdownParitySandbox.a11y.chromium.spec.ts +1413 -0
- package/src/doc-mjs.d.ts +23 -0
- package/src/editorNodes.ts +8 -2
- package/src/editorTheme.ts +363 -56
- package/src/markdownCharacterReferences.test.ts +202 -0
- package/src/markdownCharacterReferences.ts +339 -0
- package/src/markdownHardLineBreak.ts +47 -0
- package/src/markdownListExport.ts +80 -0
- package/src/markdownListIndentation.test.ts +235 -0
- package/src/markdownListIndentation.ts +89 -0
- package/src/markdownSerializers.ts +16 -20
- package/src/markdownSource.test.tsx +646 -0
- package/src/markdownSource.ts +743 -0
- package/src/markdownTable.test.tsx +214 -0
- package/src/markdownTable.ts +255 -0
- package/src/markdownTaskList.test.tsx +445 -0
- package/src/markdownTaskList.ts +222 -0
- package/src/markdownThematicBreak.test.tsx +185 -0
- package/src/markdownThematicBreak.ts +66 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ with Astryx design tokens.
|
|
|
7
7
|
import {RichTextEditor, RichTextView} from '@astryxdesign/richtext';
|
|
8
8
|
|
|
9
9
|
<RichTextEditor label="Notes" onChange={setState} />;
|
|
10
|
-
<RichTextView
|
|
10
|
+
<RichTextView value={serializedState} />;
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The editor is deliberately minimal and extensible: pass `nodes` and `plugins` to
|
|
@@ -27,7 +27,8 @@ It ships to npm **only under the `@canary` dist-tag** — there is never a stabl
|
|
|
27
27
|
|
|
28
28
|
> Note: this package is the successor to the experimental `RichTextEditor` that
|
|
29
29
|
> used to live in `@astryxdesign/lab`; that code has moved here so it can be
|
|
30
|
-
> canaried independently
|
|
30
|
+
> canaried independently by an adopting application without a fresh package
|
|
31
|
+
> rollout.
|
|
31
32
|
|
|
32
33
|
## Status
|
|
33
34
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type JSX } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Draws a header over each top-level code block and keeps it there as the
|
|
4
|
+
* document, the editor's size, or the window changes.
|
|
5
|
+
*/
|
|
6
|
+
export declare function CodeBlockHeaderPlugin(): JSX.Element;
|
|
7
|
+
//# sourceMappingURL=CodeBlockHeaderPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeBlockHeaderPlugin.d.ts","sourceRoot":"","sources":["../src/CodeBlockHeaderPlugin.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAsB,KAAK,GAAG,EAAC,MAAM,OAAO,CAAC;AA8JpD;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,GAAG,CAAC,OAAO,CA+EnD"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file CodeBlockHeaderPlugin.tsx
|
|
7
|
+
* @input Uses @lexical/react (composer context), @lexical/code (CodeNode),
|
|
8
|
+
* lexical, and core IconButton, Icon, useClipboard, and useTranslator.
|
|
9
|
+
* @output Exports CodeBlockHeaderPlugin, which draws core CodeBlock's header
|
|
10
|
+
* over every fenced code block: the language label and a copy button, or
|
|
11
|
+
* just the copy button in the corner when the block names no language.
|
|
12
|
+
* @position Rendered by RichTextEditor and RichTextView inside the positioned
|
|
13
|
+
* element that holds the content editable. The headers are siblings of the
|
|
14
|
+
* editable text, never inside it, so they are not part of the document and
|
|
15
|
+
* cannot be edited (spec:AST-061 FR8, DEC-4). The code block's theme class
|
|
16
|
+
* reserves the header's height, so the code sits where core Markdown's does.
|
|
17
|
+
*/
|
|
18
|
+
import * as stylex from '@stylexjs/stylex';
|
|
19
|
+
import { useEffect, useState } from 'react';
|
|
20
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
21
|
+
import { $isCodeNode } from '@lexical/code';
|
|
22
|
+
import { $getNodeByKey, $getRoot } from 'lexical';
|
|
23
|
+
import { Icon } from '@astryxdesign/core/Icon';
|
|
24
|
+
import { IconButton } from '@astryxdesign/core/IconButton';
|
|
25
|
+
import { useClipboard } from '@astryxdesign/core/hooks';
|
|
26
|
+
import { useTranslator } from '@astryxdesign/core/i18n';
|
|
27
|
+
import '@astryxdesign/core/theme/tokens.stylex';
|
|
28
|
+
import { fontWeightVars, spacingVars, typeScaleVars, typographyVars } from '@astryxdesign/core/theme/tokens.stylex';
|
|
29
|
+
|
|
30
|
+
/** Where one code block's header goes, in the container's coordinates. */
|
|
31
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
32
|
+
const styles = {
|
|
33
|
+
header: {
|
|
34
|
+
kVAEAm: "x10l6tqk",
|
|
35
|
+
k1xSpc: "x78zum5",
|
|
36
|
+
kGNEyG: "x6s0dn4",
|
|
37
|
+
kjj79g: "x1qughib",
|
|
38
|
+
k8WAf4: "xce4md1",
|
|
39
|
+
kg3NbH: "x1pzlopt",
|
|
40
|
+
kB7OPa: "x9f619",
|
|
41
|
+
$$css: true
|
|
42
|
+
},
|
|
43
|
+
corner: {
|
|
44
|
+
kVAEAm: "x10l6tqk",
|
|
45
|
+
k1xSpc: "x78zum5",
|
|
46
|
+
kjj79g: "x13a6bvl",
|
|
47
|
+
kmVPX3: "xlsj2fj",
|
|
48
|
+
kB7OPa: "x9f619",
|
|
49
|
+
kfzvcC: "x47corl",
|
|
50
|
+
$$css: true
|
|
51
|
+
},
|
|
52
|
+
cornerButton: {
|
|
53
|
+
kfzvcC: "x67bb7w",
|
|
54
|
+
$$css: true
|
|
55
|
+
},
|
|
56
|
+
copyButton: {
|
|
57
|
+
kMwMTN: "x1mjzq1q",
|
|
58
|
+
$$css: true
|
|
59
|
+
},
|
|
60
|
+
placement: (top, left, width) => [{
|
|
61
|
+
k87sOh: top != null ? "xjbys53" : top,
|
|
62
|
+
kbCHJM: left != null ? "xgq9j65" : left,
|
|
63
|
+
kzqmXN: width != null ? "x5lhr3w" : width,
|
|
64
|
+
$$css: true
|
|
65
|
+
}, {
|
|
66
|
+
"--x-top": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(top),
|
|
67
|
+
"--x-left": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(left),
|
|
68
|
+
"--x-width": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(width)
|
|
69
|
+
}]
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The language a header names, as core CodeBlock decides it: none for a fence
|
|
74
|
+
* without one, and none for exactly `plaintext`, which core Markdown gives a
|
|
75
|
+
* fence with no info string.
|
|
76
|
+
*/
|
|
77
|
+
function displayLanguageOf(language) {
|
|
78
|
+
return language == null || language === '' || language === PLAIN_TEXT ? null : language;
|
|
79
|
+
}
|
|
80
|
+
const PLAIN_TEXT = 'plaintext';
|
|
81
|
+
function samePlacements(a, b) {
|
|
82
|
+
return a.length === b.length && a.every((placement, index) => placement.key === b[index].key && placement.language === b[index].language && placement.top === b[index].top && placement.left === b[index].left && placement.width === b[index].width);
|
|
83
|
+
}
|
|
84
|
+
function CodeBlockHeader({
|
|
85
|
+
placement
|
|
86
|
+
}) {
|
|
87
|
+
const [editor] = useLexicalComposerContext();
|
|
88
|
+
const t = useTranslator();
|
|
89
|
+
const {
|
|
90
|
+
copy,
|
|
91
|
+
isCopied
|
|
92
|
+
} = useClipboard({
|
|
93
|
+
announce: t('@astryx.codeBlock.copied')
|
|
94
|
+
});
|
|
95
|
+
const copyButton = /*#__PURE__*/_jsx(IconButton, {
|
|
96
|
+
variant: "ghost",
|
|
97
|
+
size: "sm",
|
|
98
|
+
icon: /*#__PURE__*/_jsx(Icon, {
|
|
99
|
+
icon: isCopied ? 'check' : 'copy',
|
|
100
|
+
size: "sm",
|
|
101
|
+
color: "inherit"
|
|
102
|
+
}),
|
|
103
|
+
tooltip: t('@astryx.codeBlock.copyCode'),
|
|
104
|
+
label: isCopied ? t('@astryx.codeBlock.copied') : t('@astryx.codeBlock.copyCode'),
|
|
105
|
+
onClick: () => {
|
|
106
|
+
const code = editor.getEditorState().read(() => $getNodeByKey(placement.key)?.getTextContent() ?? '');
|
|
107
|
+
void copy(code);
|
|
108
|
+
},
|
|
109
|
+
xstyle: [styles.copyButton, placement.language == null && styles.cornerButton]
|
|
110
|
+
});
|
|
111
|
+
const position = styles.placement(placement.top, placement.left, placement.width);
|
|
112
|
+
if (placement.language == null) {
|
|
113
|
+
return /*#__PURE__*/_jsx("div", {
|
|
114
|
+
"data-richtext-code-header": "",
|
|
115
|
+
...stylex.props(styles.corner, position),
|
|
116
|
+
children: copyButton
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
120
|
+
"data-richtext-code-header": "",
|
|
121
|
+
...stylex.props(styles.header, position),
|
|
122
|
+
children: [/*#__PURE__*/_jsx("span", {
|
|
123
|
+
...{
|
|
124
|
+
className: "x141an7d x9m5x89 x1e4wzip x1ltkj2j x1mjzq1q xeuugli xb3r6kr xlyipyv xuxw1ft"
|
|
125
|
+
},
|
|
126
|
+
children: placement.language
|
|
127
|
+
}), copyButton]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Draws a header over each top-level code block and keeps it there as the
|
|
133
|
+
* document, the editor's size, or the window changes.
|
|
134
|
+
*/
|
|
135
|
+
export function CodeBlockHeaderPlugin() {
|
|
136
|
+
const [editor] = useLexicalComposerContext();
|
|
137
|
+
const [placements, setPlacements] = useState([]);
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
let frame = 0;
|
|
140
|
+
const measure = () => {
|
|
141
|
+
frame = 0;
|
|
142
|
+
const root = editor.getRootElement();
|
|
143
|
+
const container = root?.parentElement;
|
|
144
|
+
if (root == null || container == null) {
|
|
145
|
+
setPlacements(current => current.length === 0 ? current : []);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const origin = container.getBoundingClientRect();
|
|
149
|
+
const next = editor.getEditorState().read(() => $getRoot().getChildren().filter($isCodeNode).flatMap(node => {
|
|
150
|
+
const element = editor.getElementByKey(node.getKey());
|
|
151
|
+
if (element == null) {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
const box = element.getBoundingClientRect();
|
|
155
|
+
// Inside the block's border, so the header lines up with the
|
|
156
|
+
// padding the theme reserves for it.
|
|
157
|
+
return [{
|
|
158
|
+
key: node.getKey(),
|
|
159
|
+
language: displayLanguageOf(node.getLanguage()),
|
|
160
|
+
top: box.top - origin.top + element.clientTop,
|
|
161
|
+
left: box.left - origin.left + element.clientLeft,
|
|
162
|
+
width: element.clientWidth
|
|
163
|
+
}];
|
|
164
|
+
}));
|
|
165
|
+
setPlacements(current => samePlacements(current, next) ? current : next);
|
|
166
|
+
};
|
|
167
|
+
const schedule = () => {
|
|
168
|
+
if (frame === 0) {
|
|
169
|
+
frame = requestAnimationFrame(measure);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(schedule);
|
|
173
|
+
const unregisterRoot = editor.registerRootListener(root => {
|
|
174
|
+
observer?.disconnect();
|
|
175
|
+
if (root != null) {
|
|
176
|
+
observer?.observe(root);
|
|
177
|
+
}
|
|
178
|
+
schedule();
|
|
179
|
+
});
|
|
180
|
+
const unregisterUpdate = editor.registerUpdateListener(schedule);
|
|
181
|
+
window.addEventListener('resize', schedule);
|
|
182
|
+
schedule();
|
|
183
|
+
return () => {
|
|
184
|
+
cancelAnimationFrame(frame);
|
|
185
|
+
observer?.disconnect();
|
|
186
|
+
unregisterRoot();
|
|
187
|
+
unregisterUpdate();
|
|
188
|
+
window.removeEventListener('resize', schedule);
|
|
189
|
+
};
|
|
190
|
+
}, [editor]);
|
|
191
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
192
|
+
children: placements.map(placement => /*#__PURE__*/_jsx(CodeBlockHeader, {
|
|
193
|
+
placement: placement
|
|
194
|
+
}, placement.key))
|
|
195
|
+
});
|
|
196
|
+
}
|
package/dist/RichTextEditor.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* LexicalExtensionComposer), Field, VisuallyHidden, useInputStatusIcon,
|
|
5
5
|
* mergeProps, design tokens
|
|
6
6
|
* @output Exports an accessibly labelled RichTextEditor component with a flush
|
|
7
|
-
* top toolbar slot
|
|
7
|
+
* top toolbar slot, configurable editable-surface minimum height, and distinct
|
|
8
|
+
* read-only and disabled states that follow prop changes, RichTextEditorProps,
|
|
8
9
|
* RichTextEditorStatus, RichTextEditorStatusType, RichTextEditorSize
|
|
9
10
|
* @position Experimental (richtext) implementation; consumed by the package index.ts and
|
|
10
11
|
* re-exported from @astryxdesign/richtext. Tested by RichTextEditor.test.tsx.
|
|
@@ -56,8 +57,10 @@ export interface RichTextEditorRef {
|
|
|
56
57
|
/**
|
|
57
58
|
* Serialize the current content to a Markdown string, using the same
|
|
58
59
|
* `transformers` the editor is configured with (so custom transformers
|
|
59
|
-
* layered in via the `transformers` prop are honored).
|
|
60
|
-
*
|
|
60
|
+
* layered in via the `transformers` prop are honored). Content imported
|
|
61
|
+
* with `markdownToEditorStateJSON` comes back as written: blocks nobody
|
|
62
|
+
* changed byte for byte, and only edited or added blocks in canonical
|
|
63
|
+
* Markdown.
|
|
61
64
|
*/
|
|
62
65
|
getMarkdown: () => string;
|
|
63
66
|
/**
|
|
@@ -107,12 +110,16 @@ export interface RichTextEditorProps extends Omit<BaseProps, 'onChange' | 'defau
|
|
|
107
110
|
/** Placeholder text shown when the editor is empty. */
|
|
108
111
|
placeholder?: string;
|
|
109
112
|
/**
|
|
110
|
-
* Whether the editor is read-only (non-editable).
|
|
113
|
+
* Whether the editor is read-only (non-editable). The content stays at full
|
|
114
|
+
* opacity, in the tab order, and announced as read-only, so people can still
|
|
115
|
+
* reach, read, and copy it. Takes effect when changed after mount.
|
|
111
116
|
* @default false
|
|
112
117
|
*/
|
|
113
118
|
isReadOnly?: boolean;
|
|
114
119
|
/**
|
|
115
|
-
* Whether the editor is disabled
|
|
120
|
+
* Whether the editor is disabled: non-editable, dimmed, out of the tab
|
|
121
|
+
* order, and announced as disabled. Wins when `isReadOnly` is also set.
|
|
122
|
+
* Takes effect when changed after mount.
|
|
116
123
|
* @default false
|
|
117
124
|
*/
|
|
118
125
|
isDisabled?: boolean;
|
|
@@ -171,13 +178,14 @@ export interface RichTextEditorProps extends Omit<BaseProps, 'onChange' | 'defau
|
|
|
171
178
|
/**
|
|
172
179
|
* Whether to enable Markdown shortcut typing (e.g. `# ` for a heading,
|
|
173
180
|
* `- ` for a list). Uses the `transformers` prop (defaults to the standard
|
|
174
|
-
* `@lexical/markdown` transformers).
|
|
181
|
+
* `@lexical/markdown` transformers plus GFM tables).
|
|
175
182
|
* @default true
|
|
176
183
|
*/
|
|
177
184
|
hasMarkdownShortcuts?: boolean;
|
|
178
185
|
/**
|
|
179
186
|
* Markdown transformers — the single source of truth for markdown behaviour.
|
|
180
|
-
* Defaults to the standard `@lexical/markdown` `TRANSFORMERS
|
|
187
|
+
* Defaults to the standard `@lexical/markdown` `TRANSFORMERS` plus GFM
|
|
188
|
+
* tables. A custom array replaces the default, tables included.
|
|
181
189
|
*
|
|
182
190
|
* The same array drives all three markdown operations in Lexical (see the
|
|
183
191
|
* lexical-playground reference, where one `PLAYGROUND_TRANSFORMERS` array
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../src/RichTextEditor.tsx"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../src/RichTextEditor.tsx"],"names":[],"mappings":"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"}
|
package/dist/RichTextEditor.js
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* LexicalExtensionComposer), Field, VisuallyHidden, useInputStatusIcon,
|
|
9
9
|
* mergeProps, design tokens
|
|
10
10
|
* @output Exports an accessibly labelled RichTextEditor component with a flush
|
|
11
|
-
* top toolbar slot
|
|
11
|
+
* top toolbar slot, configurable editable-surface minimum height, and distinct
|
|
12
|
+
* read-only and disabled states that follow prop changes, RichTextEditorProps,
|
|
12
13
|
* RichTextEditorStatus, RichTextEditorStatusType, RichTextEditorSize
|
|
13
14
|
* @position Experimental (richtext) implementation; consumed by the package index.ts and
|
|
14
15
|
* re-exported from @astryxdesign/richtext. Tested by RichTextEditor.test.tsx.
|
|
@@ -46,9 +47,15 @@ import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
|
|
|
46
47
|
import { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin';
|
|
47
48
|
import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin';
|
|
48
49
|
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
|
|
49
|
-
import {
|
|
50
|
+
import { TablePlugin } from '@lexical/react/LexicalTablePlugin';
|
|
51
|
+
import { HorizontalRuleExtension } from '@lexical/extension';
|
|
52
|
+
import { TableColumnFloorPlugin } from "./TableColumnFloorPlugin.js";
|
|
53
|
+
import { CodeBlockHeaderPlugin } from "./CodeBlockHeaderPlugin.js";
|
|
54
|
+
import { TaskCheckboxPlugin } from "./TaskCheckboxPlugin.js";
|
|
50
55
|
import { $generateHtmlFromNodes } from '@lexical/html';
|
|
51
56
|
import { DEFAULT_NODES } from "./editorNodes.js";
|
|
57
|
+
import { $exportMarkdownKeepingSource } from "./markdownSource.js";
|
|
58
|
+
import { DEFAULT_TRANSFORMERS } from "./markdownTable.js";
|
|
52
59
|
import { BLUR_COMMAND, COMMAND_PRIORITY_LOW, defineExtension, KEY_DOWN_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, mergeRegister } from 'lexical';
|
|
53
60
|
|
|
54
61
|
/**
|
|
@@ -214,7 +221,7 @@ export const RichTextEditor = /*#__PURE__*/forwardRef(function RichTextEditor({
|
|
|
214
221
|
toolbar,
|
|
215
222
|
plugins,
|
|
216
223
|
hasMarkdownShortcuts = true,
|
|
217
|
-
transformers =
|
|
224
|
+
transformers = DEFAULT_TRANSFORMERS,
|
|
218
225
|
hasAutoFocus = false,
|
|
219
226
|
tabEscapeHint = DEFAULT_TAB_ESCAPE_HINT,
|
|
220
227
|
maxLength,
|
|
@@ -268,6 +275,8 @@ export const RichTextEditor = /*#__PURE__*/forwardRef(function RichTextEditor({
|
|
|
268
275
|
theme: themeRef.current,
|
|
269
276
|
editable,
|
|
270
277
|
nodes: nodes ? [...DEFAULT_NODES, ...nodes] : [...DEFAULT_NODES],
|
|
278
|
+
// Horizontal rules select on click and show their selection.
|
|
279
|
+
dependencies: [HorizontalRuleExtension],
|
|
271
280
|
// `undefined` (not `null`) leaves Lexical's default initializer in place,
|
|
272
281
|
// which seeds the empty document with one paragraph — what
|
|
273
282
|
// LexicalComposer did when no `editorState` was given. `null` would mean
|
|
@@ -314,7 +323,10 @@ export const RichTextEditor = /*#__PURE__*/forwardRef(function RichTextEditor({
|
|
|
314
323
|
...mergeProps(themeProps('rich-text-editor', {
|
|
315
324
|
size,
|
|
316
325
|
status: status?.type ?? null
|
|
317
|
-
}), stylex.props(inputWrapperStyles.base, styles.wrapper,
|
|
326
|
+
}), stylex.props(inputWrapperStyles.base, styles.wrapper,
|
|
327
|
+
// Only disabled is dimmed, matching TextArea: a read-only editor
|
|
328
|
+
// keeps full-opacity text and stays keyboard-reachable.
|
|
329
|
+
isDisabled && inputWrapperStyles.disabled, isDisabled && styles.disabled, status && inputStatusBorderStyles[status.type], status && !isDisabled && !isReadOnly && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type], xstyle), className, style),
|
|
318
330
|
children: [/*#__PURE__*/_jsxs(LexicalExtensionComposer, {
|
|
319
331
|
extension: extensionRef.current,
|
|
320
332
|
contentEditable: null,
|
|
@@ -332,6 +344,8 @@ export const RichTextEditor = /*#__PURE__*/forwardRef(function RichTextEditor({
|
|
|
332
344
|
ariaDescribedBy: ariaDescribedBy,
|
|
333
345
|
ariaRequired: isRequired && !isOptional,
|
|
334
346
|
ariaInvalid: status?.type === 'error',
|
|
347
|
+
isReadOnly: isReadOnly,
|
|
348
|
+
isDisabled: isDisabled,
|
|
335
349
|
placeholderText: placeholder,
|
|
336
350
|
placeholderID: placeholderID,
|
|
337
351
|
minHeight: minHeight,
|
|
@@ -339,7 +353,14 @@ export const RichTextEditor = /*#__PURE__*/forwardRef(function RichTextEditor({
|
|
|
339
353
|
}),
|
|
340
354
|
placeholder: null,
|
|
341
355
|
ErrorBoundary: LexicalErrorBoundary
|
|
342
|
-
}), /*#__PURE__*/_jsx(HistoryPlugin, {}), /*#__PURE__*/_jsx(ListPlugin, {}), /*#__PURE__*/_jsx(
|
|
356
|
+
}), /*#__PURE__*/_jsx(HistoryPlugin, {}), /*#__PURE__*/_jsx(ListPlugin, {}), /*#__PURE__*/_jsx(TaskCheckboxPlugin, {
|
|
357
|
+
isReadOnly: isReadOnly || isDisabled
|
|
358
|
+
}), /*#__PURE__*/_jsx(LinkPlugin, {}), /*#__PURE__*/_jsx(TablePlugin, {
|
|
359
|
+
hasCellMerge: false,
|
|
360
|
+
hasCellBackgroundColor: false,
|
|
361
|
+
hasTabHandler: false,
|
|
362
|
+
hasHorizontalScroll: true
|
|
363
|
+
}), /*#__PURE__*/_jsx(TableColumnFloorPlugin, {}), /*#__PURE__*/_jsx(CodeBlockHeaderPlugin, {}), /*#__PURE__*/_jsx(TabIndentationPlugin, {}), /*#__PURE__*/_jsx(TabFocusEscapePlugin, {}), hasMarkdownShortcuts && /*#__PURE__*/_jsx(MarkdownShortcutPlugin, {
|
|
343
364
|
transformers: markdownTransformers
|
|
344
365
|
}), hasAutoFocus && /*#__PURE__*/_jsx(AutoFocusOnMount, {}), onChange && /*#__PURE__*/_jsx(OnChangePlugin, {
|
|
345
366
|
onChange: onChange,
|
|
@@ -468,6 +489,22 @@ function EditorRefBridge({
|
|
|
468
489
|
transformers
|
|
469
490
|
}) {
|
|
470
491
|
const [editor] = useLexicalComposerContext();
|
|
492
|
+
|
|
493
|
+
// The extension applies `editable` once, when the composer builds the
|
|
494
|
+
// editor, so a later isReadOnly/isDisabled change would leave
|
|
495
|
+
// contenteditable at its mount value while the wrapper styling and ARIA
|
|
496
|
+
// follow the props. Sync the editor on a prop change only: the mount value
|
|
497
|
+
// is already applied, and this bridge renders after `plugins`, so
|
|
498
|
+
// re-asserting it on mount would undo a plugin that set editability during
|
|
499
|
+
// its own mount.
|
|
500
|
+
const syncedEditableRef = useRef(editable);
|
|
501
|
+
useEffect(() => {
|
|
502
|
+
if (syncedEditableRef.current === editable) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
syncedEditableRef.current = editable;
|
|
506
|
+
editor.setEditable(editable);
|
|
507
|
+
}, [editor, editable]);
|
|
471
508
|
useImperativeHandle(editorRef, () => ({
|
|
472
509
|
focus: () => {
|
|
473
510
|
if (!editable) {
|
|
@@ -487,11 +524,11 @@ function EditorRefBridge({
|
|
|
487
524
|
},
|
|
488
525
|
getEditorState: () => editor.getEditorState(),
|
|
489
526
|
getMarkdown: () =>
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
// transformers round-trip
|
|
493
|
-
//
|
|
494
|
-
editor.getEditorState().read(() => $
|
|
527
|
+
// Untouched blocks export exactly as imported and changed blocks in
|
|
528
|
+
// canonical form (spec:AST-062). Honors the same transformers the
|
|
529
|
+
// editor uses for shortcuts, so custom transformers round-trip. Reads
|
|
530
|
+
// the state without changing it.
|
|
531
|
+
editor.getEditorState().read(() => $exportMarkdownKeepingSource(transformers)),
|
|
495
532
|
getHTML: () =>
|
|
496
533
|
// $generateHtmlFromNodes serializes the whole document (null selection)
|
|
497
534
|
// to HTML; must run in a read context and requires a DOM.
|
|
@@ -541,6 +578,8 @@ function EditorContentEditable({
|
|
|
541
578
|
ariaDescribedBy,
|
|
542
579
|
ariaRequired,
|
|
543
580
|
ariaInvalid,
|
|
581
|
+
isReadOnly,
|
|
582
|
+
isDisabled,
|
|
544
583
|
placeholderText,
|
|
545
584
|
placeholderID,
|
|
546
585
|
minHeight,
|
|
@@ -555,6 +594,20 @@ function EditorContentEditable({
|
|
|
555
594
|
'aria-describedby': ariaDescribedBy,
|
|
556
595
|
'aria-required': ariaRequired ? 'true' : undefined,
|
|
557
596
|
'aria-invalid': ariaInvalid ? 'true' : undefined,
|
|
597
|
+
// Lexical announces every non-editable surface as aria-readonly and
|
|
598
|
+
// leaves it out of the tab order. Split the two states: read-only stays
|
|
599
|
+
// reachable and is announced read-only; disabled is announced disabled
|
|
600
|
+
// instead. These keys land after Lexical's computed attributes, so the
|
|
601
|
+
// disabled branch's explicit `undefined` removes the wrong read-only
|
|
602
|
+
// announcement. With neither prop set no keys are passed, so a plugin
|
|
603
|
+
// that drives editor.setEditable keeps Lexical's own aria-readonly.
|
|
604
|
+
...(isDisabled ? {
|
|
605
|
+
'aria-disabled': 'true',
|
|
606
|
+
'aria-readonly': undefined
|
|
607
|
+
} : isReadOnly ? {
|
|
608
|
+
tabIndex: 0,
|
|
609
|
+
'aria-readonly': 'true'
|
|
610
|
+
} : null),
|
|
558
611
|
...stylex.props(styles.contentEditable, dynamicStyles.contentEditableMinHeight(minHeight)),
|
|
559
612
|
...rest
|
|
560
613
|
};
|
|
@@ -18,22 +18,21 @@
|
|
|
18
18
|
* NOTE: Experimental `@astryxdesign/richtext` component (canary). `lexical` and
|
|
19
19
|
* `@lexical/*` are OPTIONAL peer dependencies — install them to use this.
|
|
20
20
|
*
|
|
21
|
-
* COMPATIBILITY:
|
|
22
|
-
*
|
|
23
|
-
* matcher
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `AutoLinkPlugin`, and EPS can substitute its own plugin in the same slot.
|
|
21
|
+
* COMPATIBILITY: the plugin is deliberately a thin pass-through so an
|
|
22
|
+
* application with its own link conventions can adopt it without forking. It
|
|
23
|
+
* uses the stock matcher shape (`createLinkMatcherWithRegExp` + `attributes`)
|
|
24
|
+
* and new-tab defaults, so a consumer supplies a richer matcher set — an
|
|
25
|
+
* application-specific identifier or ticket syntax, say — through the
|
|
26
|
+
* `matchers` prop without changing the contract. An application needing a
|
|
27
|
+
* hardened transform (expanded separators, code-block exclusion) substitutes
|
|
28
|
+
* its own plugin in the same slot; astryx stays on the upstream
|
|
29
|
+
* `AutoLinkPlugin`.
|
|
31
30
|
*/
|
|
32
31
|
import { type LinkMatcher } from '@lexical/react/LexicalAutoLinkPlugin';
|
|
33
32
|
/**
|
|
34
33
|
* Attributes written onto every auto-created link so it opens in a new tab.
|
|
35
34
|
* `rel="noopener noreferrer"` is required whenever `target="_blank"` is set, to
|
|
36
|
-
* prevent reverse-tabnabbing.
|
|
35
|
+
* prevent reverse-tabnabbing.
|
|
37
36
|
*/
|
|
38
37
|
export declare const NEW_TAB_LINK_ATTRIBUTES: {
|
|
39
38
|
readonly target: "_blank";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichTextEditorAutoLinkPlugin.d.ts","sourceRoot":"","sources":["../src/RichTextEditorAutoLinkPlugin.tsx"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"RichTextEditorAutoLinkPlugin.d.ts","sourceRoot":"","sources":["../src/RichTextEditorAutoLinkPlugin.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,sCAAsC,CAAC;AAG9C;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;CAG1B,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,EAc9C,CAAC;AAEF,MAAM,WAAW,iCAAiC;IAChD;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAAC,EAC3C,QAAgC,EAChC,QAAQ,GACT,EAAE,iCAAiC,+BAEnC;yBALe,4BAA4B"}
|
|
@@ -22,16 +22,15 @@
|
|
|
22
22
|
* NOTE: Experimental `@astryxdesign/richtext` component (canary). `lexical` and
|
|
23
23
|
* `@lexical/*` are OPTIONAL peer dependencies — install them to use this.
|
|
24
24
|
*
|
|
25
|
-
* COMPATIBILITY:
|
|
26
|
-
*
|
|
27
|
-
* matcher
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* `AutoLinkPlugin`, and EPS can substitute its own plugin in the same slot.
|
|
25
|
+
* COMPATIBILITY: the plugin is deliberately a thin pass-through so an
|
|
26
|
+
* application with its own link conventions can adopt it without forking. It
|
|
27
|
+
* uses the stock matcher shape (`createLinkMatcherWithRegExp` + `attributes`)
|
|
28
|
+
* and new-tab defaults, so a consumer supplies a richer matcher set — an
|
|
29
|
+
* application-specific identifier or ticket syntax, say — through the
|
|
30
|
+
* `matchers` prop without changing the contract. An application needing a
|
|
31
|
+
* hardened transform (expanded separators, code-block exclusion) substitutes
|
|
32
|
+
* its own plugin in the same slot; astryx stays on the upstream
|
|
33
|
+
* `AutoLinkPlugin`.
|
|
35
34
|
*/
|
|
36
35
|
import { AutoLinkPlugin, createLinkMatcherWithRegExp } from '@lexical/react/LexicalAutoLinkPlugin';
|
|
37
36
|
import { URL_MATCHER, EMAIL_MATCHER, sanitizeUrl } from "./linkUtils.js";
|
|
@@ -39,7 +38,7 @@ import { URL_MATCHER, EMAIL_MATCHER, sanitizeUrl } from "./linkUtils.js";
|
|
|
39
38
|
/**
|
|
40
39
|
* Attributes written onto every auto-created link so it opens in a new tab.
|
|
41
40
|
* `rel="noopener noreferrer"` is required whenever `target="_blank"` is set, to
|
|
42
|
-
* prevent reverse-tabnabbing.
|
|
41
|
+
* prevent reverse-tabnabbing.
|
|
43
42
|
*/
|
|
44
43
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
45
44
|
export const NEW_TAB_LINK_ATTRIBUTES = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichTextEditorToolbar.d.ts","sourceRoot":"","sources":["../src/RichTextEditorToolbar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAgHf;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAwOX,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAClD;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnE;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAyB,EACzB,aAAkC,EAClC,IAAW,EACX,OAAc,EACd,YAAY,EACZ,iBAAwB,EACxB,UAAU,GACX,EAAE,0BAA0B,+
|
|
1
|
+
{"version":3,"file":"RichTextEditorToolbar.d.ts","sourceRoot":"","sources":["../src/RichTextEditorToolbar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAgHf;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAwOX,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAClD;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnE;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAyB,EACzB,aAAkC,EAClC,IAAW,EACX,OAAc,EACd,YAAY,EACZ,iBAAwB,EACxB,UAAU,GACX,EAAE,0BAA0B,+BA6d5B;yBAree,qBAAqB"}
|
|
@@ -431,9 +431,8 @@ export function RichTextEditorToolbar({
|
|
|
431
431
|
setActiveFormats(formats);
|
|
432
432
|
|
|
433
433
|
// Link active state — a link is "active" when the caret/selection anchor
|
|
434
|
-
// sits inside a LinkNode (or its immediate parent is one)
|
|
435
|
-
//
|
|
436
|
-
// the implementation astryx aims to be swappable with.
|
|
434
|
+
// sits inside a LinkNode (or its immediate parent is one):
|
|
435
|
+
// `$isLinkNode(parent) || $isLinkNode(node)`.
|
|
437
436
|
const node = selection.anchor.getNode();
|
|
438
437
|
const parent = node.getParent();
|
|
439
438
|
const linkNode = $isLinkNode(node) ? node : $isLinkNode(parent) ? parent : null;
|
package/dist/RichTextView.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file RichTextView.tsx
|
|
3
3
|
* @input Uses React, Lexical (lexical + @lexical/react, composed through
|
|
4
|
-
* LexicalExtensionComposer), design tokens
|
|
4
|
+
* LexicalExtensionComposer), mergeProps from core utils, design tokens,
|
|
5
|
+
* TableScrollRegionPlugin
|
|
5
6
|
* @output Exports RichTextView component and RichTextViewProps
|
|
6
|
-
* @position Read-only renderer for serialized Lexical editor state
|
|
7
|
-
*
|
|
7
|
+
* @position Read-only renderer for serialized Lexical editor state, exposed to
|
|
8
|
+
* assistive technology as document content rather than a form field;
|
|
9
|
+
* experimental (richtext), exported from @astryxdesign/richtext
|
|
8
10
|
*
|
|
9
11
|
* SYNC: When modified, update these files to stay in sync:
|
|
10
|
-
* - /packages/richtext/src/
|
|
12
|
+
* - /packages/richtext/src/RichTextEditor.test.tsx
|
|
11
13
|
* - /packages/richtext/src/index.ts
|
|
12
14
|
* - /apps/storybook/stories/RichTextEditor.stories.tsx
|
|
13
15
|
*/
|
|
@@ -52,6 +54,12 @@ export interface RichTextViewProps extends BaseProps {
|
|
|
52
54
|
* A read-only renderer for serialized Lexical content. Renders the same styled
|
|
53
55
|
* output as {@link RichTextEditor} without any editing affordances.
|
|
54
56
|
*
|
|
57
|
+
* The output is document content, not a form field: headings, lists and links
|
|
58
|
+
* keep their own roles for assistive technology, and the view takes no label.
|
|
59
|
+
* For a labelled, read-only field, use `<RichTextEditor isReadOnly />`. A
|
|
60
|
+
* table wider than the view scrolls inside a region named "Table" that takes a
|
|
61
|
+
* tab stop while it overflows, as core `Table` does.
|
|
62
|
+
*
|
|
55
63
|
* @example
|
|
56
64
|
* ```
|
|
57
65
|
* import {RichTextView} from '@astryxdesign/richtext';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichTextView.d.ts","sourceRoot":"","sources":["../src/RichTextView.tsx"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"RichTextView.d.ts","sourceRoot":"","sources":["../src/RichTextView.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAA8B,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGlE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAalD,OAAO,KAAK,EAEV,KAAK,EACL,WAAW,EAEZ,MAAM,SAAS,CAAC;AAyCjB,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1C;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACtC;;;;OAIG;IACH,aAAa,CAAC,EAAE,SAAS,CAAC;CAC3B;AAyCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,OAAO,EACP,SAAyB,EACzB,YAAY,EACZ,aAAoB,EACpB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,iBAAiB,+BAqHnB;yBAhIe,YAAY"}
|