@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,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file RichTextEditorAutoLinkPlugin.tsx
|
|
3
|
+
* @input Uses `@lexical/react/LexicalAutoLinkPlugin` (`AutoLinkPlugin`,
|
|
4
|
+
* `createLinkMatcherWithRegExp`) and the shared URL/email matchers from
|
|
5
|
+
* `linkUtils`.
|
|
6
|
+
* @output Exports `RichTextEditorAutoLinkPlugin` and its props type, plus the
|
|
7
|
+
* default `DEFAULT_LINK_MATCHERS`.
|
|
8
|
+
* @position @blue-patterns/richtext. Drop into RichTextEditor's `plugins` slot to
|
|
9
|
+
* auto-linkify URLs and emails as they are typed or pasted, except inside
|
|
10
|
+
* a code block. Requires `AutoLinkNode` to be registered (it is, by
|
|
11
|
+
* default).
|
|
12
|
+
*
|
|
13
|
+
* SYNC: When modified, update:
|
|
14
|
+
* - /packages/richtext/src/index.ts (exports / barrel)
|
|
15
|
+
* - /packages/richtext/src/RichTextEditor.doc.mjs (usage notes)
|
|
16
|
+
* - /packages/richtext/src/RichTextEditor.test.tsx (tests)
|
|
17
|
+
* - /apps/storybook/stories/RichTextEditor.stories.tsx (story)
|
|
18
|
+
*
|
|
19
|
+
* NOTE: `lexical` and `@lexical/*` are OPTIONAL peer dependencies — install them
|
|
20
|
+
* to use this.
|
|
21
|
+
*
|
|
22
|
+
* COMPATIBILITY: the plugin is deliberately a thin pass-through so an
|
|
23
|
+
* application with its own link conventions can adopt it without forking. It
|
|
24
|
+
* uses the stock matcher shape (`createLinkMatcherWithRegExp` + `attributes`)
|
|
25
|
+
* and new-tab defaults, so a consumer supplies a richer matcher set — an
|
|
26
|
+
* application-specific identifier or ticket syntax, say — through the
|
|
27
|
+
* `matchers` prop without changing the contract. An application needing a
|
|
28
|
+
* hardened transform (expanded separators, say) substitutes its own plugin in
|
|
29
|
+
* the same slot; astryx stays on the upstream `AutoLinkPlugin`.
|
|
30
|
+
*/
|
|
31
|
+
import { type LinkMatcher } from '@lexical/react/LexicalAutoLinkPlugin';
|
|
32
|
+
/**
|
|
33
|
+
* Attributes written onto every auto-created link so it opens in a new tab.
|
|
34
|
+
* `rel="noopener noreferrer"` is required whenever `target="_blank"` is set, to
|
|
35
|
+
* prevent reverse-tabnabbing.
|
|
36
|
+
*/
|
|
37
|
+
export declare const NEW_TAB_LINK_ATTRIBUTES: {
|
|
38
|
+
readonly target: "_blank";
|
|
39
|
+
readonly rel: "noopener noreferrer";
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Default matchers: bare URLs (defaulting to `https://` when scheme-less) and
|
|
43
|
+
* email addresses (as `mailto:` links). Both carry {@link NEW_TAB_LINK_ATTRIBUTES}.
|
|
44
|
+
* URLs are passed through {@link sanitizeUrl} so only http/https/mailto/tel
|
|
45
|
+
* schemes are ever written.
|
|
46
|
+
*/
|
|
47
|
+
export declare const DEFAULT_LINK_MATCHERS: LinkMatcher[];
|
|
48
|
+
export interface RichTextEditorAutoLinkPluginProps {
|
|
49
|
+
/**
|
|
50
|
+
* Link matchers to use. Defaults to {@link DEFAULT_LINK_MATCHERS} (URLs +
|
|
51
|
+
* emails, opening in a new tab). Provide a custom array to recognize
|
|
52
|
+
* additional patterns (e.g. product-specific shortform references) — build
|
|
53
|
+
* each with `createLinkMatcherWithRegExp` from
|
|
54
|
+
* `@lexical/react/LexicalAutoLinkPlugin`.
|
|
55
|
+
*/
|
|
56
|
+
matchers?: LinkMatcher[];
|
|
57
|
+
/**
|
|
58
|
+
* Called when a link is created, updated, or removed by auto-linking.
|
|
59
|
+
* Receives the new URL (or `null` when removed) and the previous URL.
|
|
60
|
+
*/
|
|
61
|
+
onChange?: (url: string | null, prevUrl: string | null) => void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Automatically converts typed/pasted URLs and email addresses into links.
|
|
65
|
+
* Render it inside the editor's `plugins` slot — it reaches the editor via
|
|
66
|
+
* `useLexicalComposerContext()`, so it must live within the editor's
|
|
67
|
+
* `LexicalComposer`. Requires `AutoLinkNode` (registered by default).
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```
|
|
71
|
+
* import {RichTextEditor, RichTextEditorAutoLinkPlugin} from '@blue-patterns/richtext';
|
|
72
|
+
*
|
|
73
|
+
* <RichTextEditor
|
|
74
|
+
* label="Notes"
|
|
75
|
+
* plugins={<RichTextEditorAutoLinkPlugin />}
|
|
76
|
+
* />
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function RichTextEditorAutoLinkPlugin({ matchers, onChange, }: RichTextEditorAutoLinkPluginProps): import("react").JSX.Element;
|
|
80
|
+
export declare namespace RichTextEditorAutoLinkPlugin {
|
|
81
|
+
var displayName: string;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=RichTextEditorAutoLinkPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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;AAK9C;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;CAG1B,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,EAc9C,CAAC;AAMF,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,+BAQnC;yBAXe,4BAA4B"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file RichTextEditorAutoLinkPlugin.tsx
|
|
7
|
+
* @input Uses `@lexical/react/LexicalAutoLinkPlugin` (`AutoLinkPlugin`,
|
|
8
|
+
* `createLinkMatcherWithRegExp`) and the shared URL/email matchers from
|
|
9
|
+
* `linkUtils`.
|
|
10
|
+
* @output Exports `RichTextEditorAutoLinkPlugin` and its props type, plus the
|
|
11
|
+
* default `DEFAULT_LINK_MATCHERS`.
|
|
12
|
+
* @position @blue-patterns/richtext. Drop into RichTextEditor's `plugins` slot to
|
|
13
|
+
* auto-linkify URLs and emails as they are typed or pasted, except inside
|
|
14
|
+
* a code block. Requires `AutoLinkNode` to be registered (it is, by
|
|
15
|
+
* default).
|
|
16
|
+
*
|
|
17
|
+
* SYNC: When modified, update:
|
|
18
|
+
* - /packages/richtext/src/index.ts (exports / barrel)
|
|
19
|
+
* - /packages/richtext/src/RichTextEditor.doc.mjs (usage notes)
|
|
20
|
+
* - /packages/richtext/src/RichTextEditor.test.tsx (tests)
|
|
21
|
+
* - /apps/storybook/stories/RichTextEditor.stories.tsx (story)
|
|
22
|
+
*
|
|
23
|
+
* NOTE: `lexical` and `@lexical/*` are OPTIONAL peer dependencies — install them
|
|
24
|
+
* to use this.
|
|
25
|
+
*
|
|
26
|
+
* COMPATIBILITY: the plugin is deliberately a thin pass-through so an
|
|
27
|
+
* application with its own link conventions can adopt it without forking. It
|
|
28
|
+
* uses the stock matcher shape (`createLinkMatcherWithRegExp` + `attributes`)
|
|
29
|
+
* and new-tab defaults, so a consumer supplies a richer matcher set — an
|
|
30
|
+
* application-specific identifier or ticket syntax, say — through the
|
|
31
|
+
* `matchers` prop without changing the contract. An application needing a
|
|
32
|
+
* hardened transform (expanded separators, say) substitutes its own plugin in
|
|
33
|
+
* the same slot; astryx stays on the upstream `AutoLinkPlugin`.
|
|
34
|
+
*/
|
|
35
|
+
import { AutoLinkPlugin, createLinkMatcherWithRegExp } from '@lexical/react/LexicalAutoLinkPlugin';
|
|
36
|
+
import { $isCodeNode } from '@lexical/code';
|
|
37
|
+
import { URL_MATCHER, EMAIL_MATCHER, sanitizeUrl } from "./linkUtils.js";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Attributes written onto every auto-created link so it opens in a new tab.
|
|
41
|
+
* `rel="noopener noreferrer"` is required whenever `target="_blank"` is set, to
|
|
42
|
+
* prevent reverse-tabnabbing.
|
|
43
|
+
*/
|
|
44
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
45
|
+
export const NEW_TAB_LINK_ATTRIBUTES = {
|
|
46
|
+
target: '_blank',
|
|
47
|
+
rel: 'noopener noreferrer'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default matchers: bare URLs (defaulting to `https://` when scheme-less) and
|
|
52
|
+
* email addresses (as `mailto:` links). Both carry {@link NEW_TAB_LINK_ATTRIBUTES}.
|
|
53
|
+
* URLs are passed through {@link sanitizeUrl} so only http/https/mailto/tel
|
|
54
|
+
* schemes are ever written.
|
|
55
|
+
*/
|
|
56
|
+
export const DEFAULT_LINK_MATCHERS = [text => {
|
|
57
|
+
const match = createLinkMatcherWithRegExp(URL_MATCHER, url => sanitizeUrl(url))(text);
|
|
58
|
+
return match ? {
|
|
59
|
+
...match,
|
|
60
|
+
attributes: NEW_TAB_LINK_ATTRIBUTES
|
|
61
|
+
} : null;
|
|
62
|
+
}, text => {
|
|
63
|
+
const match = createLinkMatcherWithRegExp(EMAIL_MATCHER, email => `mailto:${email}`)(text);
|
|
64
|
+
return match ? {
|
|
65
|
+
...match,
|
|
66
|
+
attributes: NEW_TAB_LINK_ATTRIBUTES
|
|
67
|
+
} : null;
|
|
68
|
+
}];
|
|
69
|
+
|
|
70
|
+
// Text in a code block is never linked. The upstream plugin registers again
|
|
71
|
+
// when this array changes. Keep it a module constant.
|
|
72
|
+
const EXCLUDE_PARENTS = [$isCodeNode];
|
|
73
|
+
/**
|
|
74
|
+
* Automatically converts typed/pasted URLs and email addresses into links.
|
|
75
|
+
* Render it inside the editor's `plugins` slot — it reaches the editor via
|
|
76
|
+
* `useLexicalComposerContext()`, so it must live within the editor's
|
|
77
|
+
* `LexicalComposer`. Requires `AutoLinkNode` (registered by default).
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```
|
|
81
|
+
* import {RichTextEditor, RichTextEditorAutoLinkPlugin} from '@blue-patterns/richtext';
|
|
82
|
+
*
|
|
83
|
+
* <RichTextEditor
|
|
84
|
+
* label="Notes"
|
|
85
|
+
* plugins={<RichTextEditorAutoLinkPlugin />}
|
|
86
|
+
* />
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export function RichTextEditorAutoLinkPlugin({
|
|
90
|
+
matchers = DEFAULT_LINK_MATCHERS,
|
|
91
|
+
onChange
|
|
92
|
+
}) {
|
|
93
|
+
return /*#__PURE__*/_jsx(AutoLinkPlugin, {
|
|
94
|
+
matchers: matchers,
|
|
95
|
+
onChange: onChange,
|
|
96
|
+
excludeParents: EXCLUDE_PARENTS
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
RichTextEditorAutoLinkPlugin.displayName = 'RichTextEditorAutoLinkPlugin';
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file RichTextEditorToolbar.tsx
|
|
3
|
+
* @input Uses React, @lexical/react (composer context), @lexical/rich-text,
|
|
4
|
+
* @lexical/selection, @lexical/list, @lexical/utils, and the lexical core
|
|
5
|
+
* command constants, plus Astryx Toolbar / IconButton / Selector /
|
|
6
|
+
* ToggleButton / Divider / Layout primitives, and the link popover in
|
|
7
|
+
* ToolbarLinkPopover.
|
|
8
|
+
* @output Exports RichTextEditorToolbar (a compact formatting toolbar with a
|
|
9
|
+
* RichText-owned 4px control gutter, a horizontally scrollable action row,
|
|
10
|
+
* and a link popover anchored to its Link button) and
|
|
11
|
+
* RichTextEditorToolbarProps, plus format and glyph helpers RichText shares
|
|
12
|
+
* internally.
|
|
13
|
+
* @position @blue-patterns/richtext. Drop into RichTextEditor's `toolbar` slot to
|
|
14
|
+
* add a flush top formatting toolbar. Themed via Astryx Toolbar, Selector,
|
|
15
|
+
* IconButton, and ToggleButton, so it inherits the active theme. Base props
|
|
16
|
+
* pass through to the Astryx Toolbar exactly as Toolbar places them
|
|
17
|
+
* (spec:AST-061/DEC-8).
|
|
18
|
+
*
|
|
19
|
+
* SYNC: When modified, update:
|
|
20
|
+
* - /packages/richtext/src/index.ts (exports)
|
|
21
|
+
* - /packages/richtext/src/RichTextEditor.doc.mjs (usage notes)
|
|
22
|
+
* - /packages/richtext/src/RichTextEditor.test.tsx (tests)
|
|
23
|
+
* - /apps/storybook/stories/RichTextEditor.stories.tsx (WithToolbar story)
|
|
24
|
+
*
|
|
25
|
+
* NOTE: `lexical` and `@lexical/*` are OPTIONAL peer dependencies — install them
|
|
26
|
+
* to use this.
|
|
27
|
+
* Behavior mirrors the Lexical playground toolbar (selection sync + format
|
|
28
|
+
* commands); the UI is built from Astryx primitives so it matches the theme.
|
|
29
|
+
*
|
|
30
|
+
* ICONS: Each control resolves its glyph through the core icon registry under a
|
|
31
|
+
* stable `richtext:*` key (see {@link RICHTEXT_ICON_KEYS}) for the active
|
|
32
|
+
* theme, falling back to the bundled inline SVGs below — the library seam
|
|
33
|
+
* `getExtendedIcon` documents. A theme restyles any glyph by naming its key:
|
|
34
|
+
* defineTheme({icons: {'richtext:bold': <MyBoldIcon />}});
|
|
35
|
+
* Undo and redo point backward and forward in time, so they mirror under RTL
|
|
36
|
+
* whichever glyph draws them.
|
|
37
|
+
*/
|
|
38
|
+
import { type ReactNode, type Ref } from 'react';
|
|
39
|
+
import type { BaseProps } from '@blue-patterns/core';
|
|
40
|
+
import { type TranslatorFn } from '@blue-patterns/core/i18n';
|
|
41
|
+
import { type LexicalEditor, type NodeSelection, type RangeSelection } from 'lexical';
|
|
42
|
+
/**
|
|
43
|
+
* Stable icon-registry keys for the toolbar's controls. A theme overrides any
|
|
44
|
+
* of these by key: `defineTheme({icons: {'richtext:bold': <MyIcon />}})`.
|
|
45
|
+
* Keys are namespaced (`richtext:*`) to avoid collisions with the core
|
|
46
|
+
* semantic icon set.
|
|
47
|
+
*/
|
|
48
|
+
export declare const RICHTEXT_ICON_KEYS: {
|
|
49
|
+
readonly bold: "richtext:bold";
|
|
50
|
+
readonly italic: "richtext:italic";
|
|
51
|
+
readonly underline: "richtext:underline";
|
|
52
|
+
readonly strikethrough: "richtext:strikethrough";
|
|
53
|
+
readonly code: "richtext:code";
|
|
54
|
+
readonly link: "richtext:link";
|
|
55
|
+
readonly paragraph: "richtext:paragraph";
|
|
56
|
+
readonly h1: "richtext:h1";
|
|
57
|
+
readonly h2: "richtext:h2";
|
|
58
|
+
readonly h3: "richtext:h3";
|
|
59
|
+
readonly quote: "richtext:quote";
|
|
60
|
+
readonly bullet: "richtext:bullet";
|
|
61
|
+
readonly number: "richtext:number";
|
|
62
|
+
readonly undo: "richtext:undo";
|
|
63
|
+
readonly redo: "richtext:redo";
|
|
64
|
+
};
|
|
65
|
+
/** The inline formats, in the order a toolbar offers them. */
|
|
66
|
+
export declare const INLINE_FORMAT_ACTIONS: readonly [{
|
|
67
|
+
readonly format: "bold";
|
|
68
|
+
readonly icon: "bold";
|
|
69
|
+
}, {
|
|
70
|
+
readonly format: "italic";
|
|
71
|
+
readonly icon: "italic";
|
|
72
|
+
}, {
|
|
73
|
+
readonly format: "underline";
|
|
74
|
+
readonly icon: "underline";
|
|
75
|
+
}, {
|
|
76
|
+
readonly format: "strikethrough";
|
|
77
|
+
readonly icon: "strikethrough";
|
|
78
|
+
}, {
|
|
79
|
+
readonly format: "code";
|
|
80
|
+
readonly icon: "code";
|
|
81
|
+
}];
|
|
82
|
+
export type InlineFormat = (typeof INLINE_FORMAT_ACTIONS)[number]['format'];
|
|
83
|
+
/** The inline formats' button labels. */
|
|
84
|
+
export declare function inlineFormatLabels(t: TranslatorFn): Record<InlineFormat, string>;
|
|
85
|
+
/**
|
|
86
|
+
* The inline formats a range or node selection carries, which their buttons
|
|
87
|
+
* show pressed. A selection of Markdown plugin nodes alone (a range around
|
|
88
|
+
* them, or a node selection from a click) shows their formats. Any other
|
|
89
|
+
* node selection, such as a rule, has none.
|
|
90
|
+
*/
|
|
91
|
+
export declare function $inlineFormatsOf(selection: RangeSelection | NodeSelection): Set<InlineFormat>;
|
|
92
|
+
/** Toggles an inline format over the editor's selection. */
|
|
93
|
+
export declare function formatSelection(editor: LexicalEditor, format: InlineFormat): void;
|
|
94
|
+
export type ToolbarIconName = keyof typeof RICHTEXT_ICON_KEYS;
|
|
95
|
+
/** The glyph resolver for the active theme, as the toolbars draw glyphs. */
|
|
96
|
+
export declare function useToolbarIcon(): (name: ToolbarIconName) => ReactNode;
|
|
97
|
+
export interface RichTextEditorToolbarProps extends BaseProps<HTMLDivElement> {
|
|
98
|
+
/**
|
|
99
|
+
* Ref to the toolbar's root element. Base props pass through to the
|
|
100
|
+
* underlying Astryx `Toolbar`: the ref, `className`, `style`, and `xstyle`
|
|
101
|
+
* reach its root, and `data-*`, other `aria-*` attributes, and DOM
|
|
102
|
+
* handlers reach the `role="toolbar"` element inside it. The toolbar names
|
|
103
|
+
* itself, so pass `label` rather than `aria-label`.
|
|
104
|
+
*/
|
|
105
|
+
ref?: Ref<HTMLDivElement>;
|
|
106
|
+
/**
|
|
107
|
+
* Accessible label for the toolbar element.
|
|
108
|
+
* @default 'Text formatting', translated for the active locale
|
|
109
|
+
*/
|
|
110
|
+
label?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Which heading levels to expose in the block-format selector, in order.
|
|
113
|
+
* @default ['h1', 'h2', 'h3']
|
|
114
|
+
*/
|
|
115
|
+
headingLevels?: ReadonlyArray<'h1' | 'h2' | 'h3'>;
|
|
116
|
+
/**
|
|
117
|
+
* Toolbar size. Cascades to formatting controls and coordinates the
|
|
118
|
+
* Toolbar's internal padding.
|
|
119
|
+
* @default 'sm'
|
|
120
|
+
*/
|
|
121
|
+
size?: 'sm' | 'md' | 'lg';
|
|
122
|
+
/**
|
|
123
|
+
* Whether to show the insert/edit-link button. By default, pressing it (or
|
|
124
|
+
* Cmd/Ctrl+K in the editor) opens an Astryx Popover anchored to the button:
|
|
125
|
+
* one URL field, applied with Enter, with Remove when the selection is in a
|
|
126
|
+
* link. The popover is not modal. Escape or Cancel closes it and returns
|
|
127
|
+
* focus and the selection to the editor; a URL that cannot be linked shows
|
|
128
|
+
* an error under the field, which keeps focus. With a collapsed selection,
|
|
129
|
+
* applying inserts the entered URL as link text at the caret; with a
|
|
130
|
+
* non-empty selection it links the selected text.
|
|
131
|
+
*
|
|
132
|
+
* Requires `LinkNode` to be registered (it is, by default) — no extra setup.
|
|
133
|
+
* The entered URL is sanitized (see `sanitizeUrl`) so only
|
|
134
|
+
* http/https/mailto/tel links are written.
|
|
135
|
+
* @default true
|
|
136
|
+
*/
|
|
137
|
+
hasLink?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Called to obtain a URL when the link button is pressed on a non-link
|
|
140
|
+
* selection. Return the URL string to link, or `null`/`''` to cancel.
|
|
141
|
+
* Receives the currently selected text as a hint. When omitted, the built-in
|
|
142
|
+
* link popover is used. This synchronous override is retained
|
|
143
|
+
* for consumers that already provide their own URL UI.
|
|
144
|
+
*/
|
|
145
|
+
promptForUrl?: (selectedText: string) => string | null | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* Whether links created via the toolbar open in a new tab. When `true`
|
|
148
|
+
* (default), the created link carries `target="_blank"` and
|
|
149
|
+
* `rel="noopener noreferrer"` — written into the link node's data (so it
|
|
150
|
+
* serializes and round-trips), not patched onto the DOM. Set `false` to
|
|
151
|
+
* create same-tab links.
|
|
152
|
+
* @default true
|
|
153
|
+
*/
|
|
154
|
+
hasNewTabLinks?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Extra items rendered at the end of the toolbar (after a divider). Use this
|
|
157
|
+
* to compose product-specific controls (e.g. mentions, AI) alongside the
|
|
158
|
+
* default formatting buttons.
|
|
159
|
+
*/
|
|
160
|
+
endContent?: ReactNode;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* A composable formatting toolbar for {@link RichTextEditor}, built from Astryx
|
|
164
|
+
* `Toolbar` / `ToggleButton` primitives so it matches the active theme. Reads
|
|
165
|
+
* the current selection to keep the active states in sync and dispatches the
|
|
166
|
+
* standard Lexical formatting commands.
|
|
167
|
+
*
|
|
168
|
+
* Render it inside the editor's `toolbar` slot — it uses
|
|
169
|
+
* `useLexicalComposerContext()` to reach the editor, so it must live within the
|
|
170
|
+
* `LexicalComposer` the editor sets up.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```
|
|
174
|
+
* import {RichTextEditor, RichTextEditorToolbar} from '@blue-patterns/richtext';
|
|
175
|
+
*
|
|
176
|
+
* <RichTextEditor
|
|
177
|
+
* label="Notes"
|
|
178
|
+
* toolbar={<RichTextEditorToolbar />}
|
|
179
|
+
* />
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export declare function RichTextEditorToolbar({ label: labelFromProps, headingLevels, size, hasLink, promptForUrl, hasNewTabLinks, endContent, xstyle, ref, ...rest }: RichTextEditorToolbarProps): import("react").JSX.Element;
|
|
183
|
+
export declare namespace RichTextEditorToolbar {
|
|
184
|
+
var displayName: string;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=RichTextEditorToolbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RichTextEditorToolbar.d.ts","sourceRoot":"","sources":["../src/RichTextEditorToolbar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAmBf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAenD,OAAO,EAAgB,KAAK,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAYL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,EAGpB,MAAM,SAAS,CAAC;AAwEjB;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;CAgBrB,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;EAMxB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC;AAE5E,yCAAyC;AACzC,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,YAAY,GACd,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAS9B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,cAAc,GAAG,aAAa,GACxC,GAAG,CAAC,YAAY,CAAC,CAanB;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,YAAY,GACnB,IAAI,CAEN;AA4MD,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,kBAAkB,CAAC;AAkB9D,4EAA4E;AAC5E,wBAAgB,cAAc,IAAI,CAAC,IAAI,EAAE,eAAe,KAAK,SAAS,CAGrE;AAaD,MAAM,WAAW,0BAA2B,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC3E;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;IAC1B;;;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;;;;;;;;;;;;;;OAcG;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,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EAAE,cAAc,EACrB,aAAkC,EAClC,IAAW,EACX,OAAc,EACd,YAAY,EACZ,cAAqB,EACrB,UAAU,EACV,MAAM,EACN,GAAG,EACH,GAAG,IAAI,EACR,EAAE,0BAA0B,+BAyR5B;yBApSe,qBAAqB"}
|