@clevertask/scribe 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/dist/{BarMenu-O2IVhHXx.js → BarMenu-x4sf3ECS.js} +1 -1
- package/dist/components/Menu/BarMenu.js +1 -1
- package/dist/components/Menu/BubbleMenu.js +2 -2
- package/dist/components/Menu/CalloutBubbleMenu.js +2 -2
- package/dist/components/Menu/ExternalLinkDisplayOptions.d.ts +13 -0
- package/dist/components/Menu/ExternalLinkDisplayOptions.d.ts.map +1 -0
- package/dist/components/Menu/ExternalLinkDisplayOptions.js +90 -0
- package/dist/components/Menu/LinkBubbleMenu.d.ts.map +1 -1
- package/dist/components/Menu/LinkBubbleMenu.js +161 -61
- package/dist/components/Menu/LinkEditor.d.ts +9 -0
- package/dist/components/Menu/LinkEditor.d.ts.map +1 -1
- package/dist/components/Menu/LinkEditor.js +117 -64
- package/dist/components/Menu/Mobile/ListOptionBar.js +1 -1
- package/dist/components/Menu/TableBubbleMenu.js +2 -2
- package/dist/components/Menu/contextualMenuOwner.d.ts +1 -1
- package/dist/components/Menu/contextualMenuOwner.d.ts.map +1 -1
- package/dist/components/Menu/contextualMenuOwner.js +9 -6
- package/dist/components/Menu/linkBubbleMenuPlugin.d.ts +24 -1
- package/dist/components/Menu/linkBubbleMenuPlugin.d.ts.map +1 -1
- package/dist/components/Menu/linkBubbleMenuPlugin.js +43 -6
- package/dist/components/Scribe/extension/callout.js +1 -1
- package/dist/components/Scribe/extension/emoji/suggest.js +1 -1
- package/dist/components/Scribe/extension/extension-link.js +1 -1
- package/dist/components/Scribe/extension/extension-markdown-paste.js +2 -2
- package/dist/components/Scribe/extension/extension-selectedText.js +1 -1
- package/dist/components/Scribe/extension/external-link-preview/attributes.d.ts +18 -0
- package/dist/components/Scribe/extension/external-link-preview/attributes.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/attributes.js +82 -0
- package/dist/components/Scribe/extension/external-link-preview/commands.d.ts +53 -0
- package/dist/components/Scribe/extension/external-link-preview/commands.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/commands.js +134 -0
- package/dist/components/Scribe/extension/external-link-preview/index.d.ts +13 -0
- package/dist/components/Scribe/extension/external-link-preview/index.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/index.js +140 -0
- package/dist/components/Scribe/extension/external-link-preview/node-view.d.ts +3 -0
- package/dist/components/Scribe/extension/external-link-preview/node-view.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/node-view.js +97 -0
- package/dist/components/Scribe/extension/external-link-preview/normalization.d.ts +7 -0
- package/dist/components/Scribe/extension/external-link-preview/normalization.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/normalization.js +21 -0
- package/dist/components/Scribe/extension/external-link-preview/paste.d.ts +9 -0
- package/dist/components/Scribe/extension/external-link-preview/paste.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/paste.js +54 -0
- package/dist/components/Scribe/extension/external-link-preview/policy.d.ts +7 -0
- package/dist/components/Scribe/extension/external-link-preview/policy.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/policy.js +38 -0
- package/dist/components/Scribe/extension/external-link-preview/render-html.d.ts +7 -0
- package/dist/components/Scribe/extension/external-link-preview/render-html.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/render-html.js +62 -0
- package/dist/components/Scribe/extension/external-link-preview/resolver.d.ts +23 -0
- package/dist/components/Scribe/extension/external-link-preview/resolver.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/resolver.js +118 -0
- package/dist/components/Scribe/extension/external-link-preview/serialization.d.ts +10 -0
- package/dist/components/Scribe/extension/external-link-preview/serialization.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/serialization.js +69 -0
- package/dist/components/Scribe/extension/external-link-preview/types.d.ts +58 -0
- package/dist/components/Scribe/extension/external-link-preview/types.d.ts.map +1 -0
- package/dist/components/Scribe/extension/external-link-preview/types.js +4 -0
- package/dist/components/Scribe/extension/index.d.ts +1 -1
- package/dist/components/Scribe/extension/index.d.ts.map +1 -1
- package/dist/components/Scribe/extension/index.js +1 -1
- package/dist/components/Scribe/extension/resizable-table.js +1 -1
- package/dist/components/Scribe/extension/slashCommand/index.js +1 -1
- package/dist/components/Scribe/extension/slashCommand/renderItems.js +1 -1
- package/dist/components/Scribe/extension/tableOfContents.js +1 -1
- package/dist/components/Scribe/index.d.ts +14 -0
- package/dist/components/Scribe/index.d.ts.map +1 -1
- package/dist/components/Scribe/index.js +5 -5
- package/dist/{dist-BoYfa2nz.js → dist-DDjaA1Pn.js} +309 -150
- package/dist/{dist-W9E-K577.js → dist-tNcpTcFT.js} +738 -637
- package/dist/{extension-D5WIAWhc.js → extension-dRUfQQo6.js} +1940 -1938
- package/dist/{extension-link-D8Zi7OSa.js → extension-link-RYtPpHwt.js} +28 -27
- package/dist/{html-to-markdown-C920nQtn.js → html-to-markdown-nbQ6qHyO.js} +173 -162
- package/dist/main.css +148 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -9
- package/dist/{markdown-to-html-CW0Nb9Ye.js → markdown-to-html-B-KKCZRs.js} +115 -111
- package/dist/{menus-B1Zz0GjH.js → menus-U2HdvQnu.js} +11 -11
- package/dist/{resizable-table-Bf-fb9iv.js → resizable-table-m0AzovsZ.js} +14 -14
- package/dist/{slashCommand-47omO4ob.js → slashCommand-CtvgnL0Z.js} +1 -1
- package/dist/utils/create-scribe-editor.d.ts +4 -1
- package/dist/utils/create-scribe-editor.d.ts.map +1 -1
- package/dist/utils/html-to-markdown.d.ts.map +1 -1
- package/dist/utils/html-to-markdown.js +1 -1
- package/dist/utils/index.js +7 -7
- package/dist/utils/markdown-to-html.d.ts.map +1 -1
- package/dist/utils/markdown-to-html.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ A versatile, block-based rich text editor for diverse applications, built with T
|
|
|
11
11
|
- **Markdown Support:** Parse and render Markdown content effortlessly.
|
|
12
12
|
- **Markdown Paste:** Paste plain-text markdown into the editor and have it converted into rich content automatically.
|
|
13
13
|
- **Table Authoring:** Insert, resize, and edit tables with controls that stay next to the active table.
|
|
14
|
+
- **Experimental External Link Previews:** Opt into Compact and Preview card presentations while keeping ordinary links available.
|
|
14
15
|
- **Versatile Integration:** Easily integrate `@clevertask/scribe` into any project requiring rich text editing.
|
|
15
16
|
- **View and Edit:** Seamlessly switch between viewing and editing modes.
|
|
16
17
|
- **Experimental Table of Contents:** Subscribe to heading changes and render an app-owned table of contents outside the editor.
|
|
@@ -21,6 +22,7 @@ A versatile, block-based rich text editor for diverse applications, built with T
|
|
|
21
22
|
- [Installation](#installation)
|
|
22
23
|
- [Usage](#usage)
|
|
23
24
|
- [Table Authoring](#table-authoring)
|
|
25
|
+
- [External Link Previews](#external-link-previews)
|
|
24
26
|
- [Experimental Table of Contents](#experimental-table-of-contents)
|
|
25
27
|
- [Math Expressions](#math-expressions)
|
|
26
28
|
- [Props](#props)
|
|
@@ -119,6 +121,55 @@ Keyboard users can press `Alt + F10` while editing a table to focus its controls
|
|
|
119
121
|
|
|
120
122
|
Simple headed tables serialize as GFM Markdown. Tables with merged cells, multiple blocks in a cell, resized columns, or other structures that GFM cannot represent are kept as sanitized raw HTML inside the Markdown output so their structure is not silently lost.
|
|
121
123
|
|
|
124
|
+
## External Link Previews
|
|
125
|
+
|
|
126
|
+
> [!NOTE]
|
|
127
|
+
> External Link Previews are experimental. Their public API, built-in card presentation, and link-options UI may change as we test them in real document workflows.
|
|
128
|
+
|
|
129
|
+
External link previews are opt-in. Scribe owns their editor behavior and presentation, while your app owns metadata fetching. Pass a resolver that calls an authenticated app endpoint; Scribe never requests the destination website directly.
|
|
130
|
+
|
|
131
|
+
That endpoint should validate the destination, block private or reserved network addresses, re-check redirects, and enforce response-size and timeout limits before returning sanitized metadata.
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { Scribe, type ExternalLinkPreviewResolver } from "@clevertask/scribe";
|
|
135
|
+
import { useCallback } from "react";
|
|
136
|
+
|
|
137
|
+
function DocumentEditor() {
|
|
138
|
+
const resolveLinkPreview = useCallback<ExternalLinkPreviewResolver>(async (href, { signal }) => {
|
|
139
|
+
const response = await fetch(`/api/link-previews?url=${encodeURIComponent(href)}`, {
|
|
140
|
+
credentials: "include",
|
|
141
|
+
signal,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return response.json();
|
|
149
|
+
}, []);
|
|
150
|
+
const shouldPreview = useCallback((href: string) => {
|
|
151
|
+
return new URL(href).origin !== window.location.origin;
|
|
152
|
+
}, []);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<Scribe
|
|
156
|
+
externalLinkPreview={{
|
|
157
|
+
resolve: resolveLinkPreview,
|
|
158
|
+
shouldPreview,
|
|
159
|
+
// Defaults to false. Enable only if standalone pastes should fetch immediately.
|
|
160
|
+
autoPreviewOnPaste: false,
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
By default, pasting a standalone external URL creates an ordinary link and does not call the resolver. Select the link and choose Compact or Preview card to request metadata. Set `autoPreviewOnPaste: true` if standalone URL pastes should become Compact previews automatically. Pasting a URL over selected text always keeps an ordinary labeled link. While editing, select a Plain, Compact, or Card link to open its contextual menu. From there you can edit or open the destination, refresh preview metadata, or switch presentation; a Preview card is available only when the link has its own line. Keyboard users can press `Alt + F10` from a selected link to open the same menu and press Escape to return to the document.
|
|
168
|
+
|
|
169
|
+
The resolver runs only after an explicit conversion, programmatic preview insertion, preview destination edit, refresh, or—when deliberately enabled—an automatic standalone paste. It never runs merely because a saved document opens. It receives an `AbortSignal`, and can return `pageTitle`, `description`, `siteName`, `faviconUrl`, `imageUrl`, and `fetchedAt`. Use `shouldPreview` to keep app-owned or otherwise unsupported destinations on the ordinary-link path.
|
|
170
|
+
|
|
171
|
+
Preview nodes use sanitized raw HTML when content is serialized as Markdown, so their metadata and presentation survive Scribe's current Markdown round trip. A caller-owned `externalEditor` must register `ExternalLinkPreview` itself.
|
|
172
|
+
|
|
122
173
|
## Experimental Table of Contents
|
|
123
174
|
|
|
124
175
|
Scribe can expose table-of-contents data without rendering a table-of-contents block inside the editable document. Enable the experimental API with `enableTableOfContents`, keep the latest items in your app state, and call `scrollToTableOfContentsItem` when a user selects an entry.
|
|
@@ -201,6 +252,7 @@ If your content arrives as HTML (for example from a server), use the helper belo
|
|
|
201
252
|
| `autoFocus` | `boolean` | `false` | Controls whether the editor should automatically focus when mounted. |
|
|
202
253
|
| `extensions` | `Extension[]` | `undefined` | You can set your own extensions for the text editor. For more information, [check the tip tap extensions docs](https://tiptap.dev/docs/editor/core-concepts/extensions) |
|
|
203
254
|
| `externalEditor` | `Editor` | `undefined` | Uses a caller-owned Tiptap editor. The caller remains responsible for its extension and plugin lifecycle, including table resizing, and for destroying it. |
|
|
255
|
+
| `externalLinkPreview` | `Partial<ExternalLinkPreviewOptions>` | `undefined` | Experimental. Opts into external-link metadata resolution and enhanced Compact/Card presentation. The consumer owns fetching and destination policy; automatic previews on paste default to disabled. |
|
|
204
256
|
| `editorProps` | `EditorProps` | `undefined` | A tiptap-based prop to handle advanced use cases, you can read about it on their [documentation](https://tiptap.dev/docs/editor/api/editor#editorprops) |
|
|
205
257
|
| `showBarMenu` | `boolean` | `true` | Determines whether to show the text editor top menu bar or not. This menu bar shows options to format the text |
|
|
206
258
|
| `placeholderText` | `string` | `Type "/" for commands...` | Change the initial placeholder for your text editor |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as e } from "./dist-DDjaA1Pn.js";
|
|
2
2
|
import { getPopupMountTarget as t } from "./components/Scribe/extension/getPopupMountTarget.js";
|
|
3
3
|
import n from "./components/Menu/LinkEditor.js";
|
|
4
4
|
import { hideLinkBubbleMenu as r } from "./components/Menu/linkBubbleMenuPlugin.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "../../BarMenu-
|
|
1
|
+
import { t as e } from "../../BarMenu-x4sf3ECS.js";
|
|
2
2
|
export { e as default };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as e } from "../../dist-DDjaA1Pn.js";
|
|
2
2
|
import { getPopupMountTarget as t } from "../Scribe/extension/getPopupMountTarget.js";
|
|
3
|
-
import { t as n } from "../../menus-
|
|
3
|
+
import { t as n } from "../../menus-U2HdvQnu.js";
|
|
4
4
|
import { Flex as r, IconButton as i } from "@radix-ui/themes";
|
|
5
5
|
import { useCallback as a } from "react";
|
|
6
6
|
import { jsx as o } from "react/jsx-runtime";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as e } from "../../dist-DDjaA1Pn.js";
|
|
2
2
|
import { getPopupMountTarget as t } from "../Scribe/extension/getPopupMountTarget.js";
|
|
3
|
-
import { t as n } from "../../menus-
|
|
3
|
+
import { t as n } from "../../menus-U2HdvQnu.js";
|
|
4
4
|
import { CalloutIcon as r, RemoveCalloutIcon as i } from "../../icons/CalloutIcon.js";
|
|
5
5
|
import { CALLOUT_VARIANTS as a, CALLOUT_VARIANT_LABELS as o, isCalloutVariant as s } from "../Scribe/extension/callout.js";
|
|
6
6
|
import { calloutBubbleMenuPluginKey as c, getSelectionCalloutContext as l } from "./calloutBubbleMenuPlugin.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/react";
|
|
2
|
+
import type { ExternalLinkDisplay } from "../Scribe/extension/external-link-preview/types";
|
|
3
|
+
export type { ExternalLinkDisplay } from "../Scribe/extension/external-link-preview/types";
|
|
4
|
+
export interface ExternalLinkDisplayOptionsProps {
|
|
5
|
+
currentDisplay: ExternalLinkDisplay;
|
|
6
|
+
editor: Editor;
|
|
7
|
+
executeDisplayChange?: (display: ExternalLinkDisplay) => boolean;
|
|
8
|
+
onDisplayChange?: (display: ExternalLinkDisplay) => void;
|
|
9
|
+
targetPosition?: number;
|
|
10
|
+
}
|
|
11
|
+
declare const ExternalLinkDisplayOptions: ({ currentDisplay, editor, executeDisplayChange, onDisplayChange, targetPosition, }: ExternalLinkDisplayOptionsProps) => import("react").JSX.Element | null;
|
|
12
|
+
export default ExternalLinkDisplayOptions;
|
|
13
|
+
//# sourceMappingURL=ExternalLinkDisplayOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalLinkDisplayOptions.d.ts","sourceRoot":"","sources":["../../../lib/components/Menu/ExternalLinkDisplayOptions.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAC;AAE3F,YAAY,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAC;AAE3F,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,mBAAmB,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC;IACjE,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAuCD,QAAA,MAAM,0BAA0B,uFAM7B,+BAA+B,uCA4FjC,CAAC;eAEa,0BAA0B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Button as e, Flex as t, Text as n } from "@radix-ui/themes";
|
|
2
|
+
import { useCallback as r, useId as i } from "react";
|
|
3
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
4
|
+
//#region lib/components/Menu/ExternalLinkDisplayOptions.tsx
|
|
5
|
+
var s = [
|
|
6
|
+
{
|
|
7
|
+
description: "Show a regular text link.",
|
|
8
|
+
display: "plain",
|
|
9
|
+
label: "Plain link"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
description: "Show the page title and site icon.",
|
|
13
|
+
display: "compact",
|
|
14
|
+
label: "Compact"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
description: "Show an image, title, and description.",
|
|
18
|
+
display: "card",
|
|
19
|
+
label: "Preview card"
|
|
20
|
+
}
|
|
21
|
+
], c = (e) => e.commands, l = (e) => e.can(), u = ({ currentDisplay: u, editor: d, executeDisplayChange: f, onDisplayChange: p, targetPosition: m }) => {
|
|
22
|
+
let h = i(), g = c(d), _ = l(d), v = typeof g.setExternalLinkDisplay == "function", y = (e) => typeof m == "number" ? !!_.setExternalLinkDisplay?.(e, m) : !!_.setExternalLinkDisplay?.(e), b = {
|
|
23
|
+
plain: u === "plain" || y("plain"),
|
|
24
|
+
compact: u === "compact" || y("compact"),
|
|
25
|
+
card: u === "card" || y("card")
|
|
26
|
+
}, x = v && b.compact, S = v && b.card, C = u !== "plain" || x || S, w = r((e) => {
|
|
27
|
+
e !== u && (f?.(e) ?? (typeof m == "number" ? d.chain().focus().setExternalLinkDisplay(e, m).run() : c(d).setExternalLinkDisplay?.(e))) && p?.(e);
|
|
28
|
+
}, [
|
|
29
|
+
u,
|
|
30
|
+
d,
|
|
31
|
+
f,
|
|
32
|
+
p,
|
|
33
|
+
m
|
|
34
|
+
]);
|
|
35
|
+
return !v || !C ? null : /* @__PURE__ */ o(t, {
|
|
36
|
+
direction: "column",
|
|
37
|
+
gap: "2",
|
|
38
|
+
children: [/* @__PURE__ */ a(n, {
|
|
39
|
+
as: "p",
|
|
40
|
+
size: "2",
|
|
41
|
+
weight: "medium",
|
|
42
|
+
children: "Display as"
|
|
43
|
+
}), /* @__PURE__ */ a(t, {
|
|
44
|
+
role: "group",
|
|
45
|
+
"aria-label": "Display as",
|
|
46
|
+
direction: "column",
|
|
47
|
+
gap: "1",
|
|
48
|
+
children: s.map((r) => {
|
|
49
|
+
let i = u === r.display, s = b[r.display], c = `${h}-${r.display}-description`, l = r.display === "card" && !s ? "Preview card needs its own line." : r.description;
|
|
50
|
+
return /* @__PURE__ */ a(e, {
|
|
51
|
+
type: "button",
|
|
52
|
+
"aria-describedby": c,
|
|
53
|
+
"aria-label": r.label,
|
|
54
|
+
"aria-pressed": i,
|
|
55
|
+
color: "gray",
|
|
56
|
+
disabled: !s,
|
|
57
|
+
variant: i ? "soft" : "ghost",
|
|
58
|
+
onClick: () => w(r.display),
|
|
59
|
+
style: {
|
|
60
|
+
height: "auto",
|
|
61
|
+
justifyContent: "flex-start",
|
|
62
|
+
paddingBottom: 8,
|
|
63
|
+
paddingTop: 8,
|
|
64
|
+
textAlign: "left",
|
|
65
|
+
width: "100%"
|
|
66
|
+
},
|
|
67
|
+
children: /* @__PURE__ */ o(t, {
|
|
68
|
+
direction: "column",
|
|
69
|
+
gap: "1",
|
|
70
|
+
align: "start",
|
|
71
|
+
children: [/* @__PURE__ */ a(n, {
|
|
72
|
+
as: "span",
|
|
73
|
+
size: "2",
|
|
74
|
+
weight: "medium",
|
|
75
|
+
children: r.label
|
|
76
|
+
}), /* @__PURE__ */ a(n, {
|
|
77
|
+
id: c,
|
|
78
|
+
as: "span",
|
|
79
|
+
size: "1",
|
|
80
|
+
color: "gray",
|
|
81
|
+
children: l
|
|
82
|
+
})]
|
|
83
|
+
})
|
|
84
|
+
}, r.display);
|
|
85
|
+
})
|
|
86
|
+
})]
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
//#endregion
|
|
90
|
+
export { u as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LinkBubbleMenu.d.ts","sourceRoot":"","sources":["../../../lib/components/Menu/LinkBubbleMenu.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAkB,MAAM,eAAe,CAAC;AAKvD,OAAO,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"LinkBubbleMenu.d.ts","sourceRoot":"","sources":["../../../lib/components/Menu/LinkBubbleMenu.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAkB,MAAM,eAAe,CAAC;AAKvD,OAAO,EAAE,EAAE,EAA2E,MAAM,OAAO,CAAC;AAepG,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;CAChB;AAiCD,QAAA,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAia3C,CAAC;eAEa,cAAc"}
|
|
@@ -1,92 +1,192 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as e } from "../../dist-DDjaA1Pn.js";
|
|
2
2
|
import { getPopupMountTarget as t } from "../Scribe/extension/getPopupMountTarget.js";
|
|
3
3
|
import n from "./LinkEditor.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import { getExternalLinkPreviewHostname as r } from "../Scribe/extension/external-link-preview/attributes.js";
|
|
5
|
+
import { consumeLinkBubbleMenuFocusTarget as i, getPlainLinkContextAtPosition as a, getSelectionLinkContext as o, hideLinkBubbleMenu as s, linkBubbleMenuPluginKey as c, showLinkBubbleMenu as l } from "./linkBubbleMenuPlugin.js";
|
|
6
|
+
import { t as u } from "../../menus-U2HdvQnu.js";
|
|
7
|
+
import { getSelectionContextualMenuOwner as d } from "./contextualMenuOwner.js";
|
|
8
|
+
import { getExternalLinkPreviewResolutionStatus as f } from "../Scribe/extension/external-link-preview/resolver.js";
|
|
9
|
+
import { Box as p } from "@radix-ui/themes";
|
|
10
|
+
import { useCallback as m, useEffect as h, useMemo as g, useRef as _, useState as v } from "react";
|
|
11
|
+
import { jsx as y } from "react/jsx-runtime";
|
|
9
12
|
//#region lib/components/Menu/LinkBubbleMenu.tsx
|
|
10
|
-
var
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
+
var b = /auto|overlay|scroll/, x = (e) => {
|
|
14
|
+
let t = e.ownerDocument.defaultView;
|
|
15
|
+
if (!t) return [];
|
|
16
|
+
let n = [], r = e.parentElement;
|
|
17
|
+
for (; r && r !== e.ownerDocument.body && r !== e.ownerDocument.documentElement;) {
|
|
18
|
+
let e = t.getComputedStyle(r);
|
|
19
|
+
b.test(`${e.overflow} ${e.overflowX} ${e.overflowY}`) && n.push(r), r = r.parentElement;
|
|
20
|
+
}
|
|
21
|
+
return n;
|
|
22
|
+
}, S = ({ editor: b }) => {
|
|
23
|
+
let [S, C] = v(""), [w, T] = v(0), [E, D] = v(null), O = _(null), k = _(null), A = _(null), j = e({
|
|
24
|
+
editor: b,
|
|
13
25
|
selector: ({ editor: e }) => {
|
|
14
|
-
let
|
|
15
|
-
return {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
let t = o(e.state);
|
|
27
|
+
return !t || t.kind === "plain" ? {
|
|
28
|
+
canRefresh: !1,
|
|
29
|
+
context: t,
|
|
30
|
+
status: "idle",
|
|
31
|
+
statusLabel: ""
|
|
32
|
+
} : {
|
|
33
|
+
canRefresh: e.can().refreshExternalLinkPreview(t.position),
|
|
34
|
+
context: t,
|
|
35
|
+
status: f(e.state, t.position),
|
|
36
|
+
statusLabel: t.attributes.siteName || r(t.attributes.href)
|
|
19
37
|
};
|
|
20
38
|
}
|
|
21
39
|
});
|
|
22
|
-
|
|
23
|
-
|
|
40
|
+
h(() => {
|
|
41
|
+
C(j.context?.href ?? "");
|
|
24
42
|
}, [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
]),
|
|
29
|
-
|
|
30
|
-
}, []),
|
|
31
|
-
if (
|
|
32
|
-
let e =
|
|
33
|
-
|
|
43
|
+
j.context?.from,
|
|
44
|
+
j.context?.href,
|
|
45
|
+
j.context?.to
|
|
46
|
+
]), h(() => () => {
|
|
47
|
+
A.current !== null && window.cancelAnimationFrame(A.current);
|
|
48
|
+
}, []), h(() => {
|
|
49
|
+
if (b.isDestroyed) return;
|
|
50
|
+
let e = b.view.dom, t = null, n = (e) => !e || (b.commands.setTextSelection({
|
|
51
|
+
from: e.from,
|
|
52
|
+
to: e.to
|
|
53
|
+
}), d(b.state) !== "link") ? !1 : (l(b, "url"), !0), r = (n) => {
|
|
54
|
+
if (n.button !== 0 || !b.isEditable) return;
|
|
55
|
+
let r = n.target?.closest?.("a");
|
|
56
|
+
!r || !e.contains(r) || r.closest("[data-type=\"external-link-preview\"]") || (t = {
|
|
57
|
+
x: n.clientX,
|
|
58
|
+
y: n.clientY
|
|
59
|
+
});
|
|
60
|
+
}, i = (r) => {
|
|
61
|
+
if (r.button !== 0 || !b.isEditable) return;
|
|
34
62
|
let i = r.target?.closest?.("a");
|
|
35
|
-
!i || !e.contains(i) ||
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
63
|
+
if (!i || !e.contains(i) || i.closest("[data-type=\"external-link-preview\"]")) return;
|
|
64
|
+
let o = r.detail > 0 && t !== null && Math.hypot(r.clientX - t.x, r.clientY - t.y) > 4;
|
|
65
|
+
if (t = null, o) return;
|
|
66
|
+
let s;
|
|
67
|
+
try {
|
|
68
|
+
s = b.view.posAtDOM(i, 0);
|
|
69
|
+
} catch {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let c = a(b.state, s), l = c ? b.view.nodeDOM(c.from) : null;
|
|
73
|
+
!l || !i.contains(l) || n(c) && r.preventDefault();
|
|
74
|
+
};
|
|
75
|
+
return e.addEventListener("mousedown", r), e.addEventListener("click", i), () => {
|
|
76
|
+
e.removeEventListener("mousedown", r), e.removeEventListener("click", i);
|
|
77
|
+
};
|
|
78
|
+
}, [b]), h(() => {
|
|
79
|
+
let e = b.view.dom, t = (e) => {
|
|
80
|
+
if (e.key !== "F10" || !e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || !b.isEditable) return;
|
|
81
|
+
let t = o(b.state);
|
|
82
|
+
t?.kind === "plain" && (b.chain().extendMarkRange("link").run(), t = o(b.state)), !(!t || d(b.state) !== "link") && (e.preventDefault(), e.stopImmediatePropagation(), l(b, t.kind === "preview" ? "dialog" : "url"));
|
|
83
|
+
};
|
|
84
|
+
return e.addEventListener("keydown", t, !0), () => e.removeEventListener("keydown", t, !0);
|
|
85
|
+
}, [b]), h(() => {
|
|
86
|
+
let e = b.view.dom.ownerDocument, t = e.defaultView;
|
|
87
|
+
if (!t) return;
|
|
88
|
+
let n = (e) => {
|
|
89
|
+
let n = O.current;
|
|
90
|
+
!n?.isConnected || !(e instanceof t.Node) || n.contains(e) || b.view.dom.contains(e) || s(b);
|
|
91
|
+
}, r = (e) => n(e.target), i = (e) => n(e.target);
|
|
92
|
+
return e.addEventListener("pointerdown", r, !0), e.addEventListener("focusin", i), () => {
|
|
93
|
+
e.removeEventListener("pointerdown", r, !0), e.removeEventListener("focusin", i);
|
|
94
|
+
};
|
|
95
|
+
}, [b]), h(() => {
|
|
96
|
+
let e = b.view.dom.ownerDocument.defaultView;
|
|
97
|
+
if (!e) return;
|
|
98
|
+
let t = x(b.view.dom), n = null, r = () => {
|
|
99
|
+
n === null && (n = e.requestAnimationFrame(() => {
|
|
100
|
+
n = null, b.isDestroyed || b.view.dispatch(b.state.tr.setMeta(c, "updatePosition"));
|
|
39
101
|
}));
|
|
40
102
|
};
|
|
41
|
-
return e.addEventListener("
|
|
42
|
-
|
|
103
|
+
return e.addEventListener("scroll", r, { passive: !0 }), t.forEach((e) => {
|
|
104
|
+
e.addEventListener("scroll", r, { passive: !0 });
|
|
105
|
+
}), () => {
|
|
106
|
+
n !== null && e.cancelAnimationFrame(n), e.removeEventListener("scroll", r), t.forEach((e) => {
|
|
107
|
+
e.removeEventListener("scroll", r);
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
}, [b]), h(() => {
|
|
111
|
+
let e = b.view.dom.closest("[data-scribe-root]"), t = b.view.dom.ownerDocument.defaultView;
|
|
112
|
+
if (!e || !t) return;
|
|
113
|
+
let n = () => {
|
|
114
|
+
let t = e.getBoundingClientRect().width;
|
|
115
|
+
D(t > 0 ? Math.max(t - 16, 0) : null);
|
|
116
|
+
};
|
|
117
|
+
if (n(), !t.ResizeObserver) return;
|
|
118
|
+
let r = new t.ResizeObserver(n);
|
|
119
|
+
return r.observe(e), () => r.disconnect();
|
|
120
|
+
}, [b]);
|
|
121
|
+
let M = m(() => {
|
|
122
|
+
if (b.isDestroyed) return;
|
|
123
|
+
let e = b.state.selection.to;
|
|
124
|
+
s(b), b.chain().setTextSelection(e).focus().run();
|
|
125
|
+
}, [b]), N = m(() => {
|
|
126
|
+
let e = o(b.state);
|
|
127
|
+
e?.kind === "preview" && b.commands.refreshExternalLinkPreview(e.position);
|
|
128
|
+
}, [b]), P = m(() => {
|
|
129
|
+
A.current !== null && window.cancelAnimationFrame(A.current);
|
|
130
|
+
let e = o(b.state), t = i(b), n = () => {
|
|
131
|
+
t === "dialog" ? O.current?.focus() : (k.current?.focus(), k.current?.select());
|
|
43
132
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (m.isDestroyed) return;
|
|
47
|
-
let e = m.state.selection.to;
|
|
48
|
-
r(m), m.chain().setTextSelection(e).focus().run();
|
|
49
|
-
}, [m]), x = c(() => {
|
|
50
|
-
v.current !== null && window.cancelAnimationFrame(v.current), v.current = window.requestAnimationFrame(() => {
|
|
51
|
-
_.current?.focus(), _.current?.select(), v.current = null;
|
|
133
|
+
C(e?.href ?? ""), T((e) => e + 1), n(), A.current = window.requestAnimationFrame(() => {
|
|
134
|
+
n(), A.current = null;
|
|
52
135
|
});
|
|
53
|
-
}, []),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
136
|
+
}, [b]), F = m(() => {
|
|
137
|
+
A.current !== null && (window.cancelAnimationFrame(A.current), A.current = null);
|
|
138
|
+
}, []), I = m((e) => {
|
|
139
|
+
e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), M());
|
|
140
|
+
}, [M]), L = m(({ editor: e, element: t, state: n }) => {
|
|
141
|
+
let r = t.contains(t.ownerDocument.activeElement);
|
|
142
|
+
return e.isEditable && !!o(n) && d(n) === "link" && r;
|
|
143
|
+
}, []), R = m(() => t(b), [b]), z = g(() => ({
|
|
57
144
|
strategy: "fixed",
|
|
58
145
|
placement: "bottom",
|
|
59
146
|
offset: 8,
|
|
60
147
|
flip: {},
|
|
61
148
|
shift: { padding: 8 },
|
|
62
149
|
inline: !0,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
150
|
+
onHide: F,
|
|
151
|
+
onShow: P
|
|
152
|
+
}), [F, P]), B = j.context;
|
|
153
|
+
return /* @__PURE__ */ y(u, {
|
|
154
|
+
editor: b,
|
|
155
|
+
pluginKey: c,
|
|
68
156
|
updateDelay: 0,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
157
|
+
resizeDelay: 0,
|
|
158
|
+
appendTo: R,
|
|
159
|
+
shouldShow: L,
|
|
160
|
+
options: z,
|
|
161
|
+
children: /* @__PURE__ */ y(p, {
|
|
162
|
+
ref: O,
|
|
73
163
|
className: "scribe-link-popover",
|
|
74
164
|
role: "dialog",
|
|
75
165
|
"aria-label": "Edit link",
|
|
166
|
+
"aria-keyshortcuts": "Alt+F10",
|
|
167
|
+
tabIndex: -1,
|
|
168
|
+
onKeyDown: I,
|
|
76
169
|
style: {
|
|
77
|
-
maxWidth: "calc(100vw - 32px)",
|
|
170
|
+
maxWidth: E === null ? "calc(100vw - 32px)" : `min(${E}px, calc(100vw - 32px))`,
|
|
78
171
|
width: 320
|
|
79
172
|
},
|
|
80
|
-
children: /* @__PURE__ */
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
173
|
+
children: /* @__PURE__ */ y(n, {
|
|
174
|
+
canRefreshPreview: j.canRefresh,
|
|
175
|
+
currentDisplay: B?.display ?? "plain",
|
|
176
|
+
editor: b,
|
|
177
|
+
existingHref: B?.href ?? "",
|
|
178
|
+
inputRef: k,
|
|
179
|
+
onClose: M,
|
|
180
|
+
onRefreshPreview: N,
|
|
181
|
+
onValueChange: C,
|
|
182
|
+
previewStatus: j.status,
|
|
183
|
+
previewStatusLabel: j.statusLabel,
|
|
184
|
+
resetToken: w,
|
|
185
|
+
targetPosition: B?.kind === "preview" ? B.position : void 0,
|
|
186
|
+
value: S
|
|
87
187
|
})
|
|
88
188
|
})
|
|
89
189
|
});
|
|
90
190
|
};
|
|
91
191
|
//#endregion
|
|
92
|
-
export {
|
|
192
|
+
export { S as default };
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { Editor } from "@tiptap/react";
|
|
2
2
|
import { FC, RefObject } from "react";
|
|
3
|
+
import type { ExternalLinkPreviewResolutionStatus } from "../Scribe/extension/external-link-preview/types";
|
|
4
|
+
import type { ExternalLinkDisplay } from "./ExternalLinkDisplayOptions";
|
|
3
5
|
export interface LinkEditorProps {
|
|
6
|
+
canRefreshPreview?: boolean;
|
|
7
|
+
currentDisplay?: ExternalLinkDisplay;
|
|
4
8
|
editor: Editor;
|
|
5
9
|
existingHref: string;
|
|
6
10
|
inputRef?: RefObject<HTMLInputElement | null>;
|
|
7
11
|
onClose: () => void;
|
|
12
|
+
onRefreshPreview?: () => void;
|
|
8
13
|
onValueChange: (value: string) => void;
|
|
14
|
+
previewStatus?: ExternalLinkPreviewResolutionStatus;
|
|
15
|
+
previewStatusLabel?: string;
|
|
16
|
+
resetToken?: number;
|
|
9
17
|
selectTextblockEndAfterSave?: boolean;
|
|
18
|
+
targetPosition?: number;
|
|
10
19
|
value: string;
|
|
11
20
|
}
|
|
12
21
|
declare const LinkEditor: FC<LinkEditorProps>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LinkEditor.d.ts","sourceRoot":"","sources":["../../../lib/components/Menu/LinkEditor.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EACL,EAAE,EAGF,SAAS,EAKV,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"LinkEditor.d.ts","sourceRoot":"","sources":["../../../lib/components/Menu/LinkEditor.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EACL,EAAE,EAGF,SAAS,EAKV,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,iDAAiD,CAAC;AAE3G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGxE,MAAM,WAAW,eAAe;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC9C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,mCAAmC,CAAC;IACpD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,QAAA,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAkRnC,CAAC;eAEa,UAAU"}
|