@trafica/editor 1.0.20 → 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 +135 -115
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +135 -115
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
}
|