@meowdown/react 0.7.0 → 0.8.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
@@ -45,7 +45,7 @@ The Markdown editor component. Renders inside a `div.meowdown` wrapper that fill
45
45
  - `onWikilinkSearch?: (query: string) => WikilinkItem[] | Promise<WikilinkItem[]>`: enables the wikilink menu, which opens as soon as `[[` is typed in a rich mode. Returns ranked rows `{ target, label?, detail?, onSelect? }` (the menu does not re-sort). Selecting a row inserts `[[target]]` then runs its `onSelect`. Omit to disable.
46
46
  - `onWikilinkClick?: (payload: { target: string; event: MouseEvent }) => void`: called when a rendered wiki link is clicked. A plain click inside a link the caret already sits in just places the caret; `Mod`-click always fires. Pass a stable function (e.g. from `useCallback`). Ignored in source mode.
47
47
  - `resolveImageUrl?: (src: string) => string | undefined`: maps an image `src` to a displayable URL (or `undefined` to skip). Enables inline image rendering: `![alt](src)` stays literal text and the image renders beneath its line. Pass a stable function. Ignored in source mode.
48
- - `onImagePaste?: (file: File) => Promise<string | undefined>`: persists a pasted or dropped image file and returns its markdown `src` (or `undefined` to decline). Pass a stable function. Ignored in source mode.
48
+ - `onImagePaste?: (file: File) => string | undefined | Promise<string | undefined>`: persists a pasted or dropped image file and returns its markdown `src` (or `undefined` to decline), synchronously or as a promise. Pass a stable function. Ignored in source mode.
49
49
  - `onImageSaveError?: (error: unknown, file: File) => void`: called when `onImagePaste` throws. Defaults to `console.error`. Ignored in source mode.
50
50
  - `placeholder?: string | ((state) => string)`: placeholder text shown when the whole document is empty. Pass a stable function. Ignored in source mode.
51
51
  - `readOnly?: boolean`: makes the editor read-only, in both the rich and source modes.
package/dist/index.js CHANGED
@@ -10,11 +10,13 @@ import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import { codeBlockLanguages, defineEditorExtension, defineImages, defineMarkMode, definePlaceholder, defineReadonly, defineWikilinkClickHandler, docToMarkdown, markdownToDoc } from "@meowdown/core";
11
11
  import { canUseRegexLookbehind, createEditor, defineDocChangeHandler, union } from "@prosekit/core";
12
12
  import { Selection, TextSelection } from "@prosekit/pm/state";
13
- import { ProseKit, defineReactNodeView, useEditor, useEditor as useEditor$1, useExtension } from "@prosekit/react";
13
+ import { ProseKit, defineReactNodeView, useEditor, useEditor as useEditor$1, useEditorDerivedValue, useExtension } from "@prosekit/react";
14
14
  import { Combobox } from "@base-ui/react/combobox";
15
15
  import { BlockHandleAdd, BlockHandleDraggable, BlockHandlePopup, BlockHandlePositioner, BlockHandleRoot } from "@prosekit/react/block-handle";
16
16
  import { DropIndicator } from "@prosekit/react/drop-indicator";
17
17
  import { AutocompleteEmpty, AutocompleteItem, AutocompletePopup, AutocompletePositioner, AutocompleteRoot } from "@prosekit/react/autocomplete";
18
+ import { MenuItem, MenuPopup, MenuPositioner } from "@prosekit/react/menu";
19
+ import { TableHandleColumnMenuRoot, TableHandleColumnMenuTrigger, TableHandleColumnPopup, TableHandleColumnPositioner, TableHandleDragPreview, TableHandleDropIndicator, TableHandleRoot, TableHandleRowMenuRoot, TableHandleRowMenuTrigger, TableHandleRowPopup, TableHandleRowPositioner } from "@prosekit/react/table-handle";
18
20
 
19
21
  //#region src/components/codemirror-editor.tsx
20
22
  function resolveSelection$1(selection, docLength) {
@@ -545,7 +547,8 @@ function SlashMenu() {
545
547
  label: "Table",
546
548
  onSelect: () => editor.commands.insertTable({
547
549
  row: 3,
548
- col: 3
550
+ col: 3,
551
+ header: true
549
552
  })
550
553
  }),
