@malaya_jeeva/rich-text-editor 1.0.1 → 1.0.2

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.
Files changed (3) hide show
  1. package/dist/index.js +534 -95
  2. package/dist/index.mjs +534 -95
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -12,26 +12,27 @@ var CSS = `
12
12
  display: flex; flex-wrap: wrap; align-items: center; gap: 1px;
13
13
  padding: 4px 8px; background: #f8f8f8; border-bottom: 1px solid #e0e0e0;
14
14
  }
15
- @media (prefers-color-scheme: dark) {
16
- .rte-toolbar { background: #1e1e1e; border-color: #333; }
17
- }
15
+ @media (prefers-color-scheme: dark) { .rte-toolbar { background: #1e1e1e; border-color: #333; } }
16
+
18
17
  .rte-btn {
19
- background: transparent; border: none; border-radius: 3px;
20
- cursor: pointer; height: 30px; min-width: 30px; padding: 0 6px;
21
- color: #444; font-size: 13px; font-weight: 500;
22
- font-family: var(--font-sans); display: inline-flex; align-items: center;
23
- justify-content: center; user-select: none; white-space: nowrap;
24
- transition: background 0.1s; flex-shrink: 0;
18
+ background: transparent; border: none; border-radius: 3px; cursor: pointer;
19
+ height: 30px; min-width: 30px; padding: 0 6px; color: #444; font-size: 13px;
20
+ font-weight: 500; font-family: var(--font-sans); display: inline-flex;
21
+ align-items: center; justify-content: center; user-select: none;
22
+ white-space: nowrap; transition: background 0.1s; flex-shrink: 0;
25
23
  }
26
- .rte-btn:hover { background: #e8e8e8; }
27
- .rte-btn.active { background: #d0e4ff; color: #1a5fb4; }
24
+ .rte-btn:hover { background: #e8e8e8; }
25
+ .rte-btn.active { background: #d0e4ff; color: #1a5fb4; }
26
+ .rte-btn.danger { color: #c0392b; }
27
+ .rte-btn.danger:hover { background: #fdecea; }
28
28
  @media (prefers-color-scheme: dark) {
29
- .rte-btn { color: #ccc; }
30
- .rte-btn:hover { background: #2e2e2e; }
29
+ .rte-btn { color: #ccc; } .rte-btn:hover { background: #2e2e2e; }
31
30
  .rte-btn.active { background: #1a3a5c; color: #90c4ff; }
31
+ .rte-btn.danger { color: #ff6b6b; } .rte-btn.danger:hover { background: #3a1a1a; }
32
32
  }
33
33
  .rte-sep { width: 1px; height: 20px; background: #d8d8d8; margin: 0 4px; flex-shrink: 0; }
34
34
  @media (prefers-color-scheme: dark) { .rte-sep { background: #3a3a3a; } }
35
+
35
36
  .rte-select {
36
37
  height: 28px; border: 1px solid #d8d8d8; border-radius: 3px;
37
38
  background: #fff; color: #333; font-size: 12px; padding: 0 22px 0 7px;
@@ -42,8 +43,70 @@ var CSS = `
42
43
  }
