@meowdown/core 0.72.1 → 0.74.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
@@ -7,7 +7,8 @@ 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
9
  import { HorizontalRuleExtension } from "@prosekit/extensions/horizontal-rule";
10
- import { Resolver } from "@post-embed/elements/x";
10
+ import { Resolver, XPostMediaClickEvent } from "@meowdown/embed/x";
11
+ import { YouTubeVideoClickEvent } from "@meowdown/embed/youtube";
11
12
  import { render } from "katex";
12
13
  import { XPost, YouTubeVideo } from "@post-embed/types";
13
14
  import { VirtualElement } from "@floating-ui/dom";
@@ -656,6 +657,11 @@ interface ImageClickPayload {
656
657
  * from it; a touch surface delivers the `touchend` instead of a click.
657
658
  */
658
659
  event: MouseEvent | TouchEvent | KeyboardEvent;
660
+ /**
661
+ * The rendered `<img>` of a click or tap, for example to zoom a lightbox
662
+ * from. A key press has none.
663
+ */
664
+ element?: HTMLImageElement | undefined;
659
665
  /**
660
666
  * Whether the platform's mod key (`Command` on Apple, `Ctrl` elsewhere) was held
661
667
  * beyond the gesture that triggered the activation.
@@ -823,7 +829,7 @@ interface ImageOptions {
823
829
  mediaUrlProtocols?: string[];
824
830
  /**
825
831
  * Resolve the data behind a YouTube video URL, rendered as a
826
- * `post-embed-youtube-video` card. Defaults to `defaultResolveYouTubeVideo`,
832
+ * `meowdown-embed-youtube` card. Defaults to `defaultResolveYouTubeVideo`,
827
833
  * which reads YouTube's oEmbed endpoint.
828
834
  */
829
835
  resolveYouTubeVideo?: YouTubeVideoResolver;
@@ -1070,10 +1076,39 @@ export declare function inlineTextToMarkChunksWithContext(marks: TypedMarkBuilde
1070
1076
  */
1071
1077
  type MarkMode = 'hide' | 'focus' | 'show';
1072
1078
  //#endregion
1079
+ //#region src/extensions/x-post-media-click.d.ts
1080
+ /**
1081
+ * Receives the `meowdown-embed-media-click` event of an X post card. Its
1082
+ * `detail` holds the activated photo or video, its sibling items, and the
1083
+ * rendered thumbnail element. Call `event.preventDefault()` to cancel the
1084
+ * card's own default (open the photo URL, play the video in place).
1085
+ */
1086
+ type XPostMediaClickHandler = (event: XPostMediaClickEvent) => void;
1087
+ /**
1088
+ * Call `onClick` when the user activates a photo or video inside an X post
1089
+ * card.
1090
+ */
1091
+ export declare function defineXPostMediaClickHandler(getOnClick?: (state: EditorState) => XPostMediaClickHandler | undefined): PlainExtension;
1092
+ //#endregion
1093
+ //#region src/extensions/youtube-video-click.d.ts
1094
+ /**
1095
+ * Receives the `meowdown-embed-youtube-click` event of a YouTube card. Its
1096
+ * `detail` holds the video, the player URL, and the rendered thumbnail
1097
+ * element. Call `event.preventDefault()` to cancel the card's own default
1098
+ * (play the video in place).
1099
+ */
1100
+ type YouTubeVideoClickHandler = (event: YouTubeVideoClickEvent) => void;
1101
+ /**
1102
+ * Call `onClick` when the user activates the poster of a YouTube card.
1103
+ */
1104
+ export declare function defineYouTubeVideoClickHandler(getOnClick?: (state: EditorState) => YouTubeVideoClickHandler | undefined): PlainExtension;
1105
+ //#endregion
1073
1106
  //#region src/extensions/editor-config-types.d.ts
1074
1107
  interface EditorConfig extends InlineMarkOptions, FollowLinkHandlers, FilePasteOptions, FileViewOptions, ImageOptions {
1075
1108
  markMode?: MarkMode;
1076
1109
  onExitBoundary?: ExitBoundaryHandler;
1110
+ onXPostMediaClick?: XPostMediaClickHandler;
1111
+ onYouTubeVideoClick?: YouTubeVideoClickHandler;
1077
1112
  embedPaste?: boolean;
1078
1113
  linkPaste?: boolean;
1079
1114
  bulletAfterHeading?: boolean;
@@ -1226,7 +1261,7 @@ declare function defineEditorExtensionImpl(options: EditorExtensionOptions): imp
1226
1261
  Marks: {
1227
1262
  mdPack: MdPackAttrs;
1228
1263
  };
1229
- }>]>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Extension<import("@prosekit/core").ExtensionTyping<any, any, any>>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Union<readonly [import("@prosekit/core").Extension<{
1264
+ }>]>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Extension<import("@prosekit/core").ExtensionTyping<any, any, any>>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").Union<readonly [import("@prosekit/core").Extension<{
1230
1265
  Commands: {
1231
1266
  insertSoftBreak: [];
1232
1267
  };
@@ -1639,4 +1674,4 @@ export declare function getSelectedText(state: EditorState): string;
1639
1674
  */
1640
1675
  export declare function getVirtualElementFromRange(view: EditorView, range: PositionRange): VirtualElement;
1641
1676
  //#endregion
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 };
1677
+ 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 XPostMediaClickHandler, type XPostResolver, type YouTubeVideoClickHandler, type YouTubeVideoResolver, defineCodeBlockPreviewPlugin, definePlaceholder, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
package/dist/index.js CHANGED
@@ -34,8 +34,8 @@ import { defineListCommands, defineListDropIndicator, defineListKeymap, defineLi
34
34
  import { chainCommands, lift, newlineInCode, splitBlock } from "@prosekit/pm/commands";
35
35
  import { closeHistory } from "@prosekit/pm/history";
36
36
  import { defineHorizontalRule } from "@prosekit/extensions/horizontal-rule";
37
- import { registerXPost } from "@post-embed/elements/x";
38
- import { registerYouTubeVideo } from "@post-embed/elements/youtube";
37
+ import { X_POST_MEDIA_CLICK, registerXPost } from "@meowdown/embed/x";
38
+ import { YOUTUBE_VIDEO_CLICK, registerYouTubeVideo } from "@meowdown/embed/youtube";
39
39
  import { registerResizableHandleElement, registerResizableRootElement } from "@prosekit/web/resizable";
40
40
  import { fromSyndication } from "@post-embed/exporter/x/syndication";
41
41
  import { XPostSchema, YouTubeVideoSchema } from "@post-embed/schema";
@@ -3104,6 +3104,9 @@ function getClosestImagePreview(target) {
3104
3104
  if (!preview || preview.dataset.postEmbed != null) return;
3105
3105
  return preview;
3106
3106
  }
3107
+ function getPreviewImage(preview) {
3108
+ return preview.querySelector("img") ?? void 0;
3109
+ }
3107
3110
  function findImageAt(state, pos) {
3108
3111
  const range = getMarkRangeAt(state, pos, "mdImage");
3109
3112
  if (!range) return;
@@ -3164,6 +3167,7 @@ function defineImageClickHandler(getOnClick) {
3164
3167
  src: hit.src,
3165
3168
  alt: hit.alt,
3166
3169
  event,
3170
+ element: getPreviewImage(preview),
3167
3171
  mod: isModEvent(event)
3168
3172
  });
3169
3173
  return true;
@@ -3216,6 +3220,7 @@ function defineImageClickHandler(getOnClick) {
3216
3220
  src: hit.src,
3217
3221
  alt: hit.alt,
3218
3222
  event,
3223
+ element: getPreviewImage(preview),
3219
3224
  mod: isModEvent(event)
3220
3225
  });
