@pega/cosmos-react-rte 9.0.0 → 10.0.0-build.1.0
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/lib/components/DynamicContentEditor/DynamicContentEditor.d.ts.map +1 -1
- package/lib/components/DynamicContentEditor/DynamicContentEditor.js +81 -7
- package/lib/components/DynamicContentEditor/DynamicContentEditor.js.map +1 -1
- package/lib/components/DynamicContentEditor/DynamicContentEditor.types.d.ts +2 -0
- package/lib/components/DynamicContentEditor/DynamicContentEditor.types.d.ts.map +1 -1
- package/lib/components/DynamicContentEditor/DynamicContentEditor.types.js.map +1 -1
- package/lib/components/Editor/Editor.d.ts.map +1 -1
- package/lib/components/Editor/Editor.js +2 -2
- package/lib/components/Editor/Editor.js.map +1 -1
- package/lib/components/Editor/Editor.styles.d.ts.map +1 -1
- package/lib/components/Editor/Editor.styles.js +8 -3
- package/lib/components/Editor/Editor.styles.js.map +1 -1
- package/lib/components/Editor/Editor.types.d.ts +25 -0
- package/lib/components/Editor/Editor.types.d.ts.map +1 -1
- package/lib/components/Editor/Editor.types.js.map +1 -1
- package/lib/components/Editor/Toolbar/AnchorButton.d.ts +3 -1
- package/lib/components/Editor/Toolbar/AnchorButton.d.ts.map +1 -1
- package/lib/components/Editor/Toolbar/AnchorButton.js +120 -13
- package/lib/components/Editor/Toolbar/AnchorButton.js.map +1 -1
- package/lib/components/Editor/Toolbar/Toolbar.d.ts +3 -2
- package/lib/components/Editor/Toolbar/Toolbar.d.ts.map +1 -1
- package/lib/components/Editor/Toolbar/Toolbar.js +2 -2
- package/lib/components/Editor/Toolbar/Toolbar.js.map +1 -1
- package/package.json +2 -2
|
@@ -27,6 +27,29 @@ export type CustomComponent = {
|
|
|
27
27
|
extensionAttributes?: string[];
|
|
28
28
|
style?: string;
|
|
29
29
|
};
|
|
30
|
+
export interface LinkCustomSourceEditValue {
|
|
31
|
+
id: string;
|
|
32
|
+
text: string;
|
|
33
|
+
namespace?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface LinkCustomSourceConfig {
|
|
36
|
+
/** A custom picker ReactNode rendered inline in the link popover when the custom source option is selected. */
|
|
37
|
+
picker?: ReactNode;
|
|
38
|
+
/** Called when Apply is clicked in the link popover with custom source mode selected. Receives the link display text. */
|
|
39
|
+
onSubmit?: (linkText: string) => void;
|
|
40
|
+
/** Indicates whether custom-source submit is currently allowed. Defaults to true when omitted. */
|
|
41
|
+
canSubmit?: boolean;
|
|
42
|
+
/** Called when editing an existing custom-source link and the source field can be resolved from link markup. */
|
|
43
|
+
onEditSelectionChange?: (value: LinkCustomSourceEditValue) => void;
|
|
44
|
+
/** When set, opens the link popover in custom source mode with pre-populated text for editing an existing custom-source link. Set to null to dismiss. */
|
|
45
|
+
edit?: LinkCustomSourceEditValue | null | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Called when the link popover opened via linkCustomSource.edit is dismissed.
|
|
48
|
+
* reason is 'apply' when user applies changes, otherwise 'cancel'.
|
|
49
|
+
* Consumer should set linkCustomSource.edit to null.
|
|
50
|
+
*/
|
|
51
|
+
onDismissEdit?: (reason?: 'cancel' | 'apply') => void;
|
|
52
|
+
}
|
|
30
53
|
export interface EditorProps extends FormControlProps, BaseProps, TestIdProp {
|
|
31
54
|
/** An array of strings that activate features on the toolbar */
|
|
32
55
|
toolbar?: Features[];
|
|
@@ -96,6 +119,8 @@ export interface EditorProps extends FormControlProps, BaseProps, TestIdProp {
|
|
|
96
119
|
imageInsertionMode?: 'file' | 'url' | 'all';
|
|
97
120
|
/** A callback when the AI rewrite toolbar button is used. The onSuccess callback should be called with the rewritten text. */
|
|
98
121
|
onRewriteClick?: (originalText: string, rewriteAction: AIAction, additionalInstructions: string, onSuccess: (rewrittenText: string) => void) => void;
|
|
122
|
+
/** Link custom-source configuration for inserting and editing links using consumer-provided source selection. */
|
|
123
|
+
linkCustomSource?: LinkCustomSourceConfig;
|
|
99
124
|
/** If there is a progress state (e.g. AI rewrite in progress), you must indicate as such. Shows a Progress overlay on the editor. */
|
|
100
125
|
progress?: boolean | string;
|
|
101
126
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Editor.types.d.ts","sourceRoot":"","sources":["../../../src/components/Editor/Editor.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Editor.types.d.ts","sourceRoot":"","sources":["../../../src/components/Editor/Editor.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Editor.types.js","sourceRoot":"","sources":["../../../src/components/Editor/Editor.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ReactNode,\n Ref,\n MouseEvent as ReactMouseEvent,\n KeyboardEvent as ReactKeyboardEvent\n} from 'react';\nimport type { Editor as TiptapEditor } from '@tiptap/core';\n\nimport type {\n Action,\n BaseProps,\n FormControlProps,\n TestIdProp,\n AIAction\n} from '@pega/cosmos-react-core';\n\nimport type { Features } from '../RichTextEditor/Toolbar/Toolbar.types';\nimport type { RichTextEditorState } from '../RichTextEditor';\n\nexport type EditorState = RichTextEditorState & {\n getEditor: () => TiptapEditor | null;\n element?: HTMLElement;\n setCursorLocationToStart?: () => void;\n updateAttachmentAttributes: (id: string, progress?: number, error?: string) => void;\n};\n\nexport type CustomAction = {\n text: Action['text'];\n icon: NonNullable<Action['icon']>;\n onMouseDown: (e: ReactMouseEvent | ReactKeyboardEvent) => void;\n active?: (editor: TiptapEditor) => boolean;\n shortcut?: {\n pattern: string;\n description: string;\n command: (editor: TiptapEditor) => void;\n };\n 'data-testid'?: string;\n};\n\nexport type CustomComponent = {\n createCustomElement: (window: typeof globalThis) => CustomElementConstructor;\n name: string;\n extensionAttributes?: string[];\n style?: string;\n};\n\nexport interface EditorProps extends FormControlProps, BaseProps, TestIdProp {\n /** An array of strings that activate features on the toolbar */\n toolbar?: Features[];\n /** Children content */\n children?: ReactNode;\n /** A callback that supplies an object with functions that can manipulate the editor and retrieve it's content/state */\n onChange?: (editor?: TiptapEditor) => void;\n /** KeyDown event custom handlers for the editor */\n onKeyDown?: (event?: KeyboardEvent) => void;\n /** A callback that runs if the editor is focused */\n onFocus?: () => void;\n /** A callback that runs if the editor loses focus */\n onBlur?: () => void;\n /** A callback when an image is added through the toolbar image feature */\n onImageAdded?: (image: File, id: string, altText?: string) => void;\n /** A callback for when the editor is finished initializing */\n onInit?: (editor: TiptapEditor) => void;\n /** A callback that runs when the iframe is about to unload, useful for saving editor state */\n onUnload?: (value: string) => void;\n /** Standard placeholder for an input */\n placeholder?: string;\n /** Default value for the RTE - HTML String */\n defaultValue?: string;\n /** Will automatically focus the RTE on render if true */\n autoFocus?: boolean;\n /** Sets the height for the RTE. If no max height is set the RTE will continue to expand, otherwise an overflow will be applied */\n height?: {\n min?: number;\n max?: number;\n };\n /**\n * Determines if the editor resizes its height based on content and user interactions.\n * @default true;\n */\n autoResize?: boolean;\n /** An array of custom components, custom components must use web component API */\n customComponents?: CustomComponent[];\n /** An array of custom buttons to be inserted into the toolbar */\n customActions?: CustomAction[];\n /**\n * Enables browser spellcheck.\n * @default true\n */\n spellcheck?: boolean;\n /** Options used during init of the editor */\n initOptions?: {\n /** Disables pasting of images in editor when false */\n pasteDataImages?: boolean;\n /** Converts formatted text to plain text upon pasting */\n pasteAsText?: boolean;\n /** Disables inline, block, and replacement text patterns when false and can be array of allowed formats */\n textPatterns?: boolean;\n /** Function called during init_instance_callback as part of editor init */\n initInstanceCallback?: (editor: TiptapEditor) => void;\n /** Styles to set within the iframe's document */\n contentStyle?: string;\n };\n /** Handle to the state. */\n ref?: Ref<EditorState>;\n /**\n * Determines the image insertion mode for the editor.\n * - 'file': Only allows uploading image files from local system\n * - 'url': Only allows adding images via URL/link\n * - 'all': Allows all image files upload options\n * @default 'all'\n */\n imageInsertionMode?: 'file' | 'url' | 'all';\n /** A callback when the AI rewrite toolbar button is used. The onSuccess callback should be called with the rewritten text. */\n onRewriteClick?: (\n originalText: string,\n rewriteAction: AIAction,\n additionalInstructions: string,\n onSuccess: (rewrittenText: string) => void\n ) => void;\n /** If there is a progress state (e.g. AI rewrite in progress), you must indicate as such. Shows a Progress overlay on the editor. */\n progress?: boolean | string;\n /**\n * Enables secure mode which sanitizes content to prevent XSS attacks.\n * Strips scripts, iframes, event handlers, and dangerous URLs.\n * @default false\n */\n secure?: boolean;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Editor.types.js","sourceRoot":"","sources":["../../../src/components/Editor/Editor.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ReactNode,\n Ref,\n MouseEvent as ReactMouseEvent,\n KeyboardEvent as ReactKeyboardEvent\n} from 'react';\nimport type { Editor as TiptapEditor } from '@tiptap/core';\n\nimport type {\n Action,\n BaseProps,\n FormControlProps,\n TestIdProp,\n AIAction\n} from '@pega/cosmos-react-core';\n\nimport type { Features } from '../RichTextEditor/Toolbar/Toolbar.types';\nimport type { RichTextEditorState } from '../RichTextEditor';\n\nexport type EditorState = RichTextEditorState & {\n getEditor: () => TiptapEditor | null;\n element?: HTMLElement;\n setCursorLocationToStart?: () => void;\n updateAttachmentAttributes: (id: string, progress?: number, error?: string) => void;\n};\n\nexport type CustomAction = {\n text: Action['text'];\n icon: NonNullable<Action['icon']>;\n onMouseDown: (e: ReactMouseEvent | ReactKeyboardEvent) => void;\n active?: (editor: TiptapEditor) => boolean;\n shortcut?: {\n pattern: string;\n description: string;\n command: (editor: TiptapEditor) => void;\n };\n 'data-testid'?: string;\n};\n\nexport type CustomComponent = {\n createCustomElement: (window: typeof globalThis) => CustomElementConstructor;\n name: string;\n extensionAttributes?: string[];\n style?: string;\n};\n\nexport interface LinkCustomSourceEditValue {\n id: string;\n text: string;\n namespace?: string;\n}\n\nexport interface LinkCustomSourceConfig {\n /** A custom picker ReactNode rendered inline in the link popover when the custom source option is selected. */\n picker?: ReactNode;\n /** Called when Apply is clicked in the link popover with custom source mode selected. Receives the link display text. */\n onSubmit?: (linkText: string) => void;\n /** Indicates whether custom-source submit is currently allowed. Defaults to true when omitted. */\n canSubmit?: boolean;\n /** Called when editing an existing custom-source link and the source field can be resolved from link markup. */\n onEditSelectionChange?: (value: LinkCustomSourceEditValue) => void;\n /** When set, opens the link popover in custom source mode with pre-populated text for editing an existing custom-source link. Set to null to dismiss. */\n edit?: LinkCustomSourceEditValue | null | undefined;\n /**\n * Called when the link popover opened via linkCustomSource.edit is dismissed.\n * reason is 'apply' when user applies changes, otherwise 'cancel'.\n * Consumer should set linkCustomSource.edit to null.\n */\n onDismissEdit?: (reason?: 'cancel' | 'apply') => void;\n}\n\nexport interface EditorProps extends FormControlProps, BaseProps, TestIdProp {\n /** An array of strings that activate features on the toolbar */\n toolbar?: Features[];\n /** Children content */\n children?: ReactNode;\n /** A callback that supplies an object with functions that can manipulate the editor and retrieve it's content/state */\n onChange?: (editor?: TiptapEditor) => void;\n /** KeyDown event custom handlers for the editor */\n onKeyDown?: (event?: KeyboardEvent) => void;\n /** A callback that runs if the editor is focused */\n onFocus?: () => void;\n /** A callback that runs if the editor loses focus */\n onBlur?: () => void;\n /** A callback when an image is added through the toolbar image feature */\n onImageAdded?: (image: File, id: string, altText?: string) => void;\n /** A callback for when the editor is finished initializing */\n onInit?: (editor: TiptapEditor) => void;\n /** A callback that runs when the iframe is about to unload, useful for saving editor state */\n onUnload?: (value: string) => void;\n /** Standard placeholder for an input */\n placeholder?: string;\n /** Default value for the RTE - HTML String */\n defaultValue?: string;\n /** Will automatically focus the RTE on render if true */\n autoFocus?: boolean;\n /** Sets the height for the RTE. If no max height is set the RTE will continue to expand, otherwise an overflow will be applied */\n height?: {\n min?: number;\n max?: number;\n };\n /**\n * Determines if the editor resizes its height based on content and user interactions.\n * @default true;\n */\n autoResize?: boolean;\n /** An array of custom components, custom components must use web component API */\n customComponents?: CustomComponent[];\n /** An array of custom buttons to be inserted into the toolbar */\n customActions?: CustomAction[];\n /**\n * Enables browser spellcheck.\n * @default true\n */\n spellcheck?: boolean;\n /** Options used during init of the editor */\n initOptions?: {\n /** Disables pasting of images in editor when false */\n pasteDataImages?: boolean;\n /** Converts formatted text to plain text upon pasting */\n pasteAsText?: boolean;\n /** Disables inline, block, and replacement text patterns when false and can be array of allowed formats */\n textPatterns?: boolean;\n /** Function called during init_instance_callback as part of editor init */\n initInstanceCallback?: (editor: TiptapEditor) => void;\n /** Styles to set within the iframe's document */\n contentStyle?: string;\n };\n /** Handle to the state. */\n ref?: Ref<EditorState>;\n /**\n * Determines the image insertion mode for the editor.\n * - 'file': Only allows uploading image files from local system\n * - 'url': Only allows adding images via URL/link\n * - 'all': Allows all image files upload options\n * @default 'all'\n */\n imageInsertionMode?: 'file' | 'url' | 'all';\n /** A callback when the AI rewrite toolbar button is used. The onSuccess callback should be called with the rewritten text. */\n onRewriteClick?: (\n originalText: string,\n rewriteAction: AIAction,\n additionalInstructions: string,\n onSuccess: (rewrittenText: string) => void\n ) => void;\n /** Link custom-source configuration for inserting and editing links using consumer-provided source selection. */\n linkCustomSource?: LinkCustomSourceConfig;\n /** If there is a progress state (e.g. AI rewrite in progress), you must indicate as such. Shows a Progress overlay on the editor. */\n progress?: boolean | string;\n /**\n * Enables secure mode which sanitizes content to prevent XSS attacks.\n * Strips scripts, iframes, event handlers, and dangerous URLs.\n * @default false\n */\n secure?: boolean;\n}\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Editor as TiptapEditor } from '@tiptap/core';
|
|
2
2
|
import type { ForwardProps } from '@pega/cosmos-react-core';
|
|
3
|
+
import type { LinkCustomSourceConfig } from '../Editor.types';
|
|
3
4
|
interface AnchorButtonProps {
|
|
4
5
|
osx: boolean;
|
|
5
6
|
editor: TiptapEditor;
|
|
7
|
+
linkCustomSource?: LinkCustomSourceConfig;
|
|
6
8
|
}
|
|
7
|
-
declare const AnchorButton: ({ osx, editor, ...restProps }: AnchorButtonProps & ForwardProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
declare const AnchorButton: ({ osx, editor, linkCustomSource, ...restProps }: AnchorButtonProps & ForwardProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
10
|
export default AnchorButton;
|
|
9
11
|
//# sourceMappingURL=AnchorButton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnchorButton.d.ts","sourceRoot":"","sources":["../../../../src/components/Editor/Toolbar/AnchorButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"AnchorButton.d.ts","sourceRoot":"","sources":["../../../../src/components/Editor/Toolbar/AnchorButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AAmB3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAK5D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAM9D,UAAU,iBAAiB;IACzB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AAED,QAAA,MAAM,YAAY,GAAI,iDAKnB,iBAAiB,GAAG,YAAY,4CAqclC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useRef, useState, useEffect, useLayoutEffect, useCallback } from 'react';
|
|
3
|
-
import { Button, CardContent, Grid, Icon, registerIcon, Input, useOuterEvent, Form, useI18n, Text, useElement, useEscape, isInstance } from '@pega/cosmos-react-core';
|
|
3
|
+
import { Button, CardContent, Grid, Icon, registerIcon, Input, RadioButton, RadioButtonGroup, useOuterEvent, Form, useI18n, Text, useElement, useEscape, isInstance } from '@pega/cosmos-react-core';
|
|
4
4
|
import * as chainIcon from '@pega/cosmos-react-core/lib/components/Icon/icons/chain.icon';
|
|
5
5
|
import ToolbarButton from '../../RichTextEditor/Toolbar/ToolbarButton';
|
|
6
6
|
import { getKeyCommand } from '../../RichTextEditor/Toolbar/utils';
|
|
7
7
|
import { StyledEditPopover } from '../Editor.styles';
|
|
8
8
|
import useCloseOnEditorClick from '../hooks/useCloseOnEditorClick';
|
|
9
9
|
registerIcon(chainIcon);
|
|
10
|
-
const AnchorButton = ({ osx, editor, ...restProps }) => {
|
|
10
|
+
const AnchorButton = ({ osx, editor, linkCustomSource, ...restProps }) => {
|
|
11
11
|
const t = useI18n();
|
|
12
12
|
const buttonRef = useRef(null);
|
|
13
13
|
const [textInputEl, setTextInputEl] = useElement();
|
|
@@ -18,25 +18,59 @@ const AnchorButton = ({ osx, editor, ...restProps }) => {
|
|
|
18
18
|
const [urlMatch, setUrlMatch] = useState(true);
|
|
19
19
|
const [anchorMenu, setAnchorMenu] = useState(false);
|
|
20
20
|
const [shouldFocusInput, setShouldFocusInput] = useState(false);
|
|
21
|
+
const [linkSourceType, setLinkSourceType] = useState('url');
|
|
22
|
+
const hasFieldLinkMode = Boolean(linkCustomSource?.picker && linkCustomSource?.onSubmit);
|
|
23
|
+
const canSubmitCustomSource = linkCustomSource?.canSubmit ?? true;
|
|
24
|
+
const wasAnchorMenuVisibleRef = useRef(false);
|
|
21
25
|
// Store the original selection range when menu opens so we can restore it when creating the link
|
|
22
26
|
const originalSelectionRef = useRef(null);
|
|
27
|
+
// Track whether the popover was opened via linkCustomSource.edit
|
|
28
|
+
const openedViaEditCustomSourceRef = useRef(false);
|
|
29
|
+
// Track whether popover was initialized from an existing field link (selection-based edit path)
|
|
30
|
+
const initializedFromExistingFieldLinkRef = useRef(false);
|
|
23
31
|
const tooltip = getKeyCommand(osx, ({ ctrl }) => `${t('rte_link')} (${ctrl}K)`);
|
|
32
|
+
const parseCustomSourceFromHref = useCallback((href) => {
|
|
33
|
+
const decodedHref = href
|
|
34
|
+
.replaceAll('"', '"')
|
|
35
|
+
.replaceAll('<', '<')
|
|
36
|
+
.replaceAll('>', '>')
|
|
37
|
+
.replaceAll('&', '&');
|
|
38
|
+
if (!decodedHref.includes('<pega-reference')) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const idMatch = /data-rule-id=["']([^"']+)["']/i.exec(decodedHref);
|
|
42
|
+
if (!idMatch) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const namespaceMatch = /data-rule-namespace=["']([^"']+)["']/i.exec(decodedHref);
|
|
46
|
+
return {
|
|
47
|
+
id: idMatch[1],
|
|
48
|
+
namespace: namespaceMatch?.[1]
|
|
49
|
+
};
|
|
50
|
+
}, []);
|
|
24
51
|
const openMenu = (opts = {}) => {
|
|
25
52
|
// Save the original selection before opening the menu
|
|
26
53
|
const { from, to } = editor.state.selection;
|
|
27
54
|
originalSelectionRef.current = { from, to };
|
|
55
|
+
initializedFromExistingFieldLinkRef.current = false;
|
|
28
56
|
setAnchorMenu(true);
|
|
29
57
|
if (opts.focusInput) {
|
|
30
58
|
setShouldFocusInput(true);
|
|
31
59
|
}
|
|
32
60
|
};
|
|
33
|
-
const resetMenu = useCallback(() => {
|
|
61
|
+
const resetMenu = useCallback((dismissReason = 'cancel') => {
|
|
34
62
|
setLinkText('');
|
|
35
63
|
setUrl('');
|
|
36
64
|
setUrlMatch(true);
|
|
37
65
|
setAnchorMenu(false);
|
|
66
|
+
setLinkSourceType('url');
|
|
38
67
|
originalSelectionRef.current = null;
|
|
39
|
-
|
|
68
|
+
initializedFromExistingFieldLinkRef.current = false;
|
|
69
|
+
if (openedViaEditCustomSourceRef.current) {
|
|
70
|
+
openedViaEditCustomSourceRef.current = false;
|
|
71
|
+
linkCustomSource?.onDismissEdit?.(dismissReason);
|
|
72
|
+
}
|
|
73
|
+
}, [linkCustomSource]);
|
|
40
74
|
useOuterEvent('mousedown', [popoverEl, buttonRef], () => {
|
|
41
75
|
if (anchorMenu) {
|
|
42
76
|
resetMenu();
|
|
@@ -112,27 +146,76 @@ const AnchorButton = ({ osx, editor, ...restProps }) => {
|
|
|
112
146
|
.insertContent(' ')
|
|
113
147
|
.run();
|
|
114
148
|
}
|
|
115
|
-
resetMenu();
|
|
149
|
+
resetMenu('apply');
|
|
116
150
|
}, [url, linkText, editor, resetMenu]);
|
|
117
151
|
useEffect(() => {
|
|
118
|
-
|
|
152
|
+
const isOpening = anchorMenu && !wasAnchorMenuVisibleRef.current;
|
|
153
|
+
wasAnchorMenuVisibleRef.current = anchorMenu;
|
|
154
|
+
if (isOpening && originalSelectionRef.current) {
|
|
119
155
|
// Use the stored original selection to populate the modal
|
|
120
156
|
// This avoids issues where focus shift may collapse the editor selection
|
|
121
157
|
const { from, to } = originalSelectionRef.current;
|
|
122
158
|
const text = editor.state.doc.textBetween(from, to);
|
|
123
159
|
const linkMark = editor.getAttributes('link');
|
|
124
160
|
if (linkMark.href) {
|
|
125
|
-
|
|
126
|
-
|
|
161
|
+
// Check if href contains a pega-reference (escaped or unescaped)
|
|
162
|
+
const isPegaReference = linkMark.href.includes('<pega-reference') || linkMark.href.includes('<pega-reference');
|
|
163
|
+
if (isPegaReference) {
|
|
164
|
+
const customSourceValue = parseCustomSourceFromHref(linkMark.href);
|
|
165
|
+
if (customSourceValue) {
|
|
166
|
+
initializedFromExistingFieldLinkRef.current = true;
|
|
167
|
+
linkCustomSource?.onEditSelectionChange?.({
|
|
168
|
+
id: customSourceValue.id,
|
|
169
|
+
text: text || '',
|
|
170
|
+
namespace: customSourceValue.namespace
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
initializedFromExistingFieldLinkRef.current = false;
|
|
175
|
+
linkCustomSource?.onEditSelectionChange?.({ id: '', text: '', namespace: undefined });
|
|
176
|
+
}
|
|
177
|
+
// Don't populate URL field with pega-reference - leave it empty
|
|
178
|
+
// The field picker will handle field links
|
|
179
|
+
if (hasFieldLinkMode) {
|
|
180
|
+
setLinkSourceType('field');
|
|
181
|
+
}
|
|
182
|
+
setLinkText(text || '');
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
initializedFromExistingFieldLinkRef.current = false;
|
|
186
|
+
linkCustomSource?.onEditSelectionChange?.({ id: '', text: '', namespace: undefined });
|
|
187
|
+
setLinkSourceType('url');
|
|
188
|
+
setUrl(linkMark.href);
|
|
189
|
+
setLinkText(text || '');
|
|
190
|
+
}
|
|
127
191
|
}
|
|
128
192
|
else {
|
|
193
|
+
initializedFromExistingFieldLinkRef.current = false;
|
|
194
|
+
linkCustomSource?.onEditSelectionChange?.({ id: '', text: '', namespace: undefined });
|
|
195
|
+
setLinkSourceType('url');
|
|
129
196
|
setLinkText(text || '');
|
|
130
197
|
}
|
|
131
198
|
}
|
|
132
199
|
else if (!anchorMenu) {
|
|
133
200
|
resetMenu();
|
|
134
201
|
}
|
|
135
|
-
}, [
|
|
202
|
+
}, [
|
|
203
|
+
anchorMenu,
|
|
204
|
+
editor,
|
|
205
|
+
hasFieldLinkMode,
|
|
206
|
+
linkCustomSource,
|
|
207
|
+
parseCustomSourceFromHref,
|
|
208
|
+
resetMenu
|
|
209
|
+
]);
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
if (linkCustomSource?.edit && hasFieldLinkMode) {
|
|
212
|
+
openedViaEditCustomSourceRef.current = true;
|
|
213
|
+
initializedFromExistingFieldLinkRef.current = true;
|
|
214
|
+
setLinkText(linkCustomSource.edit.text);
|
|
215
|
+
setLinkSourceType('field');
|
|
216
|
+
setAnchorMenu(true);
|
|
217
|
+
}
|
|
218
|
+
}, [linkCustomSource, hasFieldLinkMode]);
|
|
136
219
|
const preventDef = (e) => {
|
|
137
220
|
e.preventDefault();
|
|
138
221
|
e.stopPropagation();
|
|
@@ -217,12 +300,36 @@ const AnchorButton = ({ osx, editor, ...restProps }) => {
|
|
|
217
300
|
!popoverEl?.contains(relatedTarget)) {
|
|
218
301
|
resetMenu();
|
|
219
302
|
}
|
|
220
|
-
}, active: isLinkActive(), tooltip: tooltip, label: t('rte_link'), ...restProps, children: _jsx(Icon, { name: 'chain' }) }), _jsx(StyledEditPopover, { show: anchorMenu, target: buttonRef.current, ref: setPopoverEl, placement: 'bottom', children: _jsx(CardContent, { children: _jsx(Form, { as: 'div', actions: _jsxs(_Fragment, { children: [_jsx(Button, { variant: 'secondary', onClick: cancelAnchorCreation, type: 'button', children: t('cancel') }), _jsx(Button, { variant: 'primary', disabled:
|
|
303
|
+
}, active: isLinkActive(), tooltip: tooltip, label: t('rte_link'), ...restProps, children: _jsx(Icon, { name: 'chain' }) }), _jsx(StyledEditPopover, { show: anchorMenu, target: buttonRef.current, ref: setPopoverEl, placement: 'bottom', children: _jsx(CardContent, { children: _jsx(Form, { as: 'div', actions: _jsxs(_Fragment, { children: [_jsx(Button, { variant: 'secondary', onClick: cancelAnchorCreation, type: 'button', children: t('cancel') }), _jsx(Button, { variant: 'primary', disabled: linkSourceType === 'url'
|
|
304
|
+
? !url.trim() || !urlMatch
|
|
305
|
+
: !linkCustomSource?.onSubmit || !canSubmitCustomSource, onClick: (e) => {
|
|
221
306
|
e.preventDefault();
|
|
222
|
-
|
|
307
|
+
if (linkSourceType === 'url') {
|
|
308
|
+
createLink();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (!linkCustomSource?.onSubmit) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
linkCustomSource.onSubmit(linkText);
|
|
315
|
+
resetMenu('apply');
|
|
223
316
|
}, children: t('apply') })] }), children: _jsxs(Grid, { container: { rowGap: 2 }, children: [_jsx(Text, { variant: 'h2', children: t('rte_add_link') }), _jsx(Input, { label: t('rte_link_text'), value: linkText, onClick: preventDef, onChange: (e) => {
|
|
224
317
|
setLinkText(e.target.value);
|
|
225
|
-
}, ref: setTextInputEl }),
|
|
318
|
+
}, ref: setTextInputEl }), hasFieldLinkMode && (_jsxs(RadioButtonGroup, { name: 'linkSourceType', label: t('rte_link_source'), onChange: e => {
|
|
319
|
+
const { value } = e.target;
|
|
320
|
+
if (value === 'url' || value === 'field') {
|
|
321
|
+
setLinkSourceType(value);
|
|
322
|
+
if (value === 'field' &&
|
|
323
|
+
!openedViaEditCustomSourceRef.current &&
|
|
324
|
+
!initializedFromExistingFieldLinkRef.current) {
|
|
325
|
+
linkCustomSource?.onEditSelectionChange?.({
|
|
326
|
+
id: '',
|
|
327
|
+
text: '',
|
|
328
|
+
namespace: undefined
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}, inline: true, children: [_jsx(RadioButton, { label: t('rte_link_url'), value: 'url', checked: linkSourceType === 'url' }), _jsx(RadioButton, { label: t('rte_link_field'), value: 'field', checked: linkSourceType === 'field' })] })), linkSourceType === 'url' ? (_jsx(Input, { label: t('rte_link_url'), value: url, onClick: preventDef, onChange: (e) => {
|
|
226
333
|
const urlInput = e.target.value;
|
|
227
334
|
setUrl(urlInput);
|
|
228
335
|
// Clear error while typing, validate on blur
|
|
@@ -231,7 +338,7 @@ const AnchorButton = ({ osx, editor, ...restProps }) => {
|
|
|
231
338
|
}
|
|
232
339
|
}, onBlur: () => {
|
|
233
340
|
setUrlMatch(!url || isValidUrl(url));
|
|
234
|
-
}, info: url && !urlMatch ? t('rte_invalid_url') : '', status: url && !urlMatch ? 'error' : undefined, ref: setUrlInputEl })] }) }) }) })] }));
|
|
341
|
+
}, info: url && !urlMatch ? t('rte_invalid_url') : '', status: url && !urlMatch ? 'error' : undefined, ref: setUrlInputEl })) : (linkCustomSource?.picker)] }) }) }) })] }));
|
|
235
342
|
};
|
|
236
343
|
export default AnchorButton;
|
|
237
344
|
//# sourceMappingURL=AnchorButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnchorButton.js","sourceRoot":"","sources":["../../../../src/components/Editor/Toolbar/AnchorButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useRef, useState, useEffect, useLayoutEffect, useCallback } from 'react';\nimport type { ChangeEvent, MouseEvent, KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport type { Editor as TiptapEditor } from '@tiptap/core';\n\nimport {\n Button,\n CardContent,\n Grid,\n Icon,\n registerIcon,\n Input,\n useOuterEvent,\n Form,\n useI18n,\n Text,\n useElement,\n useEscape,\n isInstance\n} from '@pega/cosmos-react-core';\nimport type { ForwardProps } from '@pega/cosmos-react-core';\nimport * as chainIcon from '@pega/cosmos-react-core/lib/components/Icon/icons/chain.icon';\n\nimport ToolbarButton from '../../RichTextEditor/Toolbar/ToolbarButton';\nimport { getKeyCommand } from '../../RichTextEditor/Toolbar/utils';\nimport { StyledEditPopover } from '../Editor.styles';\nimport useCloseOnEditorClick from '../hooks/useCloseOnEditorClick';\n\nregisterIcon(chainIcon);\n\ninterface AnchorButtonProps {\n osx: boolean;\n editor: TiptapEditor;\n}\n\nconst AnchorButton = ({ osx, editor, ...restProps }: AnchorButtonProps & ForwardProps) => {\n const t = useI18n();\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [textInputEl, setTextInputEl] = useElement<HTMLInputElement>();\n const [urlInputEl, setUrlInputEl] = useElement<HTMLInputElement>();\n const [popoverEl, setPopoverEl] = useElement<HTMLDivElement>();\n const [linkText, setLinkText] = useState('');\n const [url, setUrl] = useState('');\n const [urlMatch, setUrlMatch] = useState(true);\n const [anchorMenu, setAnchorMenu] = useState(false);\n const [shouldFocusInput, setShouldFocusInput] = useState(false);\n // Store the original selection range when menu opens so we can restore it when creating the link\n const originalSelectionRef = useRef<{ from: number; to: number } | null>(null);\n const tooltip = getKeyCommand(osx, ({ ctrl }) => `${t('rte_link')} (${ctrl}K)`);\n\n const openMenu = (opts: { focusInput?: boolean } = {}) => {\n // Save the original selection before opening the menu\n const { from, to } = editor.state.selection;\n originalSelectionRef.current = { from, to };\n setAnchorMenu(true);\n if (opts.focusInput) {\n setShouldFocusInput(true);\n }\n };\n\n const resetMenu = useCallback(() => {\n setLinkText('');\n setUrl('');\n setUrlMatch(true);\n setAnchorMenu(false);\n originalSelectionRef.current = null;\n }, []);\n\n useOuterEvent('mousedown', [popoverEl, buttonRef], () => {\n if (anchorMenu) {\n resetMenu();\n }\n });\n\n // Close menu when clicking inside the editor iframe\n const handleEditorClick = useCallback(() => {\n if (anchorMenu) {\n resetMenu();\n }\n }, [anchorMenu, resetMenu]);\n useCloseOnEditorClick(anchorMenu, handleEditorClick);\n\n const isValidUrl = (urlString: string): boolean => {\n if (!urlString.trim()) return false;\n const allowedProtocols = /^(https?|mailto|tel):/i;\n const hasProtocol = /^[a-z][a-z0-9.+-]*:/i.test(urlString);\n\n try {\n const testUrl = hasProtocol ? urlString : `https://${urlString}`;\n if (hasProtocol && !allowedProtocols.test(urlString)) {\n return false;\n }\n const urlObj = new URL(testUrl);\n return URL.canParse?.(testUrl) ?? Boolean(urlObj.href);\n } catch {\n return false;\n }\n };\n\n const createLink = useCallback(() => {\n if (!url || !isValidUrl(url)) {\n return;\n }\n\n // Only allow safe protocols to prevent XSS (e.g., javascript: URLs)\n const allowedProtocols = /^(https?|mailto|tel):/i;\n const hasProtocol = /^[a-z][a-z0-9.+-]*:/i.test(url);\n\n let normalizedUrl: string;\n if (hasProtocol) {\n // Reject URLs with disallowed protocols\n if (!allowedProtocols.test(url)) {\n return;\n }\n normalizedUrl = url;\n } else {\n normalizedUrl = `https://${url}`;\n }\n\n // Use the original selection to determine if text was selected in the editor\n const originalSelection = originalSelectionRef.current;\n\n if (originalSelection && originalSelection.from !== originalSelection.to) {\n // Text was originally selected - restore selection and apply link\n // Then collapse selection to end and clear stored mark so subsequent typing isn't linked\n editor\n .chain()\n .focus()\n .setTextSelection({ from: originalSelection.from, to: originalSelection.to })\n .setLink({ href: normalizedUrl })\n .setTextSelection(originalSelection.to)\n .unsetMark('link')\n .run();\n } else if (linkText) {\n // No text was originally selected, insert new link with the text entered in modal\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'text',\n text: linkText,\n marks: [{ type: 'link', attrs: { href: normalizedUrl } }]\n })\n .unsetMark('link')\n .insertContent(' ')\n .run();\n }\n resetMenu();\n }, [url, linkText, editor, resetMenu]);\n\n useEffect(() => {\n if (anchorMenu && originalSelectionRef.current) {\n // Use the stored original selection to populate the modal\n // This avoids issues where focus shift may collapse the editor selection\n const { from, to } = originalSelectionRef.current;\n const text = editor.state.doc.textBetween(from, to);\n const linkMark = editor.getAttributes('link');\n\n if (linkMark.href) {\n setUrl(linkMark.href);\n setLinkText(text || '');\n } else {\n setLinkText(text || '');\n }\n } else if (!anchorMenu) {\n resetMenu();\n }\n }, [anchorMenu, editor, resetMenu]);\n\n const preventDef = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n const isLinkActive = () => {\n return editor.isActive('link') && editor.isFocused;\n };\n\n const cancelAnchorCreation = useCallback(\n (event?: KeyboardEvent | MouseEvent) => {\n if (\n ((event && 'key' in event && event.key === 'Escape') ||\n event?.type === 'click' ||\n !event) &&\n anchorMenu\n ) {\n if (event && 'key' in event && event.key === 'Escape') {\n event.stopPropagation();\n }\n\n resetMenu();\n buttonRef.current?.focus();\n }\n },\n [anchorMenu, resetMenu]\n );\n\n // Ctrl+K shortcut to open link dialog from within the editor iframe\n useEffect(() => {\n const handleCtrlK = (e: KeyboardEvent) => {\n if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n openMenu({ focusInput: true });\n }\n };\n\n const iframeWindow = editor.view.dom.ownerDocument.defaultView;\n iframeWindow?.addEventListener('keydown', handleCtrlK);\n return () => iframeWindow?.removeEventListener('keydown', handleCtrlK);\n }, [editor]);\n\n // Escape to close popover - listen on both iframe and parent document\n // since focus may be in either location depending on how the popover was opened\n useEffect(() => {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && anchorMenu) {\n e.preventDefault();\n cancelAnchorCreation();\n }\n };\n const iframeWindow = editor.view.dom.ownerDocument.defaultView;\n iframeWindow?.addEventListener('keydown', handleEscape);\n document.addEventListener('keydown', handleEscape);\n return () => {\n iframeWindow?.removeEventListener('keydown', handleEscape);\n document.removeEventListener('keydown', handleEscape);\n };\n }, [editor, anchorMenu, cancelAnchorCreation]);\n\n useEscape(cancelAnchorCreation, popoverEl);\n\n useLayoutEffect(() => {\n if (textInputEl && shouldFocusInput) {\n textInputEl.focus();\n setShouldFocusInput(false);\n }\n }, [textInputEl, shouldFocusInput]);\n\n useEffect(() => {\n // These events must be added here so they run before the native event in useArrows (used in the toolbar).\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') {\n e.stopPropagation();\n }\n };\n textInputEl?.addEventListener('keydown', onKeyDown);\n urlInputEl?.addEventListener('keydown', onKeyDown);\n return () => {\n textInputEl?.removeEventListener('keydown', onKeyDown);\n urlInputEl?.removeEventListener('keydown', onKeyDown);\n };\n }, [textInputEl, urlInputEl]);\n\n return (\n <>\n <ToolbarButton\n ref={buttonRef}\n onMouseDown={e => {\n e.preventDefault();\n openMenu();\n }}\n onKeyDown={(e: ReactKeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n openMenu({ focusInput: true });\n }\n }}\n onBlur={(e: React.FocusEvent) => {\n const { relatedTarget } = e;\n if (\n isInstance(relatedTarget, Node) &&\n !buttonRef.current?.contains(relatedTarget) &&\n !popoverEl?.contains(relatedTarget)\n ) {\n resetMenu();\n }\n }}\n active={isLinkActive()}\n tooltip={tooltip}\n label={t('rte_link')}\n {...restProps}\n >\n <Icon name='chain' />\n </ToolbarButton>\n <StyledEditPopover\n show={anchorMenu}\n target={buttonRef.current}\n ref={setPopoverEl}\n placement='bottom'\n >\n <CardContent>\n <Form\n as='div'\n actions={\n <>\n <Button variant='secondary' onClick={cancelAnchorCreation} type='button'>\n {t('cancel')}\n </Button>\n <Button\n variant='primary'\n disabled={!url || !urlMatch}\n onClick={(e: MouseEvent) => {\n e.preventDefault();\n createLink();\n }}\n >\n {t('apply')}\n </Button>\n </>\n }\n >\n <Grid container={{ rowGap: 2 }}>\n <Text variant='h2'>{t('rte_add_link')}</Text>\n <Input\n label={t('rte_link_text')}\n value={linkText}\n onClick={preventDef}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n setLinkText(e.target.value);\n }}\n ref={setTextInputEl}\n />\n <Input\n label={t('rte_link_url')}\n value={url}\n onClick={preventDef}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n const urlInput = e.target.value;\n setUrl(urlInput);\n // Clear error while typing, validate on blur\n if (!urlMatch) {\n setUrlMatch(true);\n }\n }}\n onBlur={() => {\n setUrlMatch(!url || isValidUrl(url));\n }}\n info={url && !urlMatch ? t('rte_invalid_url') : ''}\n status={url && !urlMatch ? 'error' : undefined}\n ref={setUrlInputEl}\n />\n </Grid>\n </Form>\n </CardContent>\n </StyledEditPopover>\n </>\n );\n};\n\nexport default AnchorButton;\n"]}
|
|
1
|
+
{"version":3,"file":"AnchorButton.js","sourceRoot":"","sources":["../../../../src/components/Editor/Toolbar/AnchorButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useRef, useState, useEffect, useLayoutEffect, useCallback } from 'react';\nimport type { ChangeEvent, MouseEvent, KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport type { Editor as TiptapEditor } from '@tiptap/core';\n\nimport {\n Button,\n CardContent,\n Grid,\n Icon,\n registerIcon,\n Input,\n RadioButton,\n RadioButtonGroup,\n useOuterEvent,\n Form,\n useI18n,\n Text,\n useElement,\n useEscape,\n isInstance\n} from '@pega/cosmos-react-core';\nimport type { ForwardProps } from '@pega/cosmos-react-core';\nimport * as chainIcon from '@pega/cosmos-react-core/lib/components/Icon/icons/chain.icon';\n\nimport ToolbarButton from '../../RichTextEditor/Toolbar/ToolbarButton';\nimport { getKeyCommand } from '../../RichTextEditor/Toolbar/utils';\nimport type { LinkCustomSourceConfig } from '../Editor.types';\nimport { StyledEditPopover } from '../Editor.styles';\nimport useCloseOnEditorClick from '../hooks/useCloseOnEditorClick';\n\nregisterIcon(chainIcon);\n\ninterface AnchorButtonProps {\n osx: boolean;\n editor: TiptapEditor;\n linkCustomSource?: LinkCustomSourceConfig;\n}\n\nconst AnchorButton = ({\n osx,\n editor,\n linkCustomSource,\n ...restProps\n}: AnchorButtonProps & ForwardProps) => {\n const t = useI18n();\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [textInputEl, setTextInputEl] = useElement<HTMLInputElement>();\n const [urlInputEl, setUrlInputEl] = useElement<HTMLInputElement>();\n const [popoverEl, setPopoverEl] = useElement<HTMLDivElement>();\n const [linkText, setLinkText] = useState('');\n const [url, setUrl] = useState('');\n const [urlMatch, setUrlMatch] = useState(true);\n const [anchorMenu, setAnchorMenu] = useState(false);\n const [shouldFocusInput, setShouldFocusInput] = useState(false);\n const [linkSourceType, setLinkSourceType] = useState<'url' | 'field'>('url');\n const hasFieldLinkMode = Boolean(linkCustomSource?.picker && linkCustomSource?.onSubmit);\n const canSubmitCustomSource = linkCustomSource?.canSubmit ?? true;\n const wasAnchorMenuVisibleRef = useRef(false);\n // Store the original selection range when menu opens so we can restore it when creating the link\n const originalSelectionRef = useRef<{ from: number; to: number } | null>(null);\n // Track whether the popover was opened via linkCustomSource.edit\n const openedViaEditCustomSourceRef = useRef(false);\n // Track whether popover was initialized from an existing field link (selection-based edit path)\n const initializedFromExistingFieldLinkRef = useRef(false);\n const tooltip = getKeyCommand(osx, ({ ctrl }) => `${t('rte_link')} (${ctrl}K)`);\n\n const parseCustomSourceFromHref = useCallback((href: string) => {\n const decodedHref = href\n .replaceAll('"', '\"')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('&', '&');\n if (!decodedHref.includes('<pega-reference')) {\n return null;\n }\n\n const idMatch = /data-rule-id=[\"']([^\"']+)[\"']/i.exec(decodedHref);\n if (!idMatch) {\n return null;\n }\n\n const namespaceMatch = /data-rule-namespace=[\"']([^\"']+)[\"']/i.exec(decodedHref);\n return {\n id: idMatch[1],\n namespace: namespaceMatch?.[1]\n };\n }, []);\n\n const openMenu = (opts: { focusInput?: boolean } = {}) => {\n // Save the original selection before opening the menu\n const { from, to } = editor.state.selection;\n originalSelectionRef.current = { from, to };\n initializedFromExistingFieldLinkRef.current = false;\n setAnchorMenu(true);\n if (opts.focusInput) {\n setShouldFocusInput(true);\n }\n };\n\n const resetMenu = useCallback(\n (dismissReason: 'cancel' | 'apply' = 'cancel') => {\n setLinkText('');\n setUrl('');\n setUrlMatch(true);\n setAnchorMenu(false);\n setLinkSourceType('url');\n originalSelectionRef.current = null;\n initializedFromExistingFieldLinkRef.current = false;\n if (openedViaEditCustomSourceRef.current) {\n openedViaEditCustomSourceRef.current = false;\n linkCustomSource?.onDismissEdit?.(dismissReason);\n }\n },\n [linkCustomSource]\n );\n\n useOuterEvent('mousedown', [popoverEl, buttonRef], () => {\n if (anchorMenu) {\n resetMenu();\n }\n });\n\n // Close menu when clicking inside the editor iframe\n const handleEditorClick = useCallback(() => {\n if (anchorMenu) {\n resetMenu();\n }\n }, [anchorMenu, resetMenu]);\n useCloseOnEditorClick(anchorMenu, handleEditorClick);\n\n const isValidUrl = (urlString: string): boolean => {\n if (!urlString.trim()) return false;\n const allowedProtocols = /^(https?|mailto|tel):/i;\n const hasProtocol = /^[a-z][a-z0-9.+-]*:/i.test(urlString);\n\n try {\n const testUrl = hasProtocol ? urlString : `https://${urlString}`;\n if (hasProtocol && !allowedProtocols.test(urlString)) {\n return false;\n }\n const urlObj = new URL(testUrl);\n return URL.canParse?.(testUrl) ?? Boolean(urlObj.href);\n } catch {\n return false;\n }\n };\n\n const createLink = useCallback(() => {\n if (!url || !isValidUrl(url)) {\n return;\n }\n\n // Only allow safe protocols to prevent XSS (e.g., javascript: URLs)\n const allowedProtocols = /^(https?|mailto|tel):/i;\n const hasProtocol = /^[a-z][a-z0-9.+-]*:/i.test(url);\n\n let normalizedUrl: string;\n if (hasProtocol) {\n // Reject URLs with disallowed protocols\n if (!allowedProtocols.test(url)) {\n return;\n }\n normalizedUrl = url;\n } else {\n normalizedUrl = `https://${url}`;\n }\n\n // Use the original selection to determine if text was selected in the editor\n const originalSelection = originalSelectionRef.current;\n\n if (originalSelection && originalSelection.from !== originalSelection.to) {\n // Text was originally selected - restore selection and apply link\n // Then collapse selection to end and clear stored mark so subsequent typing isn't linked\n editor\n .chain()\n .focus()\n .setTextSelection({ from: originalSelection.from, to: originalSelection.to })\n .setLink({ href: normalizedUrl })\n .setTextSelection(originalSelection.to)\n .unsetMark('link')\n .run();\n } else if (linkText) {\n // No text was originally selected, insert new link with the text entered in modal\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'text',\n text: linkText,\n marks: [{ type: 'link', attrs: { href: normalizedUrl } }]\n })\n .unsetMark('link')\n .insertContent(' ')\n .run();\n }\n resetMenu('apply');\n }, [url, linkText, editor, resetMenu]);\n\n useEffect(() => {\n const isOpening = anchorMenu && !wasAnchorMenuVisibleRef.current;\n wasAnchorMenuVisibleRef.current = anchorMenu;\n\n if (isOpening && originalSelectionRef.current) {\n // Use the stored original selection to populate the modal\n // This avoids issues where focus shift may collapse the editor selection\n const { from, to } = originalSelectionRef.current;\n const text = editor.state.doc.textBetween(from, to);\n const linkMark = editor.getAttributes('link');\n\n if (linkMark.href) {\n // Check if href contains a pega-reference (escaped or unescaped)\n const isPegaReference =\n linkMark.href.includes('<pega-reference') || linkMark.href.includes('<pega-reference');\n if (isPegaReference) {\n const customSourceValue = parseCustomSourceFromHref(linkMark.href);\n if (customSourceValue) {\n initializedFromExistingFieldLinkRef.current = true;\n linkCustomSource?.onEditSelectionChange?.({\n id: customSourceValue.id,\n text: text || '',\n namespace: customSourceValue.namespace\n });\n } else {\n initializedFromExistingFieldLinkRef.current = false;\n linkCustomSource?.onEditSelectionChange?.({ id: '', text: '', namespace: undefined });\n }\n // Don't populate URL field with pega-reference - leave it empty\n // The field picker will handle field links\n if (hasFieldLinkMode) {\n setLinkSourceType('field');\n }\n setLinkText(text || '');\n } else {\n initializedFromExistingFieldLinkRef.current = false;\n linkCustomSource?.onEditSelectionChange?.({ id: '', text: '', namespace: undefined });\n setLinkSourceType('url');\n setUrl(linkMark.href);\n setLinkText(text || '');\n }\n } else {\n initializedFromExistingFieldLinkRef.current = false;\n linkCustomSource?.onEditSelectionChange?.({ id: '', text: '', namespace: undefined });\n setLinkSourceType('url');\n setLinkText(text || '');\n }\n } else if (!anchorMenu) {\n resetMenu();\n }\n }, [\n anchorMenu,\n editor,\n hasFieldLinkMode,\n linkCustomSource,\n parseCustomSourceFromHref,\n resetMenu\n ]);\n\n useEffect(() => {\n if (linkCustomSource?.edit && hasFieldLinkMode) {\n openedViaEditCustomSourceRef.current = true;\n initializedFromExistingFieldLinkRef.current = true;\n setLinkText(linkCustomSource.edit.text);\n setLinkSourceType('field');\n setAnchorMenu(true);\n }\n }, [linkCustomSource, hasFieldLinkMode]);\n\n const preventDef = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n const isLinkActive = () => {\n return editor.isActive('link') && editor.isFocused;\n };\n\n const cancelAnchorCreation = useCallback(\n (event?: KeyboardEvent | MouseEvent) => {\n if (\n ((event && 'key' in event && event.key === 'Escape') ||\n event?.type === 'click' ||\n !event) &&\n anchorMenu\n ) {\n if (event && 'key' in event && event.key === 'Escape') {\n event.stopPropagation();\n }\n\n resetMenu();\n buttonRef.current?.focus();\n }\n },\n [anchorMenu, resetMenu]\n );\n\n // Ctrl+K shortcut to open link dialog from within the editor iframe\n useEffect(() => {\n const handleCtrlK = (e: KeyboardEvent) => {\n if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n openMenu({ focusInput: true });\n }\n };\n\n const iframeWindow = editor.view.dom.ownerDocument.defaultView;\n iframeWindow?.addEventListener('keydown', handleCtrlK);\n return () => iframeWindow?.removeEventListener('keydown', handleCtrlK);\n }, [editor]);\n\n // Escape to close popover - listen on both iframe and parent document\n // since focus may be in either location depending on how the popover was opened\n useEffect(() => {\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && anchorMenu) {\n e.preventDefault();\n cancelAnchorCreation();\n }\n };\n const iframeWindow = editor.view.dom.ownerDocument.defaultView;\n iframeWindow?.addEventListener('keydown', handleEscape);\n document.addEventListener('keydown', handleEscape);\n return () => {\n iframeWindow?.removeEventListener('keydown', handleEscape);\n document.removeEventListener('keydown', handleEscape);\n };\n }, [editor, anchorMenu, cancelAnchorCreation]);\n\n useEscape(cancelAnchorCreation, popoverEl);\n\n useLayoutEffect(() => {\n if (textInputEl && shouldFocusInput) {\n textInputEl.focus();\n setShouldFocusInput(false);\n }\n }, [textInputEl, shouldFocusInput]);\n\n useEffect(() => {\n // These events must be added here so they run before the native event in useArrows (used in the toolbar).\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') {\n e.stopPropagation();\n }\n };\n textInputEl?.addEventListener('keydown', onKeyDown);\n urlInputEl?.addEventListener('keydown', onKeyDown);\n return () => {\n textInputEl?.removeEventListener('keydown', onKeyDown);\n urlInputEl?.removeEventListener('keydown', onKeyDown);\n };\n }, [textInputEl, urlInputEl]);\n\n return (\n <>\n <ToolbarButton\n ref={buttonRef}\n onMouseDown={e => {\n e.preventDefault();\n openMenu();\n }}\n onKeyDown={(e: ReactKeyboardEvent) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n openMenu({ focusInput: true });\n }\n }}\n onBlur={(e: React.FocusEvent) => {\n const { relatedTarget } = e;\n if (\n isInstance(relatedTarget, Node) &&\n !buttonRef.current?.contains(relatedTarget) &&\n !popoverEl?.contains(relatedTarget)\n ) {\n resetMenu();\n }\n }}\n active={isLinkActive()}\n tooltip={tooltip}\n label={t('rte_link')}\n {...restProps}\n >\n <Icon name='chain' />\n </ToolbarButton>\n <StyledEditPopover\n show={anchorMenu}\n target={buttonRef.current}\n ref={setPopoverEl}\n placement='bottom'\n >\n <CardContent>\n <Form\n as='div'\n actions={\n <>\n <Button variant='secondary' onClick={cancelAnchorCreation} type='button'>\n {t('cancel')}\n </Button>\n <Button\n variant='primary'\n disabled={\n linkSourceType === 'url'\n ? !url.trim() || !urlMatch\n : !linkCustomSource?.onSubmit || !canSubmitCustomSource\n }\n onClick={(e: MouseEvent) => {\n e.preventDefault();\n if (linkSourceType === 'url') {\n createLink();\n return;\n }\n if (!linkCustomSource?.onSubmit) {\n return;\n }\n linkCustomSource.onSubmit(linkText);\n resetMenu('apply');\n }}\n >\n {t('apply')}\n </Button>\n </>\n }\n >\n <Grid container={{ rowGap: 2 }}>\n <Text variant='h2'>{t('rte_add_link')}</Text>\n <Input\n label={t('rte_link_text')}\n value={linkText}\n onClick={preventDef}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n setLinkText(e.target.value);\n }}\n ref={setTextInputEl}\n />\n {hasFieldLinkMode && (\n <RadioButtonGroup\n name='linkSourceType'\n label={t('rte_link_source')}\n onChange={e => {\n const { value } = e.target;\n if (value === 'url' || value === 'field') {\n setLinkSourceType(value);\n if (\n value === 'field' &&\n !openedViaEditCustomSourceRef.current &&\n !initializedFromExistingFieldLinkRef.current\n ) {\n linkCustomSource?.onEditSelectionChange?.({\n id: '',\n text: '',\n namespace: undefined\n });\n }\n }\n }}\n inline\n >\n <RadioButton\n label={t('rte_link_url')}\n value='url'\n checked={linkSourceType === 'url'}\n />\n <RadioButton\n label={t('rte_link_field')}\n value='field'\n checked={linkSourceType === 'field'}\n />\n </RadioButtonGroup>\n )}\n {linkSourceType === 'url' ? (\n <Input\n label={t('rte_link_url')}\n value={url}\n onClick={preventDef}\n onChange={(e: ChangeEvent<HTMLInputElement>) => {\n const urlInput = e.target.value;\n setUrl(urlInput);\n // Clear error while typing, validate on blur\n if (!urlMatch) {\n setUrlMatch(true);\n }\n }}\n onBlur={() => {\n setUrlMatch(!url || isValidUrl(url));\n }}\n info={url && !urlMatch ? t('rte_invalid_url') : ''}\n status={url && !urlMatch ? 'error' : undefined}\n ref={setUrlInputEl}\n />\n ) : (\n linkCustomSource?.picker\n )}\n </Grid>\n </Form>\n </CardContent>\n </StyledEditPopover>\n </>\n );\n};\n\nexport default AnchorButton;\n"]}
|
|
@@ -2,7 +2,7 @@ import type { ReactNode } from 'react';
|
|
|
2
2
|
import type { Editor as TiptapEditor } from '@tiptap/core';
|
|
3
3
|
import type { AIAction, TestIdProp } from '@pega/cosmos-react-core';
|
|
4
4
|
import type { Features } from '../../RichTextEditor/Toolbar/Toolbar.types';
|
|
5
|
-
import type { CustomAction } from '../Editor.types';
|
|
5
|
+
import type { CustomAction, LinkCustomSourceConfig } from '../Editor.types';
|
|
6
6
|
import type { elements } from './Toolbar.test-ids';
|
|
7
7
|
export interface ToolbarProps extends TestIdProp<typeof elements> {
|
|
8
8
|
features: Features[];
|
|
@@ -11,6 +11,7 @@ export interface ToolbarProps extends TestIdProp<typeof elements> {
|
|
|
11
11
|
customActions?: CustomAction[];
|
|
12
12
|
imageInsertionMode: 'file' | 'url' | 'all';
|
|
13
13
|
onRewriteClick?: (originalText: string, rewriteAction: AIAction, additionalInstructions: string, onSuccess: (rewrittenText: string) => void) => void;
|
|
14
|
+
linkCustomSource?: LinkCustomSourceConfig;
|
|
14
15
|
renderSuggestionEditor?: (props: {
|
|
15
16
|
defaultValue?: string;
|
|
16
17
|
disabled: boolean;
|
|
@@ -21,7 +22,7 @@ export interface ToolbarProps extends TestIdProp<typeof elements> {
|
|
|
21
22
|
sourceMode?: boolean;
|
|
22
23
|
onSourceModeToggle?: (isSourceMode: boolean) => void;
|
|
23
24
|
}
|
|
24
|
-
declare const _default: (({ testId, features, sticky, editor, customActions, imageInsertionMode, onRewriteClick, renderSuggestionEditor, sourceMode, onSourceModeToggle, ...restProps }: ToolbarProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
25
|
+
declare const _default: (({ testId, features, sticky, editor, customActions, imageInsertionMode, onRewriteClick, linkCustomSource, renderSuggestionEditor, sourceMode, onSourceModeToggle, ...restProps }: ToolbarProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
25
26
|
getTestIds: (testIdProp?: TestIdProp["testId"]) => import("@pega/cosmos-react-core").TestIdsRecord<readonly ["toolbar", "text-styles", "bold", "italic", "strike-through", "underline", "subscript", "superscript", "font-family", "font-size", "text-color", "background-color", "alignment", "align-left", "align-center", "align-right", "bulleted-list", "numbered-list", "indent", "unindent", "table", "link", "image", "source-code", "ai-rewrite", "overflow", "word-count"]>;
|
|
26
27
|
};
|
|
27
28
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/Editor/Toolbar/Toolbar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AAc3D,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAmB,MAAM,yBAAyB,CAAC;AAQrF,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAEtF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"Toolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/Editor/Toolbar/Toolbar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AAc3D,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAmB,MAAM,yBAAyB,CAAC;AAQrF,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,4CAA4C,CAAC;AAEtF,OAAO,KAAK,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAa5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AA+DnD,MAAM,WAAW,YAAa,SAAQ,UAAU,CAAC,OAAO,QAAQ,CAAC;IAC/D,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,kBAAkB,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAC3C,cAAc,CAAC,EAAE,CACf,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,QAAQ,EACvB,sBAAsB,EAAE,MAAM,EAC9B,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,KACvC,IAAI,CAAC;IACV,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE;QAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;QAClB,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;QACjD,eAAe,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;KAChD,KAAK,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD;2MAiHE,YAAY;;;AAsWf,wBAAuD"}
|
|
@@ -134,7 +134,7 @@ function createActiveFeaturesMap(features) {
|
|
|
134
134
|
return { ...acc, [feature]: true };
|
|
135
135
|
}, {});
|
|
136
136
|
}
|
|
137
|
-
const Toolbar = ({ testId, features, sticky, editor, customActions, imageInsertionMode, onRewriteClick, renderSuggestionEditor, sourceMode, onSourceModeToggle, ...restProps }) => {
|
|
137
|
+
const Toolbar = ({ testId, features, sticky, editor, customActions, imageInsertionMode, onRewriteClick, linkCustomSource, renderSuggestionEditor, sourceMode, onSourceModeToggle, ...restProps }) => {
|
|
138
138
|
const t = useI18n();
|
|
139
139
|
const { macintosh: osx } = useOS();
|
|
140
140
|
const toolbarRef = useRef(null);
|
|
@@ -280,7 +280,7 @@ const Toolbar = ({ testId, features, sticky, editor, customActions, imageInserti
|
|
|
280
280
|
onMouseDown(e);
|
|
281
281
|
}, tooltip: text, label: text, key: icon, active: active?.(editor) || false },
|
|
282
282
|
_jsx(Icon, { name: icon })));
|
|
283
|
-
}), activeFeatures.links && (_jsx(AnchorButton, { "data-testid": testIds.link, editor: editor, osx: osx })), activeFeatures.images && (_jsx(ImageButton, { "data-testid": testIds.image, editor: editor, imageInsertionMode: imageInsertionMode })), activeFeatures.tables && _jsx(TableButton, { "data-testid": testIds.table, editor: editor }), (activeFeatures.links || activeFeatures.images || activeFeatures.tables) &&
|
|
283
|
+
}), activeFeatures.links && (_jsx(AnchorButton, { "data-testid": testIds.link, editor: editor, osx: osx, linkCustomSource: linkCustomSource })), activeFeatures.images && (_jsx(ImageButton, { "data-testid": testIds.image, editor: editor, imageInsertionMode: imageInsertionMode })), activeFeatures.tables && _jsx(TableButton, { "data-testid": testIds.table, editor: editor }), (activeFeatures.links || activeFeatures.images || activeFeatures.tables) &&
|
|
284
284
|
activeFeatures['ai-rewrite'] &&
|
|
285
285
|
onRewriteClick && _jsx(ToolbarSeparator, {}), activeFeatures['ai-rewrite'] && onRewriteClick && (_jsx(AIRewriteButton, { "data-testid": testIds.aiRewrite, editor: editor, onRewriteClick: onRewriteClick, renderSuggestionEditor: renderSuggestionEditor }))] })] }));
|
|
286
286
|
};
|