43
44
  @media (prefers-color-scheme: dark) { .rte-select { background-color: #2a2a2a; border-color: #444; color: #ccc; } }
44
45
  .rte-swatch { width: 14px; height: 3px; border-radius: 1px; margin-top: 2px; }
45
- .rte-wrap { background: #fff; }
46
- @media (prefers-color-scheme: dark) { .rte-wrap { background: #141414; } }
46
+
47
+ /* Table picker */
48
+ .rte-tp-wrap { position: relative; display: inline-flex; }
49
+ .rte-tp {
50
+ position: absolute; top: 34px; left: 0; z-index: 100;
51
+ background: #fff; border: 1px solid #d8d8d8; border-radius: 6px;
52
+ box-shadow: 0 4px 16px rgba(0,0,0,0.12); padding: 10px;
53
+ }
54
+ @media (prefers-color-scheme: dark) { .rte-tp { background: #222; border-color: #444; } }
55
+ .rte-tp-lbl { font-size: 11px; color: #888; text-align: center; margin-bottom: 8px; font-family: var(--font-sans); }
56
+ .rte-tp-grid { display: grid; grid-template-columns: repeat(8, 18px); gap: 2px; }
57
+ .rte-tp-cell { width: 18px; height: 18px; border-radius: 2px; border: 1px solid #ddd; cursor: pointer; background: #fff; transition: background 0.08s; }
58
+ .rte-tp-cell.on { background: #d0e4ff; border-color: #1a5fb4; }
59
+ @media (prefers-color-scheme: dark) {
60
+ .rte-tp-cell { background: #2a2a2a; border-color: #444; }
61
+ .rte-tp-cell.on { background: #1a3a5c; border-color: #90c4ff; }
62
+ }
63
+
64
+ /* \u2500\u2500 Floating toolbar \u2500\u2500 */
65
+ .rte-float {
66
+ position: absolute; z-index: 50;
67
+ background: #fff; border: 1px solid #d0d0d0;
68
+ border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.13);
69
+ padding: 4px 6px;
70
+ display: flex; align-items: center; gap: 1px; flex-wrap: wrap;
71
+ }
72
+ @media (prefers-color-scheme: dark) { .rte-float { background: #222; border-color: #444; } }
73
+ .rte-float-arrow {
74
+ position: absolute; top: -7px; width: 14px; height: 7px;
75
+ }
76
+ .rte-float-arrow::before,
77
+ .rte-float-arrow::after {
78
+ content: ''; position: absolute; left: 0;
79
+ border-left: 7px solid transparent; border-right: 7px solid transparent;
80
+ }
81
+ .rte-float-arrow::before { top: 0; border-bottom: 7px solid #d0d0d0; }
82
+ .rte-float-arrow::after { top: 1px; border-bottom: 6px solid #fff; }
83
+ @media (prefers-color-scheme: dark) {
84
+ .rte-float-arrow::before { border-bottom-color: #444; }
85
+ .rte-float-arrow::after { border-bottom-color: #222; }
86
+ }
87
+
88
+ /* Link bar inside float */
89
+ .rte-link-float { min-width: 340px; }
90
+ .rte-link-float input {
91
+ flex: 1; height: 26px; border: 1px solid #ccc; border-radius: 3px;
92
+ padding: 0 8px; font-size: 13px; outline: none; font-family: var(--font-sans);
93
+ background: #fff; color: #222;
94
+ min-width: 0;
95
+ }
96
+ @media (prefers-color-scheme: dark) { .rte-link-float input { background: #1a1a1a; border-color: #555; color: #ddd; } }
97
+ .rte-link-apply {
98
+ height: 26px; padding: 0 10px; background: #1a6fc4; color: #fff;
99
+ border: none; border-radius: 3px; font-size: 12px; font-weight: 600; cursor: pointer; white-space: nowrap;
100
+ }
101
+ .rte-link-cancel {
102
+ height: 26px; padding: 0 8px; background: transparent; color: #666;
103
+ border: 1px solid #ccc; border-radius: 3px; font-size: 12px; cursor: pointer;
104
+ }
105
+ @media (prefers-color-scheme: dark) { .rte-link-cancel { color: #aaa; border-color: #555; } }
106
+
107
+ /* Editor */
108
+ .rte-area { position: relative; background: #fff; }
109
+ @media (prefers-color-scheme: dark) { .rte-area { background: #141414; } }
47
110
  .rte-body {
48
111
  min-height: 280px; outline: none; font-size: 15px; line-height: 1.75;
49
112
  color: #222; caret-color: #222; padding: 18px 20px;
@@ -56,7 +119,6 @@ var CSS = `
56
119
  .rte-body ol { list-style-type: decimal; padding-left: 1.6em; margin: 0.3em 0; }
57
120
  .rte-body ol ol { list-style-type: lower-alpha; padding-left: 1.6em; }
58
121
  .rte-body ol ol ol { list-style-type: lower-roman; padding-left: 1.6em; }
59
- .rte-body ol ol ol ol { list-style-type: decimal; padding-left: 1.6em; }
60
122
  .rte-body ul { list-style-type: disc; padding-left: 1.6em; margin: 0.3em 0; }
61
123
  .rte-body ul ul { list-style-type: circle; padding-left: 1.6em; }
62
124
  .rte-body ul ul ul { list-style-type: square; padding-left: 1.6em; }
@@ -65,22 +127,23 @@ var CSS = `
65
127
  .rte-body pre { background: #f4f4f4; border: 1px solid #e0e0e0; border-radius: 4px; padding: 12px 14px; margin: 0.6em 0; overflow-x: auto; }
66
128
  .rte-body code { font-family: var(--font-mono); font-size: 13px; }
67
129
  .rte-body:empty:before { content: attr(data-ph); color: #aaa; pointer-events: none; }
68
- .rte-code {
69
- min-height: 280px; width: 100%; background: #1e1e2e; color: #cdd6f4;
70
- font-family: var(--font-mono); font-size: 13px; line-height: 1.6;
71
- padding: 18px 20px; border: none; outline: none; resize: vertical;
72
- }
73
- .rte-footer {
74
- font-size: 11px; color: #999; padding: 4px 20px 5px;
75
- border-top: 1px solid #e8e8e8; background: #fafafa;
130
+ .rte-body table { border-collapse: collapse; width: 100%; margin: 0.8em 0; }
131
+ .rte-body td, .rte-body th { border: 1px solid #ccc; padding: 7px 10px; min-width: 60px; text-align: left; vertical-align: top; }
132
+ .rte-body th { background: #f5f5f5; font-weight: 600; }
133
+ @media (prefers-color-scheme: dark) {
134
+ .rte-body td, .rte-body th { border-color: #444; }
135
+ .rte-body th { background: #2a2a2a; }
76
136
  }
137
+ .rte-body td.rte-sel, .rte-body th.rte-sel { background: rgba(26,95,180,0.15) !important; outline: 2px solid #1a5fb4; outline-offset: -2px; }
138
+ .rte-code { min-height: 280px; width: 100%; background: #1e1e2e; color: #cdd6f4; font-family: var(--font-mono); font-size: 13px; line-height: 1.6; padding: 18px 20px; border: none; outline: none; resize: vertical; }
139
+ .rte-footer { font-size: 11px; color: #999; padding: 4px 20px 5px; border-top: 1px solid #e8e8e8; background: #fafafa; }
77
140
  @media (prefers-color-scheme: dark) { .rte-footer { border-color: #2a2a2a; background: #1a1a1a; color: #555; } }
78
141
  `;
79
- function Btn({ onClick, title, active, children, style }) {
142
+ function Btn({ onClick, title, active, danger, children, style }) {
80
143
  return /* @__PURE__ */ jsx(
81
144
  "button",
82
145
  {
83
- className: `rte-btn${active ? " active" : ""}`,
146
+ className: `rte-btn${active ? " active" : ""}${danger ? " danger" : ""}`,
84
147
  style,
85
148
  onMouseDown: (e) => {
86
149
  e.preventDefault();
@@ -94,6 +157,30 @@ function Btn({ onClick, title, active, children, style }) {
94
157
  function Sep() {
95
158
  return /* @__PURE__ */ jsx("div", { className: "rte-sep" });
96
159
  }
160
+ function TablePicker({ onInsert, onClose }) {
161
+ const [hover, setHover] = useState([0, 0]);
162
+ return /* @__PURE__ */ jsxs("div", { className: "rte-tp", children: [
163
+ /* @__PURE__ */ jsx("div", { className: "rte-tp-lbl", children: hover[0] > 0 ? `${hover[0]} \xD7 ${hover[1]}` : "Select table size" }),
164
+ /* @__PURE__ */ jsx("div", { className: "rte-tp-grid", children: Array.from({ length: 64 }, (_, i) => {
165
+ const r = Math.floor(i / 8) + 1, c = i % 8 + 1;
166
+ return /* @__PURE__ */ jsx(
167
+ "div",
168
+ {
169
+ className: `rte-tp-cell${r <= hover[0] && c <= hover[1] ? " on" : ""}`,
170
+ onMouseEnter: () => setHover([r, c]),
171
+ onMouseDown: (e) => {
172
+ e.preventDefault();
173
+ if (hover[0] > 0) {
174
+ onInsert(hover[0], hover[1]);
175
+ onClose();
176
+ }
177
+ }
178
+ },
179
+ i
180
+ );
181
+ }) })
182
+ ] });
183
+ }
97
184
  function IcoUL() {
98
185
  return /* @__PURE__ */ jsxs("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [
99
186
  /* @__PURE__ */ jsx("circle", { cx: "2", cy: "4", r: "1.3", fill: "currentColor" }),
@@ -149,26 +236,123 @@ function IcoCopy() {
149
236
  /* @__PURE__ */ jsx("path", { d: "M4 1H12.5C13.1 1 13.5 1.4 13.5 2V10", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
150
237
  ] });
151
238
  }
239
+ function IcoTable() {
240
+ return /* @__PURE__ */ jsxs("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [
241
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "13", height: "13", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }),
242
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "5.5", x2: "14", y2: "5.5", stroke: "currentColor", strokeWidth: "1.1" }),
243
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "10", x2: "14", y2: "10", stroke: "currentColor", strokeWidth: "1.1" }),
244
+ /* @__PURE__ */ jsx("line", { x1: "5.5", y1: "5.5", x2: "5.5", y2: "14", stroke: "currentColor", strokeWidth: "1.1" }),
245
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "5.5", x2: "10", y2: "14", stroke: "currentColor", strokeWidth: "1.1" })
246
+ ] });
247
+ }
248
+ function IcoRowAbove() {
249
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
250
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "7", width: "14", height: "8", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
251
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "7", x2: "8", y2: "15", stroke: "currentColor", strokeWidth: "1" }),
252
+ /* @__PURE__ */ jsx("path", { d: "M8 5V1M6 3L8 1L10 3", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
253
+ ] });
254
+ }
255
+ function IcoRowBelow() {
256
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
257
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "14", height: "8", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
258
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "1", x2: "8", y2: "9", stroke: "currentColor", strokeWidth: "1" }),
259
+ /* @__PURE__ */ jsx("path", { d: "M8 11V15M6 13L8 15L10 13", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
260
+ ] });
261
+ }
262
+ function IcoDelRow() {
263
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
264
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "4", width: "14", height: "8", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
265
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "8", x2: "15", y2: "8", stroke: "currentColor", strokeWidth: "1" }),
266
+ /* @__PURE__ */ jsx("path", { d: "M5.5 6L10.5 10M10.5 6L5.5 10", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round" })
267
+ ] });
268
+ }
269
+ function IcoColLeft() {
270
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
271
+ /* @__PURE__ */ jsx("rect", { x: "7", y: "1", width: "8", height: "14", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
272
+ /* @__PURE__ */ jsx("line", { x1: "7", y1: "8", x2: "15", y2: "8", stroke: "currentColor", strokeWidth: "1" }),
273
+ /* @__PURE__ */ jsx("path", { d: "M5 8H1M3 6L1 8L3 10", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
274
+ ] });
275
+ }
276
+ function IcoColRight() {
277
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
278
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "8", height: "14", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
279
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "8", x2: "9", y2: "8", stroke: "currentColor", strokeWidth: "1" }),
280
+ /* @__PURE__ */ jsx("path", { d: "M11 8H15M13 6L15 8L13 10", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
281
+ ] });
282
+ }
283
+ function IcoDelCol() {
284
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
285
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "1", width: "8", height: "14", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
286
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "1", x2: "8", y2: "15", stroke: "currentColor", strokeWidth: "1" }),
287
+ /* @__PURE__ */ jsx("path", { d: "M6 5.5L10 10.5M10 5.5L6 10.5", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round" })
288
+ ] });
289
+ }
290
+ function IcoMerge() {
291
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
292
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "6", height: "14", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
293
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "1", width: "6", height: "14", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
294
+ /* @__PURE__ */ jsx("path", { d: "M7 8H9M7.5 6.5L9 8L7.5 9.5M8.5 6.5L7 8L8.5 9.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
295
+ ] });
296
+ }
297
+ function IcoSplit() {
298
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
299
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "14", height: "14", rx: "1", stroke: "currentColor", strokeWidth: "1.1" }),
300
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "1", x2: "8", y2: "15", stroke: "currentColor", strokeWidth: "1.2" }),
301
+ /* @__PURE__ */ jsx("path", { d: "M5.5 8H3M12.5 8H10", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }),
302
+ /* @__PURE__ */ jsx("path", { d: "M4.5 6.5L3 8L4.5 9.5M11.5 6.5L13 8L11.5 9.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
303
+ ] });
304
+ }
305
+ function IcoDelTable() {
306
+ return /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
307
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "14", height: "14", rx: "1.5", stroke: "currentColor", strokeWidth: "1.1" }),
308
+ /* @__PURE__ */ jsx("path", { d: "M5 5L11 11M11 5L5 11", stroke: "currentColor", strokeWidth: "1.4", strokeLinecap: "round" })
309
+ ] });
310
+ }
152
311
  function AlignIco({ t }) {
153
312
  const w = { left: [13, 9, 11], center: [9, 7, 11], right: [13, 9, 11], justify: [13, 13, 13] };
154
- return /* @__PURE__ */ jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
155
- "rect",
156
- {
157
- x: t === "right" ? 15 - w[t][i] - 1 : 1,
158
- y: [2, 6.5, 11][i],
159
- width: w[t][i],
160
- height: "1.6",
161
- rx: ".8",
162
- fill: "currentColor"
163
- },
164
- i
165
- )) });
313
+ return /* @__PURE__ */ jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx("rect", { x: t === "right" ? 15 - w[t][i] - 1 : 1, y: [2, 6.5, 11][i], width: w[t][i], height: "1.6", rx: ".8", fill: "currentColor" }, i)) });
314
+ }
315
+ function getCurrentCell() {
316
+ var _a;
317
+ const node = (_a = window.getSelection()) == null ? void 0 : _a.anchorNode;
318
+ const el = (node == null ? void 0 : node.nodeType) === 1 ? node : node == null ? void 0 : node.parentElement;
319
+ return el == null ? void 0 : el.closest("td, th");
320
+ }
321
+ function getCurrentTable() {
322
+ var _a;
323
+ return (_a = getCurrentCell()) == null ? void 0 : _a.closest("table");
324
+ }
325
+ function getCellCoords(table, cell) {
326
+ const rows = Array.from(table.rows);
327
+ for (let r = 0; r < rows.length; r++) {
328
+ const cells = Array.from(rows[r].cells);
329
+ for (let c = 0; c < cells.length; c++) {
330
+ if (cells[c] === cell) return [r, c];
331
+ }
332
+ }
333
+ return null;
334
+ }
335
+ function getCellsInRange(table, a, b) {
336
+ const ca = getCellCoords(table, a), cb = getCellCoords(table, b);
337
+ if (!ca || !cb) return [a];
338
+ const [r1, c1] = [Math.min(ca[0], cb[0]), Math.min(ca[1], cb[1])];
339
+ const [r2, c2] = [Math.max(ca[0], cb[0]), Math.max(ca[1], cb[1])];
340
+ const result = [];
341
+ Array.from(table.rows).forEach((row, ri) => {
342
+ if (ri >= r1 && ri <= r2) Array.from(row.cells).forEach((cell, ci) => {
343
+ if (ci >= c1 && ci <= c2) result.push(cell);
344
+ });
345
+ });
346
+ return result;
166
347
  }
167
348
  function RichTextEditor({ value, onChange }) {
168
349
  var _a;
169
350
  const editorRef = useRef(null);
351
+ const editorAreaRef = useRef(null);
170
352
  const colorRef = useRef(null);
171
353
  const savedRangeRef = useRef(null);
354
+ const dragStartCell = useRef(null);
355
+ const isDragging = useRef(false);
172
356
  const [isCode, setIsCode] = useState(false);
173
357
  const [codeVal, setCodeVal] = useState("");
174
358
  const [fmt, setFmt] = useState({ block: "p" });
@@ -176,6 +360,32 @@ function RichTextEditor({ value, onChange }) {
176
360
  const [words, setWords] = useState(0);
177
361
  const [linkBar, setLinkBar] = useState(false);
178
362
  const [linkUrl, setLinkUrl] = useState("https://");
363
+ const [showTable, setShowTable] = useState(false);
364
+ const [selCells, setSelCells] = useState([]);
365
+ const [tableFP, setTableFP] = useState(null);
366
+ const [linkFP, setLinkFP] = useState(null);
367
+ const calcFloat = useCallback((el, toolbarW) => {
368
+ const area = editorAreaRef.current;
369
+ const er = el.getBoundingClientRect();
370
+ const ar = area.getBoundingClientRect();
371
+ const arrowCenter = er.left + er.width / 2 - ar.left;
372
+ const rawLeft = arrowCenter - toolbarW / 2;
373
+ const left = Math.max(4, Math.min(rawLeft, ar.width - toolbarW - 4));
374
+ const arrowLeft = Math.max(8, Math.min(arrowCenter - left - 7, toolbarW - 22));
375
+ return { top: er.bottom - ar.top + 10, left, arrowLeft };
376
+ }, []);
377
+ const applySelection = useCallback((cells) => {
378
+ var _a2;
379
+ (_a2 = editorRef.current) == null ? void 0 : _a2.querySelectorAll(".rte-sel").forEach((c) => c.classList.remove("rte-sel"));
380
+ cells.forEach((c) => c.classList.add("rte-sel"));
381
+ setSelCells(cells);
382
+ }, []);
383
+ const clearSelection = useCallback(() => {
384
+ var _a2;
385
+ (_a2 = editorRef.current) == null ? void 0 : _a2.querySelectorAll(".rte-sel").forEach((c) => c.classList.remove("rte-sel"));
386
+ setSelCells([]);
387
+ dragStartCell.current = null;
388
+ }, []);
179
389
  const exec = useCallback((cmd, val = null) => {
180
390
  var _a2;
181
391
  (_a2 = editorRef.current) == null ? void 0 : _a2.focus();
@@ -191,6 +401,9 @@ function RichTextEditor({ value, onChange }) {
191
401
  const m = c.match(/\d+/g);
192
402
  if (m) setColor("#" + m.slice(0, 3).map((n) => parseInt(n).toString(16).padStart(2, "0")).join(""));
193
403
  }
404
+ const cell = getCurrentCell();
405
+ const inTable = !!cell;
406
+ const cellMerged = cell ? cell.colSpan > 1 || cell.rowSpan > 1 : false;
194
407
  setFmt({
195
408
  bold: document.queryCommandState("bold"),
196
409
  italic: document.queryCommandState("italic"),
@@ -201,16 +414,64 @@ function RichTextEditor({ value, onChange }) {
201
414
  aC: document.queryCommandState("justifyCenter"),
202
415
  aR: document.queryCommandState("justifyRight"),
203
416
  aJ: document.queryCommandState("justifyFull"),
204
- block
417
+ block,
418
+ inTable,
419
+ cellMerged
205
420
  });
421
+ if (cell && editorAreaRef.current) setTableFP(calcFloat(cell, 370));
422
+ else setTableFP(null);
206
423
  const txt = (_b = (_a2 = editorRef.current) == null ? void 0 : _a2.innerText) != null ? _b : "";
207
424
  setWords(txt.trim() ? txt.trim().split(/\s+/).length : 0);
208
425
  onChange == null ? void 0 : onChange((_d = (_c = editorRef.current) == null ? void 0 : _c.innerHTML) != null ? _d : "");
209
- }, [onChange]);
426
+ }, [onChange, calcFloat]);
427
+ const handleEditorMouseDown = useCallback((e) => {
428
+ const target = e.target.closest("td, th");
429
+ if (!target) {
430
+ clearSelection();
431
+ return;
432
+ }
433
+ if (e.shiftKey && dragStartCell.current) {
434
+ const table = target.closest("table");
435
+ if (dragStartCell.current.closest("table") === table) {
436
+ e.preventDefault();
437
+ applySelection(getCellsInRange(table, dragStartCell.current, target));
438
+ return;
439
+ }
440
+ }
441
+ dragStartCell.current = target;
442
+ isDragging.current = true;
443
+ applySelection([target]);
444
+ }, [applySelection, clearSelection]);
445
+ const handleEditorMouseMove = useCallback((e) => {
446
+ if (!isDragging.current || !dragStartCell.current) return;
447
+ const target = e.target.closest("td, th");
448
+ if (!target || target === dragStartCell.current) return;
449
+ const table = dragStartCell.current.closest("table");
450
+ if (target.closest("table") !== table) return;
451
+ const cells = getCellsInRange(table, dragStartCell.current, target);
452
+ if (cells.length > 1) {
453
+ e.preventDefault();
454
+ applySelection(cells);
455
+ }
456
+ }, [applySelection]);
457
+ const handleEditorMouseUp = useCallback(() => {
458
+ isDragging.current = false;
459
+ }, []);
210
460
  const handleKeyDown = useCallback((e) => {
211
461
  var _a2, _b;
462
+ clearSelection();
212
463
  if (e.key === "Tab") {
213
464
  e.preventDefault();
465
+ const cell = getCurrentCell();
466
+ if (cell) {
467
+ const cells = Array.from(cell.closest("table").querySelectorAll("td, th"));
468
+ const next = e.shiftKey ? cells[cells.indexOf(cell) - 1] : cells[cells.indexOf(cell) + 1];
469
+ if (next) {
470
+ next.focus();
471
+ next.click();
472
+ }
473
+ return;
474
+ }
214
475
  const node = (_a2 = window.getSelection()) == null ? void 0 : _a2.anchorNode;
215
476
  const li = (node == null ? void 0 : node.nodeType) === 1 ? node.closest("li") : (_b = node == null ? void 0 : node.parentElement) == null ? void 0 : _b.closest("li");
216
477
  if (li) exec(e.shiftKey ? "outdent" : "indent");
@@ -230,20 +491,114 @@ function RichTextEditor({ value, onChange }) {
230
491
  exec("underline");
231
492
  }
232
493
  }
233
- }, [exec]);
234
- const toCode = () => {
235
- var _a2, _b;
236
- setCodeVal((_b = (_a2 = editorRef.current) == null ? void 0 : _a2.innerHTML) != null ? _b : "");
237
- setIsCode(true);
238
- };
239
- const toVisual = () => {
240
- if (editorRef.current) editorRef.current.innerHTML = codeVal;
241
- setIsCode(false);
494
+ }, [exec, clearSelection]);
495
+ const insertTable = (rows, cols) => {
496
+ var _a2;
497
+ (_a2 = editorRef.current) == null ? void 0 : _a2.focus();
498
+ let html = `<table>`;
499
+ for (let r = 0; r < rows; r++) {
500
+ html += "<tr>";
501
+ for (let c = 0; c < cols; c++) html += r === 0 ? `<th><br></th>` : `<td><br></td>`;
502
+ html += "</tr>";
503
+ }
504
+ html += "</table><p><br></p>";
505
+ document.execCommand("insertHTML", false, html);
242
506
  refresh();
243
507
  };
508
+ const tableOp = useCallback((op) => {
509
+ const cell = getCurrentCell(), table = getCurrentTable();
510
+ if (!cell || !table) return;
511
+ const row = cell.closest("tr");
512
+ const rows = Array.from(table.rows);
513
+ const ri = rows.indexOf(row), ci = Array.from(row.cells).indexOf(cell);
514
+ if (op === "addRowAbove" || op === "addRowBelow") {
515
+ const nr = document.createElement("tr");
516
+ for (let i = 0; i < row.cells.length; i++) {
517
+ const td = document.createElement("td");
518
+ td.innerHTML = "<br>";
519
+ nr.appendChild(td);
520
+ }
521
+ op === "addRowBelow" ? row.insertAdjacentElement("afterend", nr) : row.insertAdjacentElement("beforebegin", nr);
522
+ }
523
+ if (op === "deleteRow") {
524
+ rows.length > 1 ? row.remove() : table.remove();
525
+ }
526
+ if (op === "addColLeft" || op === "addColRight") {
527
+ rows.forEach((r, rIdx) => {
528
+ const td = document.createElement(rIdx === 0 ? "th" : "td");
529
+ td.innerHTML = "<br>";
530
+ const ref = r.cells[op === "addColRight" ? ci + 1 : ci];
531
+ ref ? r.insertBefore(td, ref) : r.appendChild(td);
532
+ });
533
+ }
534
+ if (op === "deleteCol") {
535
+ row.cells.length > 1 ? rows.forEach((r) => {
536
+ var _a2;
537
+ return (_a2 = r.cells[ci]) == null ? void 0 : _a2.remove();
538
+ }) : table.remove();
539
+ }
540
+ if (op === "deleteTable") {
541
+ table.remove();
542
+ clearSelection();
543
+ }
544
+ refresh();
545
+ }, [clearSelection, refresh]);
546
+ const doMerge = useCallback((cells) => {
547
+ var _a2;
548
+ if (cells.length < 2) return;
549
+ const table = cells[0].closest("table");
550
+ const coords = cells.map((c) => getCellCoords(table, c)).filter((x) => x !== null);
551
+ const minR = Math.min(...coords.map((c) => c[0])), maxR = Math.max(...coords.map((c) => c[0]));
552
+ const minC = Math.min(...coords.map((c) => c[1])), maxC = Math.max(...coords.map((c) => c[1]));
553
+ const anchor = (_a2 = cells.find((c) => {
554
+ const co = getCellCoords(table, c);
555
+ return co && co[0] === minR && co[1] === minC;
556
+ })) != null ? _a2 : cells[0];
557
+ anchor.innerHTML = cells.map((c) => c.innerHTML.replace(/<br\s*\/?>/gi, "").trim()).filter(Boolean).join(" ") || "<br>";
558
+ anchor.colSpan = maxC - minC + 1;
559
+ anchor.rowSpan = maxR - minR + 1;
560
+ cells.filter((c) => c !== anchor).forEach((c) => c.remove());
561
+ clearSelection();
562
+ refresh();
563
+ }, [clearSelection, refresh]);
564
+ const doSplit = useCallback(() => {
565
+ const cell = getCurrentCell();
566
+ if (!cell || cell.colSpan === 1 && cell.rowSpan === 1) return;
567
+ const cs = cell.colSpan, rs = cell.rowSpan;
568
+ const table = cell.closest("table");
569
+ const rows = Array.from(table.rows), row = cell.closest("tr");
570
+ const ri = rows.indexOf(row), ci = Array.from(row.cells).indexOf(cell);
571
+ cell.colSpan = 1;
572
+ cell.rowSpan = 1;
573
+ for (let c = 1; c < cs; c++) {
574
+ const td = document.createElement(ri === 0 ? "th" : "td");
575
+ td.innerHTML = "<br>";
576
+ const ref = row.cells[ci + c];
577
+ ref ? row.insertBefore(td, ref) : row.appendChild(td);
578
+ }
579
+ for (let r = 1; r < rs; r++) {
580
+ const tr = rows[ri + r];
581
+ if (!tr) continue;
582
+ for (let c = 0; c < cs; c++) {
583
+ const td = document.createElement("td");
584
+ td.innerHTML = "<br>";
585
+ const ref = tr.cells[ci + c];
586
+ ref ? tr.insertBefore(td, ref) : tr.appendChild(td);
587
+ }
588
+ }
589
+ refresh();
590
+ }, [refresh]);
244
591
  const openLinkBar = () => {
245
592
  const sel = window.getSelection();
246
593
  savedRangeRef.current = (sel == null ? void 0 : sel.rangeCount) ? sel.getRangeAt(0).cloneRange() : null;
594
+ if ((sel == null ? void 0 : sel.rangeCount) && editorAreaRef.current) {
595
+ const rect = sel.getRangeAt(0).getBoundingClientRect();
596
+ if (rect.width > 0 || rect.height > 0) setLinkFP(calcFloat({ getBoundingClientRect: () => rect }, 360));
597
+ else {
598
+ const area = editorAreaRef.current.getBoundingClientRect();
599
+ setLinkFP({ top: 60, left: 20, arrowLeft: 20 });
600
+ }
601
+ }
247
602
  setLinkUrl("https://");
248
603
  setLinkBar(true);
249
604
  };
@@ -256,9 +611,8 @@ function RichTextEditor({ value, onChange }) {
256
611
  sel.removeAllRanges();
257
612
  sel.addRange(savedRangeRef.current);
258
613
  }
259
- if ((_b = savedRangeRef.current) == null ? void 0 : _b.toString()) {
260
- document.execCommand("createLink", false, linkUrl);
261
- } else if (savedRangeRef.current) {
614
+ if ((_b = savedRangeRef.current) == null ? void 0 : _b.toString()) document.execCommand("createLink", false, linkUrl);
615
+ else if (savedRangeRef.current) {
262
616
  const a = document.createElement("a");
263
617
  a.href = linkUrl;
264
618
  a.textContent = linkUrl;
@@ -266,6 +620,65 @@ function RichTextEditor({ value, onChange }) {
266
620
  }
267
621
  setLinkBar(false);
268
622
  setLinkUrl("https://");
623
+ setLinkFP(null);
624
+ refresh();
625
+ };
626
+ const prettifyHtml = (html) => {
627
+ const INLINE = /* @__PURE__ */ new Set(["a", "b", "i", "u", "em", "strong", "span", "code", "br", "small", "sub", "sup"]);
628
+ let indent = 0;
629
+ const pad = () => " ".repeat(indent);
630
+ const tokens = html.replace(/>\s+</g, "><").replace(/(<\/?[^>]+>)/g, "\0$1\0").split("\0").filter(Boolean);
631
+ const lines = [];
632
+ let inline = "";
633
+ const flush = () => {
634
+ if (inline.trim()) {
635
+ lines.push(pad() + inline.trim());
636
+ inline = "";
637
+ }
638
+ };
639
+ for (const tok of tokens) {
640
+ const ot = tok.match(/^<([a-zA-Z][a-zA-Z0-9]*)[^>]*>$/), ct = tok.match(/^<\/([a-zA-Z][a-zA-Z0-9]*)>$/);
641
+ if (tok.match(/^<[^>]+\/>$/)) {
642
+ flush();
643
+ lines.push(pad() + tok);
644
+ continue;
645
+ }
646
+ if (ot) {
647
+ const tag = ot[1].toLowerCase();
648
+ if (INLINE.has(tag)) {
649
+ inline += tok;
650
+ continue;
651
+ }
652
+ flush();
653
+ lines.push(pad() + tok);
654
+ indent++;
655
+ continue;
656
+ }
657
+ if (ct) {
658
+ const tag = ct[1].toLowerCase();
659
+ if (INLINE.has(tag)) {
660
+ inline += tok;
661
+ continue;
662
+ }
663
+ flush();
664
+ indent = Math.max(0, indent - 1);
665
+ const prev = lines[lines.length - 1];
666
+ prev && prev.trim().startsWith("<") && !prev.includes("</") ? lines[lines.length - 1] = prev + tok : lines.push(pad() + tok);
667
+ continue;
668
+ }
669
+ inline += tok;
670
+ }
671
+ flush();
672
+ return lines.join("\n");
673
+ };
674
+ const toCode = () => {
675
+ var _a2, _b;
676
+ setCodeVal(prettifyHtml((_b = (_a2 = editorRef.current) == null ? void 0 : _a2.innerHTML) != null ? _b : ""));
677
+ setIsCode(true);
678
+ };
679
+ const toVisual = () => {
680
+ if (editorRef.current) editorRef.current.innerHTML = codeVal;
681
+ setIsCode(false);
269
682
  refresh();
270
683
  };
271
684
  const insertCodeBlock = () => {
@@ -297,9 +710,17 @@ function RichTextEditor({ value, onChange }) {
297
710
  refresh();
298
711
  }
299
712
  }, []);
713
+ useEffect(() => {
714
+ if (!showTable) return;
715
+ const h = () => setShowTable(false);
716
+ document.addEventListener("mousedown", h);
717
+ return () => document.removeEventListener("mousedown", h);
718
+ }, [showTable]);
719
+ const canMerge = selCells.length >= 2;
720
+ const canSplit = fmt.cellMerged;
300
721
  return /* @__PURE__ */ jsxs("div", { style: { padding: "1rem 0" }, children: [
301
722
  /* @__PURE__ */ jsx("style", { children: CSS }),
302
- /* @__PURE__ */ jsxs("div", { style: { border: "1px solid #d8d8d8", borderRadius: 4, overflow: "hidden", boxShadow: "0 1px 3px rgba(0,0,0,0.06)" }, children: [
723
+ /* @__PURE__ */ jsxs("div", { style: { border: "1px solid #d8d8d8", borderRadius: 4, boxShadow: "0 1px 3px rgba(0,0,0,0.06)" }, children: [
303
724
  /* @__PURE__ */ jsxs("div", { className: "rte-toolbar", children: [
304
725
  !isCode && /* @__PURE__ */ jsxs(Fragment, { children: [
305
726
  /* @__PURE__ */ jsx(Btn, { onClick: () => exec("bold"), title: "Bold (Ctrl+B)", active: fmt.bold, style: { fontWeight: 800, fontFamily: "Georgia,serif" }, children: "B" }),
@@ -362,13 +783,20 @@ function RichTextEditor({ value, onChange }) {
362
783
  /* @__PURE__ */ jsx(Sep, {}),
363
784
  /* @__PURE__ */ jsx(Btn, { onClick: openLinkBar, title: "Insert link", active: linkBar, children: /* @__PURE__ */ jsx(IcoLink, {}) }),
364
785
  /* @__PURE__ */ jsx(Btn, { onClick: insertCodeBlock, title: "Code block", children: /* @__PURE__ */ jsx(IcoCode, {}) }),
786
+ /* @__PURE__ */ jsxs("div", { className: "rte-tp-wrap", onMouseDown: (e) => e.stopPropagation(), children: [
787
+ /* @__PURE__ */ jsx(Btn, { onClick: () => setShowTable((v) => !v), title: "Insert table", active: showTable || !!fmt.inTable, children: /* @__PURE__ */ jsx(IcoTable, {}) }),
788
+ showTable && /* @__PURE__ */ jsx(TablePicker, { onInsert: (r, c) => {
789
+ insertTable(r, c);
790
+ setShowTable(false);
791
+ }, onClose: () => setShowTable(false) })
792
+ ] }),
365
793
  /* @__PURE__ */ jsx(Sep, {})
366
794
  ] }),
367
795
  /* @__PURE__ */ jsx(
368
796
  Btn,
369
797
  {
370
798
  onClick: isCode ? toVisual : toCode,
371
- title: "Toggle HTML source",
799
+ title: "Toggle HTML",
372
800
  active: isCode,
373
801
  style: { fontSize: 12, fontWeight: 600, letterSpacing: "0.03em", padding: "0 8px" },
374
802
  children: isCode ? "Visual" : "HTML"
@@ -382,41 +810,7 @@ function RichTextEditor({ value, onChange }) {
382
810
  words === 1 ? "word" : "words"
383
811
  ] })
384
812
  ] }),
385
- linkBar && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, padding: "6px 10px", background: "#f0f4ff", borderBottom: "1px solid #c8d8f8" }, children: [
386
- /* @__PURE__ */ jsx(IcoLink, {}),
387
- /* @__PURE__ */ jsx(
388
- "input",
389
- {
390
- autoFocus: true,
391
- type: "text",
392
- value: linkUrl,
393
- onChange: (e) => setLinkUrl(e.target.value),
394
- onKeyDown: (e) => {
395
- if (e.key === "Enter") applyLink();
396
- if (e.key === "Escape") setLinkBar(false);
397
- },
398
- placeholder: "https://example.com",
399
- style: { flex: 1, height: 26, border: "1px solid #b0c4f0", borderRadius: 3, padding: "0 8px", fontSize: 13, outline: "none", fontFamily: "var(--font-sans)" }
400
- }
401
- ),
402
- /* @__PURE__ */ jsx(
403
- "button",
404
- {
405
- onClick: applyLink,
406
- style: { height: 26, padding: "0 12px", background: "#1a6fc4", color: "#fff", border: "none", borderRadius: 3, fontSize: 12, fontWeight: 600, cursor: "pointer" },
407
- children: "Apply"
408
- }
409
- ),
410
- /* @__PURE__ */ jsx(
411
- "button",
412
- {
413
- onClick: () => setLinkBar(false),
414
- style: { height: 26, padding: "0 10px", background: "transparent", color: "#666", border: "1px solid #ccc", borderRadius: 3, fontSize: 12, cursor: "pointer" },
415
- children: "Cancel"
416
- }
417
- )
418
- ] }),
419
- /* @__PURE__ */ jsxs("div", { className: "rte-wrap", children: [
813
+ /* @__PURE__ */ jsxs("div", { className: "rte-area", ref: editorAreaRef, children: [
420
814
  /* @__PURE__ */ jsx(
421
815
  "textarea",
422
816
  {
@@ -435,20 +829,65 @@ function RichTextEditor({ value, onChange }) {
435
829
  contentEditable: true,
436
830
  suppressContentEditableWarning: true,
437
831
  "data-ph": "Start typing...",
832
+ onMouseDown: handleEditorMouseDown,
833
+ onMouseMove: handleEditorMouseMove,
834
+ onMouseUp: handleEditorMouseUp,
438
835
  onKeyDown: handleKeyDown,
439
836
  onKeyUp: refresh,
440
- onMouseUp: refresh,
441
837
  onSelect: refresh,
442
838
  style: { display: isCode ? "none" : "block" }
443
839
  }
444
- )
840
+ ),
841
+ !isCode && fmt.inTable && tableFP && /* @__PURE__ */ jsxs("div", { className: "rte-float", style: { top: tableFP.top, left: tableFP.left }, children: [
842
+ /* @__PURE__ */ jsx("div", { className: "rte-float-arrow", style: { left: tableFP.arrowLeft } }),
843
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("addRowAbove"), title: "Add row above", children: /* @__PURE__ */ jsx(IcoRowAbove, {}) }),
844
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("addRowBelow"), title: "Add row below", children: /* @__PURE__ */ jsx(IcoRowBelow, {}) }),
845
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("deleteRow"), title: "Delete row", danger: true, children: /* @__PURE__ */ jsx(IcoDelRow, {}) }),
846
+ /* @__PURE__ */ jsx(Sep, {}),
847
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("addColLeft"), title: "Add column left", children: /* @__PURE__ */ jsx(IcoColLeft, {}) }),
848
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("addColRight"), title: "Add column right", children: /* @__PURE__ */ jsx(IcoColRight, {}) }),
849
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("deleteCol"), title: "Delete column", danger: true, children: /* @__PURE__ */ jsx(IcoDelCol, {}) }),
850
+ /* @__PURE__ */ jsx(Sep, {}),
851
+ canMerge && /* @__PURE__ */ jsx(Btn, { onClick: () => doMerge(selCells), title: `Merge ${selCells.length} cells`, children: /* @__PURE__ */ jsx(IcoMerge, {}) }),
852
+ canSplit && /* @__PURE__ */ jsx(Btn, { onClick: doSplit, title: "Split merged cell", children: /* @__PURE__ */ jsx(IcoSplit, {}) }),
853
+ (canMerge || canSplit) && /* @__PURE__ */ jsx(Sep, {}),
854
+ /* @__PURE__ */ jsx(Btn, { onClick: () => tableOp("deleteTable"), title: "Delete table", danger: true, children: /* @__PURE__ */ jsx(IcoDelTable, {}) })
855
+ ] }),
856
+ !isCode && linkBar && linkFP && /* @__PURE__ */ jsxs("div", { className: "rte-float rte-link-float", style: { top: linkFP.top, left: linkFP.left }, children: [
857
+ /* @__PURE__ */ jsx("div", { className: "rte-float-arrow", style: { left: linkFP.arrowLeft } }),
858
+ /* @__PURE__ */ jsx(IcoLink, {}),
859
+ /* @__PURE__ */ jsx(
860
+ "input",
861
+ {
862
+ autoFocus: true,
863
+ type: "text",
864
+ value: linkUrl,
865
+ onChange: (e) => setLinkUrl(e.target.value),
866
+ onKeyDown: (e) => {
867
+ if (e.key === "Enter") applyLink();
868
+ if (e.key === "Escape") {
869
+ setLinkBar(false);
870
+ setLinkFP(null);
871
+ }
872
+ },
873
+ placeholder: "https://example.com"
874
+ }
875
+ ),
876
+ /* @__PURE__ */ jsx("button", { className: "rte-link-apply", onClick: applyLink, children: "Apply" }),
877
+ /* @__PURE__ */ jsx("button", { className: "rte-link-cancel", onClick: () => {
878
+ setLinkBar(false);
879
+ setLinkFP(null);
880
+ }, children: "\u2715" })
881
+ ] })
445
882
  ] }),
446
883
  !isCode && /* @__PURE__ */ jsxs("div", { className: "rte-footer", children: [
447
- "Inside a list: ",
884
+ "Table: ",
885
+ /* @__PURE__ */ jsx("strong", { children: "drag" }),
886
+ " or ",
887
+ /* @__PURE__ */ jsx("strong", { children: "Shift+click" }),
888
+ " to select cells \xA0\xB7\xA0 ",
448
889
  /* @__PURE__ */ jsx("strong", { children: "Tab" }),
449
- " to go deeper \xA0\xB7\xA0 ",
450
- /* @__PURE__ */ jsx("strong", { children: "Shift+Tab" }),
451
- " to go back up"
890
+ " moves between cells"
452
891
  ] })
453
892
  ] })
454
893
  ] });