3221
3226
  return true;
@@ -3593,6 +3598,16 @@ function defineHTMLComment() {
3593
3598
  });
3594
3599
  }
3595
3600
 
3601
+ //#endregion
3602
+ //#region src/utils/to-positive-number.ts
3603
+ /**
3604
+ * The value rounded to an integer, or nothing unless it is a finite number
3605
+ * above zero.
3606
+ */
3607
+ function toPositiveNumber(value) {
3608
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.round(value);
3609
+ }
3610
+
3596
3611
  //#endregion
3597
3612
  //#region src/extensions/magic-comment.ts
3598
3613
  const MAGIC_COMMENT_RE = /^<!--\s*(\{[\s\S]*?\})\s*-->/;
@@ -3623,9 +3638,6 @@ function parseMagicComment(comment) {
3623
3638
  snapshot
3624
3639
  };
3625
3640
  }
3626
- function toPositiveNumber(value) {
3627
- if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.round(value);
3628
- }
3629
3641
  /**
3630
3642
  * The canonical comment meowdown writes for the metadata. `--` inside a JSON
3631
3643
  * string becomes `--`: the inline comment rule of `@lezer/markdown`
@@ -3673,7 +3685,12 @@ const defaultResolveXPost = cached(async (url) => {
3673
3685
  const response = await fetch(X_POST_API + id);
3674
3686
  if (!response.ok) return;
3675
3687
  const json = await response.json();
3676
- return fromSyndication(json.data);
3688
+ const result = fromSyndication(json.data);
3689
+ if (result.issues) {
3690
+ console.warn(`[meowdown] Invalid X post data for ${url}:`, result.issues);
3691
+ return;
3692
+ }
3693
+ return result.value;
3677
3694
  });
3678
3695
  const YOUTUBE_OEMBED_API = "https://www.youtube.com/oembed?format=json&url=";
3679
3696
  const defaultResolveYouTubeVideo = cached(async (url) => {
@@ -3964,14 +3981,14 @@ var ImageMarkView = class {
3964
3981
  const saved = this.#attrs.snapshot == null ? void 0 : parsePostEmbedSnapshot(this.#attrs.snapshot);
3965
3982
  if (kind === "x-post") {
3966
3983
  registerXPost();
3967
- const element = document.createElement("post-embed-x-post");
3984
+ const element = document.createElement("meowdown-embed-x");
3968
3985
  element.mediaUrlProtocols = this.#mediaUrlProtocols ?? null;
3969
3986
  element.resolver = this.#resolveXPost;
3970
3987
  element.url = src;
3971
3988
  return element;
3972
3989
  }
3973
3990
  registerYouTubeVideo();
3974
- const element = document.createElement("post-embed-youtube-video");
3991
+ const element = document.createElement("meowdown-embed-youtube");
3975
3992
  element.playback = "inline";
3976
3993
  element.data = saved?.kind === "youtube-video" ? saved.data : null;
3977
3994
  element.resolver = this.#persisting(kind, this.#resolveYouTubeVideo);
@@ -7599,10 +7616,47 @@ function defineWikilink() {
7599
7616
  });
7600
7617
  }
7601
7618
 
7619
+ //#endregion
7620
+ //#region src/extensions/x-post-media-click.ts
7621
+ const xPostMediaClickKey = new PluginKey("meowdown-x-post-media-click");
7622
+ /**
7623
+ * Call `onClick` when the user activates a photo or video inside an X post
7624
+ * card.
7625
+ */
7626
+ function defineXPostMediaClickHandler(getOnClick) {
7627
+ return definePlugin(new Plugin({
7628
+ key: xPostMediaClickKey,
7629
+ props: { handleDOMEvents: { [X_POST_MEDIA_CLICK]: (view, event) => {
7630
+ const handler = getOnClick?.(view.state);
7631
+ if (!handler) return false;
7632
+ handler(event);
7633
+ return event.defaultPrevented;
7634
+ } } }
7635
+ }));
7636
+ }
7637
+
7638
+ //#endregion
7639
+ //#region src/extensions/youtube-video-click.ts
7640
+ const youTubeVideoClickKey = new PluginKey("meowdown-youtube-video-click");
7641
+ /**
7642
+ * Call `onClick` when the user activates the poster of a YouTube card.
7643
+ */
7644
+ function defineYouTubeVideoClickHandler(getOnClick) {
7645
+ return definePlugin(new Plugin({
7646
+ key: youTubeVideoClickKey,
7647
+ props: { handleDOMEvents: { [YOUTUBE_VIDEO_CLICK]: (view, event) => {
7648
+ const handler = getOnClick?.(view.state);
7649
+ if (!handler) return false;
7650
+ handler(event);
7651
+ return event.defaultPrevented;
7652
+ } } }
7653
+ }));
7654
+ }
7655
+
7602
7656
  //#endregion
