@meowdown/core 0.71.1 → 0.72.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 CHANGED
@@ -6,7 +6,6 @@ import { SearchStatus, SearchStatusHandler, defineSearchStatusHandler, getSearch
6
6
  import { EditorView } from "@prosekit/pm/view";
7
7
  import { EditorNode, Mark, ProseMirrorNode } from "@prosekit/pm/model";
8
8
  import { ListAttrs } from "@prosekit/extensions/list";
9
- import { parseXPostId } from "@post-embed/schema";
10
9
  import { HorizontalRuleExtension } from "@prosekit/extensions/horizontal-rule";
11
10
  import { Resolver } from "@post-embed/elements/x";
12
11
  import { render } from "katex";
@@ -781,11 +780,6 @@ export declare function defineFollowLinkHandler(getHandlers?: (state: EditorStat
781
780
  //#region src/extensions/post-embed.d.ts
782
781
  type XPostResolver = Resolver<XPost>;
783
782
  type YouTubeVideoResolver = Resolver<YouTubeVideo>;
784
- type PostEmbedKind = 'x-post' | 'youtube-video';
785
- /**
786
- * The post-embed card an image `src` renders as, or `undefined` for a plain image.
787
- */
788
- export declare function matchPostEmbed(src: string): PostEmbedKind | undefined;
789
783
  export declare const defaultResolveXPost: XPostResolver;
790
784
  export declare const defaultResolveYouTubeVideo: YouTubeVideoResolver;
791
785
  /**
@@ -1447,7 +1441,7 @@ interface LinkHoverOptions {
1447
1441
  }
1448
1442
  /**
1449
1443
  * Track the link under the user's attention: a mouse hover after a short
1450
- * dwell, or a touch tap immediately, since touch has no hover. Without the
1444
+ * delay, or a touch tap immediately, since touch has no hover. Without the
1451
1445
  * tap entry, the popup's preview and actions would stay unreachable on
1452
1446
  * phones, where a tap on a link only places the caret and raises the
1453
1447
  * software keyboard.
@@ -1564,13 +1558,16 @@ interface WikilinkHoverHit extends WikilinkHit {
1564
1558
  */
1565
1559
  type WikilinkHoverHandler = (hit: WikilinkHoverHit | undefined) => void;
1566
1560
  /**
1567
- * Track the wikilink under the pointer without attaching per-link listeners.
1561
+ * Track the wikilink the pointer rests on without attaching per-link
1562
+ * listeners.
1568
1563
  *
1569
- * The handler is revalidated after document transactions and receives leave
1570
- * when the hovered link is deleted, replaced, or changes target. Moving among
1571
- * descendants of one label is de-duplicated.
1564
+ * A cold pointer must rest on a link for `openDelay` ms before enter fires.
1565
+ * Moving to an adjacent link restarts the delay, or switches at once when a
1566
+ * link is already entered. Leave fires `closeDelay` ms after the pointer
1567
+ * leaves, and immediately when the hovered link is deleted, replaced, or
1568
+ * changes target. Moving among descendants of one label is de-duplicated.
1572
1569
  */
1573
- export declare function defineWikilinkHoverHandler(onHoverChange: WikilinkHoverHandler): PlainExtension;
1570
+ export declare function defineWikilinkHoverHandler(onHoverChange: WikilinkHoverHandler, openDelay?: number, closeDelay?: number): PlainExtension;
1574
1571
  //#endregion
1575
1572
  //#region src/extensions/wikilink-trigger.d.ts
1576
1573
  /**
@@ -1642,4 +1639,4 @@ export declare function getSelectedText(state: EditorState): string;
1642
1639
  */
1643
1640
  export declare function getVirtualElementFromRange(view: EditorView, range: PositionRange): VirtualElement;
1644
1641
  //#endregion
1645
- export { type AcceptPendingReplacementOptions, type CheckRoundTripOptions, type CodeBlockAttrs, type CodeBlockFenceStyle, type CodeToken, type DocToMarkdownOptions, type EditorConfig, type EditorExtension, type EditorExtensionOptions, type ExitBoundaryHandler, type ExitBoundaryOptions, type FileClickHandler, type FileClickPayload, type FileInfo, type FileInfoResolver, type FileLinkOptions, type FileLinkPayload, type FileLinkResolver, type FilePasteHandler, type FilePasteOptions, type FileSaveErrorHandler, type FileViewOptions, type FollowLinkHandlers, type ImageClickHandler, type ImageClickPayload, type ImageOptions, type InlineMarkContext, type InlineMarkOptions, type KaTeXRender, type LanguageItem, type LinkAttrs, type LinkClickHandler, type LinkClickPayload, type LinkCopyHandler, type LinkCopyPayload, type LinkEditHandler, type LinkEditOptions, type LinkHoverHandler, type LinkHoverOptions, type LinkPreview, type LinkPreviewResolver, type LinkUnit, type ListMarker, type MarkChunk, type MarkMode, type MarkName, type MarkdownToDocOptions, type MdFileAttrs, type MdImageAttrs, type MdLinkTextAttrs, type MdMathAttrs, type MdWikilinkAttrs, type MeowdownCodeBlockAttrs, type MeowdownHTMLCommentAttrs, type MeowdownListAttrs, type MeowdownTableCellAttrs, type NodeName, type ParsedWikiEmbed, type PendingReplacement, type PendingReplacementEvent, type PendingReplacementHandler, type PendingReplacementMode, type PendingReplacementOutcome, type PlaceholderOptions, type PositionRange, type PostEmbedKind, type PostEmbedSnapshot, Priority, type ReferenceDefinition, type ReferenceDefinitionIndex, type ReferenceDefinitions, type RoundTripFidelity, type SearchStatus, type SearchStatusHandler, type StartPendingReplacementOptions, type TableColumnAlign, type TagClickHandler, type TagClickPayload, type TypedEditor, type TypedMarkBuilders, type VirtualElement, type WikiEmbedOptions, type WikiEmbedResolution, type WikiEmbedResolver, type WikilinkClickHandler, type WikilinkClickPayload, type WikilinkHoverHandler, type WikilinkHoverHit, type WikilinkOptions, type WikilinkPayload, type WikilinkResolution, type WikilinkResolver, type XPostResolver, type YouTubeVideoResolver, defineCodeBlockPreviewPlugin, definePlaceholder, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, parseXPostId, withPriority };
1642
+ export { type AcceptPendingReplacementOptions, type CheckRoundTripOptions, type CodeBlockAttrs, type CodeBlockFenceStyle, type CodeToken, type DocToMarkdownOptions, type EditorConfig, type EditorExtension, type EditorExtensionOptions, type ExitBoundaryHandler, type ExitBoundaryOptions, type FileClickHandler, type FileClickPayload, type FileInfo, type FileInfoResolver, type FileLinkOptions, type FileLinkPayload, type FileLinkResolver, type FilePasteHandler, type FilePasteOptions, type FileSaveErrorHandler, type FileViewOptions, type FollowLinkHandlers, type ImageClickHandler, type ImageClickPayload, type ImageOptions, type InlineMarkContext, type InlineMarkOptions, type KaTeXRender, type LanguageItem, type LinkAttrs, type LinkClickHandler, type LinkClickPayload, type LinkCopyHandler, type LinkCopyPayload, type LinkEditHandler, type LinkEditOptions, type LinkHoverHandler, type LinkHoverOptions, type LinkPreview, type LinkPreviewResolver, type LinkUnit, type ListMarker, type MarkChunk, type MarkMode, type MarkName, type MarkdownToDocOptions, type MdFileAttrs, type MdImageAttrs, type MdLinkTextAttrs, type MdMathAttrs, type MdWikilinkAttrs, type MeowdownCodeBlockAttrs, type MeowdownHTMLCommentAttrs, type MeowdownListAttrs, type MeowdownTableCellAttrs, type NodeName, type ParsedWikiEmbed, type PendingReplacement, type PendingReplacementEvent, type PendingReplacementHandler, type PendingReplacementMode, type PendingReplacementOutcome, type PlaceholderOptions, type PositionRange, type PostEmbedSnapshot, Priority, type ReferenceDefinition, type ReferenceDefinitionIndex, type ReferenceDefinitions, type RoundTripFidelity, type SearchStatus, type SearchStatusHandler, type StartPendingReplacementOptions, type TableColumnAlign, type TagClickHandler, type TagClickPayload, type TypedEditor, type TypedMarkBuilders, type VirtualElement, type WikiEmbedOptions, type WikiEmbedResolution, type WikiEmbedResolver, type WikilinkClickHandler, type WikilinkClickPayload, type WikilinkHoverHandler, type WikilinkHoverHit, type WikilinkOptions, type WikilinkPayload, type WikilinkResolution, type WikilinkResolver, type XPostResolver, type YouTubeVideoResolver, defineCodeBlockPreviewPlugin, definePlaceholder, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { defineCodeBlock, defineCodeBlockHighlight, defineCodeBlockPreviewPlugin
3
3
  import { definePlaceholder, definePlaceholder as definePlaceholder$1 } from "@prosekit/extensions/placeholder";
4
4
  import { NodeSelection, Plugin, PluginKey, Selection, TextSelection } from "@prosekit/pm/state";
5
5
  import { defineSearchCommands, defineSearchQuery, defineSearchStatusHandler, getSearchStatus, getSearchStatus as getSearchStatus$1 } from "@prosekit/extensions/search";
6
- import { LEZER_NODE_IDS, collectInlineElements, getAutolinkHref, gfmBlockOnlyParser, gfmParser, isSpaceChar, parseInline } from "@meowdown/markdown";
6
+ import { LEZER_NODE_IDS, collectInlineElements, getAutolinkHref, gfmBlockOnlyParser, gfmParser, isSpaceChar, matchEmbed, parseInline, parseXPostId } from "@meowdown/markdown";
7
7
  import { isElementLike, isHTMLElement, isObject, once } from "@ocavue/utils";
8
8
  import { defineBlockquote } from "@prosekit/extensions/blockquote";
9
9
  import { defineDoc } from "@prosekit/extensions/doc";
@@ -33,14 +33,14 @@ import { triggerAutocomplete } from "@prosekit/extensions/autocomplete";
33
33
  import { defineListCommands, defineListDropIndicator, defineListKeymap, defineListSpec, moveList, toggleList, unwrapList, wrapInList } from "@prosekit/extensions/list";
34
34
  import { chainCommands, lift, newlineInCode, splitBlock } from "@prosekit/pm/commands";
35
35
  import { closeHistory } from "@prosekit/pm/history";
36
- import { fromSyndication } from "@post-embed/exporter/x/syndication";
37
- import { XPostSchema, YouTubeVideoSchema, parseXPostId } from "@post-embed/schema";
38
- import { createLRU } from "lru.min";
39
- import * as v from "valibot";
40
36
  import { defineHorizontalRule } from "@prosekit/extensions/horizontal-rule";
41
37
  import { registerXPost } from "@post-embed/elements/x";
42
38
  import { registerYouTubeVideo } from "@post-embed/elements/youtube";
43
39
  import { registerResizableHandleElement, registerResizableRootElement } from "@prosekit/web/resizable";
40
+ import { fromSyndication } from "@post-embed/exporter/x/syndication";
41
+ import { XPostSchema, YouTubeVideoSchema } from "@post-embed/schema";
42
+ import { createLRU } from "lru.min";
43
+ import * as v from "valibot";
44
44
  import { AttrStep, ReplaceStep, Step, StepResult, Transform } from "@prosekit/pm/transform";
45
45
  import { decodeString } from "micromark-util-decode-string";
46
46
  import { normalizeIdentifier } from "micromark-util-normalize-identifier";
@@ -2478,99 +2478,13 @@ function getPastedText(event, slice) {
2478
2478
  return slice.content.textBetween(0, slice.content.size, "\n");
2479
2479
  }
2480
2480
 
2481
- //#endregion
2482
- //#region src/extensions/post-embed.ts
2483
- const YOUTUBE_HOSTS = /^(?:www\.|m\.)?(?:youtube\.com|youtube-nocookie\.com)$/i;
2484
- const YOUTU_BE_HOST = /^(?:www\.)?youtu\.be$/i;
2485
- const VIDEO_ID = /^[\w-]{11}$/;
2486
- function parseURL(src) {
2487
- try {
2488
- return new URL(src);
2489
- } catch {
2490
- return;
2491
- }
2492
- }
2493
- function isYouTubeVideo(src) {
2494
- const url = parseURL(src);
2495
- if (!url) return false;
2496
- let videoId = null;
2497
- if (YOUTU_BE_HOST.test(url.hostname)) videoId = url.pathname.slice(1);
2498
- else if (YOUTUBE_HOSTS.test(url.hostname)) {
2499
- const [, firstSegment, secondSegment] = url.pathname.split("/");
2500
- if (url.pathname === "/watch") videoId = url.searchParams.get("v");
2501
- else if (firstSegment === "shorts" || firstSegment === "embed" || firstSegment === "live") videoId = secondSegment ?? null;
2502
- }
2503
- return videoId !== null && VIDEO_ID.test(videoId);
2504
- }
2505
- /**
2506
- * The post-embed card an image `src` renders as, or `undefined` for a plain image.
2507
- */
2508
- function matchPostEmbed(src) {
2509
- if (parseXPostId(src) !== void 0) return "x-post";
2510
- if (isYouTubeVideo(src)) return "youtube-video";
2511
- }
2512
- /**
2513
- * Wrap a loader in a 64-entry LRU keyed by URL. A settled URL answers
2514
- * synchronously, so a revisited document renders its cards in the first
2515
- * frame; the first visit returns the in-flight load.
2516
- */
2517
- function cached(load) {
2518
- const cache = createLRU({ max: 64 });
2519
- return (url) => {
2520
- if (cache.has(url)) return cache.get(url);
2521
- const pending = load(url).then((value) => {
2522
- cache.set(url, value);
2523
- return value;
2524
- }, (error) => {
2525
- cache.delete(url);
2526
- throw error;
2527
- });
2528
- cache.set(url, pending);
2529
- return pending;
2530
- };
2531
- }
2532
- const X_POST_API = "https://react-tweet.vercel.app/api/tweet/";
2533
- const defaultResolveXPost = cached(async (url) => {
2534
- const id = parseXPostId(url);
2535
- if (id === void 0) return;
2536
- const response = await fetch(X_POST_API + id);
2537
- if (!response.ok) return;
2538
- const json = await response.json();
2539
- return fromSyndication(json.data);
2540
- });
2541
- const YOUTUBE_OEMBED_API = "https://www.youtube.com/oembed?format=json&url=";
2542
- const defaultResolveYouTubeVideo = cached(async (url) => {
2543
- const response = await fetch(YOUTUBE_OEMBED_API + encodeURIComponent(url));
2544
- if (!response.ok) return;
2545
- return {
2546
- url,
2547
- ...await response.json()
2548
- };
2549
- });
2550
- const PostEmbedSnapshotSchema = v.variant("kind", [v.object({
2551
- kind: v.literal("x-post"),
2552
- data: XPostSchema
2553
- }), v.object({
2554
- kind: v.literal("youtube-video"),
2555
- data: YouTubeVideoSchema
2556
- })]);
2557
- /**
2558
- * The snapshot a card renders from a saved JSON object, or `undefined` when
2559
- * the object does not validate. Unknown fields are dropped, so a persisted
2560
- * snapshot is exactly what the card needs.
2561
- */
2562
- function parsePostEmbedSnapshot(value) {
2563
- const result = v.safeParse(PostEmbedSnapshotSchema, value);
2564
- return result.success ? result.output : void 0;
2565
- }
2566
-
2567
2481
  //#endregion
2568
2482
  //#region src/extensions/embed-paste.ts
2569
2483
  const embedPasteKey = new PluginKey("meowdown-embed-paste");
2570
2484
  function detectEmbedUrl(text) {
2571
2485
  const trimmed = text.trim();
2572
2486
  if (!trimmed || /\s/.test(trimmed)) return void 0;
2573
- return matchPostEmbed(trimmed) ? trimmed : void 0;
2487
+ return matchEmbed(trimmed) ? trimmed : void 0;
2574
2488
  }
2575
2489
  function insertEmbedFromPaste(view, url) {
2576
2490
  const { from, to } = view.state.selection;
@@ -3663,6 +3577,63 @@ function stripMagicComment(source) {
3663
3577
  return source.replace(TRAILING_MAGIC_COMMENT_RE, "");
3664
3578
  }
3665
3579
 
3580
+ //#endregion
3581
+ //#region src/extensions/post-embed.ts
3582
+ /**
3583
+ * Wrap a loader in a 64-entry LRU keyed by URL. A settled URL answers
3584
+ * synchronously, so a revisited document renders its cards in the first
3585
+ * frame; the first visit returns the in-flight load.
3586
+ */
3587
+ function cached(load) {
3588
+ const cache = createLRU({ max: 64 });
3589
+ return (url) => {
3590
+ if (cache.has(url)) return cache.get(url);
3591
+ const pending = load(url).then((value) => {
3592
+ cache.set(url, value);
3593
+ return value;
3594
+ }, (error) => {
3595
+ cache.delete(url);
3596
+ throw error;
3597
+ });
3598
+ cache.set(url, pending);
3599
+ return pending;
3600
+ };
3601
+ }
3602
+ const X_POST_API = "https://react-tweet.vercel.app/api/tweet/";
3603
+ const defaultResolveXPost = cached(async (url) => {
3604
+ const id = parseXPostId(url);
3605
+ if (id === void 0) return;
3606
+ const response = await fetch(X_POST_API + id);
3607
+ if (!response.ok) return;
3608
+ const json = await response.json();
3609
+ return fromSyndication(json.data);
3610
+ });
3611
+ const YOUTUBE_OEMBED_API = "https://www.youtube.com/oembed?format=json&url=";
3612
+ const defaultResolveYouTubeVideo = cached(async (url) => {
3613
+ const response = await fetch(YOUTUBE_OEMBED_API + encodeURIComponent(url));
3614
+ if (!response.ok) return;
3615
+ return {
3616
+ url,
3617
+ ...await response.json()
3618
+ };
3619
+ });
3620
+ const PostEmbedSnapshotSchema = v.variant("kind", [v.object({
3621
+ kind: v.literal("x-post"),
3622
+ data: XPostSchema
3623
+ }), v.object({
3624
+ kind: v.literal("youtube-video"),
3625
+ data: YouTubeVideoSchema
3626
+ })]);
3627
+ /**
3628
+ * The snapshot a card renders from a saved JSON object, or `undefined` when
3629
+ * the object does not validate. Unknown fields are dropped, so a persisted
3630
+ * snapshot is exactly what the card needs.
3631
+ */
3632
+ function parsePostEmbedSnapshot(value) {
3633
+ const result = v.safeParse(PostEmbedSnapshotSchema, value);
3634
+ return result.success ? result.output : void 0;
3635
+ }
3636
+
3666
3637
  //#endregion
3667
3638
  //#region src/extensions/wiki-embed.ts
3668
3639
  const WIKI_EMBED_SIZE = /^(\d+)(?:x(\d+))?$/i;
@@ -3906,7 +3877,7 @@ var ImageMarkView = class {
3906
3877
  const { src } = this.#attrs;
3907
3878
  const wrapper = document.createElement("span");
3908
3879
  wrapper.className = "md-image-view-preview md-atom-view-preview";
3909
- const kind = matchPostEmbed(src);
3880
+ const kind = matchEmbed(src);
3910
3881
  if (kind) {
3911
3882
  wrapper.dataset.testid = `${kind}-embed`;
3912
3883
  wrapper.dataset.postEmbed = kind;
@@ -8550,17 +8521,17 @@ function defineMarkHoverHandler(config) {
8550
8521
  //#region src/extensions/link-hover.ts
8551
8522
  const linkHoverKey = new PluginKey("meowdown-link-hover");
8552
8523
  /**
8553
- * Dwell before a cold hover enters, in ms.
8524
+ * Delay before a cold hover enters, in ms.
8554
8525
  */
8555
- const OPEN_DELAY = 300;
8526
+ const OPEN_DELAY$1 = 300;
8556
8527
  /**
8557
8528
  * Grace before a leave fires, in ms. The window lets a pointer travel from
8558
8529
  * the hovered link onto the popup it anchors.
8559
8530
  */
8560
- const CLOSE_DELAY = 100;
8531
+ const CLOSE_DELAY$1 = 100;
8561
8532
  /**
8562
8533
  * Track the link under the user's attention: a mouse hover after a short
8563
- * dwell, or a touch tap immediately, since touch has no hover. Without the
8534
+ * delay, or a touch tap immediately, since touch has no hover. Without the
8564
8535
  * tap entry, the popup's preview and actions would stay unreachable on
8565
8536
  * phones, where a tap on a link only places the caret and raises the
8566
8537
  * software keyboard.
@@ -8569,8 +8540,8 @@ function defineLinkHoverHandler(onHoverChange, { canLeave } = {}) {
8569
8540
  return defineMarkHoverHandler({
8570
8541
  key: linkHoverKey,
8571
8542
  selector: ".md-link",
8572
- openDelay: OPEN_DELAY,
8573
- closeDelay: CLOSE_DELAY,
8543
+ openDelay: OPEN_DELAY$1,
8544
+ closeDelay: CLOSE_DELAY$1,
8574
8545
  tap: true,
8575
8546
  canLeave,
8576
8547
  findPayloadAt: (state, pos) => {
@@ -8821,18 +8792,30 @@ function defineVirtualCaret(layer) {
8821
8792
  //#region src/extensions/wikilink-hover.ts
8822
8793
  const wikilinkHoverKey = new PluginKey("meowdown-wikilink-hover");
8823
8794
  /**
8824
- * Track the wikilink under the pointer without attaching per-link listeners.
8795
+ * Delay before a cold hover enters, in ms.
8796
+ */
8797
+ const OPEN_DELAY = 300;
8798
+ /**
8799
+ * Grace before a leave fires, in ms. Returning within it re-enters without
8800
+ * a new delay.
8801
+ */
8802
+ const CLOSE_DELAY = 100;
8803
+ /**
8804
+ * Track the wikilink the pointer rests on without attaching per-link
8805
+ * listeners.
8825
8806
  *
8826
- * The handler is revalidated after document transactions and receives leave
8827
- * when the hovered link is deleted, replaced, or changes target. Moving among
8828
- * descendants of one label is de-duplicated.
8807
+ * A cold pointer must rest on a link for `openDelay` ms before enter fires.
8808
+ * Moving to an adjacent link restarts the delay, or switches at once when a
8809
+ * link is already entered. Leave fires `closeDelay` ms after the pointer
8810
+ * leaves, and immediately when the hovered link is deleted, replaced, or
8811
+ * changes target. Moving among descendants of one label is de-duplicated.
8829
8812
  */
8830
- function defineWikilinkHoverHandler(onHoverChange) {
8813
+ function defineWikilinkHoverHandler(onHoverChange, openDelay = OPEN_DELAY, closeDelay = CLOSE_DELAY) {
8831
8814
  return defineMarkHoverHandler({
8832
8815
  key: wikilinkHoverKey,
8833
8816
  selector: ".md-wikilink-view-preview",
8834
- openDelay: 0,
8835
- closeDelay: 0,
8817
+ openDelay,
8818
+ closeDelay,
8836
8819
  tap: false,
8837
8820
  findPayloadAt: findWikilinkAt,
8838
8821
  findPayloadForElement: findWikilinkForElement,
@@ -8937,4 +8920,4 @@ function getVirtualElementFromRange(view, range) {
8937
8920
  }
8938
8921
 
8939
8922
  //#endregion
8940
- export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineBulletAfterHeading, defineCodeBlockPreviewPlugin, defineCodeBlockSyntaxHighlight, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineFileClickHandler, defineFilePaste, defineFileView, defineFollowLinkHandler, defineHTMLComment, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkCommands, defineLinkEditKeymap, defineLinkHoverHandler, defineLinkPaste, defineMath, definePendingReplacementHandler, definePlaceholder, defineReadonly, defineSearchStatusHandler, defineSubstitution, defineTagClickHandler, defineViewAttributes, defineVirtualCaret, defineWikilinkClickHandler, defineWikilinkHoverHandler, defineWikilinkTrigger, docToMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getEditorConfig, getFileKind, getIsComposing, getLinkText, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isMarkOfType, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, matchPostEmbed, normalizeHref, parsePostEmbedSnapshot, parseWikiEmbed, parseXPostId, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };
8923
+ export { EDITOR_KEY_BINDINGS, Priority, buildFileMarkdown, checkRoundTrip, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineBulletAfterHeading, defineCodeBlockPreviewPlugin, defineCodeBlockSyntaxHighlight, defineEditorExtension, defineEmbedPaste, defineExitBoundaryHandler, defineFileClickHandler, defineFilePaste, defineFileView, defineFollowLinkHandler, defineHTMLComment, defineImage, defineImageClickHandler, defineLinkClickHandler, defineLinkCommands, defineLinkEditKeymap, defineLinkHoverHandler, defineLinkPaste, defineMath, definePendingReplacementHandler, definePlaceholder, defineReadonly, defineSearchStatusHandler, defineSubstitution, defineTagClickHandler, defineViewAttributes, defineVirtualCaret, defineWikilinkClickHandler, defineWikilinkHoverHandler, defineWikilinkTrigger, docToMarkdown, formatFileSize, formatSizedWikiEmbed, getCodeTokens, getEditorConfig, getFileKind, getIsComposing, getLinkText, getLinkUnitAt, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunks, inlineTextToMarkChunksWithContext, insertLink, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isMarkOfType, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, parsePostEmbedSnapshot, parseWikiEmbed, removeLink, renderMathInto, updateEditorConfig, updateLink, wikiEmbedBasename, withPriority };
package/dist/style.css CHANGED
@@ -183,224 +183,261 @@
183
183
  inherits: true
184
184
  }
185
185
 
186
- @layer post-embed {
187
- :where([data-post-embed="x-post"]) {
188
- --_hairline: var(--post-embed-border-color, color-mix(in srgb, currentColor 15%, transparent));
189
- --_muted: var(--post-embed-muted-color, color-mix(in srgb, currentColor 58%, transparent));
190
- --_link: var(--post-embed-link-color, #1d9bf0);
191
- font: inherit;
192
- color: var(--post-embed-color, inherit);
193
- text-decoration-skip-ink: none;
194
- display: block;
186
+ [data-post-embed="x-post"] [data-root], [data-post-embed="x-post"] [data-root] *, [data-post-embed="x-post"] [data-root] :before, [data-post-embed="x-post"] [data-root] :after {
187
+ all: revert;
188
+ box-sizing: border-box;
189
+ }
195
190
 
196
- & :where([data-root]) {
197
- background: var(--post-embed-background, transparent);
198
- border: 1px solid var(--_hairline);
199
- border-radius: var(--post-embed-radius, 1rem);
200
- padding: var(--post-embed-padding, 1rem);
201
- overflow-wrap: anywhere;
202
- line-height: 1.4;
203
- position: relative;
204
- }
191
+ [data-post-embed="x-post"] {
192
+ --_hairline: var(--post-embed-border-color, color-mix(in srgb, currentColor 14%, transparent));
193
+ --_muted: var(--post-embed-muted-color, color-mix(in srgb, currentColor 55%, transparent));
194
+ --_link: var(--post-embed-link-color, #1d9bf0);
195
+ --_tint: color-mix(in srgb, currentColor 5%, transparent);
196
+ font: inherit;
197
+ color: var(--post-embed-color, inherit);
198
+ text-decoration-skip-ink: none;
199
+ display: block;
200
+ }
205
201
 
206
- & :where([hidden]) {
207
- display: none !important;
208
- }
202
+ [data-post-embed="x-post"] [data-root] {
203
+ color: var(--post-embed-color, inherit);
204
+ background: var(--post-embed-background, transparent);
205
+ border: 1px solid var(--_hairline);
206
+ border-radius: var(--post-embed-radius, .75rem);
207
+ padding: var(--post-embed-padding, 1rem);
208
+ letter-spacing: normal;
209
+ text-align: start;
210
+ text-transform: none;
211
+ text-indent: 0;
212
+ text-shadow: none;
213
+ word-spacing: normal;
214
+ font-variant: normal;
215
+ hyphens: manual;
216
+ white-space: normal;
217
+ overflow-wrap: anywhere;
218
+ cursor: auto;
219
+ font-size: 1em;
220
+ font-style: normal;
221
+ font-weight: 400;
222
+ line-height: 1.45;
223
+ display: block;
224
+ position: relative;
209
225
 
210
- & :where(a) {
211
- color: var(--_link);
212
- text-decoration: none;
213
- }
226
+ & [hidden] {
227
+ display: none !important;
228
+ }
214
229
 
215
- & :where(a:hover) {
216
- text-underline-offset: .15em;
217
- text-decoration: underline;
218
- }
230
+ & p {
231
+ margin: 0;
232
+ }
219
233
 
220
- & :where(a:focus-visible, button:focus-visible) {
221
- outline: 2px solid var(--_link);
222
- outline-offset: 2px;
223
- border-radius: 4px;
224
- }
234
+ & a {
235
+ color: var(--_link);
236
+ cursor: pointer;
237
+ text-decoration: none;
238
+ }
225
239
 
226
- & :where([data-author]) {
227
- align-items: center;
228
- gap: .75rem;
229
- display: flex;
230
- }
240
+ & a:hover {
241
+ text-underline-offset: .15em;
242
+ text-decoration: underline;
243
+ }
231
244
 
232
- & :where([data-avatar]) {
233
- object-fit: cover;
234
- border-radius: 50%;
235
- flex: none;
236
- width: 3rem;
237
- height: 3rem;
238
- }
245
+ & a:focus-visible {
246
+ outline: 2px solid var(--_link);
247
+ outline-offset: 2px;
248
+ border-radius: 4px;
249
+ }
239
250
 
240
- & :where([data-avatar][data-shape="square"]) {
241
- border-radius: .5rem;
242
- }
251
+ & [data-author] {
252
+ align-items: center;
253
+ gap: .625rem;
254
+ min-width: 0;
255
+ display: flex;
256
+ }
243
257
 
244
- & :where([data-avatar][data-shape="hexagon"]) {
245
- clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
246
- }
258
+ & [data-avatar] {
259
+ object-fit: cover;
260
+ background: var(--_tint);
261
+ border-radius: 50%;
262
+ flex: none;
263
+ width: 2.5rem;
264
+ height: 2.5rem;
265
+ display: block;
266
+ }
247
267
 
248
- & :where([data-author-details]) {
249
- min-width: 0;
250
- color: var(--_muted);
251
- flex: 1;
252
- line-height: 1.3;
253
- }
268
+ & [data-avatar][data-shape="square"] {
269
+ border-radius: .5rem;
270
+ }
254
271
 
255
- & :where([data-author-name]) {
256
- color: var(--post-embed-color, inherit);
257
- flex-wrap: wrap;
258
- align-items: center;
259
- gap: .25rem;
260
- font-weight: 700;
261
- display: flex;
262
- }
272
+ & [data-avatar][data-shape="hexagon"] {
273
+ clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
274
+ }
263
275
 
264
- & :where([data-author-details] > bdi > a) {
265
- color: inherit;
266
- }
276
+ & [data-author-details] {
277
+ flex: 1;
278
+ min-width: 0;
279
+ line-height: 1.3;
280
+ display: block;
281
+ }
267
282
 
268
- & :where([data-reply-to]) {
269
- color: var(--_muted);
270
- margin-block-start: .75rem;
271
- font-size: .9375em;
272
- }
283
+ & [data-author-name] {
284
+ flex-wrap: wrap;
285
+ align-items: center;
286
+ gap: .25rem;
287
+ font-weight: 600;
288
+ display: flex;
289
+ }
273
290
 
274
- & :where([data-body]) {
275
- margin-block: .75rem 0;
276
- font-size: 1.0625em;
277
- line-height: 1.45;
278
- }
291
+ & [data-author-details] > bdi {
292
+ color: var(--_muted);
293
+ }
279
294
 
280
- & :where([data-text]) {
281
- white-space: pre-wrap;
282
- }
295
+ & [data-author-details] > bdi > a {
296
+ color: inherit;
297
+ }
283
298
 
284
- & :where([data-media]) {
285
- border: 1px solid var(--_hairline);
286
- border-radius: 1rem;
287
- grid-template-columns: repeat(2, minmax(0, 1fr));
288
- gap: 2px;
289
- margin-block-start: .75rem;
290
- display: grid;
291
- overflow: hidden;
292
- }
299
+ & [data-reply-to] {
300
+ color: var(--_muted);
301
+ margin-block-start: .625rem;
302
+ font-size: .9375em;
303
+ display: block;
304
+ }
293
305
 
294
- & :where([data-media][data-count="1"]) {
295
- grid-template-columns: minmax(0, 1fr);
296
- }
306
+ & [data-body] {
307
+ margin-block: .625rem 0;
308
+ font-size: 1em;
309
+ line-height: 1.5;
310
+ display: block;
311
+ }
297
312
 
298
- & :where([data-media-item]) {
299
- min-width: 0;
300
- overflow: hidden;
301
- }
313
+ & [data-text] {
314
+ white-space: pre-wrap;
315
+ }
302
316
 
303
- & :where([data-media-item] > a) {
304
- height: 100%;
305
- display: block;
306
- }
317
+ & [data-media] {
318
+ background: var(--_hairline);
319
+ border-radius: .5rem;
320
+ grid-template-columns: repeat(2, minmax(0, 1fr));
321
+ gap: 2px;
322
+ margin-block-start: .75rem;
323
+ display: grid;
324
+ overflow: hidden;
325
+ }
307
326
 
308
- & :where([data-media-item] img, [data-media-item] video) {
309
- object-fit: contain;
310
- background: color-mix(in srgb, currentColor 6%, transparent);
311
- width: 100%;
312
- height: auto;
313
- max-height: 36rem;
314
- display: block;
315
- }
327
+ & [data-media][data-count="1"] {
328
+ grid-template-columns: minmax(0, 1fr);
329
+ }
316
330
 
317
- & :where([data-media]:not([data-count="1"]) [data-media-item] img) {
318
- aspect-ratio: 1;
319
- object-fit: cover;
320
- height: 100%;
321
- }
331
+ & [data-media-item] {
332
+ min-width: 0;
333
+ display: block;
334
+ overflow: hidden;
335
+ }
322
336
 
323
- & :where([data-media][data-count="3"] [data-media-item]:first-child) {
324
- grid-row: span 2;
325
- }
337
+ & [data-media-item] > a {
338
+ height: 100%;
339
+ display: block;
340
+ }
326
341
 
327
- & :where([data-media-unavailable], [data-media-error]) {
328
- color: var(--_muted);
329
- background: color-mix(in srgb, currentColor 4%, transparent);
330
- padding: .75rem 1rem;
331
- }
342
+ & [data-media-item] img, & [data-media-item] video {
343
+ object-fit: contain;
344
+ background: var(--_tint);
345
+ width: 100%;
346
+ height: auto;
347
+ max-height: 32rem;
348
+ display: block;
349
+ }
332
350
 
333
- & :where([data-quoted]) {
334
- border: 1px solid var(--_hairline);
335
- border-radius: 1rem;
336
- margin-block-start: .75rem;
337
- padding: .75rem;
338
- }
351
+ & [data-media]:not([data-count="1"]) [data-media-item] img {
352
+ aspect-ratio: 1;
353
+ object-fit: cover;
354
+ height: 100%;
355
+ }
339
356
 
340
- & :where([data-quoted] [data-author]) {
341
- gap: .5rem;
342
- }
357
+ & [data-media][data-count="3"] [data-media-item]:first-child {
358
+ grid-row: span 2;
359
+ }
343
360
 
344
- & :where([data-quoted] [data-avatar]) {
345
- width: 1.5rem;
346
- height: 1.5rem;
347
- }
361
+ & [data-media-unavailable], & [data-media-error] {
362
+ color: var(--_muted);
363
+ background: var(--_tint);
364
+ padding: .75rem 1rem;
365
+ display: block;
366
+ }
348
367
 
349
- & :where([data-quoted] [data-author-details]) {
350
- flex-wrap: wrap;
351
- align-items: baseline;
352
- gap: 0 .35rem;
353
- display: flex;
354
- }
368
+ & [data-quoted] {
369
+ border: 1px solid var(--_hairline);
370
+ border-radius: .5rem;
371
+ margin-block-start: .75rem;
372
+ padding: .75rem;
373
+ display: block;
374
+ }
355
375
 
356
- & :where([data-quoted] [data-body]) {
357
- margin-block-start: .375rem;
358
- font-size: 1em;
359
- }
376
+ & [data-quoted] [data-author] {
377
+ gap: .5rem;
378
+ }
360
379
 
361
- & :where([data-quoted] [data-media]) {
362
- border-radius: .75rem;
363
- }
380
+ & [data-quoted] [data-avatar] {
381
+ width: 1.375rem;
382
+ height: 1.375rem;
383
+ }
364
384
 
365
- & :where([data-quoted] [data-footer]) {
366
- margin-block-start: .5rem;
367
- font-size: .875em;
368
- }
385
+ & [data-quoted] [data-author-details] {
386
+ flex-wrap: wrap;
387
+ align-items: baseline;
388
+ gap: 0 .35rem;
389
+ display: flex;
390
+ }
369
391
 
370
- & :where([data-footer]) {
371
- color: var(--_muted);
372
- flex-wrap: wrap;
373
- align-items: center;
374
- gap: .25rem 0;
375
- margin-block-start: .75rem;
376
- font-size: .9375em;
377
- display: flex;
378
- }
392
+ & [data-quoted] [data-body] {
393
+ margin-block-start: .375rem;
394
+ font-size: .9375em;
395
+ }
379
396
 
380
- & :where([data-footer] > a) {
381
- color: inherit;
382
- }
397
+ & [data-quoted] [data-media] {
398
+ border-radius: .375rem;
399
+ }
383
400
 
384
- & :where([data-footer] > [data-edited]):before {
385
- content: "";
386
- vertical-align: middle;
387
- background: currentColor;
388
- border-radius: 50%;
389
- width: 3px;
390
- height: 3px;
391
- margin-inline: .45rem;
392
- display: inline-block;
393
- }
401
+ & [data-quoted] [data-footer] {
402
+ margin-block-start: .5rem;
403
+ font-size: .8125em;
404
+ }
394
405
 
395
- & :where([data-edited]) {
396
- font-style: normal;
397
- }
406
+ & [data-footer] {
407
+ color: var(--_muted);
408
+ flex-wrap: wrap;
409
+ align-items: center;
410
+ gap: .25rem 0;
411
+ margin-block-start: .625rem;
412
+ font-size: .875em;
413
+ display: flex;
414
+ }
398
415
 
399
- & :where([data-fallback] [data-body]) {
400
- color: var(--_muted);
401
- }
416
+ & [data-footer] > a {
417
+ color: inherit;
418
+ }
419
+
420
+ & [data-footer] > [data-edited]:before {
421
+ content: "";
422
+ vertical-align: middle;
423
+ background: currentColor;
424
+ border-radius: 50%;
425
+ width: 3px;
426
+ height: 3px;
427
+ margin-inline: .45rem;
428
+ display: inline-block;
429
+ }
430
+
431
+ & [data-edited] {
432
+ font-style: normal;
402
433
  }
403
434
 
435
+ & [data-fallback] [data-body] {
436
+ color: var(--_muted);
437
+ }
438
+ }
439
+
440
+ @layer post-embed {
404
441
  :where([data-post-embed="youtube-video"]) {
405
442
  --_hairline: var(--post-embed-border-color, color-mix(in srgb, currentColor 15%, transparent));
406
443
  --_muted: var(--post-embed-muted-color, color-mix(in srgb, currentColor 58%, transparent));
@@ -1209,7 +1246,8 @@
1209
1246
  }
1210
1247
 
1211
1248
  & .md-image-view-preview[data-post-embed] {
1212
- border-radius: var(--post-embed-radius, 1rem);
1249
+ border-radius: var(--post-embed-radius, .75rem);
1250
+ overflow: visible;
1213
1251
  }
1214
1252
 
1215
1253
  & .md-image-resizable {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/core",
3
3
  "type": "module",
4
- "version": "0.71.1",
4
+ "version": "0.72.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "@floating-ui/dom": "^1.8.0",
27
27
  "@lezer/highlight": "^1.2.3",
28
28
  "@ocavue/utils": "^1.8.0",
29
- "@post-embed/elements": "^0.4.1",
29
+ "@post-embed/elements": "^0.5.0",
30
30
  "@post-embed/exporter": "^0.4.1",
31
31
  "@post-embed/schema": "^0.5.0",
32
32
  "@post-embed/types": "^0.4.0",
@@ -35,7 +35,7 @@
35
35
  "@prosekit/pm": "^0.1.19",
36
36
  "@prosekit/web": "^0.9.2",
37
37
  "hast-util-to-mdast": "^10.1.2",
38
- "katex": "^0.18.5",
38
+ "katex": "^0.18.7",
39
39
  "lru.min": "^1.1.5",
40
40
  "mdast-util-to-markdown": "^2.1.2",
41
41
  "micromark-util-decode-string": "^2.0.1",
@@ -49,19 +49,19 @@
49
49
  "unicode-by-name": "^0.2.0",
50
50
  "unified": "^11.0.5",
51
51
  "valibot": "^1.5.0",
52
- "@meowdown/markdown": "^0.71.1"
52
+ "@meowdown/markdown": "^0.72.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@ocavue/tsconfig": "^0.7.1",
56
- "@tsdown/css": "^0.23.0-rc.1",
56
+ "@tsdown/css": "^0.23.0",
57
57
  "@types/hast": "^3.0.5",
58
58
  "@types/mdast": "^4.0.4",
59
- "@vitest/browser-playwright": "^5.0.0",
59
+ "@vitest/browser-playwright": "^5.0.1",
60
60
  "commonmark.json": "^0.31.0",
61
61
  "dedent": "^1.7.2",
62
62
  "diffable-html-snapshot": "^0.3.0",
63
- "tsdown": "^0.23.0-rc.1",
64
- "vitest": "^5.0.0",
63
+ "tsdown": "^0.23.0",
64
+ "vitest": "^5.0.1",
65
65
  "vitest-browser-commands": "^0.4.1",
66
66
  "@meowdown/vitest": "0.0.0"
67
67
  },