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