@meowdown/react 0.16.2 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,7 +32,7 @@ export function App() {
32
32
 
33
33
  ### `<MeowdownEditor>`
34
34
 
35
- The Markdown editor component. Renders inside a `div.meowdown` wrapper that fills a flex parent. In rich modes, typing `/` opens a slash menu for inserting blocks (headings, blockquote, lists, code block, table). Hovering a block shows a handle to its left: the plus button inserts an empty paragraph below the block, and the grip selects the block and can be dragged to move it, with a drop indicator line marking the target.
35
+ The Markdown editor component. Renders inside a `div.meowdown` wrapper that fills a flex parent. In rich modes, typing `/` opens a slash menu for inserting blocks (headings, blockquote, lists, code block, table). Hovering a block shows a handle to its left: the grip selects the block and can be dragged to move it, with a drop indicator line marking the target.
36
36
 
37
37
  - `mode?: 'focus' | 'show' | 'hide' | 'source'`: defaults to `'focus'`.
38
38
  - `'focus'`: Markdown syntax is hidden, revealed around the cursor.
@@ -51,7 +51,7 @@ The Markdown editor component. Renders inside a `div.meowdown` wrapper that fill
51
51
  - `onImageClick?: (payload: { src: string; alt: string; event: MouseEvent }) => void`: called when a rendered image is clicked, with its markdown `src`, `alt`, and the originating `MouseEvent`. Pass a stable function (e.g. from `useCallback`). Ignored in source mode.
52
52
  - `embedPaste?: boolean`: auto-embeds a pasted tweet or YouTube link as a rich embed; one undo turns the embed back into the raw link. On by default; set `false` to disable. Only takes effect when `resolveImageUrl` is set, since embeds render through the image pipeline. Ignored in source mode.
53
53
  - `bulletAfterHeading?: boolean`: pressing Enter at the end of the document's first heading (the title line) starts a fresh empty bullet on the next line instead of a plain paragraph. Off by default. Ignored in source mode.
54
- - `blockHandle?: boolean`: shows the per-block gutter handle in the rich modes (a drag grip for reordering blocks and a `+` add button, plus the drop indicator). On by default; set `false` to hide the gutter affordance entirely, e.g. when the host does not want block reordering. Ignored in source mode and when `readOnly` is set.
54
+ - `blockHandle?: boolean`: shows the per-block gutter handle in the rich modes (a drag grip for reordering blocks, plus the drop indicator). On by default; set `false` to hide the gutter affordance entirely, e.g. when the host does not want block reordering. Ignored in source mode and when `readOnly` is set.
55
55
  - `placeholder?: string | ((state) => string)`: placeholder text shown when the whole document is empty. Pass a stable function. Ignored in source mode.
56
56
  - `readOnly?: boolean`: makes the editor read-only, in both the rich and source modes.
57
57
  - `spellCheck?: boolean`: toggles the browser's native spell checking in the rich modes. Defaults to the browser's behavior. Ignored in source mode.
package/dist/index.d.ts CHANGED
@@ -155,6 +155,8 @@ interface EditorProps {
155
155
  * Off by default. Ignored in source mode.
156
156
  */
157
157
  bulletAfterHeading?: boolean;
158
+ /** Handles a leading `---` frontmatter block in the rich modes (off by default, ignored in source mode). */
159
+ frontmatter?: boolean;
158
160
  /**
159
161
  * Shows the per-block gutter handle in the rich modes: a drag grip for
160
162
  * reordering blocks and a "+" add button, plus the drop indicator that
@@ -198,6 +200,7 @@ declare function MeowdownEditor({
198
200
  onImageClick,
199
201
  embedPaste,
200
202
  bulletAfterHeading,
203
+ frontmatter,
201
204
  blockHandle,
202
205
  placeholder,
203
206
  readOnly,
package/dist/index.js CHANGED
@@ -12,7 +12,8 @@ import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, union } fr
12
12
  import { Selection, TextSelection } from "@prosekit/pm/state";
13
13
  import { ProseKit, defineReactNodeView, useEditor, useEditor as useEditor$1, useEditorDerivedValue, useExtension, useExtension as useExtension$1, useKeymap } from "@prosekit/react";
14
14
  import { Combobox } from "@base-ui/react/combobox";
15
- import { BlockHandleAdd, BlockHandleDraggable, BlockHandlePopup, BlockHandlePositioner, BlockHandleRoot } from "@prosekit/react/block-handle";
15
+ import { CheckIcon, ChevronsUpDownIcon, CopyIcon, GripHorizontalIcon, GripVerticalIcon } from "lucide-react";
16
+ import { BlockHandleDraggable, BlockHandlePopup, BlockHandlePositioner, BlockHandleRoot } from "@prosekit/react/block-handle";
16
17
  import { DropIndicator } from "@prosekit/react/drop-indicator";
17
18
  import { AutocompleteEmpty, AutocompleteItem, AutocompletePopup, AutocompletePositioner, AutocompleteRoot } from "@prosekit/react/autocomplete";
18
19
  import { MenuItem, MenuPopup, MenuPositioner } from "@prosekit/react/menu";
@@ -152,58 +153,6 @@ var code_block_view_module_default = {
152
153
  "TriggerIcon": "meow_TriggerIcon_D3j_9q"
153
154
  };
154
155
 
155
- //#endregion
156
- //#region src/components/icons/check-icon.tsx
157
- function CheckIcon() {
158
- return /* @__PURE__ */ jsx("svg", {
159
- viewBox: "0 0 24 24",
160
- fill: "none",
161
- stroke: "currentColor",
162
- strokeWidth: 2,
163
- strokeLinecap: "round",
164
- strokeLinejoin: "round",
165
- "aria-hidden": "true",
166
- children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
167
- });
168
- }
169
-
170
- //#endregion
171
- //#region src/components/icons/chevrons-up-down-icon.tsx
172
- function ChevronsUpDownIcon() {
173
- return /* @__PURE__ */ jsxs("svg", {
174
- viewBox: "0 0 24 24",
175
- fill: "none",
176
- stroke: "currentColor",
177
- strokeWidth: 2,
178
- strokeLinecap: "round",
179
- strokeLinejoin: "round",
180
- "aria-hidden": "true",
181
- children: [/* @__PURE__ */ jsx("path", { d: "m7 15 5 5 5-5" }), /* @__PURE__ */ jsx("path", { d: "m7 9 5-5 5 5" })]
182
- });
183
- }
184
-
185
- //#endregion
186
- //#region src/components/icons/copy-icon.tsx
187
- function CopyIcon() {
188
- return /* @__PURE__ */ jsxs("svg", {
189
- viewBox: "0 0 24 24",
190
- fill: "none",
191
- stroke: "currentColor",
192
- strokeWidth: 2,
193
- strokeLinecap: "round",
194
- strokeLinejoin: "round",
195
- "aria-hidden": "true",
196
- children: [/* @__PURE__ */ jsx("rect", {
197
- width: "14",
198
- height: "14",
199
- x: "8",
200
- y: "8",
201
- rx: "2",
202
- ry: "2"
203
- }), /* @__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" })]
204
- });
205
- }
206
-
207
156
  //#endregion
208
157
  //#region src/components/code-block-view.tsx
209
158
  const COPIED_RESET_MS = 1500;
@@ -333,90 +282,24 @@ function defineCodeBlockView() {
333
282
  //#endregion
334
283
  //#region src/components/block-handle.module.css
335
284
  var block_handle_module_default = {
336
- "Add": "meow_Add_EvUpOG",
337
285
  "Draggable": "meow_Draggable_EvUpOG",
338
286
  "Popup": "meow_Popup_EvUpOG",
339
287
  "Positioner": "meow_Positioner_EvUpOG"
340
288
  };
341
289
 
342
- //#endregion
343
- //#region src/components/icons/grip-vertical-icon.tsx
344
- function GripVerticalIcon() {
345
- return /* @__PURE__ */ jsxs("svg", {
346
- viewBox: "0 0 24 24",
347
- fill: "none",
348
- stroke: "currentColor",
349
- strokeWidth: 2,
350
- strokeLinecap: "round",
351
- strokeLinejoin: "round",
352
- "aria-hidden": "true",
353
- children: [
354
- /* @__PURE__ */ jsx("circle", {
355
- cx: "9",
356
- cy: "5",
357
- r: "1"
358
- }),
359
- /* @__PURE__ */ jsx("circle", {
360
- cx: "9",
361
- cy: "12",
362
- r: "1"
363
- }),
364
- /* @__PURE__ */ jsx("circle", {
365
- cx: "9",
366
- cy: "19",
367
- r: "1"
368
- }),
369
- /* @__PURE__ */ jsx("circle", {
370
- cx: "15",
371
- cy: "5",
372
- r: "1"
373
- }),
374
- /* @__PURE__ */ jsx("circle", {
375
- cx: "15",
376
- cy: "12",
377
- r: "1"
378
- }),
379
- /* @__PURE__ */ jsx("circle", {
380
- cx: "15",
381
- cy: "19",
382
- r: "1"
383
- })
384
- ]
385
- });
386
- }
387
-
388
- //#endregion
389
- //#region src/components/icons/plus-icon.tsx
390
- function PlusIcon() {
391
- return /* @__PURE__ */ jsxs("svg", {
392
- viewBox: "0 0 24 24",
393
- fill: "none",
394
- stroke: "currentColor",
395
- strokeWidth: 2,
396
- strokeLinecap: "round",
397
- strokeLinejoin: "round",
398
- "aria-hidden": "true",
399
- children: [/* @__PURE__ */ jsx("path", { d: "M5 12h14" }), /* @__PURE__ */ jsx("path", { d: "M12 5v14" })]
400
- });
401
- }
402
-
403
290
  //#endregion
404
291
  //#region src/components/block-handle.tsx
405
292
  function BlockHandle() {
406
293
  return /* @__PURE__ */ jsx(BlockHandleRoot, { children: /* @__PURE__ */ jsx(BlockHandlePositioner, {
407
294
  className: block_handle_module_default.Positioner,
408
- children: /* @__PURE__ */ jsxs(BlockHandlePopup, {
295
+ children: /* @__PURE__ */ jsx(BlockHandlePopup, {
409
296
  className: block_handle_module_default.Popup,
410
297
  "data-testid": "block-handle",
411
- children: [/* @__PURE__ */ jsx(BlockHandleAdd, {
412
- className: block_handle_module_default.Add,
413
- "data-testid": "block-handle-add",
414
- children: /* @__PURE__ */ jsx(PlusIcon, {})
415
- }), /* @__PURE__ */ jsx(BlockHandleDraggable, {
298
+ children: /* @__PURE__ */ jsx(BlockHandleDraggable, {
416
299
  className: block_handle_module_default.Draggable,
417
300
  "data-testid": "block-handle-drag",
418
301
  children: /* @__PURE__ */ jsx(GripVerticalIcon, {})
419
- })]
302
+ })
420
303
  })
421
304
  }) });
422
305
  }
@@ -574,52 +457,6 @@ function SlashMenu() {
574
457
  });
575
458
  }
576
459
 
577
- //#endregion
578
- //#region src/components/icons/grip-horizontal-icon.tsx
579
- function GripHorizontalIcon() {
580
- return /* @__PURE__ */ jsxs("svg", {
581
- viewBox: "0 0 24 24",
582
- fill: "none",
583
- stroke: "currentColor",
584
- strokeWidth: 2,
585
- strokeLinecap: "round",
586
- strokeLinejoin: "round",
587
- "aria-hidden": "true",
588
- children: [
589
- /* @__PURE__ */ jsx("circle", {
590
- cx: "12",
591
- cy: "9",
592
- r: "1"
593
- }),
594
- /* @__PURE__ */ jsx("circle", {
595
- cx: "19",
596
- cy: "9",
597
- r: "1"
598
- }),
599
- /* @__PURE__ */ jsx("circle", {
600
- cx: "5",
601
- cy: "9",
602
- r: "1"
603
- }),
604
- /* @__PURE__ */ jsx("circle", {
605
- cx: "12",
606
- cy: "15",
607
- r: "1"
608
- }),
609
- /* @__PURE__ */ jsx("circle", {
610
- cx: "19",
611
- cy: "15",
612
- r: "1"
613
- }),
614
- /* @__PURE__ */ jsx("circle", {
615
- cx: "5",
616
- cy: "15",
617
- r: "1"
618
- })
619
- ]
620
- });
621
- }
622
-
623
460
  //#endregion
624
461
  //#region src/components/table-handle.module.css
625
462
  var table_handle_module_default = {
@@ -926,16 +763,19 @@ function resolveSelection(doc, selection) {
926
763
  return TextSelection.between(doc.resolve(anchor), doc.resolve(head));
927
764
  }
928
765
  }
929
- function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste, bulletAfterHeading, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
766
+ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste, bulletAfterHeading, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, ref, children }) {
930
767
  const [editor] = useState(() => {
931
768
  const editor = createEditor({ extension: union(defineEditorExtension(), defineCodeBlockView()) });
932
- if (initialMarkdown) editor.setContent(markdownToDoc(initialMarkdown, editor.nodes));
769
+ if (initialMarkdown) editor.setContent(markdownToDoc(initialMarkdown, {
770
+ nodes: editor.nodes,
771
+ frontmatter
772
+ }));
933
773
  return editor;
934
774
  });
935
775
  const suppressDocChangeRef = useRef(false);
936
776
  useImperativeHandle(ref, () => {
937
777
  function getMarkdown() {
938
- return docToMarkdown(editor.state.doc);
778
+ return docToMarkdown(editor.state.doc, { frontmatter });
939
779
  }
940
780
  function getSelection() {
941
781
  return editor.state.selection.toJSON();
@@ -947,7 +787,10 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
947
787
  if (markdown == null && !selection) return;
948
788
  const transaction = editor.state.tr;
949
789
  if (markdown != null) {
950
- const doc = markdownToDoc(markdown, editor.nodes);
790
+ const doc = markdownToDoc(markdown, {
791
+ nodes: editor.nodes,
792
+ frontmatter
793
+ });
951
794
  transaction.replaceWith(0, transaction.doc.content.size, doc.content);
952
795
  }
953
796
  if (selection) transaction.setSelection(resolveSelection(transaction.doc, selection)).scrollIntoView();
@@ -981,7 +824,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
981
824
  scrollIntoView,
982
825
  editor
983
826
  };
984
- }, [editor]);
827
+ }, [editor, frontmatter]);
985
828
  const handleDocChange = useMemo(() => {
986
829
  if (!onDocChange) return;
987
830
  return () => {
@@ -995,7 +838,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
995
838
  /* @__PURE__ */ jsx("div", {
996
839
  ref: editor.mount,
997
840
  spellCheck,
998
- className: editorClassName
841
+ className: clsx("meowdown-content", editorClassName)
999
842
  }),
1000
843
  /* @__PURE__ */ jsx(EditorExtensions, {
1001
844
  markMode,
@@ -1024,7 +867,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
1024
867
 
1025
868
  //#endregion
1026
869
  //#region src/components/editor.tsx
1027
- function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste = true, bulletAfterHeading = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
870
+ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSearch, onWikilinkSearch, onWikilinkClick, onLinkClick, resolveImageUrl, onImagePaste, onImageSaveError, onImageClick, embedPaste = true, bulletAfterHeading = false, frontmatter = false, blockHandle = true, placeholder, readOnly, spellCheck, editorClassName, wrapperClassName, handleRef, children }) {
1028
871
  const childRef = useRef(null);
1029
872
  useImperativeHandle(handleRef, () => {
1030
873
  function getMarkdown() {
@@ -1096,6 +939,7 @@ function MeowdownEditor({ mode = "focus", initialMarkdown, onDocChange, onTagSea
1096
939
  onImageClick,
1097
940
  embedPaste,
1098
941
  bulletAfterHeading,
942
+ frontmatter,
1099
943
  blockHandle,
1100
944
  placeholder,
1101
945
  readOnly,
package/dist/style.css CHANGED
@@ -228,10 +228,12 @@
228
228
  }
229
229
  }
230
230
 
231
- .meow_Add_EvUpOG, .meow_Draggable_EvUpOG {
231
+ .meow_Draggable_EvUpOG {
232
232
  box-sizing: border-box;
233
+ width: 1.25rem;
233
234
  height: 1.5rem;
234
235
  color: color-mix(in oklab, var(--meowdown-muted) 50%, transparent);
236
+ cursor: grab;
235
237
  border-radius: .25rem;
236
238
  justify-content: center;
237
239
  align-items: center;
@@ -247,16 +249,6 @@
247
249
  display: block;
248
250
  }
249
251
  }
250
-
251
- .meow_Add_EvUpOG {
252
- cursor: pointer;
253
- width: 1.5rem;
254
- }
255
-
256
- .meow_Draggable_EvUpOG {
257
- cursor: grab;
258
- width: 1.25rem;
259
- }
260
252
  .meow_DropIndicator_urNIwW {
261
253
  z-index: 50;
262
254
  background: var(--meowdown-accent);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/react",
3
3
  "type": "module",
4
- "version": "0.16.2",
4
+ "version": "0.17.1",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -26,9 +26,10 @@
26
26
  "@ocavue/utils": "^1.7.0",
27
27
  "@prosekit/core": "^0.13.0-beta.3",
28
28
  "@prosekit/pm": "^0.1.19-beta.0",
29
- "@prosekit/react": "^0.8.0-beta.6",
29
+ "@prosekit/react": "^0.8.0-beta.7",
30
30
  "clsx": "^2.1.1",
31
- "@meowdown/core": "0.16.2"
31
+ "lucide-react": "^1.21.0",
32
+ "@meowdown/core": "0.17.1"
32
33
  },
33
34
  "peerDependencies": {
34
35
  "react": "^19.0.0",