@meowdown/react 0.74.0 → 0.75.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 +9 -5
- package/dist/index.js +63 -27
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComponentProps, ReactElement, ReactNode, Ref } from "react";
|
|
2
|
-
import { AcceptPendingReplacementOptions, ExitBoundaryHandler, FileClickHandler, FileInfoResolver, FileLinkResolver, FilePasteOptions, FileViewOptions, ImageClickHandler, ImageOptions, LinkClickHandler, LinkCopyHandler, LinkPreview, LinkPreviewResolver, LinkPreviewResolver as LinkPreviewResolver$1, ListMarker, MarkMode, PendingReplacement, PendingReplacementOutcome, PlaceholderOptions, SearchStatusHandler, StartPendingReplacementOptions, TagClickHandler, TypedEditor, WikiEmbedResolver, WikilinkClickHandler, WikilinkHoverHit, WikilinkResolver, XPostMediaClickHandler, XPostResolver, XPostResolver as XPostResolver$1, YouTubeVideoClickHandler, YouTubeVideoResolver, YouTubeVideoResolver as YouTubeVideoResolver$1 } from "@meowdown/core";
|
|
2
|
+
import { AcceptPendingReplacementOptions, ExitBoundaryHandler, FileClickHandler, FileInfoResolver, FileLinkResolver, FilePasteOptions, FileViewOptions, ImageClickHandler, ImageOptions, ImageUrlResolver, LinkClickHandler, LinkCopyHandler, LinkPreview, LinkPreviewResolver, LinkPreviewResolver as LinkPreviewResolver$1, ListMarker, MarkMode, PendingReplacement, PendingReplacementOutcome, PlaceholderOptions, SearchStatusHandler, StartPendingReplacementOptions, TagClickHandler, TypedEditor, WikiEmbedResolver, WikilinkClickHandler, WikilinkHoverHit, WikilinkResolver, XPostMediaClickHandler, XPostResolver, XPostResolver as XPostResolver$1, YouTubeVideoClickHandler, YouTubeVideoResolver, YouTubeVideoResolver as YouTubeVideoResolver$1 } from "@meowdown/core";
|
|
3
3
|
import { SelectionJSON, SelectionJSON as SelectionJSON$1 } from "@prosekit/core";
|
|
4
4
|
import { ReactNodeViewComponent, ReactNodeViewComponent as ReactNodeViewComponent$1, useEditor, useExtension, useKeymap } from "@prosekit/react";
|
|
5
5
|
//#region src/utils/date-format.d.ts
|
|
@@ -372,8 +372,10 @@ interface EditorProps {
|
|
|
372
372
|
onExitBoundary?: ExitBoundaryHandler;
|
|
373
373
|
/**
|
|
374
374
|
* Maps an image `src` to a displayable URL, or `undefined` to skip that image.
|
|
375
|
-
*
|
|
376
|
-
*
|
|
375
|
+
* May return a `Promise` when the answer depends on data that has not loaded
|
|
376
|
+
* yet; the image appears once it resolves, in a box of its persisted size
|
|
377
|
+
* when one exists. Defaults to showing http(s) URLs as-is. Pass a stable
|
|
378
|
+
* function (e.g. from `useCallback`).
|
|
377
379
|
*/
|
|
378
380
|
resolveImageUrl?: ImageOptions['resolveImageUrl'];
|
|
379
381
|
/**
|
|
@@ -631,9 +633,11 @@ interface MarkdownViewProps {
|
|
|
631
633
|
*/
|
|
632
634
|
expandCollapsed?: boolean;
|
|
633
635
|
/**
|
|
634
|
-
* Map an image `src` to a displayable URL, or `undefined` to skip it.
|
|
636
|
+
* Map an image `src` to a displayable URL, or `undefined` to skip it. May
|
|
637
|
+
* return a `Promise`; the image appears once it resolves, in a box of its
|
|
638
|
+
* persisted size when both dimensions are known.
|
|
635
639
|
*/
|
|
636
|
-
resolveImageUrl?:
|
|
640
|
+
resolveImageUrl?: ImageUrlResolver;
|
|
637
641
|
/**
|
|
638
642
|
* Claim a `[label](url)` link as a file pill instead of a regular link.
|
|
639
643
|
* Must be pure; return `false` for links that should render normally.
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
|
12
12
|
import { BlockHandleDraggable, BlockHandlePopup, BlockHandlePositioner, BlockHandleRoot } from "@prosekit/react/block-handle";
|
|
13
13
|
import { DropIndicator } from "@prosekit/react/drop-indicator";
|
|
14
14
|
import { Popover } from "@base-ui/react/popover";
|
|
15
|
+
import { queueExtension } from "@prosekit/web";
|
|
15
16
|
import { AutocompleteEmpty, AutocompleteItem, AutocompletePopup, AutocompletePositioner, AutocompleteRoot } from "@prosekit/react/autocomplete";
|
|
16
17
|
import { MenuItem, MenuPopup, MenuPositioner } from "@prosekit/react/menu";
|
|
17
18
|
import { TableHandleColumnMenuRoot, TableHandleColumnMenuTrigger, TableHandleColumnPopup, TableHandleColumnPositioner, TableHandleDragPreview, TableHandleDropIndicator, TableHandleRoot, TableHandleRowMenuRoot, TableHandleRowMenuTrigger, TableHandleRowPopup, TableHandleRowPositioner } from "@prosekit/react/table-handle";
|
|
@@ -781,7 +782,7 @@ function LinkMenu({ onLinkClick, onLinkCopy, resolveLinkPreview, readOnly = fals
|
|
|
781
782
|
type: "hover",
|
|
782
783
|
link: hit?.payload
|
|
783
784
|
}), { canLeave });
|
|
784
|
-
return editor
|
|
785
|
+
return queueExtension(editor, linkHoverExtension);
|
|
785
786
|
}, [editor]);
|
|
786
787
|
useEffect(() => {
|
|
787
788
|
if (readOnly) return;
|
|
@@ -789,7 +790,7 @@ function LinkMenu({ onLinkClick, onLinkCopy, resolveLinkPreview, readOnly = fals
|
|
|
789
790
|
type: "edit",
|
|
790
791
|
edit
|
|
791
792
|
}));
|
|
792
|
-
return editor
|
|
793
|
+
return queueExtension(editor, linkEditExtension);
|
|
793
794
|
}, [editor, readOnly]);
|
|
794
795
|
const handlePointerHover = useCallback((over) => {
|
|
795
796
|
isPointerOverPopupRef.current = over;
|
|
@@ -2297,6 +2298,37 @@ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onSlashM
|
|
|
2297
2298
|
});
|
|
2298
2299
|
}
|
|
2299
2300
|
|
|
2301
|
+
//#endregion
|
|
2302
|
+
//#region src/hooks/use-maybe-promise.ts
|
|
2303
|
+
/**
|
|
2304
|
+
* The settled value of `input`: `input` itself when it is not a `Promise`,
|
|
2305
|
+
* otherwise `undefined` until it resolves. A rejection stays `undefined` and is
|
|
2306
|
+
* reported with `console.warn`, since the caller has no other way to see it. A
|
|
2307
|
+
* new `input` discards the previous `Promise`'s result at once, so a stale
|
|
2308
|
+
* value never shows for a newer input. Callers memoize `input`, or a fresh
|
|
2309
|
+
* `Promise` on every render never settles.
|
|
2310
|
+
*/
|
|
2311
|
+
function useMaybePromise(input) {
|
|
2312
|
+
const [settled, setSettled] = useState(null);
|
|
2313
|
+
useEffect(() => {
|
|
2314
|
+
if (!(input instanceof Promise)) return;
|
|
2315
|
+
let active = true;
|
|
2316
|
+
input.then((value) => {
|
|
2317
|
+
if (active) setSettled({
|
|
2318
|
+
input,
|
|
2319
|
+
value
|
|
2320
|
+
});
|
|
2321
|
+
}, (error) => {
|
|
2322
|
+
if (active) console.warn("[meowdown] useMaybePromise input rejected:", error);
|
|
2323
|
+
});
|
|
2324
|
+
return () => {
|
|
2325
|
+
active = false;
|
|
2326
|
+
};
|
|
2327
|
+
}, [input]);
|
|
2328
|
+
if (!(input instanceof Promise)) return input;
|
|
2329
|
+
return settled?.input === input ? settled.value : void 0;
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2300
2332
|
//#endregion
|
|
2301
2333
|
//#region src/components/attributes-to-props.ts
|
|
2302
2334
|
const UNCONTROLLED_COMPONENT_ATTRIBUTES = ["checked", "value"];
|
|
@@ -2453,8 +2485,14 @@ function PostEmbed(props) {
|
|
|
2453
2485
|
});
|
|
2454
2486
|
}
|
|
2455
2487
|
function ImagePreview(props) {
|
|
2456
|
-
const { src, alt, width, snapshot, resolveImageUrl, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onImageClick, interactive } = props;
|
|
2488
|
+
const { src, alt, width, height, snapshot, resolveImageUrl, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onImageClick, interactive } = props;
|
|
2457
2489
|
const kind = matchEmbed(src);
|
|
2490
|
+
const resolved = useMemo(() => kind ? void 0 : (resolveImageUrl ?? defaultResolveImageUrl)(src), [
|
|
2491
|
+
kind,
|
|
2492
|
+
resolveImageUrl,
|
|
2493
|
+
src
|
|
2494
|
+
]);
|
|
2495
|
+
const url = useMaybePromise(resolved);
|
|
2458
2496
|
if (kind) {
|
|
2459
2497
|
if (!interactive) return null;
|
|
2460
2498
|
return /* @__PURE__ */ jsx(PostEmbed, {
|
|
@@ -2467,8 +2505,23 @@ function ImagePreview(props) {
|
|
|
2467
2505
|
resolveYouTubeVideo: resolveYouTubeVideo ?? defaultResolveYouTubeVideo
|
|
2468
2506
|
}, src);
|
|
2469
2507
|
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2508
|
+
if (!url) {
|
|
2509
|
+
if (resolved instanceof Promise && width != null && height != null) return /* @__PURE__ */ jsx("span", {
|
|
2510
|
+
className: "md-image-view-preview md-atom-view-preview",
|
|
2511
|
+
"data-testid": "image-preview",
|
|
2512
|
+
contentEditable: false,
|
|
2513
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
2514
|
+
className: "md-image-resizable",
|
|
2515
|
+
"data-testid": "image-resizable",
|
|
2516
|
+
"data-loading": "",
|
|
2517
|
+
style: {
|
|
2518
|
+
width: `${width}px`,
|
|
2519
|
+
height: `${height}px`
|
|
2520
|
+
}
|
|
2521
|
+
})
|
|
2522
|
+
});
|
|
2523
|
+
return null;
|
|
2524
|
+
}
|
|
2472
2525
|
return /* @__PURE__ */ jsx("span", {
|
|
2473
2526
|
className: "md-image-view-preview md-atom-view-preview",
|
|
2474
2527
|
"data-testid": "image-preview",
|
|
@@ -2491,13 +2544,14 @@ function ImagePreview(props) {
|
|
|
2491
2544
|
});
|
|
2492
2545
|
}
|
|
2493
2546
|
function ImageView(props) {
|
|
2494
|
-
const { src, alt, width, snapshot, context, children } = props;
|
|
2547
|
+
const { src, alt, width, height, snapshot, context, children } = props;
|
|
2495
2548
|
return /* @__PURE__ */ jsxs("span", {
|
|
2496
2549
|
className: "md-image-view md-atom-view",
|
|
2497
2550
|
children: [/* @__PURE__ */ jsx(ImagePreview, {
|
|
2498
2551
|
src,
|
|
2499
2552
|
alt,
|
|
2500
2553
|
width,
|
|
2554
|
+
height,
|
|
2501
2555
|
snapshot,
|
|
2502
2556
|
resolveImageUrl: context.resolveImageUrl,
|
|
2503
2557
|
resolveXPost: context.resolveXPost,
|
|
@@ -2599,27 +2653,8 @@ function renderTokens(code, tokens) {
|
|
|
2599
2653
|
return out;
|
|
2600
2654
|
}
|
|
2601
2655
|
function CodeBlock({ code, language }) {
|
|
2602
|
-
const
|
|
2603
|
-
|
|
2604
|
-
return Array.isArray(result) ? result : null;
|
|
2605
|
-
}, [code, language]);
|
|
2606
|
-
const [asyncTokens, setAsyncTokens] = useState(null);
|
|
2607
|
-
useEffect(() => {
|
|
2608
|
-
if (syncTokens) return;
|
|
2609
|
-
let active = true;
|
|
2610
|
-
const result = getCodeTokens(code, language);
|
|
2611
|
-
if (!Array.isArray(result)) result.then((loaded) => {
|
|
2612
|
-
if (active) setAsyncTokens(loaded);
|
|
2613
|
-
});
|
|
2614
|
-
return () => {
|
|
2615
|
-
active = false;
|
|
2616
|
-
};
|
|
2617
|
-
}, [
|
|
2618
|
-
code,
|
|
2619
|
-
language,
|
|
2620
|
-
syncTokens
|
|
2621
|
-
]);
|
|
2622
|
-
const tokens = syncTokens ?? asyncTokens ?? [];
|
|
2656
|
+
const result = useMemo(() => getCodeTokens(code, language), [code, language]);
|
|
2657
|
+
const tokens = useMaybePromise(result) ?? [];
|
|
2623
2658
|
return /* @__PURE__ */ jsx("pre", {
|
|
2624
2659
|
"data-language": language || void 0,
|
|
2625
2660
|
children: /* @__PURE__ */ jsx("code", { children: tokens.length > 0 ? renderTokens(code, tokens) : code })
|
|
@@ -2698,6 +2733,7 @@ function wrapMark(mark, children, context) {
|
|
|
2698
2733
|
src: attrs.src,
|
|
2699
2734
|
alt: attrs.alt,
|
|
2700
2735
|
width: attrs.width,
|
|
2736
|
+
height: attrs.height,
|
|
2701
2737
|
snapshot: attrs.snapshot,
|
|
2702
2738
|
context,
|
|
2703
2739
|
children
|
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.75.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@base-ui/react": "^1.8.0",
|
|
25
|
-
"@meowdown/core": "0.
|
|
25
|
+
"@meowdown/core": "0.75.0",
|
|
26
26
|
"@meowdown/embed": "0.2.0",
|
|
27
27
|
"@meowdown/markdown": "0.72.0",
|
|
28
28
|
"@ocavue/utils": "^1.8.0",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"@prosekit/core": "^0.13.3",
|
|
31
31
|
"@prosekit/pm": "^0.1.20",
|
|
32
32
|
"@prosekit/react": "^0.8.3",
|
|
33
|
+
"@prosekit/web": "^0.9.3",
|
|
33
34
|
"beautiful-mermaid": "^1.1.3",
|
|
34
35
|
"clsx": "^2.1.1",
|
|
35
36
|
"github-slugger": "^2.0.0",
|