@meowdown/react 0.80.3 → 0.81.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
@@ -2,6 +2,14 @@ import { ComponentProps, ReactElement, ReactNode, Ref } from "react";
2
2
  import { AcceptPendingReplacementOptions, EditorConfig, ExitBoundaryHandler, FileClickHandler, FileInfoResolver, FileLinkResolver, FilePasteOptions, FileViewOptions, ImageClickHandler, ImageOptions, ImageUrlResolver, LinkClickHandler, LinkCopyHandler, LinkPreview, LinkPreviewResolver, LinkPreviewResolver as LinkPreviewResolver$1, ListMarker, MarkMode, PendingReplacement, PendingReplacementOutcome, PlaceholderOptions, ReferenceDefinitions, SearchStatusHandler, StartPendingReplacementOptions, TagClickHandler, TypedEditor, WikiEmbedResolver, WikilinkClickHandler, WikilinkHoverHit, WikilinkResolver, XPostMediaClickHandler, XPostResolver, XPostResolver as XPostResolver$1, YouTubeVideoClickHandler, YouTubeVideoResolver, YouTubeVideoResolver as YouTubeVideoResolver$1 } from "@meowdown/core";
3
3
  import { SelectionJSON, SelectionJSON as SelectionJSON$1 } from "@prosekit/core";
4
4
  import { ReactNodeViewComponent, ReactNodeViewComponent as ReactNodeViewComponent$1, useEditor, useExtension, useKeymap } from "@prosekit/react";
5
+ import { Popover } from "@base-ui/react/popover";
6
+ //#region src/components/collision-boundary.d.ts
7
+ /**
8
+ * The area the editor's floating menus and popovers stay inside. Same as the
9
+ * `collisionBoundary` prop of Base UI positioners.
10
+ */
11
+ type CollisionBoundary = NonNullable<Popover.Positioner.Props['collisionBoundary']>;
12
+ //#endregion
5
13
  //#region src/utils/date-format.d.ts
6
14
  type TimeFormat = '12' | '24';
7
15
  //#endregion
