@meowdown/react 0.77.0 → 0.79.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/README.md CHANGED
@@ -58,16 +58,16 @@ export function App() {
58
58
 
59
59
  Common `MarkdownEditor` props:
60
60
 
61
- | Prop | What it does |
62
- | ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
63
- | `mode` | `'focus'` (default), `'show'`, or `'hide'`: how much Markdown syntax stays in view |
64
- | `searchQuery` / `onSearchChange` | Find in document, with `EditorHandle.findNext()` / `findPrevious()` |
65
- | `onWikilinkClick` / `onLinkClick` / `onTagClick` / `onImageClick` / `onFileClick` / `onXPostMediaClick` / `onYouTubeVideoClick` | Click handling for the rendered atoms |
66
- | `resolveImageUrl` / `resolveWikiEmbed` / `resolveWikilink` / `resolveFileLink` / `resolveFileInfo` | Resolve and classify local content |
67
- | `onFilePaste` | Persist pasted or dropped files |
68
- | `onSlashMenuSearch` / `onTagSearch` / `onWikilinkSearch` / `onSelectionMenuSearch` | Search menus for `/`, `#`, `[[`, and selection commands |
69
- | `readOnly` / `placeholder` / `blockHandle` / `caretGlide` / `embedPaste` / `linkPaste` / `bulletAfterHeading` | Behavior toggles |
70
- | `CodeBlockView` | Custom React node view component for code blocks |
61
+ | Prop | What it does |
62
+ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
63
+ | `mode` | `'focus'` (default), `'show'`, or `'hide'`: how much Markdown syntax stays in view |
64
+ | `searchQuery` / `onSearchChange` | Find in document, with `EditorHandle.findNext()` / `findPrevious()` |
65
+ | `onWikilinkClick` / `onLinkClick` / `onTagClick` / `onImageClick` / `onFileClick` / `onXPostMediaClick` / `onYouTubeVideoClick` | Click handling for the rendered atoms |
66
+ | `resolveImageUrl` / `resolveWikiEmbed` / `resolveWikilink` / `resolveFileLink` / `resolveFileInfo` | Resolve and classify local content |
67
+ | `onFilePaste` | Persist pasted or dropped files |
68
+ | `onSlashMenuSearch` / `onTagSearch` / `onWikilinkSearch` / `onSelectionMenuSearch` | Search menus for `/`, `#`, `[[`, and selection commands |
69
+ | `readOnly` / `placeholder` / `blockHandle` / `caretGlide` / `embedPaste` / `linkPaste` / `bulletAfterHeading` / `backspaceDeletesEmptyFirstBlock` | Behavior toggles |
70
+ | `CodeBlockView` | Custom React node view component for code blocks |
71
71
 
72
72
  Every prop, callback, and `EditorHandle` method is documented in the [API reference](https://npmx.dev/package-docs/@meowdown%2Freact/).
73
73
 
package/dist/index.d.ts CHANGED
@@ -495,6 +495,12 @@ interface EditorProps {
495
495
  * Off by default.
496
496
  */
497
497
  bulletAfterHeading?: boolean;
498
+ /**
499
+ * Pressing Backspace in an empty paragraph that is the document's first
500
+ * block deletes that paragraph, so the rest of the document moves up one
501
+ * line. The block after it keeps its type. Off by default.
502
+ */
503
+ backspaceDeletesEmptyFirstBlock?: boolean;
498
504
  /**
499
505
  * Replaces typed character sequences with their typographic equivalents,
500
506
  * e.g. `->` with `→` and `(c)` with `©`. On by default.
@@ -577,7 +583,7 @@ interface EditorProps {
577
583
  *
578
584
  * Callbacks and resolvers should be stable; pass them via `useCallback`.
579
585
  */
580
- export declare function MarkdownEditor({ mode, initialMarkdown, singleParagraph, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, resolveLinkPreview, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onFileClick, onFilePaste, onFileSaveError, onImageClick, onXPostMediaClick, onYouTubeVideoClick, embedPaste, linkPaste, bulletAfterHeading, substitution, frontmatter, blockHandle, caretGlide, placeholder, readOnly, spellCheck, searchQuery, onSearchChange, timeFormat, editorClassName, wrapperClassName, CodeBlockView, handleRef, children }: EditorProps): ReactElement;
586
+ export declare function MarkdownEditor({ mode, initialMarkdown, singleParagraph, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, resolveLinkPreview, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onFileClick, onFilePaste, onFileSaveError, onImageClick, onXPostMediaClick, onYouTubeVideoClick, embedPaste, linkPaste, bulletAfterHeading, backspaceDeletesEmptyFirstBlock, substitution, frontmatter, blockHandle, caretGlide, placeholder, readOnly, spellCheck, searchQuery, onSearchChange, timeFormat, editorClassName, wrapperClassName, CodeBlockView, handleRef, children }: EditorProps): ReactElement;
581
587
  //#endregion
582
588
  //#region src/components/markdown-view.d.ts
583
589
  /**
@@ -625,7 +631,7 @@ interface MarkdownViewProps {
625
631
  /**
626
632
  * Interpret content as one paragraph, without block syntax.
627
633
  */
628
- inline?: boolean;
634
+ singleParagraph?: boolean;
629
635
  /**
630
636
  * Reference definitions available outside this fragment.
631
637
  */
@@ -737,7 +743,7 @@ interface MarkdownViewProps {
737
743
  * Callbacks (`onWikilinkClick`, etc.) and resolvers should be stable; pass them via
738
744
  * `useCallback` to avoid re-rendering the whole tree.
739
745
  */
740
- export declare function MarkdownView({ markdown, inline, referenceDefinitions: suppliedDefinitions, markMode, frontmatter, interactive, expandCollapsed, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onWikilinkClick, onLinkClick, onImageClick, onXPostMediaClick, onYouTubeVideoClick, onFileClick, onTaskClick, className }: MarkdownViewProps): ReactElement;
746
+ export declare function MarkdownView({ markdown, singleParagraph, referenceDefinitions: suppliedDefinitions, markMode, frontmatter, interactive, expandCollapsed, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onWikilinkClick, onLinkClick, onImageClick, onXPostMediaClick, onYouTubeVideoClick, onFileClick, onTaskClick, className }: MarkdownViewProps): ReactElement;
741
747
  //#endregion
742
748
  //#region src/hooks/use-lightbox.d.ts
743
749
  /**
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { clsx } from "clsx/lite";
2
2
  import { Fragment, ViewTransition, cloneElement, createElement, memo, startTransition, useCallback, useDeferredValue, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
3
- import { buildFileMarkdown, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineCodeBlockPreviewPlugin, defineEditorExtension, defineLinkEditKeymap, defineLinkHoverHandler, definePendingReplacementHandler, defineSearchStatusHandler, defineSingleParagraph, defineVirtualCaret, defineWikilinkHoverHandler, dismissLinkHover, docToMarkdown, docToParagraphMarkdown, formatFileSize, getCodeTokens, getFileKind, getLinkText, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunksWithContext, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, paragraphMarkdownToDoc, parsePostEmbedSnapshot, renderMathInto, updateEditorConfig } from "@meowdown/core";
3
+ import { buildFileMarkdown, codeBlockLanguages, collectReferenceDefinitions, defaultResolveImageUrl, defaultResolveXPost, defaultResolveYouTubeVideo, defineCodeBlockPreviewPlugin, defineEditorExtension, defineLinkEditKeymap, defineLinkHoverHandler, definePendingReplacementHandler, defineSearchStatusHandler, defineVirtualCaret, defineWikilinkHoverHandler, dismissLinkHover, docToMarkdown, docToParagraphMarkdown, formatFileSize, getCodeTokens, getFileKind, getLinkText, getMarkBuilders, getPendingReplacement, getSearchStatus, getSelectedText, getTableColumnAlign, getTextblockDisplayText, getVirtualElementFromRange, inlineTextToMarkChunksWithContext, isCodeBlockPreviewHiddenDecoration, isLinkTextForHref, isModEvent, isNodeOfType, isReferenceDefinitionNode, isSelectionInTableCell, loadKaTeX, markdownToDoc, normalizeHref, paragraphMarkdownToDoc, parsePostEmbedSnapshot, renderMathInto, updateEditorConfig } from "@meowdown/core";
4
4
  import { clamp } from "@ocavue/utils";
5
5
  import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, defineUpdateHandler, isTextSelection, union } from "@prosekit/core";
6
6
  import { Selection, TextSelection } from "@prosekit/pm/state";
@@ -1884,7 +1884,7 @@ function findHeadingPosition(doc, fragment) {
1884
1884
  });
1885
1885
  return match;
1886
1886
  }
1887
- function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph = false, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, resolveLinkPreview, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onFileClick, onFilePaste, onFileSaveError, onImageClick, onXPostMediaClick, onYouTubeVideoClick, embedPaste, linkPaste, bulletAfterHeading, substitution = true, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, searchQuery = "", onSearchChange, timeFormat, editorClassName, CodeBlockView, ref, children }) {
1887
+ function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph = false, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, resolveLinkPreview, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onFileClick, onFilePaste, onFileSaveError, onImageClick, onXPostMediaClick, onYouTubeVideoClick, embedPaste, linkPaste, bulletAfterHeading, backspaceDeletesEmptyFirstBlock, substitution = true, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, searchQuery = "", onSearchChange, timeFormat, editorClassName, CodeBlockView, ref, children }) {
1888
1888
  const suppressDocChangeRef = useRef(false);
1889
1889
  const handleDocChange = useMemo(() => {
1890
1890
  if (!onDocChange) return;
@@ -1917,7 +1917,9 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph =
1917
1917
  embedPaste,
1918
1918
  linkPaste,
1919
1919
  bulletAfterHeading,
1920
+ backspaceDeletesEmptyFirstBlock,
1920
1921
  substitution,
1922
+ singleParagraph,
1921
1923
  placeholder,
1922
1924
  readOnly,
1923
1925
  spellCheck,
@@ -1947,7 +1949,9 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph =
1947
1949
  embedPaste,
1948
1950
  linkPaste,
1949
1951
  bulletAfterHeading,
1952
+ backspaceDeletesEmptyFirstBlock,
1950
1953
  substitution,
1954
+ singleParagraph,
1951
1955
  placeholder,
1952
1956
  readOnly,
1953
1957
  spellCheck,
@@ -1956,7 +1960,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph =
1956
1960
  referenceDefinitions
1957
1961
  ]);
1958
1962
  const [editor] = useState(() => {
1959
- const baseExtension = singleParagraph ? union(defineEditorExtension(config), defineSingleParagraph()) : defineEditorExtension(config);
1963
+ const baseExtension = defineEditorExtension(config);
1960
1964
  const extension = CodeBlockView === false ? baseExtension : union(baseExtension, defineCodeBlockView(CodeBlockView));
1961
1965
  const editor = createEditor({ extension });
1962
1966
  if (initialMarkdown || singleParagraph) editor.setContent(singleParagraph ? paragraphMarkdownToDoc(initialMarkdown ?? "", editor.nodes) : markdownToDoc(initialMarkdown ?? "", {
@@ -2157,7 +2161,7 @@ const CARET_GLIDE_OFF = { "--meowdown-caret-glide": "0ms" };
2157
2161
  *
2158
2162
  * Callbacks and resolvers should be stable; pass them via `useCallback`.
2159
2163
  */
2160
- function MarkdownEditor({ mode = "focus", initialMarkdown, singleParagraph, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, resolveLinkPreview, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onFileClick, onFilePaste, onFileSaveError, onImageClick, onXPostMediaClick, onYouTubeVideoClick, embedPaste = true, linkPaste = true, bulletAfterHeading = false, substitution = true, frontmatter = false, blockHandle = true, caretGlide = true, placeholder, readOnly, spellCheck, searchQuery, onSearchChange, timeFormat, editorClassName, wrapperClassName, CodeBlockView, handleRef, children }) {
2164
+ function MarkdownEditor({ mode = "focus", initialMarkdown, singleParagraph, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, pendingReplacementActions, onPendingReplacementResolve, onWikilinkClick, onLinkClick, onLinkCopy, resolveLinkPreview, onTagClick, onExitBoundary, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onFileClick, onFilePaste, onFileSaveError, onImageClick, onXPostMediaClick, onYouTubeVideoClick, embedPaste = true, linkPaste = true, bulletAfterHeading = false, backspaceDeletesEmptyFirstBlock = false, substitution = true, frontmatter = false, blockHandle = true, caretGlide = true, placeholder, readOnly, spellCheck, searchQuery, onSearchChange, timeFormat, editorClassName, wrapperClassName, CodeBlockView, handleRef, children }) {
2161
2165
  const childRef = useRef(null);
2162
2166
  useImperativeHandle(handleRef, () => {
2163
2167
  function getMarkdown() {
@@ -2295,6 +2299,7 @@ function MarkdownEditor({ mode = "focus", initialMarkdown, singleParagraph, refe
2295
2299
  embedPaste,
2296
2300
  linkPaste,
2297
2301
  bulletAfterHeading,
2302
+ backspaceDeletesEmptyFirstBlock,
2298
2303
  substitution,
2299
2304
  frontmatter,
2300
2305
  blockHandle,
@@ -2875,7 +2880,7 @@ function renderCodeBlock(node, key) {
2875
2880
  }, key);
2876
2881
  }
2877
2882
  function renderBlock(node, context, parent, index) {
2878
- if (!context.inline && isReferenceDefinitionNode(node, parent, index)) return null;
2883
+ if (!context.singleParagraph && isReferenceDefinitionNode(node, parent, index)) return null;
2879
2884
  const key = context.keyCounter.value++;
2880
2885
  const typeName = node.type.name;
2881
2886
  let handleTaskClick;
@@ -2958,9 +2963,9 @@ const MarkdownBlock = memo(function MarkdownBlock({ node, taskBase, context, ref
2958
2963
  * Callbacks (`onWikilinkClick`, etc.) and resolvers should be stable; pass them via
2959
2964
  * `useCallback` to avoid re-rendering the whole tree.
2960
2965
  */
2961
- function MarkdownView({ markdown, inline = false, referenceDefinitions: suppliedDefinitions, markMode = "hide", frontmatter = false, interactive = true, expandCollapsed = false, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onWikilinkClick, onLinkClick, onImageClick, onXPostMediaClick, onYouTubeVideoClick, onFileClick, onTaskClick, className }) {
2966
+ function MarkdownView({ markdown, singleParagraph = false, referenceDefinitions: suppliedDefinitions, markMode = "hide", frontmatter = false, interactive = true, expandCollapsed = false, resolveImageUrl, resolveFileLink, resolveWikiEmbed, resolveWikilink, resolveFileInfo, resolveXPost, mediaUrlProtocols, resolveYouTubeVideo, onWikilinkClick, onLinkClick, onImageClick, onXPostMediaClick, onYouTubeVideoClick, onFileClick, onTaskClick, className }) {
2962
2967
  const context = useMemo(() => ({
2963
- inline,
2968
+ singleParagraph,
2964
2969
  interactive,
2965
2970
  expandCollapsed,
2966
2971
  resolveImageUrl,
@@ -2977,7 +2982,7 @@ function MarkdownView({ markdown, inline = false, referenceDefinitions: supplied
2977
2982
  onFileClick: interactive ? onFileClick : void 0,
2978
2983
  onTaskClick: interactive ? onTaskClick : void 0
2979
2984
  }), [
2980
- inline,
2985
+ singleParagraph,
2981
2986
  interactive,
2982
2987
  expandCollapsed,
2983
2988
  resolveImageUrl,
@@ -2995,8 +3000,8 @@ function MarkdownView({ markdown, inline = false, referenceDefinitions: supplied
2995
3000
  onTaskClick
2996
3001
  ]);
2997
3002
  const { blocks, referenceDefinitions, definitionsKey } = useMemo(() => {
2998
- const doc = inline ? paragraphMarkdownToDoc(markdown) : markdownToDoc(markdown, { frontmatter });
2999
- const localDefinitions = inline ? /* @__PURE__ */ new Map() : collectReferenceDefinitions(doc).definitions;
3003
+ const doc = singleParagraph ? paragraphMarkdownToDoc(markdown) : markdownToDoc(markdown, { frontmatter });
3004
+ const localDefinitions = singleParagraph ? /* @__PURE__ */ new Map() : collectReferenceDefinitions(doc).definitions;
3000
3005
  const referenceDefinitions = suppliedDefinitions ? new Map([...suppliedDefinitions, ...localDefinitions]) : localDefinitions;
3001
3006
  return {
3002
3007
  blocks: splitBlocks(doc),
@@ -3006,7 +3011,7 @@ function MarkdownView({ markdown, inline = false, referenceDefinitions: supplied
3006
3011
  }, [
3007
3012
  markdown,
3008
3013
  frontmatter,
3009
- inline,
3014
+ singleParagraph,
3010
3015
  suppliedDefinitions
3011
3016
  ]);
3012
3017
  const handleXPostMediaClick = interactive ? onXPostMediaClick : void 0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/react",
3
3
  "type": "module",
4
- "version": "0.77.0",
4
+ "version": "0.79.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "dependencies": {
24
24
  "@base-ui/react": "^1.8.0",
25
- "@meowdown/core": "0.78.4",
25
+ "@meowdown/core": "0.80.0",
26
26
  "@meowdown/embed": "0.3.1",
27
27
  "@meowdown/markdown": "0.76.0",
28
28
  "@ocavue/utils": "^1.8.0",