551
554
  /* @__PURE__ */ jsx(AutocompleteEmpty, {
@@ -558,6 +561,212 @@ function SlashMenu() {
558
561
  });
559
562
  }
560
563
 
564
+ //#endregion
565
+ //#region src/components/icons/grip-horizontal-icon.tsx
566
+ function GripHorizontalIcon() {
567
+ return /* @__PURE__ */ jsxs("svg", {
568
+ viewBox: "0 0 24 24",
569
+ fill: "none",
570
+ stroke: "currentColor",
571
+ strokeWidth: 2,
572
+ strokeLinecap: "round",
573
+ strokeLinejoin: "round",
574
+ "aria-hidden": "true",
575
+ children: [
576
+ /* @__PURE__ */ jsx("circle", {
577
+ cx: "12",
578
+ cy: "9",
579
+ r: "1"
580
+ }),
581
+ /* @__PURE__ */ jsx("circle", {
582
+ cx: "19",
583
+ cy: "9",
584
+ r: "1"
585
+ }),
586
+ /* @__PURE__ */ jsx("circle", {
587
+ cx: "5",
588
+ cy: "9",
589
+ r: "1"
590
+ }),
591
+ /* @__PURE__ */ jsx("circle", {
592
+ cx: "12",
593
+ cy: "15",
594
+ r: "1"
595
+ }),
596
+ /* @__PURE__ */ jsx("circle", {
597
+ cx: "19",
598
+ cy: "15",
599
+ r: "1"
600
+ }),
601
+ /* @__PURE__ */ jsx("circle", {
602
+ cx: "5",
603
+ cy: "15",
604
+ r: "1"
605
+ })
606
+ ]
607
+ });
608
+ }
609
+
610
+ //#endregion
611
+ //#region src/components/table-handle.module.css
612
+ var table_handle_module_default = {
613
+ "ColumnPopup": "meow_ColumnPopup_hpZLgq",
614
+ "MenuItem": "meow_MenuItem_hpZLgq",
615
+ "MenuPopup": "meow_MenuPopup_hpZLgq",
616
+ "MenuPositioner": "meow_MenuPositioner_hpZLgq",
617
+ "Positioner": "meow_Positioner_hpZLgq",
618
+ "RowPopup": "meow_RowPopup_hpZLgq",
619
+ "Trigger": "meow_Trigger_hpZLgq"
620
+ };
621
+
622
+ //#endregion
623
+ //#region src/components/table-handle.tsx
624
+ function getTableHandleState(editor) {
625
+ const commands = editor.commands;
626
+ return {
627
+ addTableColumnBefore: {
628
+ canExec: commands.addTableColumnBefore.canExec(),
629
+ command: () => commands.addTableColumnBefore()
630
+ },
631
+ addTableColumnAfter: {
632
+ canExec: commands.addTableColumnAfter.canExec(),
633
+ command: () => commands.addTableColumnAfter()
634
+ },
635
+ addTableRowAbove: {
636
+ canExec: commands.addTableRowAbove.canExec(),
637
+ command: () => commands.addTableRowAbove()
638
+ },
639
+ addTableRowBelow: {
640
+ canExec: commands.addTableRowBelow.canExec(),
641
+ command: () => commands.addTableRowBelow()
642
+ },
643
+ deleteCellSelection: {
644
+ canExec: commands.deleteCellSelection.canExec(),
645
+ command: () => commands.deleteCellSelection()
646
+ },
647
+ deleteTableColumn: {
648
+ canExec: commands.deleteTableColumn.canExec(),
649
+ command: () => commands.deleteTableColumn()
650
+ },
651
+ deleteTableRow: {
652
+ canExec: commands.deleteTableRow.canExec(),
653
+ command: () => commands.deleteTableRow()
654
+ },
655
+ deleteTable: {
656
+ canExec: commands.deleteTable.canExec(),
657
+ command: () => commands.deleteTable()
658
+ }
659
+ };
660
+ }
661
+ function TableHandle() {
662
+ const state = useEditorDerivedValue(getTableHandleState);
663
+ return /* @__PURE__ */ jsxs(TableHandleRoot, { children: [
664
+ /* @__PURE__ */ jsx(TableHandleDragPreview, {}),
665
+ /* @__PURE__ */ jsx(TableHandleDropIndicator, {}),
666
+ /* @__PURE__ */ jsx(TableHandleColumnPositioner, {
667
+ className: table_handle_module_default.Positioner,
668
+ children: /* @__PURE__ */ jsx(TableHandleColumnPopup, {
669
+ className: table_handle_module_default.ColumnPopup,
670
+ children: /* @__PURE__ */ jsxs(TableHandleColumnMenuRoot, { children: [/* @__PURE__ */ jsx(TableHandleColumnMenuTrigger, {
671
+ className: table_handle_module_default.Trigger,
672
+ "data-testid": "table-handle-column",
673
+ children: /* @__PURE__ */ jsx(GripHorizontalIcon, {})
674
+ }), /* @__PURE__ */ jsx(MenuPositioner, {
675
+ className: table_handle_module_default.MenuPositioner,
676
+ children: /* @__PURE__ */ jsxs(MenuPopup, {
677
+ className: table_handle_module_default.MenuPopup,
678
+ "data-testid": "table-handle-column-menu",
679
+ children: [
680
+ state.addTableColumnBefore.canExec && /* @__PURE__ */ jsx(MenuItem, {
681
+ className: table_handle_module_default.MenuItem,
682
+ "data-testid": "table-insert-left",
683
+ onSelect: state.addTableColumnBefore.command,
684
+ children: /* @__PURE__ */ jsx("span", { children: "Insert Left" })
685
+ }),
686
+ state.addTableColumnAfter.canExec && /* @__PURE__ */ jsx(MenuItem, {
687
+ className: table_handle_module_default.MenuItem,
688
+ "data-testid": "table-insert-right",
689
+ onSelect: state.addTableColumnAfter.command,
690
+ children: /* @__PURE__ */ jsx("span", { children: "Insert Right" })
691
+ }),
692
+ state.deleteCellSelection.canExec && /* @__PURE__ */ jsxs(MenuItem, {
693
+ className: table_handle_module_default.MenuItem,
694
+ "data-testid": "table-clear-column",
695
+ onSelect: state.deleteCellSelection.command,
696
+ children: [/* @__PURE__ */ jsx("span", { children: "Clear Contents" }), /* @__PURE__ */ jsx("kbd", { children: "Del" })]
697
+ }),
698
+ state.deleteTableColumn.canExec && /* @__PURE__ */ jsx(MenuItem, {
699
+ className: table_handle_module_default.MenuItem,
700
+ "data-testid": "table-delete-column",
701
+ onSelect: state.deleteTableColumn.command,
702
+ children: /* @__PURE__ */ jsx("span", { children: "Delete Column" })
703
+ }),
704
+ state.deleteTable.canExec && /* @__PURE__ */ jsx(MenuItem, {
705
+ className: table_handle_module_default.MenuItem,
706
+ "data-danger": "",
707
+ "data-testid": "table-delete-table-column",
708
+ onSelect: state.deleteTable.command,
709
+ children: /* @__PURE__ */ jsx("span", { children: "Delete Table" })
710
+ })
711
+ ]
712
+ })
713
+ })] })
714
+ })
715
+ }),
716
+ /* @__PURE__ */ jsx(TableHandleRowPositioner, {
717
+ placement: "left",
718
+ className: table_handle_module_default.Positioner,
719
+ children: /* @__PURE__ */ jsx(TableHandleRowPopup, {
720
+ className: table_handle_module_default.RowPopup,
721
+ children: /* @__PURE__ */ jsxs(TableHandleRowMenuRoot, { children: [/* @__PURE__ */ jsx(TableHandleRowMenuTrigger, {
722
+ className: table_handle_module_default.Trigger,
723
+ "data-testid": "table-handle-row",
724
+ children: /* @__PURE__ */ jsx(GripVerticalIcon, {})
725
+ }), /* @__PURE__ */ jsx(MenuPositioner, {
726
+ className: table_handle_module_default.MenuPositioner,
727
+ children: /* @__PURE__ */ jsxs(MenuPopup, {
728
+ className: table_handle_module_default.MenuPopup,
729
+ "data-testid": "table-handle-row-menu",
730
+ children: [
731
+ state.addTableRowAbove.canExec && /* @__PURE__ */ jsx(MenuItem, {
732
+ className: table_handle_module_default.MenuItem,
733
+ "data-testid": "table-insert-above",
734
+ onSelect: state.addTableRowAbove.command,
735
+ children: /* @__PURE__ */ jsx("span", { children: "Insert Above" })
736
+ }),
737
+ state.addTableRowBelow.canExec && /* @__PURE__ */ jsx(MenuItem, {
738
+ className: table_handle_module_default.MenuItem,
739
+ "data-testid": "table-insert-below",
740
+ onSelect: state.addTableRowBelow.command,
741
+ children: /* @__PURE__ */ jsx("span", { children: "Insert Below" })
742
+ }),
743
+ state.deleteCellSelection.canExec && /* @__PURE__ */ jsxs(MenuItem, {
744
+ className: table_handle_module_default.MenuItem,
745
+ "data-testid": "table-clear-row",
746
+ onSelect: state.deleteCellSelection.command,
747
+ children: [/* @__PURE__ */ jsx("span", { children: "Clear Contents" }), /* @__PURE__ */ jsx("kbd", { children: "Del" })]
748
+ }),
749
+ state.deleteTableRow.canExec && /* @__PURE__ */ jsx(MenuItem, {
750
+ className: table_handle_module_default.MenuItem,
751
+ "data-testid": "table-delete-row",
752
+ onSelect: state.deleteTableRow.command,
753
+ children: /* @__PURE__ */ jsx("span", { children: "Delete Row" })
754
+ }),
755
+ state.deleteTable.canExec && /* @__PURE__ */ jsx(MenuItem, {
756
+ className: table_handle_module_default.MenuItem,
757
+ "data-danger": "",
758
+ "data-testid": "table-delete-table-row",
759
+ onSelect: state.deleteTable.command,
760
+ children: /* @__PURE__ */ jsx("span", { children: "Delete Table" })
761
+ })
762
+ ]
763
+ })
764
+ })] })
765
+ })
766
+ })
767
+ ] });
768
+ }
769
+
561
770
  //#endregion
