@valbuild/ui 0.26.0 → 0.28.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/dist/valbuild-ui.cjs.js +41 -15
- package/dist/valbuild-ui.esm.js +41 -15
- package/package.json +7 -3
- package/server/.tmp/assets/index-18cfa26c.css +1 -0
- package/server/.tmp/assets/index-513f7a9c.js +197 -0
- package/{index.html → server/.tmp/index.html} +3 -1
- package/server/dist/style.css +0 -3
- package/server/dist/valbuild-ui-main.cjs.js +60 -34
- package/server/dist/valbuild-ui-main.esm.js +60 -34
- package/server/dist/valbuild-ui-server.cjs.js +1 -1
- package/server/dist/valbuild-ui-server.esm.js +1 -1
- package/.babelrc.json +0 -10
- package/.storybook/main.js +0 -25
- package/.storybook/preview-head.html +0 -6
- package/.storybook/preview.js +0 -33
- package/.storybook/theme.css +0 -34
- package/CHANGELOG.md +0 -0
- package/components.json +0 -16
- package/fix-server-hack.js +0 -54
- package/fullscreen.vite.config.ts +0 -9
- package/jest.config.js +0 -4
- package/postcss.config.js +0 -6
- package/rollup.config.js +0 -23
- package/server.vite.config.ts +0 -31
- package/src/App.tsx +0 -73
- package/src/assets/icons/Bold.tsx +0 -23
- package/src/assets/icons/Chevron.tsx +0 -28
- package/src/assets/icons/FontColor.tsx +0 -30
- package/src/assets/icons/ImageIcon.tsx +0 -29
- package/src/assets/icons/Italic.tsx +0 -24
- package/src/assets/icons/Logo.tsx +0 -103
- package/src/assets/icons/Section.tsx +0 -41
- package/src/assets/icons/Strikethrough.tsx +0 -22
- package/src/assets/icons/TextIcon.tsx +0 -20
- package/src/assets/icons/Underline.tsx +0 -22
- package/src/assets/icons/Undo.tsx +0 -20
- package/src/components/Button.tsx +0 -68
- package/src/components/Checkbox.tsx +0 -51
- package/src/components/DraggableList.stories.tsx +0 -20
- package/src/components/DraggableList.tsx +0 -95
- package/src/components/Dropdown.tsx +0 -101
- package/src/components/EditButton.tsx +0 -10
- package/src/components/ErrorText.tsx +0 -3
- package/src/components/ExpandLogo.tsx +0 -72
- package/src/components/Grid.stories.tsx +0 -43
- package/src/components/Grid.tsx +0 -139
- package/src/components/RichTextEditor/ContentEditable.tsx +0 -117
- package/src/components/RichTextEditor/Nodes/ImageNode.tsx +0 -100
- package/src/components/RichTextEditor/Plugins/AutoFocus.tsx +0 -12
- package/src/components/RichTextEditor/Plugins/ImagePlugin.tsx +0 -45
- package/src/components/RichTextEditor/Plugins/LinkEditorPlugin.tsx +0 -58
- package/src/components/RichTextEditor/Plugins/Toolbar.tsx +0 -412
- package/src/components/RichTextEditor/RichTextEditor.tsx +0 -105
- package/src/components/UploadModal.tsx +0 -109
- package/src/components/User.tsx +0 -17
- package/src/components/ValFormField.tsx +0 -574
- package/src/components/ValFullscreen.tsx +0 -1278
- package/src/components/ValMenu.tsx +0 -92
- package/src/components/ValOverlay.tsx +0 -488
- package/src/components/ValOverlayContext.tsx +0 -80
- package/src/components/ValWindow.stories.tsx +0 -146
- package/src/components/ValWindow.tsx +0 -220
- package/src/components/dashboard/DashboardButton.tsx +0 -25
- package/src/components/dashboard/DashboardDropdown.tsx +0 -59
- package/src/components/dashboard/Dropdown.stories.tsx +0 -11
- package/src/components/dashboard/Dropdown.tsx +0 -70
- package/src/components/dashboard/FormGroup.stories.tsx +0 -37
- package/src/components/dashboard/FormGroup.tsx +0 -42
- package/src/components/dashboard/Grid2.stories.tsx +0 -56
- package/src/components/dashboard/Grid2.tsx +0 -72
- package/src/components/dashboard/Tree.stories.tsx +0 -91
- package/src/components/dashboard/Tree.tsx +0 -72
- package/src/components/dashboard/ValDashboardEditor.tsx +0 -269
- package/src/components/dashboard/ValDashboardGrid.tsx +0 -142
- package/src/components/dashboard/ValTreeNavigator.tsx +0 -253
- package/src/components/forms/Form.tsx +0 -126
- package/src/components/forms/FormContainer.tsx +0 -24
- package/src/components/forms/ImageForm.tsx +0 -195
- package/src/components/forms/TextArea.tsx +0 -24
- package/src/components/ui/accordion.tsx +0 -58
- package/src/components/ui/alert-dialog.tsx +0 -139
- package/src/components/ui/avatar.tsx +0 -48
- package/src/components/ui/button.tsx +0 -56
- package/src/components/ui/calendar.tsx +0 -62
- package/src/components/ui/card.tsx +0 -86
- package/src/components/ui/checkbox.tsx +0 -28
- package/src/components/ui/command.tsx +0 -153
- package/src/components/ui/dialog.tsx +0 -120
- package/src/components/ui/dropdown-menu.tsx +0 -198
- package/src/components/ui/form.tsx +0 -177
- package/src/components/ui/input.tsx +0 -24
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/popover.tsx +0 -29
- package/src/components/ui/progress.tsx +0 -26
- package/src/components/ui/radio-group.tsx +0 -42
- package/src/components/ui/scroll-area.tsx +0 -51
- package/src/components/ui/select.tsx +0 -119
- package/src/components/ui/switch.tsx +0 -27
- package/src/components/ui/tabs.tsx +0 -53
- package/src/components/ui/toggle.tsx +0 -43
- package/src/components/ui/tooltip.tsx +0 -28
- package/src/components/usePatch.ts +0 -86
- package/src/components/useTheme.ts +0 -45
- package/src/dto/SerializedSchema.ts +0 -69
- package/src/dto/Session.ts +0 -12
- package/src/dto/SessionMode.ts +0 -5
- package/src/dto/Tree.ts +0 -18
- package/src/exports.ts +0 -6
- package/src/index.css +0 -115
- package/src/index.tsx +0 -14
- package/src/lib/IValStore.ts +0 -6
- package/src/lib/utils.ts +0 -6
- package/src/main.jsx +0 -10
- package/src/richtext/conversion/conversion.test.ts +0 -146
- package/src/richtext/conversion/lexicalToRichTextSource.test.ts +0 -89
- package/src/richtext/conversion/lexicalToRichTextSource.ts +0 -285
- package/src/richtext/conversion/parseRichTextSource.test.ts +0 -469
- package/src/richtext/conversion/parseRichTextSource.ts +0 -233
- package/src/richtext/conversion/richTextSourceToLexical.test.ts +0 -381
- package/src/richtext/conversion/richTextSourceToLexical.ts +0 -293
- package/src/richtext/shadowRootPolyFill.js +0 -115
- package/src/server.ts +0 -70
- package/src/stories/Button.stories.tsx +0 -20
- package/src/stories/Checkbox.stories.tsx +0 -14
- package/src/stories/Dropdown.stories.tsx +0 -23
- package/src/stories/Introduction.mdx +0 -221
- package/src/stories/RichTextEditor.stories.tsx +0 -24
- package/src/stories/assets/code-brackets.svg +0 -1
- package/src/stories/assets/colors.svg +0 -1
- package/src/stories/assets/comments.svg +0 -1
- package/src/stories/assets/direction.svg +0 -1
- package/src/stories/assets/flow.svg +0 -1
- package/src/stories/assets/plugin.svg +0 -1
- package/src/stories/assets/repo.svg +0 -1
- package/src/stories/assets/stackalt.svg +0 -1
- package/src/utils/Remote.ts +0 -15
- package/src/utils/imageMimeType.ts +0 -23
- package/src/utils/readImage.ts +0 -54
- package/src/utils/resolvePath.ts +0 -32
- package/src/vite-env.d.ts +0 -1
- package/src/vite-index.tsx +0 -7
- package/src/vite-server.ts +0 -42
- package/tailwind.config.js +0 -83
- package/tsconfig.json +0 -19
- package/vite.config.ts +0 -43
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import { useCallback, useState } from "react";
|
|
4
|
-
import "../../richtext/shadowRootPolyFill";
|
|
5
|
-
|
|
6
|
-
export type Props = {
|
|
7
|
-
ariaActiveDescendant?: React.AriaAttributes["aria-activedescendant"];
|
|
8
|
-
ariaAutoComplete?: React.AriaAttributes["aria-autocomplete"];
|
|
9
|
-
ariaControls?: React.AriaAttributes["aria-controls"];
|
|
10
|
-
ariaDescribedBy?: React.AriaAttributes["aria-describedby"];
|
|
11
|
-
ariaExpanded?: React.AriaAttributes["aria-expanded"];
|
|
12
|
-
ariaLabel?: React.AriaAttributes["aria-label"];
|
|
13
|
-
ariaLabelledBy?: React.AriaAttributes["aria-labelledby"];
|
|
14
|
-
ariaMultiline?: React.AriaAttributes["aria-multiline"];
|
|
15
|
-
ariaOwns?: React.AriaAttributes["aria-owns"];
|
|
16
|
-
ariaRequired?: React.AriaAttributes["aria-required"];
|
|
17
|
-
autoCapitalize?: HTMLDivElement["autocapitalize"];
|
|
18
|
-
"data-testid"?: string | null | undefined;
|
|
19
|
-
} & React.AllHTMLAttributes<HTMLDivElement>;
|
|
20
|
-
|
|
21
|
-
export function ContentEditable({
|
|
22
|
-
ariaActiveDescendant,
|
|
23
|
-
ariaAutoComplete,
|
|
24
|
-
ariaControls,
|
|
25
|
-
ariaDescribedBy,
|
|
26
|
-
ariaExpanded,
|
|
27
|
-
ariaLabel,
|
|
28
|
-
ariaLabelledBy,
|
|
29
|
-
ariaMultiline,
|
|
30
|
-
ariaOwns,
|
|
31
|
-
ariaRequired,
|
|
32
|
-
autoCapitalize,
|
|
33
|
-
className,
|
|
34
|
-
id,
|
|
35
|
-
role = "textbox",
|
|
36
|
-
spellCheck = true,
|
|
37
|
-
style,
|
|
38
|
-
tabIndex,
|
|
39
|
-
"data-testid": testid,
|
|
40
|
-
...rest
|
|
41
|
-
}: Props): JSX.Element {
|
|
42
|
-
const [editor] = useLexicalComposerContext();
|
|
43
|
-
const [isEditable, setEditable] = useState(false);
|
|
44
|
-
|
|
45
|
-
const ref = useCallback(
|
|
46
|
-
(rootElement: null | HTMLElement) => {
|
|
47
|
-
editor.setRootElement(rootElement);
|
|
48
|
-
const shadowRoot = document.getElementById("val-ui")?.shadowRoot;
|
|
49
|
-
if (!shadowRoot) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// Lexical doesnt officially support shadow dom yet, but this is a workaround
|
|
53
|
-
// It happens to work in firefox since their document.getSelection pierces shadow dom
|
|
54
|
-
// Chrome does not do this,. but has getSelection on the shadowRoot
|
|
55
|
-
// Safari does not have getSelection on the shadowRoot, and document.getSelection does not pierce shadow dom
|
|
56
|
-
// So for Safari this is polyfilled in shadowRootPolyFill.js
|
|
57
|
-
// https://github.com/facebook/lexical/issues/2119
|
|
58
|
-
//
|
|
59
|
-
// In the code below we have a hack to override the window object on the editor with the shadowRoot
|
|
60
|
-
// then it will call getSelection on the shadowRoot instead of the document
|
|
61
|
-
if ("getSelection" in shadowRoot) {
|
|
62
|
-
// safari (if polyfilled) and chrome
|
|
63
|
-
editor._window = shadowRoot as unknown as Window;
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
[editor]
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
React.useLayoutEffect(() => {
|
|
71
|
-
setEditable(editor.isEditable());
|
|
72
|
-
return editor.registerEditableListener((currentIsEditable) => {
|
|
73
|
-
setEditable(currentIsEditable);
|
|
74
|
-
});
|
|
75
|
-
}, [editor]);
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<div
|
|
79
|
-
{...rest}
|
|
80
|
-
aria-activedescendant={!isEditable ? undefined : ariaActiveDescendant}
|
|
81
|
-
aria-autocomplete={!isEditable ? "none" : ariaAutoComplete}
|
|
82
|
-
aria-controls={!isEditable ? undefined : ariaControls}
|
|
83
|
-
aria-describedby={ariaDescribedBy}
|
|
84
|
-
aria-expanded={
|
|
85
|
-
!isEditable
|
|
86
|
-
? undefined
|
|
87
|
-
: role === "combobox"
|
|
88
|
-
? !!ariaExpanded
|
|
89
|
-
: undefined
|
|
90
|
-
}
|
|
91
|
-
aria-label={ariaLabel}
|
|
92
|
-
aria-labelledby={ariaLabelledBy}
|
|
93
|
-
aria-multiline={ariaMultiline}
|
|
94
|
-
aria-owns={!isEditable ? undefined : ariaOwns}
|
|
95
|
-
aria-readonly={!isEditable ? true : undefined}
|
|
96
|
-
aria-required={ariaRequired}
|
|
97
|
-
autoCapitalize={autoCapitalize}
|
|
98
|
-
className={className}
|
|
99
|
-
contentEditable={isEditable}
|
|
100
|
-
data-testid={testid}
|
|
101
|
-
id={id}
|
|
102
|
-
ref={ref}
|
|
103
|
-
role={role}
|
|
104
|
-
spellCheck={spellCheck}
|
|
105
|
-
style={style}
|
|
106
|
-
tabIndex={tabIndex}
|
|
107
|
-
/>
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export default function LexicalContentEditable({
|
|
112
|
-
className,
|
|
113
|
-
}: {
|
|
114
|
-
className?: string;
|
|
115
|
-
}): JSX.Element {
|
|
116
|
-
return <ContentEditable className={className} />;
|
|
117
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DecoratorNode,
|
|
3
|
-
LexicalNode,
|
|
4
|
-
NodeKey,
|
|
5
|
-
SerializedLexicalNode,
|
|
6
|
-
Spread,
|
|
7
|
-
} from "lexical";
|
|
8
|
-
|
|
9
|
-
export type ImagePayload = {
|
|
10
|
-
src: string;
|
|
11
|
-
altText?: string;
|
|
12
|
-
height?: number;
|
|
13
|
-
width?: number;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export type SerializedImageNode = Spread<ImagePayload, SerializedLexicalNode>;
|
|
17
|
-
|
|
18
|
-
export class ImageNode extends DecoratorNode<JSX.Element> {
|
|
19
|
-
__src: string;
|
|
20
|
-
__sha256?: string;
|
|
21
|
-
__imageFileExt?: string;
|
|
22
|
-
__altText?: string;
|
|
23
|
-
__width?: number;
|
|
24
|
-
__height?: number;
|
|
25
|
-
|
|
26
|
-
static getType(): string {
|
|
27
|
-
return "image";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static clone(node: ImageNode): ImageNode {
|
|
31
|
-
return new ImageNode({
|
|
32
|
-
src: node.__src,
|
|
33
|
-
altText: node.__altText,
|
|
34
|
-
width: node.__width,
|
|
35
|
-
height: node.__height,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
constructor(payload: ImagePayload, key?: NodeKey) {
|
|
40
|
-
super(key);
|
|
41
|
-
this.__src = payload.src;
|
|
42
|
-
this.__altText = payload.altText;
|
|
43
|
-
this.__width = payload.width;
|
|
44
|
-
this.__height = payload.height;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
exportJSON(): SerializedImageNode {
|
|
48
|
-
return {
|
|
49
|
-
altText: this.__altText,
|
|
50
|
-
height: this.__width,
|
|
51
|
-
src: this.__src,
|
|
52
|
-
type: "image",
|
|
53
|
-
version: 1,
|
|
54
|
-
width: this.__width,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
static importJSON(serializedNode: SerializedImageNode): ImageNode {
|
|
59
|
-
return $createImageNode(serializedNode);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
createDOM(): HTMLElement {
|
|
63
|
-
return document.createElement("div");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
updateDOM(): false {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
decorate(): JSX.Element {
|
|
71
|
-
return (
|
|
72
|
-
<ImageComponent
|
|
73
|
-
src={this.__src}
|
|
74
|
-
altText={this.__altText}
|
|
75
|
-
empty={this.__empty}
|
|
76
|
-
height={this.__height}
|
|
77
|
-
nodeKey={this.getKey()}
|
|
78
|
-
/>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function ImageComponent(props: {
|
|
84
|
-
empty: boolean;
|
|
85
|
-
altText?: string;
|
|
86
|
-
height?: number;
|
|
87
|
-
nodeKey?: NodeKey;
|
|
88
|
-
src: string;
|
|
89
|
-
width?: number;
|
|
90
|
-
}): JSX.Element {
|
|
91
|
-
return <img src={props.src}></img>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function $createImageNode(payload: ImagePayload): ImageNode {
|
|
95
|
-
return new ImageNode(payload);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function $isImageNode(node: LexicalNode | null): boolean {
|
|
99
|
-
return node instanceof ImageNode;
|
|
100
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
3
|
-
|
|
4
|
-
export function AutoFocus() {
|
|
5
|
-
const [editor] = useLexicalComposerContext();
|
|
6
|
-
|
|
7
|
-
useEffect(() => {
|
|
8
|
-
editor.focus();
|
|
9
|
-
}, [editor]);
|
|
10
|
-
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
2
|
-
import { $wrapNodeInElement, mergeRegister } from "@lexical/utils";
|
|
3
|
-
import {
|
|
4
|
-
$createParagraphNode,
|
|
5
|
-
$insertNodes,
|
|
6
|
-
$isRootOrShadowRoot,
|
|
7
|
-
COMMAND_PRIORITY_EDITOR,
|
|
8
|
-
createCommand,
|
|
9
|
-
LexicalCommand,
|
|
10
|
-
} from "lexical";
|
|
11
|
-
import { useEffect } from "react";
|
|
12
|
-
|
|
13
|
-
import { $createImageNode, ImageNode, ImagePayload } from "../Nodes/ImageNode";
|
|
14
|
-
|
|
15
|
-
export type InsertImagePayload = Readonly<ImagePayload>;
|
|
16
|
-
|
|
17
|
-
export const INSERT_IMAGE_COMMAND: LexicalCommand<InsertImagePayload> =
|
|
18
|
-
createCommand("INSERT_IMAGE_COMMAND");
|
|
19
|
-
|
|
20
|
-
export default function ImagesPlugin(): JSX.Element | null {
|
|
21
|
-
const [editor] = useLexicalComposerContext();
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
if (!editor.hasNodes([ImageNode])) {
|
|
25
|
-
throw new Error("ImagesPlugin: ImageNode not registered on editor");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return mergeRegister(
|
|
29
|
-
editor.registerCommand<InsertImagePayload>(
|
|
30
|
-
INSERT_IMAGE_COMMAND,
|
|
31
|
-
(payload) => {
|
|
32
|
-
const imageNode = $createImageNode(payload);
|
|
33
|
-
$insertNodes([imageNode]);
|
|
34
|
-
if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
|
|
35
|
-
$wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
|
|
36
|
-
}
|
|
37
|
-
return true;
|
|
38
|
-
},
|
|
39
|
-
COMMAND_PRIORITY_EDITOR
|
|
40
|
-
)
|
|
41
|
-
);
|
|
42
|
-
}, [editor]);
|
|
43
|
-
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { $isLinkNode } from "@lexical/link";
|
|
2
|
-
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
3
|
-
import { $isAtNodeEnd } from "@lexical/selection";
|
|
4
|
-
import { $findMatchingParent, mergeRegister } from "@lexical/utils";
|
|
5
|
-
import {
|
|
6
|
-
$getSelection,
|
|
7
|
-
$isRangeSelection,
|
|
8
|
-
CLICK_COMMAND,
|
|
9
|
-
COMMAND_PRIORITY_LOW,
|
|
10
|
-
ElementNode,
|
|
11
|
-
RangeSelection,
|
|
12
|
-
TextNode,
|
|
13
|
-
} from "lexical";
|
|
14
|
-
import { useEffect } from "react";
|
|
15
|
-
|
|
16
|
-
export function getSelectedNode(
|
|
17
|
-
selection: RangeSelection
|
|
18
|
-
): TextNode | ElementNode {
|
|
19
|
-
const anchor = selection.anchor;
|
|
20
|
-
const focus = selection.focus;
|
|
21
|
-
const anchorNode = selection.anchor.getNode();
|
|
22
|
-
const focusNode = selection.focus.getNode();
|
|
23
|
-
if (anchorNode === focusNode) {
|
|
24
|
-
return anchorNode;
|
|
25
|
-
}
|
|
26
|
-
const isBackward = selection.isBackward();
|
|
27
|
-
if (isBackward) {
|
|
28
|
-
return $isAtNodeEnd(focus) ? anchorNode : focusNode;
|
|
29
|
-
} else {
|
|
30
|
-
return $isAtNodeEnd(anchor) ? anchorNode : focusNode;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export default function LinkEditorPlugin() {
|
|
35
|
-
const [editor] = useLexicalComposerContext();
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
return mergeRegister(
|
|
39
|
-
editor.registerCommand(
|
|
40
|
-
CLICK_COMMAND,
|
|
41
|
-
(payload) => {
|
|
42
|
-
const selection = $getSelection();
|
|
43
|
-
if ($isRangeSelection(selection)) {
|
|
44
|
-
const node = getSelectedNode(selection);
|
|
45
|
-
const linkNode = $findMatchingParent(node, $isLinkNode);
|
|
46
|
-
if ($isLinkNode(linkNode) && (payload.metaKey || payload.ctrlKey)) {
|
|
47
|
-
window.open(linkNode.getURL(), "_blank");
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return false;
|
|
52
|
-
},
|
|
53
|
-
COMMAND_PRIORITY_LOW
|
|
54
|
-
)
|
|
55
|
-
);
|
|
56
|
-
}, []);
|
|
57
|
-
return null;
|
|
58
|
-
}
|