@meowdown/core 0.72.0 → 0.73.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,7 @@ 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
11
  import { render } from "katex";
12
12
  import { XPost, YouTubeVideo } from "@post-embed/types";
13
13
  import { VirtualElement } from "@floating-ui/dom";
@@ -656,6 +656,11 @@ interface ImageClickPayload {
656
656
  * from it; a touch surface delivers the `touchend` instead of a click.
657
657
  */
658
658
  event: MouseEvent | TouchEvent | KeyboardEvent;
659
+ /**
660
+ * The rendered `<img>` of a click or tap, for example to zoom a lightbox
661
+ * from. A key press has none.
662
+ */
663
+ element?: HTMLImageElement | undefined;
659
664
  /**
660
665
  * Whether the platform's mod key (`Command` on Apple, `Ctrl` elsewhere) was held
661
666
  * beyond the gesture that triggered the activation.
@@ -823,7 +828,7 @@ interface ImageOptions {
823
828
  mediaUrlProtocols?: string[];
824
829
  /**
825
830
  * Resolve the data behind a YouTube video URL, rendered as a
826
- * `post-embed-youtube-video` card. Defaults to `defaultResolveYouTubeVideo`,
831
+ * `meowdown-embed-youtube` card. Defaults to `defaultResolveYouTubeVideo`,
827
832
  * which reads YouTube's oEmbed endpoint.
828
833
  */
829
834
  resolveYouTubeVideo?: YouTubeVideoResolver;
@@ -1070,10 +1075,25 @@ export declare function inlineTextToMarkChunksWithContext(marks: TypedMarkBuilde
1070
1075
  */
1071
1076
  type MarkMode = 'hide' | 'focus' | 'show';
1072
1077
  //#endregion
1078
+ //#region src/extensions/x-post-media-click.d.ts
1079
+ /**
1080
+ * Receives the `meowdown-embed-media-click` event of an X post card. Its
1081
+ * `detail` holds the activated photo or video, its sibling items, and the
1082
+ * rendered thumbnail element. Call `event.preventDefault()` to cancel the
1083
+ * card's own default (open the photo URL, play the video in place).
1084
+ */
1085
+ type XPostMediaClickHandler = (event: XPostMediaClickEvent) => void;
1086
+ /**
1087
+ * Call `onClick` when the user activates a photo or video inside an X post
1088
+ * card.
1089
+ */
1090
+ export declare function defineXPostMediaClickHandler(getOnClick?: (state: EditorState) => XPostMediaClickHandler | undefined): PlainExtension;
1091
+ //#endregion
1073
1092
  //#region src/extensions/editor-config-types.d.ts
1074
1093
  interface EditorConfig extends InlineMarkOptions, FollowLinkHandlers, FilePasteOptions, FileViewOptions, ImageOptions {
1075
1094
  markMode?: MarkMode;
1076
1095
  onExitBoundary?: ExitBoundaryHandler;
1096
+ onXPostMediaClick?: XPostMediaClickHandler;
1077
1097
  embedPaste?: boolean;
1078
1098
  linkPaste?: boolean;
1079
1099
  bulletAfterHeading?: boolean;
@@ -1162,7 +1182,7 @@ declare function defineEditorExtensionImpl(options: EditorExtensionOptions): imp
1162
1182
  fenceLength?: number | null;
1163
1183
  };
1164
1184
  };
1165
- }>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension]>, MeowdownHorizontalRuleExtension, import("@prosekit/core").Extension<{
1185
+ }>, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension, import("@prosekit/core").PlainExtension]>, MeowdownHorizontalRuleExtension, import("@prosekit/core").Extension<{
1166
1186
  Nodes: {
1167
1187
  htmlComment: MeowdownHTMLCommentAttrs;
1168
1188
  };
@@ -1226,7 +1246,7 @@ declare function defineEditorExtensionImpl(options: EditorExtensionOptions): imp
1226
1246
  Marks: {
1227
1247
  mdPack: MdPackAttrs;
1228
1248
  };
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").Union<readonly [import("@prosekit/core").Extension<{
1249
+ }>]>, 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
1250
  Commands: {
1231
1251
  insertSoftBreak: [];
1232
1252
  };
