@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.
Files changed (90) hide show
  1. package/README.md +3 -2
  2. package/dist/CodeBlockHeaderPlugin.d.ts +7 -0
  3. package/dist/CodeBlockHeaderPlugin.d.ts.map +1 -0
  4. package/dist/CodeBlockHeaderPlugin.js +196 -0
  5. package/dist/RichTextEditor.d.ts +15 -7
  6. package/dist/RichTextEditor.d.ts.map +1 -1
  7. package/dist/RichTextEditor.js +63 -10
  8. package/dist/RichTextEditorAutoLinkPlugin.d.ts +10 -11
  9. package/dist/RichTextEditorAutoLinkPlugin.d.ts.map +1 -1
  10. package/dist/RichTextEditorAutoLinkPlugin.js +10 -11
  11. package/dist/RichTextEditorToolbar.d.ts.map +1 -1
  12. package/dist/RichTextEditorToolbar.js +2 -3
  13. package/dist/RichTextView.d.ts +12 -4
  14. package/dist/RichTextView.d.ts.map +1 -1
  15. package/dist/RichTextView.js +80 -18
  16. package/dist/TableColumnFloorPlugin.d.ts +12 -0
  17. package/dist/TableColumnFloorPlugin.d.ts.map +1 -0
  18. package/dist/TableColumnFloorPlugin.js +84 -0
  19. package/dist/TableScrollRegionPlugin.d.ts +9 -0
  20. package/dist/TableScrollRegionPlugin.d.ts.map +1 -0
  21. package/dist/TableScrollRegionPlugin.js +95 -0
  22. package/dist/TaskCheckboxPlugin.d.ts +7 -0
  23. package/dist/TaskCheckboxPlugin.d.ts.map +1 -0
  24. package/dist/TaskCheckboxPlugin.js +193 -0
  25. package/dist/editorNodes.d.ts +2 -2
  26. package/dist/editorNodes.d.ts.map +1 -1
  27. package/dist/editorNodes.js +5 -3
  28. package/dist/editorTheme.d.ts.map +1 -1
  29. package/dist/editorTheme.js +256 -46
  30. package/dist/markdownCharacterReferences.d.ts +28 -0
  31. package/dist/markdownCharacterReferences.d.ts.map +1 -0
  32. package/dist/markdownCharacterReferences.js +314 -0
  33. package/dist/markdownHardLineBreak.d.ts +22 -0
  34. package/dist/markdownHardLineBreak.d.ts.map +1 -0
  35. package/dist/markdownHardLineBreak.js +38 -0
  36. package/dist/markdownListExport.d.ts +3 -0
  37. package/dist/markdownListExport.d.ts.map +1 -0
  38. package/dist/markdownListExport.js +65 -0
  39. package/dist/markdownListIndentation.d.ts +8 -0
  40. package/dist/markdownListIndentation.d.ts.map +1 -0
  41. package/dist/markdownListIndentation.js +85 -0
  42. package/dist/markdownSerializers.d.ts +4 -3
  43. package/dist/markdownSerializers.d.ts.map +1 -1
  44. package/dist/markdownSerializers.js +8 -11
  45. package/dist/markdownSource.d.ts +79 -0
  46. package/dist/markdownSource.d.ts.map +1 -0
  47. package/dist/markdownSource.js +577 -0
  48. package/dist/markdownTable.d.ts +32 -0
  49. package/dist/markdownTable.d.ts.map +1 -0
  50. package/dist/markdownTable.js +191 -0
  51. package/dist/markdownTaskList.d.ts +48 -0
  52. package/dist/markdownTaskList.d.ts.map +1 -0
  53. package/dist/markdownTaskList.js +166 -0
  54. package/dist/markdownThematicBreak.d.ts +3 -0
  55. package/dist/markdownThematicBreak.d.ts.map +1 -0
  56. package/dist/markdownThematicBreak.js +55 -0
  57. package/dist/richtext.css +95 -16
  58. package/package.json +14 -3
  59. package/src/CodeBlockHeaderPlugin.test.tsx +100 -0
  60. package/src/CodeBlockHeaderPlugin.tsx +261 -0
  61. package/src/RichTextEditor.doc.mjs +28 -7
  62. package/src/RichTextEditor.test.tsx +420 -18
  63. package/src/RichTextEditor.tsx +82 -19
  64. package/src/RichTextEditorAutoLinkPlugin.tsx +10 -11
  65. package/src/RichTextEditorToolbar.tsx +2 -3
  66. package/src/RichTextView.tsx +85 -26
  67. package/src/TableColumnFloorPlugin.test.tsx +49 -0
  68. package/src/TableColumnFloorPlugin.tsx +99 -0
  69. package/src/TableScrollRegionPlugin.test.tsx +138 -0
  70. package/src/TableScrollRegionPlugin.tsx +107 -0
  71. package/src/TaskCheckboxPlugin.tsx +242 -0
  72. package/src/__tests__/MarkdownParitySandbox.a11y.chromium.spec.ts +1413 -0
  73. package/src/doc-mjs.d.ts +23 -0
  74. package/src/editorNodes.ts +8 -2
  75. package/src/editorTheme.ts +363 -56
  76. package/src/markdownCharacterReferences.test.ts +202 -0
  77. package/src/markdownCharacterReferences.ts +339 -0
  78. package/src/markdownHardLineBreak.ts +47 -0
  79. package/src/markdownListExport.ts +80 -0
  80. package/src/markdownListIndentation.test.ts +235 -0
  81. package/src/markdownListIndentation.ts +89 -0
  82. package/src/markdownSerializers.ts +16 -20
  83. package/src/markdownSource.test.tsx +646 -0
  84. package/src/markdownSource.ts +743 -0
  85. package/src/markdownTable.test.tsx +214 -0
  86. package/src/markdownTable.ts +255 -0
  87. package/src/markdownTaskList.test.tsx +445 -0
  88. package/src/markdownTaskList.ts +222 -0
  89. package/src/markdownThematicBreak.test.tsx +185 -0
  90. 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 label="Notes" value={serializedState} />;
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 (e.g. into EPS/Nest) without a fresh package rollout.
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
+ }
@@ -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 and configurable editable-surface minimum height, RichTextEditorProps,
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). Equivalent to
60
- * `$convertToMarkdownString` run in a read context.
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 (non-editable, dimmed).
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":"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"}
1
+ {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../src/RichTextEditor.tsx"],"names":[],"mappings":"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"}
@@ -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 and configurable editable-surface minimum height, RichTextEditorProps,
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 { TRANSFORMERS, $convertToMarkdownString } from '@lexical/markdown';
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 = 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, (isDisabled || isReadOnly) && inputWrapperStyles.disabled, isDisabled && styles.disabled, status && inputStatusBorderStyles[status.type], status && !isDisabled && !isReadOnly && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type], xstyle), className, style),
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(LinkPlugin, {}), /*#__PURE__*/_jsx(TabIndentationPlugin, {}), /*#__PURE__*/_jsx(TabFocusEscapePlugin, {}), hasMarkdownShortcuts && /*#__PURE__*/_jsx(MarkdownShortcutPlugin, {
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
- // $convertToMarkdownString must run inside a read context. Honors the
491
- // same transformers the editor uses for shortcuts, so custom
492
- // transformers round-trip to Markdown. `@lexical/markdown` is a
493
- // subpackage (built dist) — safe, unlike a top-level `lexical` import.
494
- editor.getEditorState().read(() => $convertToMarkdownString(transformers)),
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: astryx aims for its RichTextEditor internals to eventually
22
- * back Meta's EPS `EPSRichTextArea` (nest/libs/eps-lexical). EPS's auto-link is
23
- * matcher-driven and applies `target="_blank"` + `rel="noopener noreferrer"` to
24
- * created links (its `NEW_TAB_LINK_ATTRIBUTES`). This plugin uses the same
25
- * matcher shape (`createLinkMatcherWithRegExp` + `attributes`) and the same
26
- * new-tab defaults, so EPS can pass its own richer matcher set (e.g. shortform
27
- * `D123` / `T456` / `S789` intern URLs) through the `matchers` prop without
28
- * changing the contract. EPS ships a hardened fork of the transform itself
29
- * (expanded separators, code-block exclusion) — astryx stays on the OSS
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. Matches EPS eps-lexical's `NEW_TAB_LINK_ATTRIBUTES`.
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;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"}
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: astryx aims for its RichTextEditor internals to eventually
26
- * back Meta's EPS `EPSRichTextArea` (nest/libs/eps-lexical). EPS's auto-link is
27
- * matcher-driven and applies `target="_blank"` + `rel="noopener noreferrer"` to
28
- * created links (its `NEW_TAB_LINK_ATTRIBUTES`). This plugin uses the same
29
- * matcher shape (`createLinkMatcherWithRegExp` + `attributes`) and the same
30
- * new-tab defaults, so EPS can pass its own richer matcher set (e.g. shortform
31
- * `D123` / `T456` / `S789` intern URLs) through the `matchers` prop without
32
- * changing the contract. EPS ships a hardened fork of the transform itself
33
- * (expanded separators, code-block exclusion) — astryx stays on the OSS
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. Matches EPS eps-lexical's `NEW_TAB_LINK_ATTRIBUTES`.
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,+BA8d5B;yBAtee,qBAAqB"}
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). Mirrors the EPS
435
- // eps-lexical toolbar (`$isLinkNode(parent) || $isLinkNode(node)`), which is
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;
@@ -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; experimental
7
- * (richtext), exported from @astryxdesign/richtext
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/RichTextView.test.tsx
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;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA8B,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGlE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAWlD,OAAO,KAAK,EAEV,KAAK,EACL,WAAW,EAEZ,MAAM,SAAS,CAAC;AAoBjB,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;;;;;;;;;GASG;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,+BAyFnB;yBApGe,YAAY"}
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"}