@meowdown/react 0.4.0 → 0.6.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.js CHANGED
@@ -1 +1,869 @@
1
- import{useCallback as e,useEffect as t,useImperativeHandle as n,useLayoutEffect as r,useMemo as i,useRef as a,useState as o}from"react";import{defaultKeymap as s,history as c,historyKeymap as l}from"@codemirror/commands";import{markdown as u,markdownLanguage as d}from"@codemirror/lang-markdown";import{defaultHighlightStyle as f,syntaxHighlighting as p}from"@codemirror/language";import{EditorSelection as m,EditorState as h}from"@codemirror/state";import{EditorView as g,keymap as _}from"@codemirror/view";import{clamp as v}from"@ocavue/utils";import{jsx as y,jsxs as b}from"react/jsx-runtime";import{defineEditorExtension as x,defineMarkMode as S,docToMarkdown as C,markdownToDoc as w}from"@meowdown/core";import{canUseRegexLookbehind as T,createEditor as E,defineDocChangeHandler as D}from"@prosekit/core";import{Selection as O,TextSelection as k}from"@prosekit/pm/state";import{ProseKit as A,useEditor as j,useExtension as M}from"@prosekit/react";import{BlockHandleAdd as N,BlockHandleDraggable as P,BlockHandlePopup as F,BlockHandlePositioner as I,BlockHandleRoot as L}from"@prosekit/react/block-handle";import{DropIndicator as R}from"@prosekit/react/drop-indicator";import{AutocompleteEmpty as z,AutocompleteItem as B,AutocompletePopup as V,AutocompletePositioner as H,AutocompleteRoot as U}from"@prosekit/react/autocomplete";function W(e,t){return e===`start`?m.single(0):e===`end`?m.single(t):m.single(v(e.anchor,0,t),v(e.head,0,t))}function G({initialMarkdown:e,onDocChange:t,ref:i}){let o=a(null),m=a(null),v=a(t);r(()=>{v.current=t},[t]);let b=a(e??``);return n(i,()=>{function e(){return m.current?.state.doc.toString()??b.current}function t(){let e=m.current?.state.selection.main;return{type:`text`,anchor:e?.anchor??0,head:e?.head??0}}function n(){return[e(),t()]}function r(e,t){let n=m.current;if(!n){e!=null&&(b.current=e);return}if(e==null&&!t)return;let r=e==null?n.state.doc.length:e.length;n.dispatch({changes:e==null?void 0:{from:0,to:n.state.doc.length,insert:e},selection:t?W(t,r):void 0,scrollIntoView:!0})}function i(e){r(e)}function a(e){r(void 0,e)}function o(){m.current?.focus()}function s(){m.current?.dispatch({scrollIntoView:!0})}return{getMarkdown:e,setMarkdown:i,getState:n,setState:r,getSelection:t,setSelection:a,focus:o,scrollIntoView:s}},[]),r(()=>{let e=o.current;if(!e)return;let t=new g({parent:e,state:h.create({doc:b.current,extensions:[c(),_.of([...s,...l]),u({base:d}),p(f,{fallback:!0}),g.lineWrapping,g.updateListener.of(e=>{e.docChanged&&v.current?.()})]})});return m.current=t,()=>{t.destroy(),m.current=null}},[]),y(`div`,{ref:o,"data-editor":`codemirror`})}function K(){return b(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[y(`circle`,{cx:`9`,cy:`5`,r:`1`}),y(`circle`,{cx:`9`,cy:`12`,r:`1`}),y(`circle`,{cx:`9`,cy:`19`,r:`1`}),y(`circle`,{cx:`15`,cy:`5`,r:`1`}),y(`circle`,{cx:`15`,cy:`12`,r:`1`}),y(`circle`,{cx:`15`,cy:`19`,r:`1`})]})}function q(){return b(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:[y(`path`,{d:`M5 12h14`}),y(`path`,{d:`M12 5v14`})]})}function J(){return y(L,{children:y(I,{className:`meowdown-block-handle-positioner`,children:b(F,{className:`meowdown-block-handle`,"data-testid":`block-handle`,children:[y(N,{className:`meowdown-block-handle-add`,"data-testid":`block-handle-add`,children:y(q,{})}),y(P,{className:`meowdown-block-handle-drag`,"data-testid":`block-handle-drag`,children:y(K,{})})]})})})}function Y(){return y(R,{className:`meowdown-drop-indicator`,"data-testid":`drop-indicator`})}const X=T()?/(?<!\S)\/(\S.*)?$/u:/\/(\S.*)?$/u;function Z({label:e,kbd:t,onSelect:n}){return b(B,{className:`meowdown-autocomplete-menu-item`,onSelect:n,children:[y(`span`,{children:e}),t&&y(`kbd`,{children:t})]})}function Q(){let e=j();return y(U,{regex:X,children:y(H,{className:`meowdown-autocomplete-menu-positioner`,children:b(V,{className:`meowdown-autocomplete-menu`,"data-testid":`slash-menu`,children:[y(Z,{label:`Heading 1`,kbd:`#`,onSelect:()=>e.commands.setHeading({level:1})}),y(Z,{label:`Heading 2`,kbd:`##`,onSelect:()=>e.commands.setHeading({level:2})}),y(Z,{label:`Heading 3`,kbd:`###`,onSelect:()=>e.commands.setHeading({level:3})}),y(Z,{label:`Heading 4`,kbd:`####`,onSelect:()=>e.commands.setHeading({level:4})}),y(Z,{label:`Blockquote`,kbd:`>`,onSelect:()=>e.commands.setBlockquote()}),y(Z,{label:`Bullet list`,kbd:`-`,onSelect:()=>e.commands.wrapInList({kind:`bullet`})}),y(Z,{label:`Ordered list`,kbd:`1.`,onSelect:()=>e.commands.wrapInList({kind:`ordered`})}),y(Z,{label:`Task list`,kbd:`[]`,onSelect:()=>e.commands.wrapInList({kind:`task`})}),y(Z,{label:`Code block`,kbd:"```",onSelect:()=>e.commands.setCodeBlock()}),y(Z,{label:`Table`,onSelect:()=>e.commands.insertTable({row:3,col:3})}),y(z,{className:`meowdown-autocomplete-menu-item`,children:`No results`})]})})})}function $(){return!0}const ee=T()?/(?<!\S)#[\da-z]+$/iu:/#[\da-z]+$/iu;function te({onTagSearch:n}){let r=j(),[i,a]=o(!1),[s,c]=o(``),[l,u]=o([]),[d,f]=o(!1),p=e(async(e,t)=>{if(t.aborted)return;f(!0);let r=await n(e);t.aborted||(u(r),f(!1))},[n]);return t(()=>{if(!i)return;let e=new AbortController;return queueMicrotask(()=>{p(s,e.signal)}),()=>{e.abort()}},[i,s,p]),y(U,{regex:ee,filter:$,onOpenChange:e=>a(e.detail),onQueryChange:e=>c(e.detail),children:y(H,{className:`meowdown-autocomplete-menu-positioner`,children:b(V,{className:`meowdown-autocomplete-menu`,"data-testid":`tag-menu`,children:[l.map(e=>b(B,{className:`meowdown-autocomplete-menu-item`,onSelect:()=>r.commands.insertText({text:`#${e} `}),children:[`#`,e]},e)),y(z,{className:`meowdown-autocomplete-menu-item`,children:d?`Loading...`:`No tags found`})]})})})}const ne=/\[\[[^[\]]*$/u;function re({onWikilinkSearch:n}){let r=j(),[i,a]=o(!1),[s,c]=o(``),[l,u]=o([]),[d,f]=o(!1),p=e(async(e,t)=>{if(t.aborted)return;f(!0);let r=await n(e);t.aborted||(u(r),f(!1))},[n]);return t(()=>{if(!i)return;let e=new AbortController;return queueMicrotask(()=>{p(s,e.signal)}),()=>{e.abort()}},[i,s,p]),y(U,{regex:ne,filter:$,onOpenChange:e=>a(e.detail),onQueryChange:e=>c(e.detail),children:y(H,{className:`meowdown-autocomplete-menu-positioner`,children:b(V,{className:`meowdown-autocomplete-menu`,"data-testid":`wikilink-menu`,children:[l.map(e=>y(B,{className:`meowdown-autocomplete-menu-item`,onSelect:()=>r.commands.insertText({text:`[[${e}]]`}),children:e},e)),y(z,{className:`meowdown-autocomplete-menu-item`,children:d?`Loading...`:`No notes found`})]})})})}function ie(e,t){if(t===`start`)return O.atStart(e);if(t===`end`)return O.atEnd(e);try{return O.fromJSON(e,t)}catch{let n=e.content.size,r=v(t.anchor??0,0,n),i=v(t.head??r,0,n);return k.between(e.resolve(r),e.resolve(i))}}function ae({markMode:e=`focus`,initialMarkdown:t,onDocChange:r,onTagSearch:a,onWikilinkSearch:s,ref:c}){let[l]=o(()=>{let e=E({extension:x()});return t&&e.setContent(w(e,t)),e});return n(c,()=>{function e(){return C(l.state.doc)}function t(){return l.state.selection.toJSON()}function n(){return[e(),t()]}function r(e,t){if(e==null&&!t)return;let n=l.state.tr;if(e!=null){let t=w(l,e);n.replaceWith(0,n.doc.content.size,t.content)}t&&n.setSelection(ie(n.doc,t)).scrollIntoView(),l.view.dispatch(n)}function i(e){r(e)}function a(e){r(void 0,e)}function o(){l.focus()}function s(){l.view.dispatch(l.state.tr.scrollIntoView())}return{getMarkdown:e,setMarkdown:i,getState:n,setState:r,getSelection:t,setSelection:a,focus:o,scrollIntoView:s}},[l]),M(i(()=>S(e),[e]),{editor:l}),M(i(()=>r?D(()=>{r()}):null,[r]),{editor:l}),b(A,{editor:l,children:[y(`div`,{ref:l.mount}),y(J,{}),y(Y,{}),y(Q,{}),a&&y(te,{onTagSearch:a}),s&&y(re,{onWikilinkSearch:s})]})}function oe({mode:e=`focus`,initialMarkdown:t,onDocChange:r,onTagSearch:i,onWikilinkSearch:o,ref:s}){let c=a(null);n(s,()=>{function e(){return c.current?.getMarkdown()??``}function t(e){c.current?.setMarkdown(e)}function n(){return c.current?.getState()??[``,{type:`text`,anchor:0,head:0}]}function r(e,t){c.current?.setState(e,t)}function i(){return c.current?.getSelection()??{type:`text`,anchor:0,head:0}}function a(e){c.current?.setSelection(e)}function o(){c.current?.focus()}function s(){c.current?.scrollIntoView()}return{getMarkdown:e,setMarkdown:t,getState:n,setState:r,getSelection:i,setSelection:a,focus:o,scrollIntoView:s}},[]);let l=c.current?.getMarkdown()??t??``;return y(`div`,{className:`meowdown`,children:e===`source`?y(G,{ref:c,initialMarkdown:l,onDocChange:r}):y(ae,{ref:c,markMode:e,initialMarkdown:l,onDocChange:r,onTagSearch:i,onWikilinkSearch:o})})}export{oe as Editor};
1
+ import { clsx } from "clsx/lite";
2
+ import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
3
+ import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
4
+ import { markdown, markdownLanguage } from "@codemirror/lang-markdown";
5
+ import { defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
6
+ import { Compartment, EditorSelection, EditorState } from "@codemirror/state";
7
+ import { EditorView, keymap } from "@codemirror/view";
8
+ import { clamp } from "@ocavue/utils";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { EDITOR_KEY_BINDINGS, checkRoundTrip, codeBlockLanguages, defineEditorExtension, defineImages, defineMarkMode, definePlaceholder, defineReadonly, defineWikilinkClickHandler, docToMarkdown, markdownToDoc } from "@meowdown/core";
11
+ import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, union } from "@prosekit/core";
12
+ import { Selection, TextSelection } from "@prosekit/pm/state";
13
+ import { ProseKit, defineReactNodeView, useEditor, useEditor as useEditor$1, useExtension } from "@prosekit/react";
14
+ import { Combobox } from "@base-ui/react/combobox";
15
+ import { BlockHandleAdd, BlockHandleDraggable, BlockHandlePopup, BlockHandlePositioner, BlockHandleRoot } from "@prosekit/react/block-handle";
16
+ import { DropIndicator } from "@prosekit/react/drop-indicator";
17
+ import { AutocompleteEmpty, AutocompleteItem, AutocompletePopup, AutocompletePositioner, AutocompleteRoot } from "@prosekit/react/autocomplete";
18
+
19
+ //#region src/components/codemirror-editor.tsx
20
+ function resolveSelection$1(selection, docLength) {
21
+ if (selection === "start") return EditorSelection.single(0);
22
+ if (selection === "end") return EditorSelection.single(docLength);
23
+ return EditorSelection.single(clamp(selection.anchor, 0, docLength), clamp(selection.head, 0, docLength));
24
+ }
25
+ function CodeMirrorEditor({ initialMarkdown, onDocChange, readOnly, ref }) {
26
+ const containerRef = useRef(null);
27
+ const viewRef = useRef(null);
28
+ const readOnlyCompartmentRef = useRef(new Compartment());
29
+ const suppressDocChangeRef = useRef(false);
30
+ const onDocChangeRef = useRef(onDocChange);
31
+ useLayoutEffect(() => {
32
+ onDocChangeRef.current = onDocChange;
33
+ }, [onDocChange]);
34
+ const initialMarkdownRef = useRef(initialMarkdown ?? "");
35
+ const initialReadOnlyRef = useRef(readOnly ?? false);
36
+ useImperativeHandle(ref, () => {
37
+ function getMarkdown() {
38
+ return viewRef.current?.state.doc.toString() ?? initialMarkdownRef.current;
39
+ }
40
+ function getSelection() {
41
+ const main = viewRef.current?.state.selection.main;
42
+ return {
43
+ type: "text",
44
+ anchor: main?.anchor ?? 0,
45
+ head: main?.head ?? 0
46
+ };
47
+ }
48
+ function getState() {
49
+ return [getMarkdown(), getSelection()];
50
+ }
51
+ function setState(markdown, selection) {
52
+ const view = viewRef.current;
53
+ if (!view) {
54
+ if (markdown != null) initialMarkdownRef.current = markdown;
55
+ return;
56
+ }
57
+ if (markdown == null && !selection) return;
58
+ const docLength = markdown == null ? view.state.doc.length : markdown.length;
59
+ suppressDocChangeRef.current = true;
60
+ try {
61
+ view.dispatch({
62
+ changes: markdown == null ? void 0 : {
63
+ from: 0,
64
+ to: view.state.doc.length,
65
+ insert: markdown
66
+ },
67
+ selection: selection ? resolveSelection$1(selection, docLength) : void 0,
68
+ scrollIntoView: true
69
+ });
70
+ } finally {
71
+ suppressDocChangeRef.current = false;
72
+ }
73
+ }
74
+ function setMarkdown(markdown) {
75
+ setState(markdown);
76
+ }
77
+ function setSelection(selection) {
78
+ setState(void 0, selection);
79
+ }
80
+ function focus() {
81
+ viewRef.current?.focus();
82
+ }
83
+ function scrollIntoView() {
84
+ viewRef.current?.dispatch({ scrollIntoView: true });
85
+ }
86
+ return {
87
+ getMarkdown,
88
+ setMarkdown,
89
+ getState,
90
+ setState,
91
+ getSelection,
92
+ setSelection,
93
+ focus,
94
+ scrollIntoView,
95
+ editor: void 0
96
+ };
97
+ }, []);
98
+ useLayoutEffect(() => {
99
+ const container = containerRef.current;
100
+ if (!container) return;
101
+ const view = new EditorView({
102
+ parent: container,
103
+ state: EditorState.create({
104
+ doc: initialMarkdownRef.current,
105
+ extensions: [
106
+ history(),
107
+ keymap.of([...defaultKeymap, ...historyKeymap]),
108
+ markdown({ base: markdownLanguage }),
109
+ syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
110
+ EditorView.lineWrapping,
111
+ readOnlyCompartmentRef.current.of(EditorState.readOnly.of(initialReadOnlyRef.current)),
112
+ EditorView.updateListener.of((update) => {
113
+ if (!update.docChanged || suppressDocChangeRef.current) return;
114
+ onDocChangeRef.current?.();
115
+ })
116
+ ]
117
+ })
118
+ });
119
+ viewRef.current = view;
120
+ return () => {
121
+ view.destroy();
122
+ viewRef.current = null;
123
+ };
124
+ }, []);
125
+ useLayoutEffect(() => {
126
+ viewRef.current?.dispatch({ effects: readOnlyCompartmentRef.current.reconfigure(EditorState.readOnly.of(readOnly ?? false)) });
127
+ }, [readOnly]);
128
+ return /* @__PURE__ */ jsx("div", {
129
+ ref: containerRef,
130
+ "data-editor": "codemirror"
131
+ });
132
+ }
133
+
134
+ //#endregion
135
+ //#region src/components/code-block-view.module.css
136
+ var code_block_view_module_default = {
137
+ "CopyButton": "meow_CopyButton_D3j_9q",
138
+ "Empty": "meow_Empty_D3j_9q",
139
+ "Item": "meow_Item_D3j_9q",
140
+ "ItemIndicator": "meow_ItemIndicator_D3j_9q",
141
+ "ItemText": "meow_ItemText_D3j_9q",
142
+ "List": "meow_List_D3j_9q",
143
+ "Popup": "meow_Popup_D3j_9q",
144
+ "Positioner": "meow_Positioner_D3j_9q",
145
+ "Root": "meow_Root_D3j_9q",
146
+ "Search": "meow_Search_D3j_9q",
147
+ "SearchRow": "meow_SearchRow_D3j_9q",
148
+ "Toolbar": "meow_Toolbar_D3j_9q",
149
+ "Trigger": "meow_Trigger_D3j_9q",
150
+ "TriggerIcon": "meow_TriggerIcon_D3j_9q"
151
+ };
152
+
153
+ //#endregion
154
+ //#region src/components/icons/check-icon.tsx
155
+ function CheckIcon() {
156
+ return /* @__PURE__ */ jsx("svg", {
157
+ viewBox: "0 0 24 24",
158
+ fill: "none",
159
+ stroke: "currentColor",
160
+ strokeWidth: 2,
161
+ strokeLinecap: "round",
162
+ strokeLinejoin: "round",
163
+ "aria-hidden": "true",
164
+ children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
165
+ });
166
+ }
167
+
168
+ //#endregion
169
+ //#region src/components/icons/chevrons-up-down-icon.tsx
170
+ function ChevronsUpDownIcon() {
171
+ return /* @__PURE__ */ jsxs("svg", {
172
+ viewBox: "0 0 24 24",
173
+ fill: "none",
174
+ stroke: "currentColor",
175
+ strokeWidth: 2,
176
+ strokeLinecap: "round",
177
+ strokeLinejoin: "round",
178
+ "aria-hidden": "true",
179
+ children: [/* @__PURE__ */ jsx("path", { d: "m7 15 5 5 5-5" }), /* @__PURE__ */ jsx("path", { d: "m7 9 5-5 5 5" })]
180
+ });
181
+ }
182
+
183
+ //#endregion
184
+ //#region src/components/icons/copy-icon.tsx
185
+ function CopyIcon() {
186
+ return /* @__PURE__ */ jsxs("svg", {
187
+ viewBox: "0 0 24 24",
188
+ fill: "none",
189
+ stroke: "currentColor",
190
+ strokeWidth: 2,
191
+ strokeLinecap: "round",
192
+ strokeLinejoin: "round",
193
+ "aria-hidden": "true",
194
+ children: [/* @__PURE__ */ jsx("rect", {
195
+ width: "14",
196
+ height: "14",
197
+ x: "8",
198
+ y: "8",
199
+ rx: "2",
200
+ ry: "2"
201
+ }), /* @__PURE__ */ jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })]
202
+ });
203
+ }
204
+
205
+ //#endregion
206
+ //#region src/components/code-block-view.tsx
207
+ const COPIED_RESET_MS = 1500;
208
+ function CodeBlockView(props) {
209
+ const language = props.node.attrs.language || "";
210
+ const selected = useMemo(() => {
211
+ return codeBlockLanguages.find((item) => item.value === language) ?? {
212
+ value: language,
213
+ label: language
214
+ };
215
+ }, [language]);
216
+ const [query, setQuery] = useState("");
217
+ const [comboboxOpen, setComboboxOpen] = useState(false);
218
+ const itemsForView = useMemo(() => {
219
+ const value = query.trim();
220
+ if (!value) return codeBlockLanguages;
221
+ const lowercased = value.toLowerCase();
222
+ return codeBlockLanguages.some((item) => item.value.toLowerCase() === lowercased || item.label.toLowerCase() === lowercased) ? codeBlockLanguages : [...codeBlockLanguages, {
223
+ value,
224
+ label: `Use "${value}"`
225
+ }];
226
+ }, [query]);
227
+ const setLanguage = (item) => {
228
+ props.setAttrs({ language: item?.value ?? "" });
229
+ };
230
+ const [copied, setCopied] = useState(false);
231
+ const resetTimerRef = useRef(void 0);
232
+ const copy = async () => {
233
+ try {
234
+ await navigator.clipboard.writeText(props.node.textContent);
235
+ setCopied(true);
236
+ clearTimeout(resetTimerRef.current);
237
+ resetTimerRef.current = setTimeout(() => setCopied(false), COPIED_RESET_MS);
238
+ } catch (error) {
239
+ console.warn("[meowdown] Failed to copy code block:", error);
240
+ }
241
+ };
242
+ return /* @__PURE__ */ jsxs("div", {
243
+ className: code_block_view_module_default.Root,
244
+ children: [/* @__PURE__ */ jsxs("div", {
245
+ className: code_block_view_module_default.Toolbar,
246
+ contentEditable: false,
247
+ "data-open": comboboxOpen || void 0,
248
+ children: [/* @__PURE__ */ jsxs(Combobox.Root, {
249
+ items: itemsForView,
250
+ value: selected,
251
+ onValueChange: setLanguage,
252
+ inputValue: query,
253
+ onInputValueChange: setQuery,
254
+ onOpenChange: (open) => {
255
+ if (open) setComboboxOpen(true);
256
+ else setQuery("");
257
+ },
258
+ onOpenChangeComplete: (open) => {
259
+ if (!open) setComboboxOpen(false);
260
+ },
261
+ children: [/* @__PURE__ */ jsxs(Combobox.Trigger, {
262
+ className: code_block_view_module_default.Trigger,
263
+ "data-testid": "code-block-language",
264
+ children: [/* @__PURE__ */ jsx(Combobox.Value, { placeholder: "Plain Text" }), /* @__PURE__ */ jsx(Combobox.Icon, {
265
+ className: code_block_view_module_default.TriggerIcon,
266
+ children: /* @__PURE__ */ jsx(ChevronsUpDownIcon, {})
267
+ })]
268
+ }), /* @__PURE__ */ jsx(Combobox.Portal, { children: /* @__PURE__ */ jsx(Combobox.Positioner, {
269
+ className: code_block_view_module_default.Positioner,
270
+ sideOffset: 4,
271
+ children: /* @__PURE__ */ jsxs(Combobox.Popup, {
272
+ className: code_block_view_module_default.Popup,
273
+ children: [
274
+ /* @__PURE__ */ jsx("div", {
275
+ className: code_block_view_module_default.SearchRow,
276
+ children: /* @__PURE__ */ jsx(Combobox.Input, {
277
+ className: code_block_view_module_default.Search,
278
+ placeholder: "Search or type a language",
279
+ "data-testid": "code-block-language-search"
280
+ })
281
+ }),
282
+ /* @__PURE__ */ jsx(Combobox.Empty, {
283
+ className: code_block_view_module_default.Empty,
284
+ children: "No languages found."
285
+ }),
286
+ /* @__PURE__ */ jsx(Combobox.List, {
287
+ className: code_block_view_module_default.List,
288
+ children: (item) => /* @__PURE__ */ jsxs(Combobox.Item, {
289
+ value: item,
290
+ className: code_block_view_module_default.Item,
291
+ children: [/* @__PURE__ */ jsx(Combobox.ItemIndicator, {
292
+ className: code_block_view_module_default.ItemIndicator,
293
+ children: /* @__PURE__ */ jsx(CheckIcon, {})
294
+ }), /* @__PURE__ */ jsx("span", {
295
+ className: code_block_view_module_default.ItemText,
296
+ children: item.label
297
+ })]
298
+ }, item.label)
299
+ })
300
+ ]
301
+ })
302
+ }) })]
303
+ }), /* @__PURE__ */ jsx("button", {
304
+ type: "button",
305
+ className: code_block_view_module_default.CopyButton,
306
+ "data-testid": "code-block-copy",
307
+ "data-copied": copied ? "" : void 0,
308
+ "aria-label": copied ? "Copied" : "Copy code",
309
+ title: copied ? "Copied" : "Copy code",
310
+ onMouseDown: (event) => event.preventDefault(),
311
+ onClick: copy,
312
+ children: copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {})
313
+ })]
314
+ }), /* @__PURE__ */ jsx("pre", {
315
+ ref: props.contentRef,
316
+ "data-language": language
317
+ })]
318
+ });
319
+ }
320
+
321
+ //#endregion
322
+ //#region src/extensions/code-block-view.ts
323
+ function defineCodeBlockView() {
324
+ return defineReactNodeView({
325
+ name: "codeBlock",
326
+ contentAs: "code",
327
+ component: CodeBlockView
328
+ });
329
+ }
330
+
331
+ //#endregion
332
+ //#region src/components/block-handle.module.css
333
+ var block_handle_module_default = {
334
+ "Add": "meow_Add_EvUpOG",
335
+ "Draggable": "meow_Draggable_EvUpOG",
336
+ "Popup": "meow_Popup_EvUpOG",
337
+ "Positioner": "meow_Positioner_EvUpOG"
338
+ };
339
+
340
+ //#endregion
341
+ //#region src/components/icons/grip-vertical-icon.tsx
342
+ function GripVerticalIcon() {
343
+ return /* @__PURE__ */ jsxs("svg", {
344
+ viewBox: "0 0 24 24",
345
+ fill: "none",
346
+ stroke: "currentColor",
347
+ strokeWidth: 2,
348
+ strokeLinecap: "round",
349
+ strokeLinejoin: "round",
350
+ "aria-hidden": "true",
351
+ children: [
352
+ /* @__PURE__ */ jsx("circle", {
353
+ cx: "9",
354
+ cy: "5",
355
+ r: "1"
356
+ }),
357
+ /* @__PURE__ */ jsx("circle", {
358
+ cx: "9",
359
+ cy: "12",
360
+ r: "1"
361
+ }),
362
+ /* @__PURE__ */ jsx("circle", {
363
+ cx: "9",
364
+ cy: "19",
365
+ r: "1"
366
+ }),
367
+ /* @__PURE__ */ jsx("circle", {
368
+ cx: "15",
369
+ cy: "5",
370
+ r: "1"
371
+ }),
372
+ /* @__PURE__ */ jsx("circle", {
373
+ cx: "15",
374
+ cy: "12",
375
+ r: "1"
376
+ }),
377
+ /* @__PURE__ */ jsx("circle", {
378
+ cx: "15",
379
+ cy: "19",
380
+ r: "1"
381
+ })
382
+ ]
383
+ });
384
+ }
385
+
386
+ //#endregion
387
+ //#region src/components/icons/plus-icon.tsx
388
+ function PlusIcon() {
389
+ return /* @__PURE__ */ jsxs("svg", {
390
+ viewBox: "0 0 24 24",
391
+ fill: "none",
392
+ stroke: "currentColor",
393
+ strokeWidth: 2,
394
+ strokeLinecap: "round",
395
+ strokeLinejoin: "round",
396
+ "aria-hidden": "true",
397
+ children: [/* @__PURE__ */ jsx("path", { d: "M5 12h14" }), /* @__PURE__ */ jsx("path", { d: "M12 5v14" })]
398
+ });
399
+ }
400
+
401
+ //#endregion
402
+ //#region src/components/block-handle.tsx
403
+ function BlockHandle() {
404
+ return /* @__PURE__ */ jsx(BlockHandleRoot, { children: /* @__PURE__ */ jsx(BlockHandlePositioner, {
405
+ className: block_handle_module_default.Positioner,
406
+ children: /* @__PURE__ */ jsxs(BlockHandlePopup, {
407
+ className: block_handle_module_default.Popup,
408
+ "data-testid": "block-handle",
409
+ children: [/* @__PURE__ */ jsx(BlockHandleAdd, {
410
+ className: block_handle_module_default.Add,
411
+ "data-testid": "block-handle-add",
412
+ children: /* @__PURE__ */ jsx(PlusIcon, {})
413
+ }), /* @__PURE__ */ jsx(BlockHandleDraggable, {
414
+ className: block_handle_module_default.Draggable,
415
+ "data-testid": "block-handle-drag",
416
+ children: /* @__PURE__ */ jsx(GripVerticalIcon, {})
417
+ })]
418
+ })
419
+ }) });
420
+ }
421
+
422
+ //#endregion
423
+ //#region src/components/drop-indicator.module.css
424
+ var drop_indicator_module_default = { "DropIndicator": "meow_DropIndicator_urNIwW" };
425
+
426
+ //#endregion
427
+ //#region src/components/drop-indicator.tsx
428
+ function DropIndicator$1() {
429
+ return /* @__PURE__ */ jsx(DropIndicator, {
430
+ className: drop_indicator_module_default.DropIndicator,
431
+ "data-testid": "drop-indicator"
432
+ });
433
+ }
434
+
435
+ //#endregion
436
+ //#region src/components/editor-extensions.tsx
437
+ function EditorExtensions({ markMode, onDocChange, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, placeholder, readOnly }) {
438
+ useExtension(useMemo(() => {
439
+ return defineMarkMode(markMode);
440
+ }, [markMode]));
441
+ useExtension(useMemo(() => {
442
+ return readOnly ? defineReadonly() : null;
443
+ }, [readOnly]));
444
+ useExtension(useMemo(() => {
445
+ return onDocChange ? defineDocChangeHandler(onDocChange) : null;
446
+ }, [onDocChange]));
447
+ useExtension(useMemo(() => {
448
+ return onWikilinkClick ? defineWikilinkClickHandler(onWikilinkClick) : null;
449
+ }, [onWikilinkClick]));
450
+ useExtension(useMemo(() => {
451
+ return resolveImageUrl ? defineImages({
452
+ resolveImageUrl,
453
+ onImagePaste,
454
+ onImageSaveError
455
+ }) : null;
456
+ }, [
457
+ resolveImageUrl,
458
+ onImagePaste,
459
+ onImageSaveError
460
+ ]));
461
+ useExtension(useMemo(() => {
462
+ return placeholder ? definePlaceholder({ placeholder }) : null;
463
+ }, [placeholder]));
464
+ return null;
465
+ }
466
+
467
+ //#endregion
468
+ //#region src/components/autocomplete-menu.module.css
469
+ var autocomplete_menu_module_default = {
470
+ "Detail": "meow_Detail_Dqll0G",
471
+ "Item": "meow_Item_Dqll0G",
472
+ "Popup": "meow_Popup_Dqll0G",
473
+ "Positioner": "meow_Positioner_Dqll0G"
474
+ };
475
+
476
+ //#endregion
477
+ //#region src/components/slash-menu.tsx
478
+ const regex$2 = canUseRegexLookbehind() ? /(?<!\S)\/(\S.*)?$/u : /\/(\S.*)?$/u;
479
+ function SlashMenuItem({ label, kbd, onSelect }) {
480
+ return /* @__PURE__ */ jsxs(AutocompleteItem, {
481
+ className: autocomplete_menu_module_default.Item,
482
+ onSelect,
483
+ children: [/* @__PURE__ */ jsx("span", { children: label }), kbd && /* @__PURE__ */ jsx("kbd", { children: kbd })]
484
+ });
485
+ }
486
+ function SlashMenu() {
487
+ const editor = useEditor$1();
488
+ return /* @__PURE__ */ jsx(AutocompleteRoot, {
489
+ regex: regex$2,
490
+ children: /* @__PURE__ */ jsx(AutocompletePositioner, {
491
+ className: autocomplete_menu_module_default.Positioner,
492
+ children: /* @__PURE__ */ jsxs(AutocompletePopup, {
493
+ className: autocomplete_menu_module_default.Popup,
494
+ "data-testid": "slash-menu",
495
+ children: [
496
+ /* @__PURE__ */ jsx(SlashMenuItem, {
497
+ label: "Heading 1",
498
+ kbd: "#",
499
+ onSelect: () => editor.commands.setHeading({ level: 1 })
500
+ }),
501
+ /* @__PURE__ */ jsx(SlashMenuItem, {
502
+ label: "Heading 2",
503
+ kbd: "##",
504
+ onSelect: () => editor.commands.setHeading({ level: 2 })
505
+ }),
506
+ /* @__PURE__ */ jsx(SlashMenuItem, {
507
+ label: "Heading 3",
508
+ kbd: "###",
509
+ onSelect: () => editor.commands.setHeading({ level: 3 })
510
+ }),
511
+ /* @__PURE__ */ jsx(SlashMenuItem, {
512
+ label: "Heading 4",
513
+ kbd: "####",
514
+ onSelect: () => editor.commands.setHeading({ level: 4 })
515
+ }),
516
+ /* @__PURE__ */ jsx(SlashMenuItem, {
517
+ label: "Blockquote",
518
+ kbd: ">",
519
+ onSelect: () => editor.commands.setBlockquote()
520
+ }),
521
+ /* @__PURE__ */ jsx(SlashMenuItem, {
522
+ label: "Bullet list",
523
+ kbd: "-",
524
+ onSelect: () => editor.commands.wrapInList({ kind: "bullet" })
525
+ }),
526
+ /* @__PURE__ */ jsx(SlashMenuItem, {
527
+ label: "Ordered list",
528
+ kbd: "1.",
529
+ onSelect: () => editor.commands.wrapInList({ kind: "ordered" })
530
+ }),
531
+ /* @__PURE__ */ jsx(SlashMenuItem, {
532
+ label: "Task list",
533
+ kbd: "[]",
534
+ onSelect: () => editor.commands.wrapInList({ kind: "task" })
535
+ }),
536
+ /* @__PURE__ */ jsx(SlashMenuItem, {
537
+ label: "Code block",
538
+ kbd: "```",
539
+ onSelect: () => editor.commands.setCodeBlock()
540
+ }),
541
+ /* @__PURE__ */ jsx(SlashMenuItem, {
542
+ label: "Table",
543
+ onSelect: () => editor.commands.insertTable({
544
+ row: 3,
545
+ col: 3
546
+ })
547
+ }),
548
+ /* @__PURE__ */ jsx(AutocompleteEmpty, {
549
+ className: autocomplete_menu_module_default.Item,
550
+ children: "No results"
551
+ })
552
+ ]
553
+ })
554
+ })
555
+ });
556
+ }
557
+
558
+ //#endregion
559
+ //#region src/utils/returns-true.ts
560
+ function returnsTrue() {
561
+ return true;
562
+ }
563
+
564
+ //#endregion
565
+ //#region src/components/tag-menu.tsx
566
+ const regex$1 = canUseRegexLookbehind() ? /(?<!\S)#[\da-z]+$/iu : /#[\da-z]+$/iu;
567
+ function TagMenu({ onTagSearch }) {
568
+ const editor = useEditor$1();
569
+ const [open, setOpen] = useState(false);
570
+ const [query, setQuery] = useState("");
571
+ const [items, setItems] = useState([]);
572
+ const [loading, setLoading] = useState(false);
573
+ const fetchItems = useCallback(async (query, signal) => {
574
+ if (signal.aborted) return;
575
+ setLoading(true);
576
+ const result = await onTagSearch(query);
577
+ if (signal.aborted) return;
578
+ setItems(result);
579
+ setLoading(false);
580
+ }, [onTagSearch]);
581
+ useEffect(() => {
582
+ if (!open) return;
583
+ const controller = new AbortController();
584
+ queueMicrotask(() => {
585
+ fetchItems(query, controller.signal);
586
+ });
587
+ return () => {
588
+ controller.abort();
589
+ };
590
+ }, [
591
+ open,
592
+ query,
593
+ fetchItems
594
+ ]);
595
+ return /* @__PURE__ */ jsx(AutocompleteRoot, {
596
+ regex: regex$1,
597
+ filter: returnsTrue,
598
+ onOpenChange: (event) => setOpen(event.detail),
599
+ onQueryChange: (event) => setQuery(event.detail),
600
+ children: /* @__PURE__ */ jsx(AutocompletePositioner, {
601
+ className: autocomplete_menu_module_default.Positioner,
602
+ children: /* @__PURE__ */ jsxs(AutocompletePopup, {
603
+ className: autocomplete_menu_module_default.Popup,
604
+ "data-testid": "tag-menu",
605
+ children: [items.map((item) => /* @__PURE__ */ jsxs(AutocompleteItem, {
606
+ className: autocomplete_menu_module_default.Item,
607
+ onSelect: () => {
608
+ editor.commands.insertText({ text: `#${item.tag} ` });
609
+ item.onSelect?.();
610
+ },
611
+ children: [/* @__PURE__ */ jsx("span", { children: item.label ?? `#${item.tag}` }), item.detail ? /* @__PURE__ */ jsx("span", {
612
+ className: autocomplete_menu_module_default.Detail,
613
+ children: item.detail
614
+ }) : null]
615
+ }, item.tag)), /* @__PURE__ */ jsx(AutocompleteEmpty, {
616
+ className: autocomplete_menu_module_default.Item,
617
+ children: loading ? "Loading..." : "No tags found"
618
+ })]
619
+ })
620
+ })
621
+ });
622
+ }
623
+
624
+ //#endregion
625
+ //#region src/components/wikilink-menu.tsx
626
+ const regex = /\[\[[^[\]]*$/u;
627
+ function WikilinkMenu({ onWikilinkSearch }) {
628
+ const editor = useEditor$1();
629
+ const [open, setOpen] = useState(false);
630
+ const [query, setQuery] = useState("");
631
+ const [items, setItems] = useState([]);
632
+ const [loading, setLoading] = useState(false);
633
+ const fetchItems = useCallback(async (query, signal) => {
634
+ if (signal.aborted) return;
635
+ setLoading(true);
636
+ const result = await onWikilinkSearch(query);
637
+ if (signal.aborted) return;
638
+ setItems(result);
639
+ setLoading(false);
640
+ }, [onWikilinkSearch]);
641
+ useEffect(() => {
642
+ if (!open) return;
643
+ const controller = new AbortController();
644
+ queueMicrotask(() => {
645
+ fetchItems(query, controller.signal);
646
+ });
647
+ return () => {
648
+ controller.abort();
649
+ };
650
+ }, [
651
+ open,
652
+ query,
653
+ fetchItems
654
+ ]);
655
+ return /* @__PURE__ */ jsx(AutocompleteRoot, {
656
+ regex,
657
+ filter: returnsTrue,
658
+ onOpenChange: (event) => setOpen(event.detail),
659
+ onQueryChange: (event) => setQuery(event.detail),
660
+ children: /* @__PURE__ */ jsx(AutocompletePositioner, {
661
+ className: autocomplete_menu_module_default.Positioner,
662
+ children: /* @__PURE__ */ jsxs(AutocompletePopup, {
663
+ className: autocomplete_menu_module_default.Popup,
664
+ "data-testid": "wikilink-menu",
665
+ children: [items.map((item) => /* @__PURE__ */ jsxs(AutocompleteItem, {
666
+ className: autocomplete_menu_module_default.Item,
667
+ onSelect: () => {
668
+ editor.commands.insertText({ text: `[[${item.target}]]` });
669
+ item.onSelect?.();
670
+ },
671
+ children: [/* @__PURE__ */ jsx("span", { children: item.label ?? item.target }), item.detail ? /* @__PURE__ */ jsx("span", {
672
+ className: autocomplete_menu_module_default.Detail,
673
+ children: item.detail
674
+ }) : null]
675
+ }, item.target)), /* @__PURE__ */ jsx(AutocompleteEmpty, {
676
+ className: autocomplete_menu_module_default.Item,
677
+ children: loading ? "Loading..." : "No notes found"
678
+ })]
679
+ })
680
+ })
681
+ });
682
+ }
683
+
684
+ //#endregion
685
+ //#region src/components/prosekit-editor.tsx
686
+ function resolveSelection(doc, selection) {
687
+ if (selection === "start") return Selection.atStart(doc);
688
+ if (selection === "end") return Selection.atEnd(doc);
689
+ try {
690
+ return Selection.fromJSON(doc, selection);
691
+ } catch {
692
+ const size = doc.content.size;
693
+ const anchor = clamp(selection.anchor ?? 0, 0, size);
694
+ const head = clamp(selection.head ?? anchor, 0, size);
695
+ return TextSelection.between(doc.resolve(anchor), doc.resolve(head));
696
+ }
697
+ }
698
+ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
699
+ const [editor] = useState(() => {
700
+ const editor = createEditor({ extension: union(defineEditorExtension(), defineCodeBlockView()) });
701
+ if (initialMarkdown) editor.setContent(markdownToDoc(editor, initialMarkdown));
702
+ return editor;
703
+ });
704
+ const suppressDocChangeRef = useRef(false);
705
+ useImperativeHandle(ref, () => {
706
+ function getMarkdown() {
707
+ return docToMarkdown(editor.state.doc);
708
+ }
709
+ function getSelection() {
710
+ return editor.state.selection.toJSON();
711
+ }
712
+ function getState() {
713
+ return [getMarkdown(), getSelection()];
714
+ }
715
+ function setState(markdown, selection) {
716
+ if (markdown == null && !selection) return;
717
+ const transaction = editor.state.tr;
718
+ if (markdown != null) {
719
+ const doc = markdownToDoc(editor, markdown);
720
+ transaction.replaceWith(0, transaction.doc.content.size, doc.content);
721
+ }
722
+ if (selection) transaction.setSelection(resolveSelection(transaction.doc, selection)).scrollIntoView();
723
+ suppressDocChangeRef.current = true;
724
+ try {
725
+ editor.view.dispatch(transaction);
726
+ } finally {
727
+ suppressDocChangeRef.current = false;
728
+ }
729
+ }
730
+ function setMarkdown(markdown) {
731
+ setState(markdown);
732
+ }
733
+ function setSelection(selection) {
734
+ setState(void 0, selection);
735
+ }
736
+ function focus() {
737
+ editor.focus();
738
+ }
739
+ function scrollIntoView() {
740
+ editor.view.dispatch(editor.state.tr.scrollIntoView());
741
+ }
742
+ return {
743
+ getMarkdown,
744
+ setMarkdown,
745
+ getState,
746
+ setState,
747
+ getSelection,
748
+ setSelection,
749
+ focus,
750
+ scrollIntoView,
751
+ editor
752
+ };
753
+ }, [editor]);
754
+ const handleDocChange = useMemo(() => {
755
+ if (!onDocChange) return void 0;
756
+ return () => {
757
+ if (suppressDocChangeRef.current) return;
758
+ onDocChange();
759
+ };
760
+ }, [onDocChange]);
761
+ return /* @__PURE__ */ jsxs(ProseKit, {
762
+ editor,
763
+ children: [
764
+ /* @__PURE__ */ jsx("div", {
765
+ ref: editor.mount,
766
+ spellCheck,
767
+ className: editorClassName
768
+ }),
769
+ /* @__PURE__ */ jsx(EditorExtensions, {
770
+ markMode,
771
+ onDocChange: handleDocChange,
772
+ onWikilinkClick,
773
+ resolveImageUrl,
774
+ onImagePaste,
775
+ onImageSaveError,
776
+ placeholder,
777
+ readOnly
778
+ }),
779
+ /* @__PURE__ */ jsx(BlockHandle, {}),
780
+ /* @__PURE__ */ jsx(DropIndicator$1, {}),
781
+ /* @__PURE__ */ jsx(SlashMenu, {}),
782
+ onTagSearch && /* @__PURE__ */ jsx(TagMenu, { onTagSearch }),
783
+ onWikilinkSearch && /* @__PURE__ */ jsx(WikilinkMenu, { onWikilinkSearch }),
784
+ children
785
+ ]
786
+ });
787
+ }
788
+
789
+ //#endregion
790
+ //#region src/components/editor.tsx
791
+ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, resolveImageUrl, onImagePaste, onImageSaveError, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
792
+ const childRef = useRef(null);
793
+ useImperativeHandle(handleRef, () => {
794
+ function getMarkdown() {
795
+ return childRef.current?.getMarkdown() ?? "";
796
+ }
797
+ function setMarkdown(markdown) {
798
+ childRef.current?.setMarkdown(markdown);
799
+ }
800
+ function getState() {
801
+ return childRef.current?.getState() ?? ["", {
802
+ type: "text",
803
+ anchor: 0,
804
+ head: 0
805
+ }];
806
+ }
807
+ function setState(markdown, selection) {
808
+ childRef.current?.setState(markdown, selection);
809
+ }
810
+ function getSelection() {
811
+ return childRef.current?.getSelection() ?? {
812
+ type: "text",
813
+ anchor: 0,
814
+ head: 0
815
+ };
816
+ }
817
+ function setSelection(selection) {
818
+ childRef.current?.setSelection(selection);
819
+ }
820
+ function focus() {
821
+ childRef.current?.focus();
822
+ }
823
+ function scrollIntoView() {
824
+ childRef.current?.scrollIntoView();
825
+ }
826
+ return {
827
+ getMarkdown,
828
+ setMarkdown,
829
+ getState,
830
+ setState,
831
+ getSelection,
832
+ setSelection,
833
+ focus,
834
+ scrollIntoView,
835
+ get editor() {
836
+ return childRef.current?.editor;
837
+ }
838
+ };
839
+ }, []);
840
+ const seedMarkdown = childRef.current?.getMarkdown() ?? initialMarkdown ?? "";
841
+ return /* @__PURE__ */ jsx("div", {
842
+ className: clsx("meowdown", wrapperClassName),
843
+ children: mode === "source" ? /* @__PURE__ */ jsx(CodeMirrorEditor, {
844
+ ref: childRef,
845
+ initialMarkdown: seedMarkdown,
846
+ onDocChange,
847
+ readOnly
848
+ }) : /* @__PURE__ */ jsx(ProseKitEditor, {
849
+ ref: childRef,
850
+ markMode: mode,
851
+ initialMarkdown: seedMarkdown,
852
+ onDocChange,
853
+ onTagSearch,
854
+ onWikilinkSearch,
855
+ onWikilinkClick,
856
+ resolveImageUrl,
857
+ onImagePaste,
858
+ onImageSaveError,
859
+ placeholder,
860
+ readOnly,
861
+ spellCheck,
862
+ editorClassName,
863
+ children
864
+ })
865
+ });
866
+ }
867
+
868
+ //#endregion
869
+ export { EDITOR_KEY_BINDINGS, MeowdownEditor, checkRoundTrip, useEditor };