@@ -1409,7 +1429,7 @@ export declare const EDITOR_KEY_BINDINGS: {
1409
1429
  readonly 'Mod-5': "Heading 5";
1410
1430
  readonly 'Mod-6': "Heading 6";
1411
1431
  readonly 'Mod-.': "Fold or unfold a bullet";
1412
- readonly 'Shift-Enter': "Insert a line break";
1432
+ readonly 'Shift-Enter': "Insert a line break, or leave a code block from its end";
1413
1433
  readonly 'Mod-Enter': "Follow the link under the caret, or cycle a checkbox task";
1414
1434
  readonly 'Mod-Shift-Enter': "Cycle a circle checkbox task";
1415
1435
  readonly 'Mod-Shift-7': "Ordered list";
@@ -1639,4 +1659,4 @@ export declare function getSelectedText(state: EditorState): string;
1639
1659
  */
1640
1660
  export declare function getVirtualElementFromRange(view: EditorView, range: PositionRange): VirtualElement;
1641
1661
  //#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 };
1662
+ 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 YouTubeVideoResolver, defineCodeBlockPreviewPlugin, definePlaceholder, defineSearchStatusHandler, getSearchStatus, isCodeBlockPreviewHiddenDecoration, withPriority };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Priority, Priority as Priority$1, createMarkBuilders, createNodeBuilders, defineBaseCommands, defineBaseKeymap, defineClipboardSerializer, defineCommands, defineHistory, defineKeymap, defineMarkSpec, defineMarkView, defineNodeAttr, defineNodeSpec, definePlugin, findMarkRange, getMarkRange, getMarkType, getNodeType, isAllSelection, isApple, isAtBlockStart, isNodeSelection, isTextSelection, setBlockType, toggleNode, union, unsetBlockType, withPriority, withPriority as withPriority$1, withSkipCodeBlock } from "@prosekit/core";
1
+ import { Priority, Priority as Priority$1, createMarkBuilders, createNodeBuilders, defaultBlockAt, defineBaseCommands, defineBaseKeymap, defineClipboardSerializer, defineCommands, defineHistory, defineKeymap, defineMarkSpec, defineMarkView, defineNodeAttr, defineNodeSpec, definePlugin, findMarkRange, getMarkRange, getMarkType, getNodeType, isAllSelection, isApple, isAtBlockStart, isNodeSelection, isTextSelection, setBlockType, toggleNode, union, unsetBlockType, withPriority, withPriority as withPriority$1, withSkipCodeBlock } from "@prosekit/core";
2
2
  import { defineCodeBlock, defineCodeBlockHighlight, defineCodeBlockPreviewPlugin, isCodeBlockPreviewHiddenDecoration } from "@prosekit/extensions/code-block";
3
3
  import { definePlaceholder, definePlaceholder as definePlaceholder$1 } from "@prosekit/extensions/placeholder";
4
4
  import { NodeSelection, Plugin, PluginKey, Selection, TextSelection } from "@prosekit/pm/state";
@@ -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 { 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";
@@ -602,6 +602,41 @@ function defineBulletAfterHeading(enabled) {
602
602
  } }), Priority$1.high);
603
603
  }
604
604
 
605
+ //#endregion
606
+ //#region src/extensions/click-below.ts
607
+ const clickBelowKey = new PluginKey("meowdown-click-below");
608
+ function acceptsCaretAtEnd(node) {
609
+ return node.isTextblock && !node.type.spec.code;
610
+ }
611
+ function handleMouseDown(view, event) {
612
+ if (event.target !== view.dom) return false;
613
+ if (event.button !== 0 || !view.editable) return false;
614
+ const { doc } = view.state;
615
+ const lastBlock = doc.lastChild;
616
+ if (!lastBlock || acceptsCaretAtEnd(lastBlock)) return false;
617
+ const lastBlockDOM = view.nodeDOM(doc.content.size - lastBlock.nodeSize);
618
+ if (!(lastBlockDOM instanceof HTMLElement)) return false;
619
+ if (event.clientY <= lastBlockDOM.getBoundingClientRect().bottom) return false;
620
+ const block = defaultBlockAt(doc.contentMatchAt(doc.childCount))?.createAndFill();
621
+ if (!block) return false;
622
+ event.preventDefault();
623
+ const end = doc.content.size;
624
+ const tr = view.state.tr.insert(end, block);
625
+ view.dispatch(tr.setSelection(TextSelection.create(tr.doc, end + 1)).scrollIntoView());
626
+ view.focus();
627
+ return true;
628
+ }
629
+ /**
630
+ * A press below the last block appends an empty paragraph and puts the caret
631
+ * in it, when that block would otherwise keep the caret inside itself.
632
+ */
633
+ function defineClickBelow() {
634
+ return definePlugin(new Plugin({
635
+ key: clickBelowKey,
636
+ props: { handleDOMEvents: { mousedown: handleMouseDown } }
637
+ }));
638
+ }
639
+
605
640
  //#endregion