@@ -330,6 +338,12 @@ interface EditorProps {
330
338
  * is set. Ignored when `readOnly` is set.
331
339
  */
332
340
  selectionMenuAffordance?: boolean | undefined;
341
+ /**
342
+ * The element the editor's menus and popovers stay inside, for example one
343
+ * that leaves out the area under a phone's status bar. Defaults to the
344
+ * viewport.
345
+ */
346
+ collisionBoundary?: CollisionBoundary | undefined;
333
347
  /**
334
348
  * Extra controls rendered in the pending-replacement preview footer, next to
335
349
  * the built-in accept ("Replace selection" / "Insert below", per the staged
@@ -583,7 +597,7 @@ interface EditorProps {
583
597
  *
584
598
  * Callbacks and resolvers should be stable; pass them via `useCallback`.
585
599
  */
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;
600
+ export declare function MarkdownEditor({ mode, initialMarkdown, singleParagraph, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance, collisionBoundary, 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;
587
601
  //#endregion
588
602
  //#region src/components/markdown-view.d.ts
589
603
  /**
@@ -930,4 +944,4 @@ interface WikilinkHoverCardProps {
930
944
  */
931
945
  export declare function WikilinkHoverCard({ children, className }: WikilinkHoverCardProps): ReactNode;
932
946
  //#endregion
933
- export { type EditorHandle, type EditorMode, type EditorProps, type EditorStateSnapshot, type LightboxCloseOptions, type LightboxController, type LightboxFrameItem, type LightboxFrameProps, type LightboxImageItem, type LightboxImageProps, type LightboxItem, type LightboxRootProps, type LightboxVideoItem, type LightboxVideoProps, type LinkPreview, type LinkPreviewResolver, type MarkdownViewProps, type PendingReplacementResolveHandler, type ReactNodeViewComponent, type SelectionHint, type SelectionJSON, type SelectionMenuContext, type SelectionMenuItem, type SelectionMenuSearchHandler, type SlashMenuItem, type SlashMenuSearchHandler, type TagItem, type TagSearchHandler, type TaskClickHandler, type TaskClickPayload, type TimeFormat, type WikilinkHoverCardProps, type WikilinkItem, type WikilinkSearchHandler, type XPostResolver, type YouTubeVideoResolver, useEditor, useExtension, useKeymap };
947
+ export { type CollisionBoundary, type EditorHandle, type EditorMode, type EditorProps, type EditorStateSnapshot, type LightboxCloseOptions, type LightboxController, type LightboxFrameItem, type LightboxFrameProps, type LightboxImageItem, type LightboxImageProps, type LightboxItem, type LightboxRootProps, type LightboxVideoItem, type LightboxVideoProps, type LinkPreview, type LinkPreviewResolver, type MarkdownViewProps, type PendingReplacementResolveHandler, type ReactNodeViewComponent, type SelectionHint, type SelectionJSON, type SelectionMenuContext, type SelectionMenuItem, type SelectionMenuSearchHandler, type SlashMenuItem, type SlashMenuSearchHandler, type TagItem, type TagSearchHandler, type TaskClickHandler, type TaskClickPayload, type TimeFormat, type WikilinkHoverCardProps, type WikilinkItem, type WikilinkSearchHandler, type XPostResolver, type YouTubeVideoResolver, useEditor, useExtension, useKeymap };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { clsx } from "clsx/lite";
2
- import { Fragment, ViewTransition, cloneElement, createElement, memo, startTransition, useCallback, useDeferredValue, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
2
+ import { Fragment, ViewTransition, cloneElement, createContext, createElement, memo, startTransition, use, useCallback, useDeferredValue, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
3
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";
@@ -98,6 +98,20 @@ var code_block_view_module_default = {
98
98
  "TriggerIcon": "meow_TriggerIcon_D3j_9q"
99
99
  };
100
100
 
101
+ //#endregion
102
+ //#region src/components/collision-boundary.ts
103
+ /**
104
+ * See `EditorProps.collisionBoundary`.
105
+ */
106
+ const CollisionBoundaryContext = createContext(void 0);
107
+ /**
108
+ * Converts a {@link CollisionBoundary} to the `boundary` prop of ProseKit
109
+ * positioners, which spell the keyword the floating-ui way.
110
+ */
111
+ function toFloatingBoundary(boundary) {
112
+ return boundary === "clipping-ancestors" ? "clippingAncestors" : boundary;
113
+ }
114
+
101
115
  //#endregion
102
116
  //#region src/components/copy-button.tsx
103
117
  const COPIED_RESET_MS = 1500;
@@ -272,6 +286,7 @@ function CodeBlockView(props) {
272
286
  });
273
287
  }
274
288
  function CodeBlockToolbar({ code, language, setLanguage }) {
289
+ const collisionBoundary = use(CollisionBoundaryContext);
275
290
  const selected = useMemo(() => {
276
291
  return codeBlockLanguages.find((item) => item.value === language) ?? {
277
292
  value: language,
@@ -316,6 +331,7 @@ function CodeBlockToolbar({ code, language, setLanguage }) {
316
331
  }), /* @__PURE__ */ jsx(Combobox.Portal, { children: /* @__PURE__ */ jsx(Combobox.Positioner, {
317
332
  className: code_block_view_module_default.Positioner,
318
333
  sideOffset: 4,
334
+ collisionBoundary,
319
335
  children: /* @__PURE__ */ jsxs(Combobox.Popup, {
320
336
  className: code_block_view_module_default.Popup,
321
337
  children: [
@@ -534,6 +550,7 @@ function selectLinkUnit(editor, link) {
534
550
  editor.focus();
535
551
  }
536
552
  function LinkPopover({ anchor, open, onClose, onCloseComplete, onPopupHover, children }) {
553
+ const collisionBoundary = use(CollisionBoundaryContext);
537
554
  return /* @__PURE__ */ jsx(Popover.Root, {
538
555
  open,
539
556
  onOpenChange: (open) => {
@@ -546,6 +563,7 @@ function LinkPopover({ anchor, open, onClose, onCloseComplete, onPopupHover, chi
546
563
  anchor,
547
564
  side: "bottom",
548
565
  sideOffset: 8,
566
+ collisionBoundary,
549
567
  className: link_menu_module_default.Positioner,
550
568
  children: /* @__PURE__ */ jsx(Popover.Popup, {
551
569
  className: link_menu_module_default.Popup,
@@ -1099,6 +1117,7 @@ var selection_menu_module_default = {
1099
1117
  */
1100
1118
  function SelectionMenu({ onSelectionMenuSearch, context, onOpen, onClose, affordance = true }) {
1101
1119
  const editor = useEditor$1();
1120
+ const collisionBoundary = use(CollisionBoundaryContext);
1102
1121
  const [selection, setSelection] = useState();
1103
1122
  useExtension$1(useMemo(() => {
1104
1123
  return defineUpdateHandler((view) => {
@@ -1120,10 +1139,7 @@ function SelectionMenu({ onSelectionMenuSearch, context, onOpen, onClose, afford
1120
1139
  }, [onClose, editor]);
1121
1140
  const menuAnchor = useMemo(() => {
1122
1141
  if (!context) return;
1123
- return getVirtualElementFromRange(editor.view, {
1124
- from: context.from,
1125
- to: context.to
1126
- });
1142
+ return getMenuAnchor(editor.view, context.from, context.to);
1127
1143
  }, [context, editor]);
1128
1144
  const showAffordance = affordance && !!!context && !!selection?.anchorable;
1129
1145
  const affordanceVisible = useDelayedFlag(showAffordance, 250, 0);
@@ -1147,6 +1163,7 @@ function SelectionMenu({ onSelectionMenuSearch, context, onOpen, onClose, afford
1147
1163
  anchor: menuAnchor,
1148
1164
  side: "bottom",
1149
1165
  sideOffset: 8,
1166
+ collisionBoundary,
1150
1167
  className: selection_menu_module_default.Positioner,
1151
1168
  children: /* @__PURE__ */ jsx(Popover.Popup, {
1152
1169
  className: selection_menu_module_default.Popup,
@@ -1167,6 +1184,7 @@ function SelectionMenu({ onSelectionMenuSearch, context, onOpen, onClose, afford
1167
1184
  anchor: affordanceAnchor,
1168
1185
  side: "bottom",
1169
1186
  sideOffset: 4,
1187
+ collisionBoundary,
1170
1188
  className: selection_menu_module_default.AffordancePositioner,
1171
1189
  children: /* @__PURE__ */ jsx(Popover.Popup, {
1172
1190
  className: selection_menu_module_default.AffordancePopup,
@@ -1188,6 +1206,30 @@ function SelectionMenu({ onSelectionMenuSearch, context, onOpen, onClose, afford
1188
1206
  return null;
1189
1207
  }
1190
1208
  /**
1209
+ * Anchors the menu to the selected range, or to the range's end when the range
1210
+ * is taller than a third of the visible height: such a range leaves no room
1211
+ * for the menu above or below it.
1212
+ */
1213
+ function getMenuAnchor(view, from, to) {
1214
+ const range = getVirtualElementFromRange(view, {
1215
+ from,
1216
+ to
1217
+ });
1218
+ if (from === to) return range;
1219
+ const end = getVirtualElementFromRange(view, {
1220
+ from: to,
1221
+ to
1222
+ });
1223
+ const pickAnchor = () => {
1224
+ const visibleHeight = view.dom.ownerDocument.defaultView?.visualViewport?.height ?? Infinity;
1225
+ return range.getBoundingClientRect().height > visibleHeight / 3 ? end : range;
1226
+ };
1227
+ return {
1228
+ getBoundingClientRect: () => pickAnchor().getBoundingClientRect(),
1229
+ contextElement: view.dom
1230
+ };
1231
+ }
1232
+ /**
1191
1233
  * The menu content. Mounted only while the menu is open, so its filter state
1192
1234
  * resets naturally on close.
1193
1235
  */
@@ -1324,6 +1366,7 @@ function selectionInTableCell(editor) {
1324
1366
  }
1325
1367
  function SlashMenu({ timeFormat = "12", onSlashMenuSearch, onFilePaste, onFileSaveError }) {
1326
1368
  const editor = useEditor$1();
1369
+ const collisionBoundary = use(CollisionBoundaryContext);
1327
1370
  const fileInputRef = useRef(null);
1328
1371
  const inTableCell = useEditorDerivedValue(selectionInTableCell);
1329
1372
  const [open, setOpen] = useState(false);
@@ -1386,6 +1429,7 @@ function SlashMenu({ timeFormat = "12", onSlashMenuSearch, onFilePaste, onFileSa
1386
1429
  onChange: handleFileInputChange
1387
1430
  }) : null, /* @__PURE__ */ jsx(AutocompletePositioner, {
1388
1431
  className: autocomplete_menu_module_default.Positioner,
1432
+ boundary: toFloatingBoundary(collisionBoundary),
1389
1433
  children: /* @__PURE__ */ jsxs(AutocompletePopup, {
1390
1434
  className: autocomplete_menu_module_default.Popup,
1391
1435
  "data-testid": "slash-menu",
@@ -1705,6 +1749,7 @@ function returnsTrue() {
1705
1749
  const regex$1 = new RegExp((canUseRegexLookbehind() ? String.raw`(?<!\S)` : "") + String.raw`#[\da-z]+$`, "iu");
1706
1750
  function TagMenu({ onTagSearch }) {
1707
1751
  const editor = useEditor$1();
1752
+ const collisionBoundary = use(CollisionBoundaryContext);
1708
1753
  const [open, setOpen] = useState(false);
1709
1754
  const [query, setQuery] = useState("");
1710
1755
  const [items, setItems] = useState([]);
@@ -1738,6 +1783,7 @@ function TagMenu({ onTagSearch }) {
1738
1783
  onQueryChange: (event) => setQuery(event.detail),
1739
1784
  children: /* @__PURE__ */ jsx(AutocompletePositioner, {
1740
1785
  className: autocomplete_menu_module_default.Positioner,
1786
+ boundary: toFloatingBoundary(collisionBoundary),
1741
1787
  children: /* @__PURE__ */ jsxs(AutocompletePopup, {
1742
1788
  className: autocomplete_menu_module_default.Popup,
1743
1789
  "data-testid": "tag-menu",
@@ -1780,6 +1826,7 @@ function queryFromRegexMatch(match) {
1780
1826
  }
1781
1827
  function WikilinkMenu({ onWikilinkSearch }) {
1782
1828
  const editor = useEditor$1();
1829
+ const collisionBoundary = use(CollisionBoundaryContext);
1783
1830
  const [open, setOpen] = useState(false);
1784
1831
  const [query, setQuery] = useState("");
1785
1832
  const [items, setItems] = useState([]);
@@ -1815,6 +1862,7 @@ function WikilinkMenu({ onWikilinkSearch }) {
1815
1862
  onQueryChange: (event) => setQuery(event.detail),
1816
1863
  children: /* @__PURE__ */ jsx(AutocompletePositioner, {
1817
1864
  className: autocomplete_menu_module_default.Positioner,
1865
+ boundary: toFloatingBoundary(collisionBoundary),
1818
1866
  children: /* @__PURE__ */ jsxs(AutocompletePopup, {
1819
1867
  className: autocomplete_menu_module_default.Popup,
1820
1868
  "data-testid": "wikilink-menu",
@@ -1887,7 +1935,7 @@ function findHeadingPosition(doc, fragment) {
1887
1935
  });
1888
1936
  return match;
1889
1937
  }
1890
- 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 }) {
1938
+ function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph = false, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, collisionBoundary, 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 }) {
1891
1939
  const suppressDocChangeRef = useRef(false);
1892
1940
  const handleDocChange = useMemo(() => {
1893
1941
  if (!onDocChange) return;
@@ -2111,47 +2159,50 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, singleParagraph =
2111
2159
  const mount = useCallback((element) => {
2112
2160
  return editor.mount(element);
2113
2161
  }, [editor]);
2114
- return /* @__PURE__ */ jsxs(ProseKit, {
2115
- editor,
2116
- children: [
2117
- /* @__PURE__ */ jsx(VirtualCaret, {}),
2118
- /* @__PURE__ */ jsx("div", { ref: mount }),
2119
- /* @__PURE__ */ jsx(EditorExtensions, {
2120
- config,
2121
- searchQuery,
2122
- onDocChange: handleDocChange,
2123
- onSearchChange
2124
- }),
2125
- blockHandle && !readOnly && /* @__PURE__ */ jsx(BlockHandle, {}),
2126
- !readOnly && /* @__PURE__ */ jsx(TableHandle, {}),
2127
- blockHandle && !readOnly && /* @__PURE__ */ jsx(DropIndicator$1, {}),
2128
- /* @__PURE__ */ jsx(SlashMenu, {
2129
- timeFormat,
2130
- onSlashMenuSearch,
2131
- onFilePaste,
2132
- onFileSaveError
2133
- }),
2134
- /* @__PURE__ */ jsx(LinkMenu, {
2135
- onLinkClick,
2136
- onLinkCopy,
2137
- resolveLinkPreview,
2138
- readOnly
2139
- }, String(readOnly)),
2140
- onTagSearch && /* @__PURE__ */ jsx(TagMenu, { onTagSearch }),
2141
- onWikilinkSearch && /* @__PURE__ */ jsx(WikilinkMenu, { onWikilinkSearch }),
2142
- onSelectionMenuSearch && !readOnly && /* @__PURE__ */ jsx(SelectionMenu, {
2143
- onSelectionMenuSearch,
2144
- context: selectionMenuContext,
2145
- onOpen: openSelectionMenu,
2146
- onClose: closeSelectionMenu,
2147
- affordance: selectionMenuAffordance
2148
- }),
2149
- !readOnly && /* @__PURE__ */ jsx(PendingReplacementPreview, {
2150
- actions: pendingReplacementActions,
2151
- onResolve: onPendingReplacementResolve
2152
- }),
2153
- children
2154
- ]
2162
+ return /* @__PURE__ */ jsx(CollisionBoundaryContext, {
2163
+ value: collisionBoundary,
2164
+ children: /* @__PURE__ */ jsxs(ProseKit, {
2165
+ editor,
2166
+ children: [
2167
+ /* @__PURE__ */ jsx(VirtualCaret, {}),
2168
+ /* @__PURE__ */ jsx("div", { ref: mount }),
2169
+ /* @__PURE__ */ jsx(EditorExtensions, {
2170
+ config,
2171
+ searchQuery,
2172
+ onDocChange: handleDocChange,
2173
+ onSearchChange
2174
+ }),
2175
+ blockHandle && !readOnly && /* @__PURE__ */ jsx(BlockHandle, {}),
2176
+ !readOnly && /* @__PURE__ */ jsx(TableHandle, {}),
2177
+ blockHandle && !readOnly && /* @__PURE__ */ jsx(DropIndicator$1, {}),
2178
+ /* @__PURE__ */ jsx(SlashMenu, {
2179
+ timeFormat,
2180
+ onSlashMenuSearch,
2181
+ onFilePaste,
2182
+ onFileSaveError
2183
+ }),
2184
+ /* @__PURE__ */ jsx(LinkMenu, {
2185
+ onLinkClick,
2186
+ onLinkCopy,
2187
+ resolveLinkPreview,
2188
+ readOnly
2189
+ }, String(readOnly)),
2190
+ onTagSearch && /* @__PURE__ */ jsx(TagMenu, { onTagSearch }),
2191
+ onWikilinkSearch && /* @__PURE__ */ jsx(WikilinkMenu, { onWikilinkSearch }),
2192
+ onSelectionMenuSearch && !readOnly && /* @__PURE__ */ jsx(SelectionMenu, {
2193
+ onSelectionMenuSearch,
2194
+ context: selectionMenuContext,
2195
+ onOpen: openSelectionMenu,
2196
+ onClose: closeSelectionMenu,
2197
+ affordance: selectionMenuAffordance
2198
+ }),
2199
+ !readOnly && /* @__PURE__ */ jsx(PendingReplacementPreview, {
2200
+ actions: pendingReplacementActions,
2201
+ onResolve: onPendingReplacementResolve
2202
+ }),
2203
+ children
2204
+ ]
2205
+ })
2155
2206
  });
2156
2207
  }
2157
2208
 
@@ -2164,7 +2215,7 @@ const CARET_GLIDE_OFF = { "--meowdown-caret-glide": "0ms" };
2164
2215
  *
2165
2216
  * Callbacks and resolvers should be stable; pass them via `useCallback`.
2166
2217
  */
2167
- 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 }) {
2218
+ function MarkdownEditor({ mode = "focus", initialMarkdown, singleParagraph, referenceDefinitions, onDocChange, onSlashMenuSearch, onTagSearch, onWikilinkSearch, onSelectionMenuSearch, selectionMenuAffordance = true, collisionBoundary, 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 }) {
2168
2219
  const childRef = useRef(null);
2169
2220
  useImperativeHandle(handleRef, () => {
2170
2221
  function getMarkdown() {
@@ -2277,6 +2328,7 @@ function MarkdownEditor({ mode = "focus", initialMarkdown, singleParagraph, refe
2277
2328
  onWikilinkSearch,
2278
2329
  onSelectionMenuSearch,
2279
2330
  selectionMenuAffordance,
2331
+ collisionBoundary,
2280
2332
  pendingReplacementActions,
2281
2333
  onPendingReplacementResolve,
2282
2334
  onWikilinkClick,
package/dist/style.css CHANGED
@@ -746,11 +746,12 @@
746
746
 
747
747
  .meow_Popup_2_4Zjq {
748
748
  box-sizing: border-box;
749
+ width: 100%;
750
+ max-height: var(--available-height);
749
751
  border: 1px solid var(--meowdown-border);
750
752
  background: var(--meowdown-popover-bg);
751
753
  border-radius: .75rem;
752
754
  flex-direction: column;
753
- width: 100%;
754
755
  padding: .25rem;
755
756
  font-size: .875rem;
756
757
  display: flex;
@@ -765,6 +766,7 @@
765
766
  border: 1px solid var(--meowdown-border);
766
767
  background: none;
767
768
  border-radius: .5rem;
769
+ flex: none;
768
770
  margin-bottom: .25rem;
769
771
  padding: .375rem .5rem;
770
772
 
@@ -776,6 +778,8 @@
776
778
 
777
779
  .meow_List_2_4Zjq {
778
780
  flex-direction: column;
781
+ flex: auto;
782
+ min-height: 6rem;
779
783
  max-height: 16rem;
780
784
  display: flex;
781
785
  overflow-y: auto;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/react",
3
3
  "type": "module",
4
- "version": "0.80.3",
4
+ "version": "0.81.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.9.0",
25
- "@meowdown/core": "0.81.1",
25
+ "@meowdown/core": "0.81.2",
26
26
  "@meowdown/embed": "0.3.1",
27
27
  "@meowdown/markdown": "0.77.0",
28
28
  "@ocavue/utils": "^1.9.0",