7603
7657
  //#region src/extensions/extension.ts
7604
7658
  function defineEditorExtensionImpl(options) {
7605
- return union(defineMeowdownParagraph(), defineDoc(), defineDocFrontmatterAttr(), defineText(), defineBlockquote(), defineMeowdownList(), defineHeading(), defineTable(), defineCodeBlock$1(), defineMeowdownHorizontalRule(), defineHTMLComment(), defineInlineMarks(), defineEditorConfig(options), defineImage(getEditorConfig), defineFileView(getEditorConfig), defineModClickPrevention(), defineFileClickHandler((state) => getEditorConfig(state).onFileClick), defineImageClickHandler((state) => getEditorConfig(state).onImageClick), defineWikilinkClickHandler((state) => getEditorConfig(state).onWikilinkClick), defineTagClickHandler((state) => getEditorConfig(state).onTagClick), defineLinkClickHandler((state) => getEditorConfig(state).onLinkClick), defineFollowLinkHandler(getEditorConfig), defineExitBoundaryHandler((state) => getEditorConfig(state).onExitBoundary), defineFilePaste(getEditorConfig), defineEmbedPaste((state) => !!getEditorConfig(state).embedPaste), defineLinkPaste((state) => !!getEditorConfig(state).linkPaste), defineBulletAfterHeading((state) => !!getEditorConfig(state).bulletAfterHeading), defineSubstitution((state) => !!getEditorConfig(state).substitution), defineWikilinkTrigger((state) => !!getEditorConfig(state).wikilinkEnabled), definePlaceholder$1({
7659
+ return union(defineMeowdownParagraph(), defineDoc(), defineDocFrontmatterAttr(), defineText(), defineBlockquote(), defineMeowdownList(), defineHeading(), defineTable(), defineCodeBlock$1(), defineMeowdownHorizontalRule(), defineHTMLComment(), defineInlineMarks(), defineEditorConfig(options), defineImage(getEditorConfig), defineFileView(getEditorConfig), defineModClickPrevention(), defineFileClickHandler((state) => getEditorConfig(state).onFileClick), defineImageClickHandler((state) => getEditorConfig(state).onImageClick), defineXPostMediaClickHandler((state) => getEditorConfig(state).onXPostMediaClick), defineYouTubeVideoClickHandler((state) => getEditorConfig(state).onYouTubeVideoClick), defineWikilinkClickHandler((state) => getEditorConfig(state).onWikilinkClick), defineTagClickHandler((state) => getEditorConfig(state).onTagClick), defineLinkClickHandler((state) => getEditorConfig(state).onLinkClick), defineFollowLinkHandler(getEditorConfig), defineExitBoundaryHandler((state) => getEditorConfig(state).onExitBoundary), defineFilePaste(getEditorConfig), defineEmbedPaste((state) => !!getEditorConfig(state).embedPaste), defineLinkPaste((state) => !!getEditorConfig(state).linkPaste), defineBulletAfterHeading((state) => !!getEditorConfig(state).bulletAfterHeading), defineSubstitution((state) => !!getEditorConfig(state).substitution), defineWikilinkTrigger((state) => !!getEditorConfig(state).wikilinkEnabled), definePlaceholder$1({
7606
7660
  placeholder: (state) => {
7607
7661
  const placeholder = getEditorConfig(state).placeholder;
7608
7662
  return typeof placeholder === "function" ? placeholder(state) : placeholder ?? "";
@@ -8987,4 +9041,4 @@ function getVirtualElementFromRange(view, range) {
8987
9041
  }
8988
9042
 
8989
9043
  //#endregion
8990
- 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 };
9044
+ 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, defineXPostMediaClickHandler, defineYouTubeVideoClickHandler, 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
@@ -148,63 +148,74 @@
148
148
  display: none;
149
149
  }
150
150
 
151
- @property --post-embed-color {
151
+ @property --meowdown-embed-color {
152
152
  syntax: "*";
153
153
  inherits: true
154
154
  }
155
155
 
156
- @property --post-embed-background {
156
+ @property --meowdown-embed-background {
157
157
  syntax: "*";
158
158
  inherits: true
159
159
  }
160
160
 
161
- @property --post-embed-border-color {
161
+ @property --meowdown-embed-border-color {
162
162
  syntax: "*";
163
163
  inherits: true
164
164
  }
165
165
 
166
- @property --post-embed-radius {
166
+ @property --meowdown-embed-radius {
167
167
  syntax: "*";
168
168
  inherits: true
169
169
  }
170
170
 
171
- @property --post-embed-padding {
171
+ @property --meowdown-embed-padding {
172
172
  syntax: "*";
173
173
  inherits: true
174
174
  }
175
175
 
176
- @property --post-embed-muted-color {
176
+ @property --meowdown-embed-muted-color {
177
177
  syntax: "*";
178
178
  inherits: true
179
179
  }
180
180
 
181
- @property --post-embed-link-color {
181
+ @property --meowdown-embed-link-color {
182
182
  syntax: "*";
183
183
  inherits: true
184
184
  }
185
185
 
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 {
186
+ [data-meowdown-embed="x"] [data-root], [data-meowdown-embed="x"] [data-root] *, [data-meowdown-embed="x"] [data-root] :before, [data-meowdown-embed="x"] [data-root] :after {
187
187
  all: revert;
188
188
  box-sizing: border-box;
189
189
  }
190
190
 
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);
191
+ [data-meowdown-embed="x"] {
192
+ --_hairline: var(--meowdown-embed-border-color, color-mix(in srgb, currentColor 14%, transparent));
193
+ --_muted: var(--meowdown-embed-muted-color, color-mix(in srgb, currentColor 55%, transparent));
194
+ --_link: var(--meowdown-embed-link-color, #1d9bf0);
195
195
  --_tint: color-mix(in srgb, currentColor 5%, transparent);
196
+ --_media-height: 7.5rem;
197
+ width: fit-content;
198
+ max-width: min(28rem, 100%);
196
199
  font: inherit;
197
- color: var(--post-embed-color, inherit);
200
+ color: var(--meowdown-embed-color, inherit);
198
201
  text-decoration-skip-ink: none;
199
202
  display: block;
200
203
  }
201
204
 
202
- [data-post-embed="x-post"] [data-root] {
203
- color: var(--post-embed-color, inherit);
204
- background: var(--post-embed-background, transparent);
205
+ [data-meowdown-embed="x"] [data-root]:before {
206
+ content: "";
207
+ width: calc(18rem - 2 * var(--meowdown-embed-padding, 1rem) - 2px);
208
+ max-width: 100%;
209
+ height: 0;
210
+ display: block;
211
+ }
212
+
213
+ [data-meowdown-embed="x"] [data-root] {
214
+ color: var(--meowdown-embed-color, inherit);
215
+ background: var(--meowdown-embed-background, transparent);
205
216
  border: 1px solid var(--_hairline);
206
- border-radius: var(--post-embed-radius, .75rem);
207
- padding: var(--post-embed-padding, 1rem);
217
+ border-radius: var(--meowdown-embed-radius, .75rem);
218
+ padding: var(--meowdown-embed-padding, 1rem);
208
219
  letter-spacing: normal;
209
220
  text-align: start;
210
221
  text-transform: none;
@@ -266,7 +277,7 @@
266
277
  }
267
278
 
268
279
  & [data-avatar][data-shape="square"] {
269
- border-radius: .5rem;
280
+ border-radius: .375rem;
270
281
  }
271
282
 
272
283
  & [data-avatar][data-shape="hexagon"] {
@@ -290,31 +301,53 @@
290
301
 
291
302
  & [data-author-details] > bdi {
292
303
  color: var(--_muted);
304
+ font-size: .9375em;
293
305
  }
294
306
 
295
307
  & [data-author-details] > bdi > a {
296
308
  color: inherit;
297
309
  }
298
310
 
311
+ & [data-date] {
312
+ white-space: nowrap;
313
+ color: var(--_muted);
314
+ flex: none;
315
+ align-self: flex-start;
316
+ padding-inline-start: .25rem;
317
+ font-size: .8125em;
318
+ line-height: 1.3rem;
319
+ display: block;
320
+ }
321
+
322
+ & [data-date] > a {
323
+ color: inherit;
324
+ }
325
+
299
326
  & [data-reply-to] {
300
327
  color: var(--_muted);
301
328
  margin-block-start: .625rem;
302
- font-size: .9375em;
329
+ font-size: .875em;
303
330
  display: block;
304
331
  }
305
332
 
306
333
  & [data-body] {
307
- margin-block: .625rem 0;
334
+ margin-block: .75rem 0;
308
335
  font-size: 1em;
309
336
  line-height: 1.5;
310
337
  display: block;
311
338
  }
312
339
 
340
+ & [data-reply-to] + [data-body] {
341
+ margin-block-start: .375rem;
342
+ }
343
+
313
344
  & [data-text] {
314
345
  white-space: pre-wrap;
315
346
  }
316
347
 
317
348
  & [data-media] {
349
+ height: var(--_media-height);
350
+ max-width: calc(2 * var(--_media-height));
318
351
  background: var(--_hairline);
319
352
  border-radius: .5rem;
320
353
  grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -324,48 +357,113 @@
324
357
  overflow: hidden;
325
358
  }
326
359
 
327
- & [data-media][data-count="1"] {
328
- grid-template-columns: minmax(0, 1fr);
329
- }
330
-
331
360
  & [data-media-item] {
332
361
  min-width: 0;
333
362
  display: block;
363
+ position: relative;
334
364
  overflow: hidden;
335
365
  }
336
366
 
367
+ & [data-media-item]:after {
368
+ content: "";
369
+ border-radius: inherit;
370
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 10%, transparent);
371
+ pointer-events: none;
372
+ position: absolute;
373
+ inset: 0;
374
+ }
375
+
337
376
  & [data-media-item] > a {
338
377
  height: 100%;
339
378
  display: block;
340
379
  }
341
380
 
342
- & [data-media-item] img, & [data-media-item] video {
343
- object-fit: contain;
381
+ & [data-media-item] > [data-poster] {
344
382
  background: var(--_tint);
345
383
  width: 100%;
346
- height: auto;
347
- max-height: 32rem;
348
- display: block;
384
+ height: 100%;
385
+ font: inherit;
386
+ color: inherit;
387
+ cursor: pointer;
388
+ border: 0;
389
+ padding: 0;
390
+ position: relative;
349
391
  }
350
392
 
351
- & [data-media]:not([data-count="1"]) [data-media-item] img {
352
- aspect-ratio: 1;
393
+ & [data-play] {
394
+ background: #0009;
395
+ border-radius: 50%;
396
+ width: 2.25rem;
397
+ height: 2.25rem;
398
+ position: absolute;
399
+ inset: 50% auto auto 50%;
400
+ translate: -50% -50%;
401
+ }
402
+
403
+ & [data-play]:after {
404
+ content: "";
405
+ border-block: .375rem solid #0000;
406
+ border-inline-start: .6rem solid #fff;
407
+ position: absolute;
408
+ inset: 50% auto auto 54%;
409
+ translate: -50% -50%;
410
+ }
411
+
412
+ & [data-media-item] img, & [data-media-item] video {
353
413
  object-fit: cover;
414
+ background: var(--_tint);
415
+ width: 100%;
354
416
  height: 100%;
417
+ display: block;
418
+ }
419
+
420
+ & [data-media-item][data-orientation="portrait"] :is(img, video) {
421
+ object-position: center 30%;
355
422
  }
356
423
 
357
424
  & [data-media][data-count="3"] [data-media-item]:first-child {
358
425
  grid-row: span 2;
359
426
  }
360
427
 
428
+ & [data-media]:is([data-count="1"], :has(video)) {
429
+ background: none;
430
+ border-radius: 0;
431
+ max-width: none;
432
+ height: auto;
433
+ display: block;
434
+ overflow: visible;
435
+ }
436
+
437
+ & [data-media]:is([data-count="1"], :has(video)) > [data-media-item] {
438
+ width: calc(var(--_media-height) * (var(--_ratio, 16 / 9)));
439
+ max-width: 100%;
440
+ aspect-ratio: var(--_ratio, 16 / 9);
441
+ border-radius: .5rem;
442
+ }
443
+
444
+ & [data-media]:has(video) > [data-media-item] + [data-media-item] {
445
+ margin-block-start: .375rem;
446
+ }
447
+
448
+ & [data-media-item]:has( > video) {
449
+ --_media-height: 20rem;
450
+ }
451
+
452
+ & [data-media-item]:has( > [data-media-error]:not([hidden])) {
453
+ aspect-ratio: auto;
454
+ width: auto;
455
+ }
456
+
361
457
  & [data-media-unavailable], & [data-media-error] {
362
458
  color: var(--_muted);
363
459
  background: var(--_tint);
460
+ border-radius: .5rem;
364
461
  padding: .75rem 1rem;
365
462
  display: block;
366
463
  }
367
464
 
368
465
  & [data-quoted] {
466
+ --_media-height: 5rem;
369
467
  border: 1px solid var(--_hairline);
370
468
  border-radius: .5rem;
371
469
  margin-block-start: .75rem;
@@ -373,59 +471,119 @@
373
471
  display: block;
374
472
  }
375
473
 
376
- & [data-quoted] [data-author] {
377
- gap: .5rem;
378
- }
379
-
380
474
  & [data-quoted] [data-avatar] {
381
475
  width: 1.375rem;
382
476
  height: 1.375rem;
383
477
  }
384
478
 
385
479
  & [data-quoted] [data-author-details] {
386
- flex-wrap: wrap;
387
480
  align-items: baseline;
388
481
  gap: 0 .35rem;
482
+ line-height: 1.375rem;
389
483
  display: flex;
390
484
  }
391
485
 
486
+ & [data-quoted] [data-author-name], & [data-quoted] [data-author-details] > bdi {
487
+ white-space: nowrap;
488
+ text-overflow: ellipsis;
489
+ min-width: 0;
490
+ display: block;
491
+ overflow: hidden;
492
+ }
493
+
494
+ & [data-quoted] [data-author-name] {
495
+ flex: 0 auto;
496
+ }
497
+
498
+ & [data-quoted] [data-author-details] > bdi {
499
+ flex: 0 100 auto;
500
+ min-width: 2.5rem;
501
+ font-size: .9375em;
502
+ }
503
+
504
+ & [data-quoted] [data-date] {
505
+ align-self: center;
506
+ }
507
+
392
508
  & [data-quoted] [data-body] {
393
- margin-block-start: .375rem;
509
+ -webkit-line-clamp: 3;
510
+ line-clamp: 3;
511
+ -webkit-box-orient: vertical;
512
+ margin-block-start: .25rem;
394
513
  font-size: .9375em;
514
+ display: -webkit-box;
515
+ overflow: hidden;
395
516
  }
396
517
 
397
518
  & [data-quoted] [data-media] {
398
519
  border-radius: .375rem;
399
- }
400
-
401
- & [data-quoted] [data-footer] {
402
520
  margin-block-start: .5rem;
403
- font-size: .8125em;
404
521
  }
405
522
 
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;
523
+ & [data-quoted] [data-play] {
524
+ scale: .75;
414
525
  }
415
526
 
416
- & [data-footer] > a {
417
- color: inherit;
527
+ & [data-quoted]:has( > [data-media]):not(:has( > [data-media] [data-poster], > [data-media] video)) {
528
+ grid-template-columns: minmax(0, 1fr) auto;
529
+ grid-template-areas: "head head"
530
+ "body media"
531
+ "foot foot";
532
+ column-gap: .75rem;
533
+ display: grid;
534
+
535
+ & > [data-author] {
536
+ grid-area: head;
537
+ }
538
+
539
+ & > [data-body] {
540
+ grid-area: body;
541
+ }
542
+
543
+ & > [data-footer] {
544
+ grid-area: foot;
545
+ }
546
+
547
+ & > [data-media] {
548
+ grid-area: media;
549
+ width: 4rem;
550
+ height: 4rem;
551
+ margin-block-start: .375rem;
552
+ display: block;
553
+ position: relative;
554
+ }
555
+
556
+ & > [data-media] > [data-media-item] {
557
+ width: 100%;
558
+ height: 100%;
559
+ }
560
+
561
+ & > [data-media] > [data-media-item]:nth-child(n+2) {
562
+ display: none;
563
+ }
564
+
565
+ & > [data-media]:not([data-count="1"]):after {
566
+ content: attr(data-count);
567
+ text-align: center;
568
+ color: #fff;
569
+ pointer-events: none;
570
+ background: #0000009e;
571
+ border-radius: .625rem;
572
+ min-width: 1.25rem;
573
+ padding: 0 .3125rem;
574
+ font-size: .6875rem;
575
+ font-weight: 600;
576
+ line-height: 1.25rem;
577
+ position: absolute;
578
+ inset: auto .25rem .25rem auto;
579
+ }
418
580
  }
419
581
 
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;
582
+ & [data-footer] {
583
+ color: var(--_muted);
584
+ margin-block-start: .5rem;
585
+ font-size: .8125em;
586
+ display: block;
429
587
  }
430
588
 
431
589
  & [data-edited] {
@@ -437,16 +595,16 @@
437
595
  }
438
596
  }
439
597
 
440
- @layer post-embed {
441
- :where([data-post-embed="youtube-video"]) {
442
- --_hairline: var(--post-embed-border-color, color-mix(in srgb, currentColor 15%, transparent));
443
- --_muted: var(--post-embed-muted-color, color-mix(in srgb, currentColor 58%, transparent));
444
- --_link: var(--post-embed-link-color, #1d9bf0);
445
- --_radius: var(--post-embed-radius, 1rem);
446
- --_page: var(--post-embed-background, Canvas);
598
+ @layer meowdown-embed {
599
+ :where([data-meowdown-embed="youtube"]) {
600
+ --_hairline: var(--meowdown-embed-border-color, color-mix(in srgb, currentColor 15%, transparent));
601
+ --_muted: var(--meowdown-embed-muted-color, color-mix(in srgb, currentColor 58%, transparent));
602
+ --_link: var(--meowdown-embed-link-color, #1d9bf0);
603
+ --_radius: var(--meowdown-embed-radius, 1rem);
604
+ --_page: var(--meowdown-embed-background, Canvas);
447
605
  --_play: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 68 48'%3E%3Cpath d='M66.52 7.74c-.78-2.93-2.49-5.41-5.42-6.19C55.79.13 34 0 34 0S12.21.13 6.9 1.55C3.97 2.33 2.27 4.81 1.48 7.74.06 13.05 0 24 0 24s.06 10.95 1.48 16.26c.78 2.93 2.49 5.41 5.42 6.19C12.21 47.87 34 48 34 48s21.79-.13 27.1-1.55c2.93-.78 4.64-3.26 5.42-6.19C67.94 34.95 68 24 68 24S67.94 13.05 66.52 7.74z' fill='%23f00'/%3E%3Cpath d='M45 24 27 14v20z' fill='%23fff'/%3E%3C/svg%3E");
448
606
  font: inherit;
449
- color: var(--post-embed-color, inherit);
607
+ color: var(--meowdown-embed-color, inherit);
450
608
  display: block;
451
609
 
452
610
  & :where([data-root]) {
@@ -551,7 +709,7 @@
551
709
  & :where([data-fallback]) {
552
710
  border: 1px solid var(--_hairline);
553
711
  border-radius: var(--_radius);
554
- padding: var(--post-embed-padding, 1rem);
712
+ padding: var(--meowdown-embed-padding, 1rem);
555
713
  }
556
714
 
557
715
  & :where([data-fallback] [data-details]) {
@@ -1075,9 +1233,12 @@
1075
1233
  padding: 2px 6px;
1076
1234
  }
1077
1235
 
1078
- .ProseMirror .md-image-view-preview post-embed-x-post, .ProseMirror .md-image-view-preview post-embed-youtube-video {
1236
+ .ProseMirror .md-image-view-preview meowdown-embed-x, .ProseMirror .md-image-view-preview meowdown-embed-youtube {
1079
1237
  -webkit-user-select: text;
1080
1238
  user-select: text;
1239
+ }
1240
+
1241
+ .ProseMirror .md-image-view-preview meowdown-embed-youtube {
1081
1242
  max-width: 550px;
1082
1243
  display: block;
1083
1244
  }
@@ -1095,7 +1256,7 @@
1095
1256
  height: auto !important;
1096
1257
  }
1097
1258
 
1098
- .ProseMirror .md-embed-resizable post-embed-youtube-video {
1259
+ .ProseMirror .md-embed-resizable meowdown-embed-youtube {
1099
1260
  width: 100%;
1100
1261
  max-width: none;
1101
1262
  }
@@ -1246,7 +1407,7 @@
1246
1407
  }
1247
1408
 
1248
1409
  & .md-image-view-preview[data-post-embed] {
1249
- border-radius: var(--post-embed-radius, .75rem);
1410
+ border-radius: var(--meowdown-embed-radius, .75rem);
1250
1411
  overflow: visible;
1251
1412
  }
1252
1413
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/core",
3
3
  "type": "module",
4
- "version": "0.72.1",
4
+ "version": "0.74.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,16 +25,16 @@
25
25
  "@codemirror/language-data": "^6.5.2",
26
26
  "@floating-ui/dom": "^1.8.0",
27
27
  "@lezer/highlight": "^1.2.3",
28
+ "@meowdown/embed": "^0.2.0",
28
29
  "@meowdown/markdown": "^0.72.0",
29
30
  "@ocavue/utils": "^1.8.0",
30
- "@post-embed/elements": "^0.5.0",
31
- "@post-embed/exporter": "^0.4.1",
32
- "@post-embed/schema": "^0.5.0",
33
- "@post-embed/types": "^0.4.0",
34
- "@prosekit/core": "^0.13.2",
35
- "@prosekit/extensions": "^0.18.2",
36
- "@prosekit/pm": "^0.1.19",
37
- "@prosekit/web": "^0.9.2",
31
+ "@post-embed/exporter": "^0.5.0",
32
+ "@post-embed/schema": "^0.5.2",
33
+ "@post-embed/types": "^0.5.0",
34
+ "@prosekit/core": "^0.13.3",
35
+ "@prosekit/extensions": "^0.18.3",
36
+ "@prosekit/pm": "^0.1.20",
37
+ "@prosekit/web": "^0.9.3",
38
38
  "hast-util-to-mdast": "^10.1.2",
39
39
  "katex": "^0.18.7",
40
40
  "lru.min": "^1.1.5",