606
641
  //#region src/converters/html-to-md.ts
607
642
  /**
@@ -2222,6 +2257,38 @@ function getCodeTokens(code, language) {
2222
2257
  return loadLanguageSupport(trimmed).then((loaded) => loaded ? tokenize(code, loaded) : []);
2223
2258
  }
2224
2259
 
2260
+ //#endregion
2261
+ //#region src/extensions/code-block-exit.ts
2262
+ /**
2263
+ * With the caret at the end of a code block, move it into the block below when
2264
+ * that block is an empty paragraph, and into a new default block otherwise.
2265
+ */
2266
+ const exitCodeBlockAtEnd = (state, dispatch) => {
2267
+ const { $head, empty } = state.selection;
2268
+ if (!empty) return false;
2269
+ const codeBlock = $head.parent;
2270
+ if (!codeBlock.type.spec.code || $head.parentOffset !== codeBlock.content.size) return false;
2271
+ const container = $head.node(-1);
2272
+ const indexAfter = $head.indexAfter(-1);
2273
+ const after = $head.after();
2274
+ const next = container.maybeChild(indexAfter);
2275
+ if (next && isNodeOfType(next, "paragraph") && next.content.size === 0) {
2276
+ dispatch?.(state.tr.setSelection(TextSelection.create(state.doc, after + 1)).scrollIntoView());
2277
+ return true;
2278
+ }
2279
+ const type = defaultBlockAt(container.contentMatchAt(indexAfter));
2280
+ const block = type?.createAndFill();
2281
+ if (!type || !block || !container.canReplaceWith(indexAfter, indexAfter, type)) return false;
2282
+ if (dispatch) {
2283
+ const tr = state.tr.insert(after, block);
2284
+ dispatch(tr.setSelection(TextSelection.create(tr.doc, after + 1)).scrollIntoView());
2285
+ }
2286
+ return true;
2287
+ };
2288
+ function defineCodeBlockExitKeymap() {
2289
+ return defineKeymap({ "Mod-Enter": exitCodeBlockAtEnd });
2290
+ }
2291
+
2225
2292
  //#endregion
2226
2293
  //#region src/extensions/code-block.ts
2227
2294
  function defineFenceStyleAttr() {
@@ -2279,7 +2346,7 @@ function defineDollarFenceEnterRule() {
2279
2346
  });
2280
2347
  }
2281
2348
  function defineCodeBlock$1() {
2282
- return union(defineCodeBlock(), defineFenceStyleAttr(), defineFenceLengthAttr(), defineTildeFenceInputRule(), defineTildeFenceEnterRule(), defineDollarFenceEnterRule());
2349
+ return union(defineCodeBlock(), defineFenceStyleAttr(), defineFenceLengthAttr(), defineTildeFenceInputRule(), defineTildeFenceEnterRule(), defineDollarFenceEnterRule(), defineCodeBlockExitKeymap());
2283
2350
  }
2284
2351
 
2285
2352
  //#endregion
@@ -3037,6 +3104,9 @@ function getClosestImagePreview(target) {
3037
3104
  if (!preview || preview.dataset.postEmbed != null) return;
3038
3105
  return preview;
3039
3106
  }
3107
+ function getPreviewImage(preview) {
3108
+ return preview.querySelector("img") ?? void 0;
3109
+ }
3040
3110
  function findImageAt(state, pos) {
3041
3111
  const range = getMarkRangeAt(state, pos, "mdImage");
3042
3112
  if (!range) return;
@@ -3097,6 +3167,7 @@ function defineImageClickHandler(getOnClick) {
3097
3167
  src: hit.src,
3098
3168
  alt: hit.alt,
3099
3169
  event,
3170
+ element: getPreviewImage(preview),
3100
3171
  mod: isModEvent(event)
3101
3172
  });
