@trafica/editor 1.0.20 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +301 -115
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +301 -115
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -665,6 +665,10 @@ declare function replaceAllMatches(matches: SearchMatch[], replacement: string):
|
|
|
665
665
|
*
|
|
666
666
|
* Tab → move cursor to next cell (adds row if on last cell)
|
|
667
667
|
* Shift+Tab → move cursor to previous cell (no-op on first cell)
|
|
668
|
+
* ArrowRight → move to next cell when at end of current cell
|
|
669
|
+
* ArrowLeft → move to previous cell when at start of current cell
|
|
670
|
+
* ArrowDown → move to cell below when on bottom line
|
|
671
|
+
* ArrowUp → move to cell above when on top line
|
|
668
672
|
*
|
|
669
673
|
* Enter inside a cell is handled by the default handleEnter command because
|
|
670
674
|
* findContentBlockPath correctly resolves to the paragraph inside the cell
|
package/dist/index.d.ts
CHANGED
|
@@ -665,6 +665,10 @@ declare function replaceAllMatches(matches: SearchMatch[], replacement: string):
|
|
|
665
665
|
*
|
|
666
666
|
* Tab → move cursor to next cell (adds row if on last cell)
|
|
667
667
|
* Shift+Tab → move cursor to previous cell (no-op on first cell)
|
|
668
|
+
* ArrowRight → move to next cell when at end of current cell
|
|
669
|
+
* ArrowLeft → move to previous cell when at start of current cell
|
|
670
|
+
* ArrowDown → move to cell below when on bottom line
|
|
671
|
+
* ArrowUp → move to cell above when on top line
|
|
668
672
|
*
|
|
669
673
|
* Enter inside a cell is handled by the default handleEnter command because
|
|
670
674
|
* findContentBlockPath correctly resolves to the paragraph inside the cell
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var reactDom = require('react-dom');
|
|
5
6
|
|
|
6
7
|
// src/editor/core/DocumentModel.ts
|
|
7
8
|
function isTextNode(node) {
|
|
@@ -5532,9 +5533,11 @@ function SpecialCharactersButton({
|
|
|
5532
5533
|
null
|
|
5533
5534
|
);
|
|
5534
5535
|
const [focusedIdx, setFocusedIdx] = react.useState(-1);
|
|
5535
|
-
const
|
|
5536
|
+
const buttonRef = react.useRef(null);
|
|
5537
|
+
const popupRef = react.useRef(null);
|
|
5536
5538
|
const searchRef = react.useRef(null);
|
|
5537
5539
|
const gridRef = react.useRef(null);
|
|
5540
|
+
const [popupPos, setPopupPos] = react.useState({ top: 0, left: 0 });
|
|
5538
5541
|
const filtered = react.useMemo(() => {
|
|
5539
5542
|
const q = search.toLowerCase();
|
|
5540
5543
|
return SPECIAL_CHARACTERS.filter(
|
|
@@ -5542,6 +5545,12 @@ function SpecialCharactersButton({
|
|
|
5542
5545
|
);
|
|
5543
5546
|
}, [category, search]);
|
|
5544
5547
|
const openModal = () => {
|
|
5548
|
+
if (buttonRef.current) {
|
|
5549
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
5550
|
+
const popupWidth = 340;
|
|
5551
|
+
const left = Math.min(rect.left, window.innerWidth - popupWidth - 8);
|
|
5552
|
+
setPopupPos({ top: rect.bottom + 4, left: Math.max(8, left) });
|
|
5553
|
+
}
|
|
5545
5554
|
setOpen(true);
|
|
5546
5555
|
setSearch("");
|
|
5547
5556
|
setFocusedIdx(-1);
|
|
@@ -5554,9 +5563,11 @@ function SpecialCharactersButton({
|
|
|
5554
5563
|
react.useEffect(() => {
|
|
5555
5564
|
if (!open) return;
|
|
5556
5565
|
const handler = (e) => {
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5566
|
+
var _a, _b;
|
|
5567
|
+
const target = e.target;
|
|
5568
|
+
const insidePopup = (_a = popupRef.current) == null ? void 0 : _a.contains(target);
|
|
5569
|
+
const insideButton = (_b = buttonRef.current) == null ? void 0 : _b.contains(target);
|
|
5570
|
+
if (!insidePopup && !insideButton) closeModal();
|
|
5560
5571
|
};
|
|
5561
5572
|
document.addEventListener("mousedown", handler);
|
|
5562
5573
|
return () => document.removeEventListener("mousedown", handler);
|
|
@@ -5604,10 +5615,11 @@ function SpecialCharactersButton({
|
|
|
5604
5615
|
const cell = gridRef.current.children[focusedIdx];
|
|
5605
5616
|
cell == null ? void 0 : cell.focus();
|
|
5606
5617
|
}, [focusedIdx]);
|
|
5607
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5618
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5608
5619
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5609
5620
|
"button",
|
|
5610
5621
|
{
|
|
5622
|
+
ref: buttonRef,
|
|
5611
5623
|
type: "button",
|
|
5612
5624
|
title: "Special Characters",
|
|
5613
5625
|
"aria-label": "Insert special character",
|
|
@@ -5615,7 +5627,11 @@ function SpecialCharactersButton({
|
|
|
5615
5627
|
"aria-expanded": open,
|
|
5616
5628
|
onMouseDown: (e) => {
|
|
5617
5629
|
e.preventDefault();
|
|
5618
|
-
|
|
5630
|
+
if (open) {
|
|
5631
|
+
closeModal();
|
|
5632
|
+
} else {
|
|
5633
|
+
openModal();
|
|
5634
|
+
}
|
|
5619
5635
|
},
|
|
5620
5636
|
className: [
|
|
5621
5637
|
"flex items-center justify-center w-8 h-8 rounded text-sm font-medium transition-colors",
|
|
@@ -5624,127 +5640,131 @@ function SpecialCharactersButton({
|
|
|
5624
5640
|
children: /* @__PURE__ */ jsxRuntime.jsx(OmegaIcon, {})
|
|
5625
5641
|
}
|
|
5626
5642
|
),
|
|
5627
|
-
open &&
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5643
|
-
"
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
] }),
|
|
5653
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5654
|
-
"input",
|
|
5655
|
-
{
|
|
5656
|
-
ref: searchRef,
|
|
5657
|
-
type: "search",
|
|
5658
|
-
placeholder: "Search characters\u2026",
|
|
5659
|
-
value: search,
|
|
5660
|
-
onChange: (e) => {
|
|
5661
|
-
setSearch(e.target.value);
|
|
5662
|
-
setFocusedIdx(-1);
|
|
5663
|
-
},
|
|
5664
|
-
onKeyDown: (e) => {
|
|
5665
|
-
var _a, _b;
|
|
5666
|
-
if (e.key === "Escape") closeModal();
|
|
5667
|
-
if (e.key === "ArrowDown") {
|
|
5668
|
-
e.preventDefault();
|
|
5669
|
-
setFocusedIdx(0);
|
|
5670
|
-
(_b = (_a = gridRef.current) == null ? void 0 : _a.children[0]) == null ? void 0 : _b.dispatchEvent(
|
|
5671
|
-
new Event("focus")
|
|
5672
|
-
);
|
|
5643
|
+
open && reactDom.createPortal(
|
|
5644
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5645
|
+
"div",
|
|
5646
|
+
{
|
|
5647
|
+
ref: popupRef,
|
|
5648
|
+
role: "dialog",
|
|
5649
|
+
"aria-label": "Special characters",
|
|
5650
|
+
"aria-modal": "true",
|
|
5651
|
+
className: "bg-white border border-gray-200 rounded-lg shadow-2xl flex flex-col",
|
|
5652
|
+
style: { position: "fixed", top: popupPos.top, left: popupPos.left, width: 340, maxHeight: 420, zIndex: 9999 },
|
|
5653
|
+
onKeyDown: (e) => {
|
|
5654
|
+
if (e.key === "Escape") closeModal();
|
|
5655
|
+
},
|
|
5656
|
+
children: [
|
|
5657
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pt-3 pb-2 border-b border-gray-100 ", children: [
|
|
5658
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
5659
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide", children: "Special Characters" }),
|
|
5660
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5661
|
+
"button",
|
|
5662
|
+
{
|
|
5663
|
+
type: "button",
|
|
5664
|
+
onClick: closeModal,
|
|
5665
|
+
"aria-label": "Close",
|
|
5666
|
+
className: "text-gray-400 hover:text-gray-600 p-0.5 rounded",
|
|
5667
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
|
|
5673
5668
|
}
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-2", children: CATEGORIES.map((cat) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5679
|
-
"button",
|
|
5680
|
-
{
|
|
5681
|
-
type: "button",
|
|
5682
|
-
onMouseDown: (e) => {
|
|
5683
|
-
e.preventDefault();
|
|
5684
|
-
setCategory(cat);
|
|
5685
|
-
setFocusedIdx(-1);
|
|
5686
|
-
},
|
|
5687
|
-
className: [
|
|
5688
|
-
"px-2 py-0.5 rounded text-xs font-medium transition-colors",
|
|
5689
|
-
category === cat ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200 "
|
|
5690
|
-
].join(" "),
|
|
5691
|
-
children: cat
|
|
5692
|
-
},
|
|
5693
|
-
cat
|
|
5694
|
-
)) })
|
|
5695
|
-
] }),
|
|
5696
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5697
|
-
"div",
|
|
5698
|
-
{
|
|
5699
|
-
ref: gridRef,
|
|
5700
|
-
role: "grid",
|
|
5701
|
-
"aria-label": "Character grid",
|
|
5702
|
-
className: "flex-1 overflow-y-auto p-2",
|
|
5703
|
-
style: {
|
|
5704
|
-
display: "grid",
|
|
5705
|
-
gridTemplateColumns: "repeat(8, 1fr)",
|
|
5706
|
-
gap: 2
|
|
5707
|
-
},
|
|
5708
|
-
onKeyDown: handleGridKeyDown,
|
|
5709
|
-
children: filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5710
|
-
"div",
|
|
5669
|
+
)
|
|
5670
|
+
] }),
|
|
5671
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5672
|
+
"input",
|
|
5711
5673
|
{
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5674
|
+
ref: searchRef,
|
|
5675
|
+
type: "search",
|
|
5676
|
+
placeholder: "Search characters\u2026",
|
|
5677
|
+
value: search,
|
|
5678
|
+
onChange: (e) => {
|
|
5679
|
+
setSearch(e.target.value);
|
|
5680
|
+
setFocusedIdx(-1);
|
|
5681
|
+
},
|
|
5682
|
+
onKeyDown: (e) => {
|
|
5683
|
+
var _a, _b;
|
|
5684
|
+
if (e.key === "Escape") closeModal();
|
|
5685
|
+
if (e.key === "ArrowDown") {
|
|
5686
|
+
e.preventDefault();
|
|
5687
|
+
setFocusedIdx(0);
|
|
5688
|
+
(_b = (_a = gridRef.current) == null ? void 0 : _a.children[0]) == null ? void 0 : _b.dispatchEvent(
|
|
5689
|
+
new Event("focus")
|
|
5690
|
+
);
|
|
5691
|
+
}
|
|
5692
|
+
},
|
|
5693
|
+
className: "w-full border border-gray-200 rounded px-2.5 py-1.5 text-sm bg-white text-gray-900 placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
5715
5694
|
}
|
|
5716
|
-
)
|
|
5695
|
+
),
|
|
5696
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 mt-2", children: CATEGORIES.map((cat) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5717
5697
|
"button",
|
|
5718
5698
|
{
|
|
5719
5699
|
type: "button",
|
|
5720
|
-
role: "gridcell",
|
|
5721
|
-
tabIndex: focusedIdx === idx ? 0 : -1,
|
|
5722
|
-
"aria-label": c.name,
|
|
5723
|
-
title: c.name,
|
|
5724
5700
|
onMouseDown: (e) => {
|
|
5725
5701
|
e.preventDefault();
|
|
5726
|
-
|
|
5702
|
+
setCategory(cat);
|
|
5703
|
+
setFocusedIdx(-1);
|
|
5727
5704
|
},
|
|
5728
|
-
onMouseEnter: () => setHovered({ char: c.char, name: c.name }),
|
|
5729
|
-
onMouseLeave: () => setHovered(null),
|
|
5730
|
-
onFocus: () => setHovered({ char: c.char, name: c.name }),
|
|
5731
|
-
onBlur: () => setHovered(null),
|
|
5732
5705
|
className: [
|
|
5733
|
-
"
|
|
5734
|
-
|
|
5706
|
+
"px-2 py-0.5 rounded text-xs font-medium transition-colors",
|
|
5707
|
+
category === cat ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200 "
|
|
5735
5708
|
].join(" "),
|
|
5736
|
-
children:
|
|
5709
|
+
children: cat
|
|
5737
5710
|
},
|
|
5738
|
-
|
|
5739
|
-
))
|
|
5740
|
-
}
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5711
|
+
cat
|
|
5712
|
+
)) })
|
|
5713
|
+
] }),
|
|
5714
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5715
|
+
"div",
|
|
5716
|
+
{
|
|
5717
|
+
ref: gridRef,
|
|
5718
|
+
role: "grid",
|
|
5719
|
+
"aria-label": "Character grid",
|
|
5720
|
+
className: "flex-1 overflow-y-auto p-2",
|
|
5721
|
+
style: {
|
|
5722
|
+
display: "grid",
|
|
5723
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
5724
|
+
gap: 2
|
|
5725
|
+
},
|
|
5726
|
+
onKeyDown: handleGridKeyDown,
|
|
5727
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5728
|
+
"div",
|
|
5729
|
+
{
|
|
5730
|
+
className: "col-span-8 text-center py-8 text-sm text-gray-400 ",
|
|
5731
|
+
role: "status",
|
|
5732
|
+
children: "No characters found"
|
|
5733
|
+
}
|
|
5734
|
+
) : filtered.map((c, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5735
|
+
"button",
|
|
5736
|
+
{
|
|
5737
|
+
type: "button",
|
|
5738
|
+
role: "gridcell",
|
|
5739
|
+
tabIndex: focusedIdx === idx ? 0 : -1,
|
|
5740
|
+
"aria-label": c.name,
|
|
5741
|
+
title: c.name,
|
|
5742
|
+
onMouseDown: (e) => {
|
|
5743
|
+
e.preventDefault();
|
|
5744
|
+
insertChar(c.char);
|
|
5745
|
+
},
|
|
5746
|
+
onMouseEnter: () => setHovered({ char: c.char, name: c.name }),
|
|
5747
|
+
onMouseLeave: () => setHovered(null),
|
|
5748
|
+
onFocus: () => setHovered({ char: c.char, name: c.name }),
|
|
5749
|
+
onBlur: () => setHovered(null),
|
|
5750
|
+
className: [
|
|
5751
|
+
"flex items-center justify-center rounded text-base h-8 w-full transition-colors cursor-pointer select-none",
|
|
5752
|
+
focusedIdx === idx ? "bg-blue-100 text-blue-700 ring-2 ring-blue-500" : "text-gray-800 hover:bg-blue-50 hover:text-blue-700 "
|
|
5753
|
+
].join(" "),
|
|
5754
|
+
children: c.char
|
|
5755
|
+
},
|
|
5756
|
+
c.char + c.name
|
|
5757
|
+
))
|
|
5758
|
+
}
|
|
5759
|
+
),
|
|
5760
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 border-t border-gray-100 flex items-center gap-3 min-h-[40px]", children: hovered ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5761
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-2xl leading-none text-gray-800 w-8 text-center", children: hovered.char }),
|
|
5762
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500 truncate", children: hovered.name })
|
|
5763
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-400 ", children: "Hover or use arrow keys to preview" }) })
|
|
5764
|
+
]
|
|
5765
|
+
}
|
|
5766
|
+
),
|
|
5767
|
+
document.body
|
|
5748
5768
|
)
|
|
5749
5769
|
] });
|
|
5750
5770
|
}
|
|
@@ -8609,6 +8629,53 @@ function prettyPrintHTML(html) {
|
|
|
8609
8629
|
}
|
|
8610
8630
|
|
|
8611
8631
|
// src/editor/table/TablePlugin.ts
|
|
8632
|
+
function getCellDOMElement(cellPathJson) {
|
|
8633
|
+
return document.querySelector(`[data-block-path='${cellPathJson}']`);
|
|
8634
|
+
}
|
|
8635
|
+
function isCaretAtContainerStart(container) {
|
|
8636
|
+
const sel = window.getSelection();
|
|
8637
|
+
if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
|
|
8638
|
+
const range = sel.getRangeAt(0);
|
|
8639
|
+
if (range.startOffset !== 0) return false;
|
|
8640
|
+
let node = range.startContainer;
|
|
8641
|
+
while (node && node !== container) {
|
|
8642
|
+
if (node.previousSibling) return false;
|
|
8643
|
+
node = node.parentNode;
|
|
8644
|
+
}
|
|
8645
|
+
return node === container;
|
|
8646
|
+
}
|
|
8647
|
+
function isCaretAtContainerEnd(container) {
|
|
8648
|
+
var _a, _b;
|
|
8649
|
+
const sel = window.getSelection();
|
|
8650
|
+
if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
|
|
8651
|
+
const range = sel.getRangeAt(0);
|
|
8652
|
+
const endNode = range.endContainer;
|
|
8653
|
+
const endOffset = range.endOffset;
|
|
8654
|
+
const len = endNode.nodeType === Node.TEXT_NODE ? (_b = (_a = endNode.textContent) == null ? void 0 : _a.length) != null ? _b : 0 : endNode.childNodes.length;
|
|
8655
|
+
if (endOffset !== len) return false;
|
|
8656
|
+
let node = endNode;
|
|
8657
|
+
while (node && node !== container) {
|
|
8658
|
+
if (node.nextSibling) return false;
|
|
8659
|
+
node = node.parentNode;
|
|
8660
|
+
}
|
|
8661
|
+
return node === container;
|
|
8662
|
+
}
|
|
8663
|
+
function isCaretOnEdgeLine(container, direction) {
|
|
8664
|
+
const sel = window.getSelection();
|
|
8665
|
+
if (!sel || sel.rangeCount === 0 || !sel.isCollapsed) return false;
|
|
8666
|
+
const caretRange = sel.getRangeAt(0).cloneRange();
|
|
8667
|
+
caretRange.collapse(true);
|
|
8668
|
+
const caretRects = caretRange.getClientRects();
|
|
8669
|
+
if (!caretRects.length) return true;
|
|
8670
|
+
const caretRect = caretRects[0];
|
|
8671
|
+
const containerRect = container.getBoundingClientRect();
|
|
8672
|
+
const lineHeight = parseFloat(getComputedStyle(container).lineHeight) || 20;
|
|
8673
|
+
if (direction === "up") {
|
|
8674
|
+
return caretRect.top < containerRect.top + lineHeight;
|
|
8675
|
+
} else {
|
|
8676
|
+
return caretRect.bottom > containerRect.bottom - lineHeight;
|
|
8677
|
+
}
|
|
8678
|
+
}
|
|
8612
8679
|
var TablePlugin = {
|
|
8613
8680
|
name: "table",
|
|
8614
8681
|
keyBindings: {
|
|
@@ -8659,6 +8726,125 @@ var TablePlugin = {
|
|
|
8659
8726
|
engine.dispatch(tr);
|
|
8660
8727
|
return true;
|
|
8661
8728
|
},
|
|
8729
|
+
"ArrowRight": (engine) => {
|
|
8730
|
+
var _a;
|
|
8731
|
+
const state = engine.getState();
|
|
8732
|
+
const sel = state.selection;
|
|
8733
|
+
if (!sel) return false;
|
|
8734
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
8735
|
+
if (!cellPos) return false;
|
|
8736
|
+
const { tablePath, row, col } = cellPos;
|
|
8737
|
+
const cellPath = [...tablePath, row, col];
|
|
8738
|
+
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
8739
|
+
if (!cellEl || !isCaretAtContainerEnd(cellEl)) return false;
|
|
8740
|
+
const table = getNodeAtPath(state.doc, tablePath);
|
|
8741
|
+
const { rows, cols } = getTableDimensions(table);
|
|
8742
|
+
let nextRow = row;
|
|
8743
|
+
let nextCol = col + 1;
|
|
8744
|
+
while (nextRow < rows) {
|
|
8745
|
+
if (nextCol >= cols) {
|
|
8746
|
+
nextCol = 0;
|
|
8747
|
+
nextRow++;
|
|
8748
|
+
continue;
|
|
8749
|
+
}
|
|
8750
|
+
const c = getNodeAtPath(state.doc, [...tablePath, nextRow, nextCol]);
|
|
8751
|
+
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
8752
|
+
nextCol++;
|
|
8753
|
+
}
|
|
8754
|
+
if (nextRow >= rows) return true;
|
|
8755
|
+
const pos = getCellFirstPosition(state.doc, tablePath, nextRow, nextCol);
|
|
8756
|
+
if (!pos) return false;
|
|
8757
|
+
const tr = createTransaction();
|
|
8758
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
8759
|
+
engine.dispatch(tr);
|
|
8760
|
+
return true;
|
|
8761
|
+
},
|
|
8762
|
+
"ArrowLeft": (engine) => {
|
|
8763
|
+
var _a;
|
|
8764
|
+
const state = engine.getState();
|
|
8765
|
+
const sel = state.selection;
|
|
8766
|
+
if (!sel) return false;
|
|
8767
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
8768
|
+
if (!cellPos) return false;
|
|
8769
|
+
const { tablePath, row, col } = cellPos;
|
|
8770
|
+
const cellPath = [...tablePath, row, col];
|
|
8771
|
+
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
8772
|
+
if (!cellEl || !isCaretAtContainerStart(cellEl)) return false;
|
|
8773
|
+
const table = getNodeAtPath(state.doc, tablePath);
|
|
8774
|
+
const { cols } = getTableDimensions(table);
|
|
8775
|
+
let prevRow = row;
|
|
8776
|
+
let prevCol = col - 1;
|
|
8777
|
+
while (prevRow >= 0) {
|
|
8778
|
+
if (prevCol < 0) {
|
|
8779
|
+
prevCol = cols - 1;
|
|
8780
|
+
prevRow--;
|
|
8781
|
+
continue;
|
|
8782
|
+
}
|
|
8783
|
+
const c = getNodeAtPath(state.doc, [...tablePath, prevRow, prevCol]);
|
|
8784
|
+
if (!((_a = c == null ? void 0 : c.attrs) == null ? void 0 : _a.covered)) break;
|
|
8785
|
+
prevCol--;
|
|
8786
|
+
}
|
|
8787
|
+
if (prevRow < 0) return true;
|
|
8788
|
+
const pos = getCellLastPosition(state.doc, tablePath, prevRow, prevCol);
|
|
8789
|
+
if (!pos) return false;
|
|
8790
|
+
const tr = createTransaction();
|
|
8791
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
8792
|
+
engine.dispatch(tr);
|
|
8793
|
+
return true;
|
|
8794
|
+
},
|
|
8795
|
+
"ArrowDown": (engine) => {
|
|
8796
|
+
var _a;
|
|
8797
|
+
const state = engine.getState();
|
|
8798
|
+
const sel = state.selection;
|
|
8799
|
+
if (!sel) return false;
|
|
8800
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
8801
|
+
if (!cellPos) return false;
|
|
8802
|
+
const { tablePath, row, col } = cellPos;
|
|
8803
|
+
const cellPath = [...tablePath, row, col];
|
|
8804
|
+
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
8805
|
+
if (!cellEl || !isCaretOnEdgeLine(cellEl, "down")) return false;
|
|
8806
|
+
const table = getNodeAtPath(state.doc, tablePath);
|
|
8807
|
+
const { rows, cols } = getTableDimensions(table);
|
|
8808
|
+
let nextRow = row + 1;
|
|
8809
|
+
while (nextRow < rows) {
|
|
8810
|
+
const c = getNodeAtPath(state.doc, [...tablePath, nextRow, col]);
|
|
8811
|
+
if (c && !((_a = c.attrs) == null ? void 0 : _a.covered)) break;
|
|
8812
|
+
nextRow++;
|
|
8813
|
+
}
|
|
8814
|
+
if (nextRow >= rows) return false;
|
|
8815
|
+
const pos = getCellFirstPosition(state.doc, tablePath, nextRow, col < cols ? col : 0);
|
|
8816
|
+
if (!pos) return false;
|
|
8817
|
+
const tr = createTransaction();
|
|
8818
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
8819
|
+
engine.dispatch(tr);
|
|
8820
|
+
return true;
|
|
8821
|
+
},
|
|
8822
|
+
"ArrowUp": (engine) => {
|
|
8823
|
+
var _a;
|
|
8824
|
+
const state = engine.getState();
|
|
8825
|
+
const sel = state.selection;
|
|
8826
|
+
if (!sel) return false;
|
|
8827
|
+
const cellPos = findCellPosition(state.doc, sel.anchor.path);
|
|
8828
|
+
if (!cellPos) return false;
|
|
8829
|
+
const { tablePath, row, col } = cellPos;
|
|
8830
|
+
const cellPath = [...tablePath, row, col];
|
|
8831
|
+
const cellEl = getCellDOMElement(JSON.stringify(cellPath));
|
|
8832
|
+
if (!cellEl || !isCaretOnEdgeLine(cellEl, "up")) return false;
|
|
8833
|
+
let prevRow = row - 1;
|
|
8834
|
+
while (prevRow >= 0) {
|
|
8835
|
+
const c = getNodeAtPath(state.doc, [...tablePath, prevRow, col]);
|
|
8836
|
+
if (c && !((_a = c.attrs) == null ? void 0 : _a.covered)) break;
|
|
8837
|
+
prevRow--;
|
|
8838
|
+
}
|
|
8839
|
+
if (prevRow < 0) return false;
|
|
8840
|
+
const { cols } = getTableDimensions(getNodeAtPath(state.doc, tablePath));
|
|
8841
|
+
const pos = getCellLastPosition(state.doc, tablePath, prevRow, col < cols ? col : 0);
|
|
8842
|
+
if (!pos) return false;
|
|
8843
|
+
const tr = createTransaction();
|
|
8844
|
+
tr.steps.push(tr_setSelection(makeCollapsedSelection(pos)));
|
|
8845
|
+
engine.dispatch(tr);
|
|
8846
|
+
return true;
|
|
8847
|
+
},
|
|
8662
8848
|
"Shift+Tab": (engine) => {
|
|
8663
8849
|
var _a;
|
|
8664
8850
|
const state = engine.getState();
|