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