@meowdown/react 0.24.1 → 0.25.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/index.d.ts +8 -1
- package/dist/index.js +311 -26
- package/dist/style.css +89 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactElement, ReactNode, Ref } from "react";
|
|
2
|
-
import { ExitBoundaryHandler, ImageClickHandler, ImageOptions, LinkClickHandler, MarkMode, PlaceholderOptions, TagClickHandler, TypedEditor, WikilinkClickHandler } from "@meowdown/core";
|
|
2
|
+
import { ExitBoundaryHandler, ImageClickHandler, ImageOptions, LinkClickHandler, LinkCopyHandler, MarkMode, PlaceholderOptions, TagClickHandler, TypedEditor, WikilinkClickHandler } from "@meowdown/core";
|
|
3
3
|
import { SelectionJSON, SelectionJSON as SelectionJSON$1 } from "@prosekit/core";
|
|
4
4
|
import { useEditor, useExtension, useKeymap } from "@prosekit/react";
|
|
5
5
|
|
|
@@ -124,6 +124,12 @@ interface EditorProps {
|
|
|
124
124
|
* in source mode.
|
|
125
125
|
*/
|
|
126
126
|
onLinkClick?: LinkClickHandler;
|
|
127
|
+
/**
|
|
128
|
+
* Called after a link is copied from the link menu, with its `href`. Useful
|
|
129
|
+
* for a toast. Pass a stable function (e.g. from `useCallback`). Ignored in
|
|
130
|
+
* source mode.
|
|
131
|
+
*/
|
|
132
|
+
onLinkCopy?: LinkCopyHandler;
|
|
127
133
|
/**
|
|
128
134
|
* Called with the tag name (without the leading `#`) on click of a rendered
|
|
129
135
|
* `#tag`. Pass a stable function (e.g. from `useCallback`). Ignored in source
|
|
@@ -209,6 +215,7 @@ declare function MeowdownEditor({
|
|
|
209
215
|
onWikilinkSearch,
|
|
210
216
|
onWikilinkClick,
|
|
211
217
|
onLinkClick,
|
|
218
|
+
onLinkCopy,
|
|
212
219
|
onTagClick,
|
|
213
220
|
onExitBoundary,
|
|
214
221
|
resolveImageUrl,
|
package/dist/index.js
CHANGED
|
@@ -7,14 +7,15 @@ import { Compartment, EditorSelection, EditorState } from "@codemirror/state";
|
|
|
7
7
|
import { EditorView, keymap } from "@codemirror/view";
|
|
8
8
|
import { clamp } from "@ocavue/utils";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import { codeBlockLanguages, defaultResolveImageUrl, defineBulletAfterHeading, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineHTMLPaste, defineImage, defineImageClickHandler, defineLinkClickHandler, defineMarkMode, defineMarkdownCopy, definePlaceholder, defineReadonly, defineTagClickHandler, defineWikilinkClickHandler, defineWikilinkTrigger, docToMarkdown, getCodeTokens, getMarkBuilders, inlineTextToMarkChunks, listenForTweetHeight, markdownToDoc, matchEmbed } from "@meowdown/core";
|
|
10
|
+
import { codeBlockLanguages, defaultResolveImageUrl, defineBulletAfterHeading, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineHTMLPaste, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkEditKeymap, defineLinkHoverHandler, defineMarkMode, defineMarkdownCopy, definePlaceholder, defineReadonly, defineTagClickHandler, defineWikilinkClickHandler, defineWikilinkTrigger, docToMarkdown, getCodeTokens, getMarkBuilders, getVirtualElementFromRange, inlineTextToMarkChunks, listenForTweetHeight, markdownToDoc, matchEmbed } from "@meowdown/core";
|
|
11
11
|
import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, union } from "@prosekit/core";
|
|
12
12
|
import { Selection, TextSelection } from "@prosekit/pm/state";
|
|
13
13
|
import { ProseKit, defineReactNodeView, useEditor, useEditor as useEditor$1, useEditorDerivedValue, useExtension, useExtension as useExtension$1, useKeymap } from "@prosekit/react";
|
|
14
14
|
import { Combobox } from "@base-ui/react/combobox";
|
|
15
|
-
import { CheckIcon, ChevronsUpDownIcon, CopyIcon, GripHorizontalIcon, GripVerticalIcon } from "lucide-react";
|
|
15
|
+
import { CheckIcon, ChevronsUpDownIcon, CopyIcon, GripHorizontalIcon, GripVerticalIcon, PencilIcon, UnlinkIcon } from "lucide-react";
|
|
16
16
|
import { BlockHandleDraggable, BlockHandlePopup, BlockHandlePositioner, BlockHandleRoot } from "@prosekit/react/block-handle";
|
|
17
17
|
import { DropIndicator } from "@prosekit/react/drop-indicator";
|
|
18
|
+
import { Popover } from "@base-ui/react/popover";
|
|
18
19
|
import { AutocompleteEmpty, AutocompleteItem, AutocompletePopup, AutocompletePositioner, AutocompleteRoot } from "@prosekit/react/autocomplete";
|
|
19
20
|
import { MenuItem, MenuPopup, MenuPositioner } from "@prosekit/react/menu";
|
|
20
21
|
import { TableHandleColumnMenuRoot, TableHandleColumnMenuTrigger, TableHandleColumnPopup, TableHandleColumnPositioner, TableHandleDragPreview, TableHandleDropIndicator, TableHandleRoot, TableHandleRowMenuRoot, TableHandleRowMenuTrigger, TableHandleRowPopup, TableHandleRowPositioner } from "@prosekit/react/table-handle";
|
|
@@ -155,8 +156,41 @@ var code_block_view_module_default = {
|
|
|
155
156
|
};
|
|
156
157
|
|
|
157
158
|
//#endregion
|
|
158
|
-
//#region src/components/
|
|
159
|
+
//#region src/components/copy-button.tsx
|
|
159
160
|
const COPIED_RESET_MS = 1500;
|
|
161
|
+
/**
|
|
162
|
+
* A copy-to-clipboard button with "copied" feedback. Shared by the code block
|
|
163
|
+
* toolbar and the link popover.
|
|
164
|
+
*/
|
|
165
|
+
function CopyButton({ getText, label, onCopy, className, ...rest }) {
|
|
166
|
+
const [copied, setCopied] = useState(false);
|
|
167
|
+
const resetTimerRef = useRef(void 0);
|
|
168
|
+
const copy = async () => {
|
|
169
|
+
try {
|
|
170
|
+
await navigator.clipboard.writeText(getText());
|
|
171
|
+
setCopied(true);
|
|
172
|
+
clearTimeout(resetTimerRef.current);
|
|
173
|
+
resetTimerRef.current = setTimeout(() => setCopied(false), COPIED_RESET_MS);
|
|
174
|
+
onCopy?.();
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.warn("[meowdown] Failed to copy:", error);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
return /* @__PURE__ */ jsx("button", {
|
|
180
|
+
type: "button",
|
|
181
|
+
className,
|
|
182
|
+
"data-copied": copied ? "" : void 0,
|
|
183
|
+
"aria-label": copied ? "Copied" : label,
|
|
184
|
+
title: copied ? "Copied" : label,
|
|
185
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
186
|
+
onClick: copy,
|
|
187
|
+
...rest,
|
|
188
|
+
children: copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {})
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/components/code-block-view.tsx
|
|
160
194
|
function CodeBlockView(props) {
|
|
161
195
|
const language = props.node.attrs.language || "";
|
|
162
196
|
const selected = useMemo(() => {
|
|
@@ -179,18 +213,6 @@ function CodeBlockView(props) {
|
|
|
179
213
|
const setLanguage = (item) => {
|
|
180
214
|
props.setAttrs({ language: item?.value ?? "" });
|
|
181
215
|
};
|
|
182
|
-
const [copied, setCopied] = useState(false);
|
|
183
|
-
const resetTimerRef = useRef(void 0);
|
|
184
|
-
const copy = async () => {
|
|
185
|
-
try {
|
|
186
|
-
await navigator.clipboard.writeText(props.node.textContent);
|
|
187
|
-
setCopied(true);
|
|
188
|
-
clearTimeout(resetTimerRef.current);
|
|
189
|
-
resetTimerRef.current = setTimeout(() => setCopied(false), COPIED_RESET_MS);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
console.warn("[meowdown] Failed to copy code block:", error);
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
216
|
return /* @__PURE__ */ jsxs("div", {
|
|
195
217
|
className: code_block_view_module_default.Root,
|
|
196
218
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -252,16 +274,11 @@ function CodeBlockView(props) {
|
|
|
252
274
|
]
|
|
253
275
|
})
|
|
254
276
|
}) })]
|
|
255
|
-
}), /* @__PURE__ */ jsx(
|
|
256
|
-
|
|
277
|
+
}), /* @__PURE__ */ jsx(CopyButton, {
|
|
278
|
+
getText: () => props.node.textContent,
|
|
279
|
+
label: "Copy code",
|
|
257
280
|
className: code_block_view_module_default.CopyButton,
|
|
258
|
-
"data-testid": "code-block-copy"
|
|
259
|
-
"data-copied": copied ? "" : void 0,
|
|
260
|
-
"aria-label": copied ? "Copied" : "Copy code",
|
|
261
|
-
title: copied ? "Copied" : "Copy code",
|
|
262
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
263
|
-
onClick: copy,
|
|
264
|
-
children: copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {})
|
|
281
|
+
"data-testid": "code-block-copy"
|
|
265
282
|
})]
|
|
266
283
|
}), /* @__PURE__ */ jsx("pre", {
|
|
267
284
|
ref: props.contentRef,
|
|
@@ -376,6 +393,269 @@ function EditorExtensions({ markMode, onDocChange, onWikilinkClick, onLinkClick,
|
|
|
376
393
|
return null;
|
|
377
394
|
}
|
|
378
395
|
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region src/hooks/use-delayed-flag.ts
|
|
398
|
+
/** Delay before the flag opens, in ms. */
|
|
399
|
+
const OPEN_DELAY = 400;
|
|
400
|
+
/** Grace before the flag closes, in ms. The window lets a pointer travel from
|
|
401
|
+
* the hovered link onto the popover it anchors. */
|
|
402
|
+
const CLOSE_DELAY = 300;
|
|
403
|
+
/**
|
|
404
|
+
* Mirrors `value` into a boolean that flips true `openDelay`ms after `value`
|
|
405
|
+
* becomes true and false `closeDelay`ms after it becomes false, cancelling any
|
|
406
|
+
* pending flip on each change.
|
|
407
|
+
*/
|
|
408
|
+
function useDelayedFlag(value, openDelay = OPEN_DELAY, closeDelay = CLOSE_DELAY) {
|
|
409
|
+
const [flag, setFlag] = useState(false);
|
|
410
|
+
const timerRef = useRef(void 0);
|
|
411
|
+
useEffect(() => {
|
|
412
|
+
clearTimeout(timerRef.current);
|
|
413
|
+
timerRef.current = setTimeout(() => setFlag(value), value ? openDelay : closeDelay);
|
|
414
|
+
return () => clearTimeout(timerRef.current);
|
|
415
|
+
}, [
|
|
416
|
+
value,
|
|
417
|
+
openDelay,
|
|
418
|
+
closeDelay
|
|
419
|
+
]);
|
|
420
|
+
return flag;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/components/link-menu.module.css
|
|
425
|
+
var link_menu_module_default = {
|
|
426
|
+
"Button": "meow_Button_IjcqKG",
|
|
427
|
+
"Form": "meow_Form_IjcqKG",
|
|
428
|
+
"Input": "meow_Input_IjcqKG",
|
|
429
|
+
"Popup": "meow_Popup_IjcqKG",
|
|
430
|
+
"Positioner": "meow_Positioner_IjcqKG",
|
|
431
|
+
"Row": "meow_Row_IjcqKG",
|
|
432
|
+
"SrOnly": "meow_SrOnly_IjcqKG",
|
|
433
|
+
"Url": "meow_Url_IjcqKG"
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/components/link-menu.tsx
|
|
438
|
+
/** Select the link unit so the text-backed commands target it, and keep the
|
|
439
|
+
* editor focused so its virtual selection stays visible behind the popover. */
|
|
440
|
+
function selectLinkUnit(editor, link) {
|
|
441
|
+
editor.commands.selectText(link.unit.from, link.unit.to);
|
|
442
|
+
editor.focus();
|
|
443
|
+
}
|
|
444
|
+
/** A Base UI popover anchored at `anchor`. Base UI dismisses it on an outside
|
|
445
|
+
* press or Escape, both routed through `onClose`. */
|
|
446
|
+
function LinkPopover({ anchor, onClose, onPopupHover, children }) {
|
|
447
|
+
return /* @__PURE__ */ jsx(Popover.Root, {
|
|
448
|
+
open: true,
|
|
449
|
+
onOpenChange: (open) => {
|
|
450
|
+
if (!open) onClose();
|
|
451
|
+
},
|
|
452
|
+
children: /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
|
|
453
|
+
anchor,
|
|
454
|
+
side: "bottom",
|
|
455
|
+
sideOffset: 8,
|
|
456
|
+
className: link_menu_module_default.Positioner,
|
|
457
|
+
children: /* @__PURE__ */ jsx(Popover.Popup, {
|
|
458
|
+
className: link_menu_module_default.Popup,
|
|
459
|
+
"data-testid": "link-popover",
|
|
460
|
+
initialFocus: false,
|
|
461
|
+
finalFocus: false,
|
|
462
|
+
onMouseEnter: () => onPopupHover?.(true),
|
|
463
|
+
onMouseLeave: () => onPopupHover?.(false),
|
|
464
|
+
children
|
|
465
|
+
})
|
|
466
|
+
}) })
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
/** The hover preview: the url plus copy, edit, and remove actions. */
|
|
470
|
+
function LinkInfoContent({ href, onLinkClick, onLinkCopy, onEdit, onRemove }) {
|
|
471
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
472
|
+
className: link_menu_module_default.Row,
|
|
473
|
+
"data-testid": "link-popover-read",
|
|
474
|
+
children: [
|
|
475
|
+
/* @__PURE__ */ jsx("a", {
|
|
476
|
+
className: link_menu_module_default.Url,
|
|
477
|
+
href,
|
|
478
|
+
title: href,
|
|
479
|
+
target: "_blank",
|
|
480
|
+
rel: "noopener noreferrer",
|
|
481
|
+
onClick: (event) => {
|
|
482
|
+
if (!onLinkClick) return;
|
|
483
|
+
event.preventDefault();
|
|
484
|
+
onLinkClick({
|
|
485
|
+
href,
|
|
486
|
+
event: event.nativeEvent
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
children: href
|
|
490
|
+
}),
|
|
491
|
+
/* @__PURE__ */ jsx(CopyButton, {
|
|
492
|
+
getText: () => href,
|
|
493
|
+
label: "Copy link",
|
|
494
|
+
className: link_menu_module_default.Button,
|
|
495
|
+
onCopy: () => onLinkCopy?.({ href })
|
|
496
|
+
}),
|
|
497
|
+
/* @__PURE__ */ jsx("button", {
|
|
498
|
+
type: "button",
|
|
499
|
+
className: link_menu_module_default.Button,
|
|
500
|
+
title: "Edit link",
|
|
501
|
+
"aria-label": "Edit link",
|
|
502
|
+
onClick: onEdit,
|
|
503
|
+
children: /* @__PURE__ */ jsx(PencilIcon, {})
|
|
504
|
+
}),
|
|
505
|
+
/* @__PURE__ */ jsx("button", {
|
|
506
|
+
type: "button",
|
|
507
|
+
className: link_menu_module_default.Button,
|
|
508
|
+
title: "Remove link",
|
|
509
|
+
"aria-label": "Remove link",
|
|
510
|
+
onClick: onRemove,
|
|
511
|
+
children: /* @__PURE__ */ jsx(UnlinkIcon, {})
|
|
512
|
+
})
|
|
513
|
+
]
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
/** The url and title form, opened by `Mod-k` or the preview's edit button. */
|
|
517
|
+
function LinkEditContent({ link, onSubmit }) {
|
|
518
|
+
const hrefInputRef = useRef(null);
|
|
519
|
+
const titleInputRef = useRef(null);
|
|
520
|
+
const href = link ? link.href : "";
|
|
521
|
+
const title = link ? link.title : "";
|
|
522
|
+
useEffect(() => {
|
|
523
|
+
hrefInputRef.current?.focus();
|
|
524
|
+
}, []);
|
|
525
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
526
|
+
className: link_menu_module_default.Form,
|
|
527
|
+
"data-testid": "link-popover-edit",
|
|
528
|
+
onSubmit: (event) => {
|
|
529
|
+
event.preventDefault();
|
|
530
|
+
onSubmit(hrefInputRef.current?.value || "", titleInputRef.current?.value || "");
|
|
531
|
+
},
|
|
532
|
+
children: [
|
|
533
|
+
/* @__PURE__ */ jsx("input", {
|
|
534
|
+
ref: hrefInputRef,
|
|
535
|
+
className: link_menu_module_default.Input,
|
|
536
|
+
defaultValue: href,
|
|
537
|
+
placeholder: "Paste link...",
|
|
538
|
+
"data-testid": "link-popover-input"
|
|
539
|
+
}),
|
|
540
|
+
/* @__PURE__ */ jsx("input", {
|
|
541
|
+
ref: titleInputRef,
|
|
542
|
+
className: link_menu_module_default.Input,
|
|
543
|
+
defaultValue: title,
|
|
544
|
+
placeholder: "Title (optional)"
|
|
545
|
+
}),
|
|
546
|
+
/* @__PURE__ */ jsx("button", {
|
|
547
|
+
type: "submit",
|
|
548
|
+
className: link_menu_module_default.SrOnly,
|
|
549
|
+
"data-testid": "link-popover-submit",
|
|
550
|
+
children: "Save"
|
|
551
|
+
})
|
|
552
|
+
]
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Owns both link triggers and shows one popover at a time:
|
|
557
|
+
*
|
|
558
|
+
* - hovering a link opens a read-only preview that follows the pointer;
|
|
559
|
+
* - `Mod-k` (or the preview's edit button) opens an edit form that stays until
|
|
560
|
+
* it is submitted, dismissed with Escape, or pressed outside.
|
|
561
|
+
*/
|
|
562
|
+
function LinkMenu({ onLinkClick, onLinkCopy }) {
|
|
563
|
+
const editor = useEditor$1();
|
|
564
|
+
const [hover, setHover] = useState();
|
|
565
|
+
const [onLink, setOnLink] = useState(false);
|
|
566
|
+
const [overPopup, setOverPopup] = useState(false);
|
|
567
|
+
const [edit, setEdit] = useState();
|
|
568
|
+
const hoverOpen = useDelayedFlag(onLink || overPopup);
|
|
569
|
+
useExtension$1(useMemo(() => {
|
|
570
|
+
return defineLinkHoverHandler((hit) => {
|
|
571
|
+
setOnLink(!!hit);
|
|
572
|
+
if (hit) setHover(hit.payload);
|
|
573
|
+
});
|
|
574
|
+
}, []));
|
|
575
|
+
useExtension$1(useMemo(() => {
|
|
576
|
+
return defineLinkEditKeymap((options) => {
|
|
577
|
+
setEdit(options);
|
|
578
|
+
});
|
|
579
|
+
}, []));
|
|
580
|
+
const closeHover = useCallback(() => {
|
|
581
|
+
setOnLink(false);
|
|
582
|
+
setOverPopup(false);
|
|
583
|
+
setHover(void 0);
|
|
584
|
+
}, []);
|
|
585
|
+
const closeEdit = useCallback(() => {
|
|
586
|
+
setEdit(void 0);
|
|
587
|
+
closeHover();
|
|
588
|
+
editor.focus();
|
|
589
|
+
}, [editor, closeHover]);
|
|
590
|
+
let rangeFrom;
|
|
591
|
+
let rangeTo;
|
|
592
|
+
if (edit) {
|
|
593
|
+
rangeFrom = edit.from;
|
|
594
|
+
rangeTo = edit.to;
|
|
595
|
+
} else if (hover) {
|
|
596
|
+
rangeFrom = hover.unit.from;
|
|
597
|
+
rangeTo = hover.unit.to;
|
|
598
|
+
}
|
|
599
|
+
const anchor = useMemo(() => {
|
|
600
|
+
if (rangeFrom == null || rangeTo == null) return;
|
|
601
|
+
return getVirtualElementFromRange(editor.view, {
|
|
602
|
+
from: rangeFrom,
|
|
603
|
+
to: rangeTo
|
|
604
|
+
});
|
|
605
|
+
}, [
|
|
606
|
+
rangeFrom,
|
|
607
|
+
rangeTo,
|
|
608
|
+
editor
|
|
609
|
+
]);
|
|
610
|
+
if (edit) return /* @__PURE__ */ jsx(LinkPopover, {
|
|
611
|
+
anchor,
|
|
612
|
+
onClose: closeEdit,
|
|
613
|
+
children: /* @__PURE__ */ jsx(LinkEditContent, {
|
|
614
|
+
link: edit.link,
|
|
615
|
+
onSubmit: (href, title) => {
|
|
616
|
+
if (edit.link) if (href.trim()) editor.commands.updateLink({
|
|
617
|
+
href,
|
|
618
|
+
title
|
|
619
|
+
});
|
|
620
|
+
else editor.commands.removeLink();
|
|
621
|
+
else if (href.trim()) editor.commands.insertLink({
|
|
622
|
+
href,
|
|
623
|
+
title
|
|
624
|
+
});
|
|
625
|
+
closeEdit();
|
|
626
|
+
}
|
|
627
|
+
})
|
|
628
|
+
});
|
|
629
|
+
if (hoverOpen && hover) {
|
|
630
|
+
const link = hover;
|
|
631
|
+
return /* @__PURE__ */ jsx(LinkPopover, {
|
|
632
|
+
anchor,
|
|
633
|
+
onClose: closeHover,
|
|
634
|
+
onPopupHover: setOverPopup,
|
|
635
|
+
children: /* @__PURE__ */ jsx(LinkInfoContent, {
|
|
636
|
+
href: link.href,
|
|
637
|
+
onLinkClick,
|
|
638
|
+
onLinkCopy,
|
|
639
|
+
onEdit: () => {
|
|
640
|
+
selectLinkUnit(editor, link);
|
|
641
|
+
setEdit({
|
|
642
|
+
from: link.unit.from,
|
|
643
|
+
to: link.unit.to,
|
|
644
|
+
link
|
|
645
|
+
});
|
|
646
|
+
closeHover();
|
|
647
|
+
},
|
|
648
|
+
onRemove: () => {
|
|
649
|
+
selectLinkUnit(editor, link);
|
|
650
|
+
editor.commands.removeLink();
|
|
651
|
+
closeHover();
|
|
652
|
+
}
|
|
653
|
+
})
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
}
|
|
658
|
+
|
|
379
659
|
//#endregion
|
|
380
660
|
//#region src/components/autocomplete-menu.module.css
|
|
381
661
|
var autocomplete_menu_module_default = {
|
|
@@ -780,7 +1060,7 @@ function resolveSelection(doc, selection) {
|
|
|
780
1060
|
return TextSelection.between(doc.resolve(anchor), doc.resolve(head));
|
|
781
1061
|
}
|
|
782
1062
|
}
|
|
783
|
-
function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, onTagClick, onExitBoundary, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste, bulletAfterHeading, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
|
|
1063
|
+
function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, onLinkCopy, onTagClick, onExitBoundary, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste, bulletAfterHeading, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
|
|
784
1064
|
const [editor] = useState(() => {
|
|
785
1065
|
const editor = createEditor({ extension: union(defineEditorExtension(), defineCodeBlockView()) });
|
|
786
1066
|
if (initialMarkdown) editor.setContent(markdownToDoc(initialMarkdown, {
|
|
@@ -878,6 +1158,10 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
878
1158
|
!readOnly && /* @__PURE__ */ jsx(TableHandle, {}),
|
|
879
1159
|
blockHandle && !readOnly && /* @__PURE__ */ jsx(DropIndicator$1, {}),
|
|
880
1160
|
/* @__PURE__ */ jsx(SlashMenu, {}),
|
|
1161
|
+
!readOnly && /* @__PURE__ */ jsx(LinkMenu, {
|
|
1162
|
+
onLinkClick,
|
|
1163
|
+
onLinkCopy
|
|
1164
|
+
}),
|
|
881
1165
|
onTagSearch && /* @__PURE__ */ jsx(TagMenu, { onTagSearch }),
|
|
882
1166
|
onWikilinkSearch && /* @__PURE__ */ jsx(WikilinkMenu, { onWikilinkSearch }),
|
|
883
1167
|
children
|
|
@@ -887,7 +1171,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
|
|
|
887
1171
|
|
|
888
1172
|
//#endregion
|
|
889
1173
|
//#region src/components/editor.tsx
|
|
890
|
-
function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, onTagClick, onExitBoundary, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste = true, bulletAfterHeading = false, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
|
|
1174
|
+
function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, onLinkCopy, onTagClick, onExitBoundary, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste = true, bulletAfterHeading = false, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
|
|
891
1175
|
const childRef = useRef(null);
|
|
892
1176
|
useImperativeHandle(handleRef, () => {
|
|
893
1177
|
function getMarkdown() {
|
|
@@ -953,6 +1237,7 @@ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSea
|
|
|
953
1237
|
onWikilinkSearch,
|
|
954
1238
|
onWikilinkClick,
|
|
955
1239
|
onLinkClick,
|
|
1240
|
+
onLinkCopy,
|
|
956
1241
|
onTagClick,
|
|
957
1242
|
onExitBoundary,
|
|
958
1243
|
resolveImageUrl,
|
package/dist/style.css
CHANGED
|
@@ -255,6 +255,95 @@
|
|
|
255
255
|
background: var(--meowdown-accent);
|
|
256
256
|
transition: all .15s;
|
|
257
257
|
}
|
|
258
|
+
.meow_Positioner_IjcqKG {
|
|
259
|
+
z-index: 50;
|
|
260
|
+
width: min(20rem, 100vw - 1rem);
|
|
261
|
+
display: block;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.meow_Popup_IjcqKG {
|
|
265
|
+
box-sizing: border-box;
|
|
266
|
+
border: 1px solid var(--meowdown-border);
|
|
267
|
+
background: var(--meowdown-link-popover-bg, light-dark(#fff, #18181b));
|
|
268
|
+
border-radius: .75rem;
|
|
269
|
+
flex-direction: column;
|
|
270
|
+
width: 100%;
|
|
271
|
+
padding: .25rem;
|
|
272
|
+
font-size: .875rem;
|
|
273
|
+
display: flex;
|
|
274
|
+
box-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.meow_Row_IjcqKG {
|
|
278
|
+
align-items: center;
|
|
279
|
+
gap: .125rem;
|
|
280
|
+
display: flex;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.meow_Url_IjcqKG {
|
|
284
|
+
white-space: nowrap;
|
|
285
|
+
text-overflow: ellipsis;
|
|
286
|
+
min-width: 0;
|
|
287
|
+
color: var(--meowdown-accent);
|
|
288
|
+
cursor: pointer;
|
|
289
|
+
flex: 1;
|
|
290
|
+
padding: .25rem .5rem;
|
|
291
|
+
overflow: hidden;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.meow_Button_IjcqKG {
|
|
295
|
+
color: var(--meowdown-text);
|
|
296
|
+
cursor: pointer;
|
|
297
|
+
border-radius: .5rem;
|
|
298
|
+
flex: none;
|
|
299
|
+
justify-content: center;
|
|
300
|
+
align-items: center;
|
|
301
|
+
padding: .375rem;
|
|
302
|
+
display: inline-flex;
|
|
303
|
+
|
|
304
|
+
&:hover {
|
|
305
|
+
background: var(--meowdown-link-popover-hover-bg, light-dark(#f4f4f5, #27272a));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
& svg {
|
|
309
|
+
width: 1rem;
|
|
310
|
+
height: 1rem;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.meow_Form_IjcqKG {
|
|
315
|
+
flex-direction: column;
|
|
316
|
+
gap: .25rem;
|
|
317
|
+
padding: .25rem;
|
|
318
|
+
display: flex;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.meow_SrOnly_IjcqKG {
|
|
322
|
+
clip: rect(0, 0, 0, 0);
|
|
323
|
+
border: 0;
|
|
324
|
+
width: 1px;
|
|
325
|
+
height: 1px;
|
|
326
|
+
margin: -1px;
|
|
327
|
+
padding: 0;
|
|
328
|
+
position: absolute;
|
|
329
|
+
overflow: hidden;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.meow_Input_IjcqKG {
|
|
333
|
+
box-sizing: border-box;
|
|
334
|
+
width: 100%;
|
|
335
|
+
font: inherit;
|
|
336
|
+
color: var(--meowdown-text);
|
|
337
|
+
border: 1px solid var(--meowdown-border);
|
|
338
|
+
background: none;
|
|
339
|
+
border-radius: .5rem;
|
|
340
|
+
padding: .375rem .5rem;
|
|
341
|
+
|
|
342
|
+
&:focus {
|
|
343
|
+
outline: 2px solid var(--meowdown-accent);
|
|
344
|
+
outline-offset: -1px;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
258
347
|
.meow_Positioner_Dqll0G {
|
|
259
348
|
z-index: 50;
|
|
260
349
|
width: min(24rem, 100vw - 1rem);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meowdown/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.25.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@prosekit/react": "^0.8.0-beta.11",
|
|
31
31
|
"clsx": "^2.1.1",
|
|
32
32
|
"lucide-react": "^1.21.0",
|
|
33
|
-
"@meowdown/core": "0.
|
|
33
|
+
"@meowdown/core": "0.25.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"react": "^19.0.0",
|