562
771
  //#region src/utils/returns-true.ts
563
772
  function returnsTrue() {
@@ -780,6 +989,7 @@ function ProseKitEditor({ markMode = "focus", initialMarkdown, onDocChange, onTa
780
989
  readOnly
781
990
  }),
782
991
  /* @__PURE__ */ jsx(BlockHandle, {}),
992
+ !readOnly && /* @__PURE__ */ jsx(TableHandle, {}),
783
993
  /* @__PURE__ */ jsx(DropIndicator$1, {}),
784
994
  /* @__PURE__ */ jsx(SlashMenu, {}),
785
995
  onTagSearch && /* @__PURE__ */ jsx(TagMenu, { onTagSearch }),
package/dist/style.css CHANGED
@@ -323,6 +323,146 @@
323
323
  flex-shrink: 0;
324
324
  font-size: .8125rem;
325
325
  }
326
+ .meow_Positioner_hpZLgq, .meow_MenuPositioner_hpZLgq {
327
+ z-index: 50;
328
+ width: min-content;
329
+ height: min-content;
330
+ transition: transform .1s ease-out;
331
+ display: block;
332
+ overflow: visible;
333
+
334
+ @media (prefers-reduced-motion: reduce) {
335
+ transition: none;
336
+ }
337
+ }
338
+
339
+ .meow_ColumnPopup_hpZLgq {
340
+ transform: translateY(50%);
341
+ }
342
+
343
+ .meow_RowPopup_hpZLgq {
344
+ transform: translateX(50%);
345
+ }
346
+
347
+ .meow_ColumnPopup_hpZLgq, .meow_RowPopup_hpZLgq {
348
+ box-sizing: border-box;
349
+ transform-origin: var(--transform-origin);
350
+ transition: opacity .1s, scale .1s;
351
+ display: flex;
352
+
353
+ &[data-state="closed"] {
354
+ opacity: 0;
355
+ transition-duration: .15s;
356
+ scale: .95;
357
+ }
358
+
359
+ @starting-style {
360
+ opacity: 0;
361
+ scale: .95;
362
+ }
363
+
364
+ @media (prefers-reduced-motion: reduce) {
365
+ transition: none;
366
+ }
367
+ }
368
+
369
+ .meow_Trigger_hpZLgq {
370
+ box-sizing: border-box;
371
+ border: 1px solid var(--meowdown-border);
372
+ color: color-mix(in oklab, var(--meowdown-muted) 50%, transparent);
373
+ cursor: grab;
374
+ background: light-dark(#fff, #18181b);
375
+ border-radius: .25rem;
376
+ outline: none;
377
+ justify-content: center;
378
+ align-items: center;
379
+ padding: 0;
380
+ transition: background-color .1s;
381
+ display: flex;
382
+ overflow: clip;
383
+
384
+ &:hover {
385
+ background: light-dark(#f4f4f5, #27272a);
386
+ }
387
+
388
+ & svg {
389
+ width: 1.25rem;
390
+ height: 1.25rem;
391
+ display: block;
392
+ }
393
+ }
394
+
395
+ .meow_MenuPopup_hpZLgq {
396
+ box-sizing: border-box;
397
+ overscroll-behavior: contain;
398
+ white-space: nowrap;
399
+ user-select: none;
400
+ border: 1px solid var(--meowdown-border);
401
+ min-width: 8rem;
402
+ max-height: 25rem;
403
+ transform-origin: var(--transform-origin);
404
+ background: light-dark(#fff, #18181b);
405
+ border-radius: .75rem;
406
+ outline: none;
407
+ flex-direction: column;
408
+ padding: .25rem;
409
+ transition: opacity .1s, scale .1s;
410
+ display: flex;
411
+ overflow: auto;
412
+ box-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;
413
+
414
+ &[data-state="closed"] {
415
+ opacity: 0;
416
+ transition-duration: .15s;
417
+ scale: .95;
418
+ }
419
+
420
+ @starting-style {
421
+ opacity: 0;
422
+ scale: .95;
423
+ }
424
+
425
+ @media (prefers-reduced-motion: reduce) {
426
+ transition: none;
427
+ }
428
+ }
429
+
430
+ .meow_MenuItem_hpZLgq {
431
+ box-sizing: border-box;
432
+ color: var(--meowdown-text);
433
+ white-space: nowrap;
434
+ cursor: default;
435
+ user-select: none;
436
+ border-radius: .5rem;
437
+ outline: none;
438
+ justify-content: space-between;
439
+ align-items: center;
440
+ gap: 1.5rem;
441
+ padding: .375rem .75rem;
442
+ scroll-margin: .25rem;
443
+ font-size: .875rem;
444
+ display: flex;
445
+
446
+ &[data-highlighted] {
447
+ background: light-dark(#f4f4f5, #27272a);
448
+ }
449
+
450
+ &[data-danger] {
451
+ color: light-dark(#ef4444, #f87171);
452
+ }
453
+
454
+ &[data-disabled="true"] {
455
+ pointer-events: none;
456
+ opacity: .5;
457
+ }
458
+
459
+ & kbd {
460
+ font-family: var(--meowdown-font-mono);
461
+ color: var(--meowdown-muted);
462
+ opacity: .8;
463
+ font-size: .75rem;
464
+ }
465
+ }
326
466
  .meowdown {
327
467
  flex-direction: column;
328
468
  flex: 1 0 auto;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meowdown/react",
3
3
  "type": "module",
4
- "version": "0.7.0",
4
+ "version": "0.8.1",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "@prosekit/pm": "^0.1.18",
29
29
  "@prosekit/react": "^0.8.0-beta.0",
30
30
  "clsx": "^2.1.1",
31
- "@meowdown/core": "0.7.0"
31
+ "@meowdown/core": "0.8.1"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "react": "^19.0.0",
@@ -49,6 +49,7 @@
49
49
  "@types/react": "^19.2.17",
50
50
  "@types/react-dom": "^19.2.3",
51
51
  "@vitest/browser-playwright": "^4.1.8",
52
+ "dedent": "^1.7.2",
52
53
  "react": "^19.2.7",
53
54
  "react-dom": "^19.2.7",
54
55
  "tsdown": "^0.22.2",