@trafica/editor 1.0.19 → 1.0.21
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 +147 -116
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -116
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { forwardRef, useRef, useEffect, useCallback, useMemo, useImperativeHandle, useState, useLayoutEffect, useSyncExternalStore } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
3
4
|
|
|
4
5
|
// src/editor/core/DocumentModel.ts
|
|
5
6
|
function isTextNode(node) {
|
|
@@ -5530,9 +5531,11 @@ function SpecialCharactersButton({
|
|
|
5530
5531
|
null
|
|
5531
5532
|
);
|
|
5532
5533
|
const [focusedIdx, setFocusedIdx] = useState(-1);
|
|
5533
|
-
const
|
|
5534
|
+
const buttonRef = useRef(null);
|
|
5535
|
+
const popupRef = useRef(null);
|
|
5534
5536
|
const searchRef = useRef(null);
|
|
5535
5537
|
const gridRef = useRef(null);
|
|
5538
|
+
const [popupPos, setPopupPos] = useState({ top: 0, left: 0 });
|
|
5536
5539
|
const filtered = useMemo(() => {
|
|
5537
5540
|
const q = search.toLowerCase();
|
|
5538
5541
|
return SPECIAL_CHARACTERS.filter(
|
|
@@ -5540,6 +5543,12 @@ function SpecialCharactersButton({
|
|
|
5540
5543
|
);
|
|
5541
5544
|
}, [category, search]);
|
|
5542
5545
|
const openModal = () => {
|
|
5546
|
+
if (buttonRef.current) {
|
|
5547
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
5548
|
+
const popupWidth = 340;
|
|
5549
|
+
const left = Math.min(rect.left, window.innerWidth - popupWidth - 8);
|
|
5550
|
+
setPopupPos({ top: rect.bottom + 4, left: Math.max(8, left) });
|
|
5551
|
+
}
|
|
5543
5552
|
setOpen(true);
|
|
5544
5553
|
setSearch("");
|
|
5545
5554
|
setFocusedIdx(-1);
|
|
@@ -5552,9 +5561,11 @@ function SpecialCharactersButton({
|
|
|
5552
5561
|
useEffect(() => {
|
|
5553
5562
|
if (!open) return;
|
|
5554
5563
|
const handler = (e) => {
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5564
|
+
var _a, _b;
|
|
5565
|
+
const target = e.target;
|
|
5566
|
+
const insidePopup = (_a = popupRef.current) == null ? void 0 : _a.contains(target);
|
|
5567
|
+
const insideButton = (_b = buttonRef.current) == null ? void 0 : _b.contains(target);
|
|
5568
|
+
if (!insidePopup && !insideButton) closeModal();
|
|
5558
5569
|
};
|
|
5559
5570
|
document.addEventListener("mousedown", handler);
|
|
5560
5571
|
return () => document.removeEventListener("mousedown", handler);
|
|
@@ -5602,10 +5613,11 @@ function SpecialCharactersButton({
|
|
|
5602
5613
|
const cell = gridRef.current.children[focusedIdx];
|
|
5603
5614
|
cell == null ? void 0 : cell.focus();
|
|
5604
5615
|
}, [focusedIdx]);
|
|
5605
|
-
return /* @__PURE__ */ jsxs(
|
|
5616
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5606
5617
|
/* @__PURE__ */ jsx(
|
|
5607
5618
|
"button",
|
|
5608
5619
|
{
|
|
5620
|
+
ref: buttonRef,
|
|
5609
5621
|
type: "button",
|
|
5610
5622
|
title: "Special Characters",
|
|
5611
5623
|
"aria-label": "Insert special character",
|
|
@@ -5613,7 +5625,11 @@ function SpecialCharactersButton({
|
|
|
5613
5625
|
"aria-expanded": open,
|
|
5614
5626
|
onMouseDown: (e) => {
|
|
5615
5627
|
e.preventDefault();
|
|
5616
|
-
|
|
5628
|
+
if (open) {
|
|
5629
|
+
closeModal();
|
|
5630
|
+
} else {
|
|
5631
|
+
openModal();
|
|
5632
|
+
}
|
|
5617
5633
|
},
|
|
5618
5634
|
className: [
|
|
5619
5635
|
"flex items-center justify-center w-8 h-8 rounded text-sm font-medium transition-colors",
|
|
@@ -5622,127 +5638,131 @@ function SpecialCharactersButton({
|
|
|
5622
5638
|
children: /* @__PURE__ */ jsx(OmegaIcon, {})
|
|
5623
5639
|
}
|
|
5624
5640
|
),
|
|
5625
|
-
open &&
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
/* @__PURE__ */
|
|
5641
|
-
"
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
] }),
|
|
5651
|
-
/* @__PURE__ */ jsx(
|
|
5652
|
-
"input",
|
|
5653
|
-
{
|
|
5654
|
-
ref: searchRef,
|
|
5655
|
-
type: "search",
|
|
5656
|
-
placeholder: "Search characters\u2026",
|
|
5657
|
-
value: search,
|
|
5658
|
-
onChange: (e) => {
|
|
5659
|
-
setSearch(e.target.value);
|
|
5660
|
-
setFocusedIdx(-1);
|
|
5661
|
-
},
|
|
5662
|
-
onKeyDown: (e) => {
|
|
5663
|
-
var _a, _b;
|
|
5664
|
-
if (e.key === "Escape") closeModal();
|
|
5665
|
-
if (e.key === "ArrowDown") {
|
|
5666
|
-
e.preventDefault();
|
|
5667
|
-
setFocusedIdx(0);
|
|
5668
|
-
(_b = (_a = gridRef.current) == null ? void 0 : _a.children[0]) == null ? void 0 : _b.dispatchEvent(
|
|
5669
|
-
new Event("focus")
|
|
5670
|
-
);
|
|
5641
|
+
open && createPortal(
|
|
5642
|
+
/* @__PURE__ */ jsxs(
|
|
5643
|
+
"div",
|
|
5644
|
+
{
|
|
5645
|
+
ref: popupRef,
|
|
5646
|
+
role: "dialog",
|
|
5647
|
+
"aria-label": "Special characters",
|
|
5648
|
+
"aria-modal": "true",
|
|
5649
|
+
className: "bg-white border border-gray-200 rounded-lg shadow-2xl flex flex-col",
|
|
5650
|
+
style: { position: "fixed", top: popupPos.top, left: popupPos.left, width: 340, maxHeight: 420, zIndex: 9999 },
|
|
5651
|
+
onKeyDown: (e) => {
|
|
5652
|
+
if (e.key === "Escape") closeModal();
|
|
5653
|
+
},
|
|
5654
|
+
children: [
|
|
5655
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 pt-3 pb-2 border-b border-gray-100 ", children: [
|
|
5656
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
5657
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide", children: "Special Characters" }),
|
|
5658
|
+
/* @__PURE__ */ jsx(
|
|
5659
|
+
"button",
|
|
5660
|
+
{
|
|
5661
|
+
type: "button",
|
|
5662
|
+
onClick: closeModal,
|
|
5663
|
+
"aria-label": "Close",
|
|
5664
|
+
className: "text-gray-400 hover:text-gray-600 p-0.5 rounded",
|
|
5665
|
+
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
5671
5666
|
}
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 mt-2", children: CATEGORIES.map((cat) => /* @__PURE__ */ jsx(
|
|
5677
|
-
"button",
|
|
5678
|
-
{
|
|
5679
|
-
type: "button",
|
|
5680
|
-
onMouseDown: (e) => {
|
|
5681
|
-
e.preventDefault();
|
|
5682
|
-
setCategory(cat);
|
|
5683
|
-
setFocusedIdx(-1);
|
|
5684
|
-
},
|
|
5685
|
-
className: [
|
|
5686
|
-
"px-2 py-0.5 rounded text-xs font-medium transition-colors",
|
|
5687
|
-
category === cat ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200 "
|
|
5688
|
-
].join(" "),
|
|
5689
|
-
children: cat
|
|
5690
|
-
},
|
|
5691
|
-
cat
|
|
5692
|
-
)) })
|
|
5693
|
-
] }),
|
|
5694
|
-
/* @__PURE__ */ jsx(
|
|
5695
|
-
"div",
|
|
5696
|
-
{
|
|
5697
|
-
ref: gridRef,
|
|
5698
|
-
role: "grid",
|
|
5699
|
-
"aria-label": "Character grid",
|
|
5700
|
-
className: "flex-1 overflow-y-auto p-2",
|
|
5701
|
-
style: {
|
|
5702
|
-
display: "grid",
|
|
5703
|
-
gridTemplateColumns: "repeat(8, 1fr)",
|
|
5704
|
-
gap: 2
|
|
5705
|
-
},
|
|
5706
|
-
onKeyDown: handleGridKeyDown,
|
|
5707
|
-
children: filtered.length === 0 ? /* @__PURE__ */ jsx(
|
|
5708
|
-
"div",
|
|
5667
|
+
)
|
|
5668
|
+
] }),
|
|
5669
|
+
/* @__PURE__ */ jsx(
|
|
5670
|
+
"input",
|
|
5709
5671
|
{
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5672
|
+
ref: searchRef,
|
|
5673
|
+
type: "search",
|
|
5674
|
+
placeholder: "Search characters\u2026",
|
|
5675
|
+
value: search,
|
|
5676
|
+
onChange: (e) => {
|
|
5677
|
+
setSearch(e.target.value);
|
|
5678
|
+
setFocusedIdx(-1);
|
|
5679
|
+
},
|
|
5680
|
+
onKeyDown: (e) => {
|
|
5681
|
+
var _a, _b;
|
|
5682
|
+
if (e.key === "Escape") closeModal();
|
|
5683
|
+
if (e.key === "ArrowDown") {
|
|
5684
|
+
e.preventDefault();
|
|
5685
|
+
setFocusedIdx(0);
|
|
5686
|
+
(_b = (_a = gridRef.current) == null ? void 0 : _a.children[0]) == null ? void 0 : _b.dispatchEvent(
|
|
5687
|
+
new Event("focus")
|
|
5688
|
+
);
|
|
5689
|
+
}
|
|
5690
|
+
},
|
|
5691
|
+
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"
|
|
5713
5692
|
}
|
|
5714
|
-
)
|
|
5693
|
+
),
|
|
5694
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 mt-2", children: CATEGORIES.map((cat) => /* @__PURE__ */ jsx(
|
|
5715
5695
|
"button",
|
|
5716
5696
|
{
|
|
5717
5697
|
type: "button",
|
|
5718
|
-
role: "gridcell",
|
|
5719
|
-
tabIndex: focusedIdx === idx ? 0 : -1,
|
|
5720
|
-
"aria-label": c.name,
|
|
5721
|
-
title: c.name,
|
|
5722
5698
|
onMouseDown: (e) => {
|
|
5723
5699
|
e.preventDefault();
|
|
5724
|
-
|
|
5700
|
+
setCategory(cat);
|
|
5701
|
+
setFocusedIdx(-1);
|
|
5725
5702
|
},
|
|
5726
|
-
onMouseEnter: () => setHovered({ char: c.char, name: c.name }),
|
|
5727
|
-
onMouseLeave: () => setHovered(null),
|
|
5728
|
-
onFocus: () => setHovered({ char: c.char, name: c.name }),
|
|
5729
|
-
onBlur: () => setHovered(null),
|
|
5730
5703
|
className: [
|
|
5731
|
-
"
|
|
5732
|
-
|
|
5704
|
+
"px-2 py-0.5 rounded text-xs font-medium transition-colors",
|
|
5705
|
+
category === cat ? "bg-blue-600 text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200 "
|
|
5733
5706
|
].join(" "),
|
|
5734
|
-
children:
|
|
5707
|
+
children: cat
|
|
5735
5708
|
},
|
|
5736
|
-
|
|
5737
|
-
))
|
|
5738
|
-
}
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5709
|
+
cat
|
|
5710
|
+
)) })
|
|
5711
|
+
] }),
|
|
5712
|
+
/* @__PURE__ */ jsx(
|
|
5713
|
+
"div",
|
|
5714
|
+
{
|
|
5715
|
+
ref: gridRef,
|
|
5716
|
+
role: "grid",
|
|
5717
|
+
"aria-label": "Character grid",
|
|
5718
|
+
className: "flex-1 overflow-y-auto p-2",
|
|
5719
|
+
style: {
|
|
5720
|
+
display: "grid",
|
|
5721
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
5722
|
+
gap: 2
|
|
5723
|
+
},
|
|
5724
|
+
onKeyDown: handleGridKeyDown,
|
|
5725
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsx(
|
|
5726
|
+
"div",
|
|
5727
|
+
{
|
|
5728
|
+
className: "col-span-8 text-center py-8 text-sm text-gray-400 ",
|
|
5729
|
+
role: "status",
|
|
5730
|
+
children: "No characters found"
|
|
5731
|
+
}
|
|
5732
|
+
) : filtered.map((c, idx) => /* @__PURE__ */ jsx(
|
|
5733
|
+
"button",
|
|
5734
|
+
{
|
|
5735
|
+
type: "button",
|
|
5736
|
+
role: "gridcell",
|
|
5737
|
+
tabIndex: focusedIdx === idx ? 0 : -1,
|
|
5738
|
+
"aria-label": c.name,
|
|
5739
|
+
title: c.name,
|
|
5740
|
+
onMouseDown: (e) => {
|
|
5741
|
+
e.preventDefault();
|
|
5742
|
+
insertChar(c.char);
|
|
5743
|
+
},
|
|
5744
|
+
onMouseEnter: () => setHovered({ char: c.char, name: c.name }),
|
|
5745
|
+
onMouseLeave: () => setHovered(null),
|
|
5746
|
+
onFocus: () => setHovered({ char: c.char, name: c.name }),
|
|
5747
|
+
onBlur: () => setHovered(null),
|
|
5748
|
+
className: [
|
|
5749
|
+
"flex items-center justify-center rounded text-base h-8 w-full transition-colors cursor-pointer select-none",
|
|
5750
|
+
focusedIdx === idx ? "bg-blue-100 text-blue-700 ring-2 ring-blue-500" : "text-gray-800 hover:bg-blue-50 hover:text-blue-700 "
|
|
5751
|
+
].join(" "),
|
|
5752
|
+
children: c.char
|
|
5753
|
+
},
|
|
5754
|
+
c.char + c.name
|
|
5755
|
+
))
|
|
5756
|
+
}
|
|
5757
|
+
),
|
|
5758
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-t border-gray-100 flex items-center gap-3 min-h-[40px]", children: hovered ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5759
|
+
/* @__PURE__ */ jsx("span", { className: "text-2xl leading-none text-gray-800 w-8 text-center", children: hovered.char }),
|
|
5760
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500 truncate", children: hovered.name })
|
|
5761
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 ", children: "Hover or use arrow keys to preview" }) })
|
|
5762
|
+
]
|
|
5763
|
+
}
|
|
5764
|
+
),
|
|
5765
|
+
document.body
|
|
5746
5766
|
)
|
|
5747
5767
|
] });
|
|
5748
5768
|
}
|
|
@@ -7917,7 +7937,18 @@ function EditorCore({
|
|
|
7917
7937
|
container.querySelectorAll(".editor-cell-active").forEach((el) => {
|
|
7918
7938
|
el.classList.remove("editor-cell-active");
|
|
7919
7939
|
});
|
|
7920
|
-
if (!inTableCellPos)
|
|
7940
|
+
if (!inTableCellPos) {
|
|
7941
|
+
setTableSelection(null);
|
|
7942
|
+
return;
|
|
7943
|
+
}
|
|
7944
|
+
if (tableSelection) {
|
|
7945
|
+
const { anchorCell, focusCell, tablePath } = tableSelection;
|
|
7946
|
+
const sameTable = JSON.stringify(tablePath) === JSON.stringify(inTableCellPos.tablePath);
|
|
7947
|
+
const singleCell = anchorCell[0] === focusCell[0] && anchorCell[1] === focusCell[1];
|
|
7948
|
+
if (!sameTable || singleCell) {
|
|
7949
|
+
setTableSelection(null);
|
|
7950
|
+
}
|
|
7951
|
+
}
|
|
7921
7952
|
const cellPath = [...inTableCellPos.tablePath, inTableCellPos.row, inTableCellPos.col];
|
|
7922
7953
|
const td = container.querySelector(
|
|
7923
7954
|
`[data-block-path="${JSON.stringify(cellPath)}"]`
|