3102
3173
  return true;
@@ -3149,6 +3220,7 @@ function defineImageClickHandler(getOnClick) {
3149
3220
  src: hit.src,
3150
3221
  alt: hit.alt,
3151
3222
  event,
3223
+ element: getPreviewImage(preview),
3152
3224
  mod: isModEvent(event)
3153
3225
  });
3154
3226
  return true;
@@ -3526,6 +3598,16 @@ function defineHTMLComment() {
3526
3598
  });
3527
3599
  }
3528
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
+
3529
3611
  //#endregion
3530
3612
  //#region src/extensions/magic-comment.ts
3531
3613
  const MAGIC_COMMENT_RE = /^<!--\s*(\{[\s\S]*?\})\s*-->/;
@@ -3556,9 +3638,6 @@ function parseMagicComment(comment) {
3556
3638
  snapshot
3557
3639
  };
3558
3640
  }
3559
- function toPositiveNumber(value) {
3560
- if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.round(value);
3561
- }
3562
3641
  /**
3563
3642
  * The canonical comment meowdown writes for the metadata. `--` inside a JSON
3564
3643
  * string becomes `--`: the inline comment rule of `@lezer/markdown`
@@ -3606,7 +3685,12 @@ const defaultResolveXPost = cached(async (url) => {
3606
3685
  const response = await fetch(X_POST_API + id);
3607
3686
  if (!response.ok) return;
3608
3687
  const json = await response.json();
3609
- 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;
3610
3694
  });
3611
3695
  const YOUTUBE_OEMBED_API = "https://www.youtube.com/oembed?format=json&url=";
3612
3696
  const defaultResolveYouTubeVideo = cached(async (url) => {
@@ -3897,14 +3981,14 @@ var ImageMarkView = class {
3897
3981
  const saved = this.#attrs.snapshot == null ? void 0 : parsePostEmbedSnapshot(this.#attrs.snapshot);
3898
3982
  if (kind === "x-post") {
3899
3983
  registerXPost();
3900
- const element = document.createElement("post-embed-x-post");
3984
+ const element = document.createElement("meowdown-embed-x");
3901
3985
  element.mediaUrlProtocols = this.#mediaUrlProtocols ?? null;
3902
3986
  element.resolver = this.#resolveXPost;
3903
3987
  element.url = src;
3904
3988
  return element;
3905
3989
  }
3906
3990
  registerYouTubeVideo();
3907
- const element = document.createElement("post-embed-youtube-video");
3991
+ const element = document.createElement("meowdown-embed-youtube");
3908
3992
  element.playback = "inline";
3909
3993
  element.data = saved?.kind === "youtube-video" ? saved.data : null;
3910
3994
  element.resolver = this.#persisting(kind, this.#resolveYouTubeVideo);
@@ -7288,7 +7372,7 @@ function insertSoftBreak() {
7288
7372
  return softBreakCommand;
7289
7373
  }
7290
7374
  function defineSoftBreak() {
7291
- return union(defineCommands({ insertSoftBreak }), defineKeymap({ "Shift-Enter": softBreakCommand }));
7375
+ return union(defineCommands({ insertSoftBreak }), defineKeymap({ "Shift-Enter": chainCommands(exitCodeBlockAtEnd, softBreakCommand) }));
7292
7376
  }
7293
7377
 
7294
7378
  //#endregion
@@ -7532,10 +7616,29 @@ function defineWikilink() {
7532
7616
  });
7533
7617
  }
7534
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
+
7535
7638
  //#endregion
7536
7639
  //#region src/extensions/extension.ts
7537
7640
  function defineEditorExtensionImpl(options) {
7538
- 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({
7641
+ 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), 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({
7539
7642
  placeholder: (state) => {
7540
7643
  const placeholder = getEditorConfig(state).placeholder;
7541
7644
  return typeof placeholder === "function" ? placeholder(state) : placeholder ?? "";
@@ -7547,7 +7650,7 @@ function defineEditorExtensionImpl(options) {
7547
7650
  if (editorClassName) attributes.class += ` ${editorClassName}`;
7548
7651
  if (spellCheck != null) attributes.spellcheck = String(spellCheck);
7549
7652
  return attributes;
7550
- }), defineCodeBlockSyntaxHighlight(), defineCrossEditorDrag(), defineEscapeCollapse(), defineSoftBreak(), defineMoveBlock(), defineSelectDocBoundary(), defineInlineMarkPlugin(getEditorConfig), defineInlineToggle(), defineLinkCommands(), defineWikilink(), defineMath(), defineMarkMode(getMarkMode), defineClipboard(), defineScrollToSelection(), defineHiddenRunCaret(), defineSystemSubstitutionGuard(), defineAtomMarkNavigation({ marks: ATOM_SOURCE_MARK_NAMES.map((name) => ({
7653
+ }), defineCodeBlockSyntaxHighlight(), defineCrossEditorDrag(), defineClickBelow(), defineEscapeCollapse(), defineSoftBreak(), defineMoveBlock(), defineSelectDocBoundary(), defineInlineMarkPlugin(getEditorConfig), defineInlineToggle(), defineLinkCommands(), defineWikilink(), defineMath(), defineMarkMode(getMarkMode), defineClipboard(), defineScrollToSelection(), defineHiddenRunCaret(), defineSystemSubstitutionGuard(), defineAtomMarkNavigation({ marks: ATOM_SOURCE_MARK_NAMES.map((name) => ({
7551
7654
  name,
7552
7655
  modes: [
7553
7656
  "hide",
@@ -8340,7 +8443,7 @@ const EDITOR_KEY_BINDINGS = {
8340
8443
  "Mod-5": "Heading 5",
8341
8444
  "Mod-6": "Heading 6",
8342
8445
  "Mod-.": "Fold or unfold a bullet",
8343
- "Shift-Enter": "Insert a line break",
8446
+ "Shift-Enter": "Insert a line break, or leave a code block from its end",
8344
8447
  "Mod-Enter": "Follow the link under the caret, or cycle a checkbox task",
8345
8448
  "Mod-Shift-Enter": "Cycle a circle checkbox task",
8346
8449
  "Mod-Shift-7": "Ordered list",
@@ -8920,4 +9023,4 @@ function getVirtualElementFromRange(view, range) {
8920
9023
  }
8921
9024
 
8922
9025
  //#endregion
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 };
9026
+ 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, 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.0",
4
+ "version": "0.73.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,15 +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.1.0",
29
+ "@meowdown/markdown": "^0.72.0",
28
30
  "@ocavue/utils": "^1.8.0",
29
- "@post-embed/elements": "^0.5.0",
30
- "@post-embed/exporter": "^0.4.1",
31
- "@post-embed/schema": "^0.5.0",
32
- "@post-embed/types": "^0.4.0",
33
- "@prosekit/core": "^0.13.2",
34
- "@prosekit/extensions": "^0.18.2",
35
- "@prosekit/pm": "^0.1.19",
36
- "@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",
37
38
  "hast-util-to-mdast": "^10.1.2",
38
39
  "katex": "^0.18.7",
39
40
  "lru.min": "^1.1.5",
@@ -48,10 +49,10 @@
48
49
  "remark-stringify": "^11.0.0",
49
50
  "unicode-by-name": "^0.2.0",
50
51
  "unified": "^11.0.5",
51
- "valibot": "^1.5.0",
52
- "@meowdown/markdown": "^0.72.0"
52
+ "valibot": "^1.5.0"
53
53
  },
54
54
  "devDependencies": {
55
+ "@meowdown/vitest": "0.0.0",
55
56
  "@ocavue/tsconfig": "^0.7.1",
56
57
  "@tsdown/css": "^0.23.0",
57
58
  "@types/hast": "^3.0.5",
@@ -61,9 +62,7 @@
61
62
  "dedent": "^1.7.2",
62
63
  "diffable-html-snapshot": "^0.3.0",
63
64
  "tsdown": "^0.23.0",
64
- "vitest": "^5.0.1",
65
- "vitest-browser-commands": "^0.4.1",
66
- "@meowdown/vitest": "0.0.0"
65
+ "vitest": "^5.0.1"
67
66
  },
68
67
  "publishConfig": {
69
68
  "access": "public"