react-lite-rich-text-editor 1.1.2 → 1.1.4
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/README.md +27 -10
- package/dist/index.cjs.js +885 -1399
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +885 -1399
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,593 +1,329 @@
|
|
|
1
1
|
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (Array.isArray(r)) return r;
|
|
10
|
-
}
|
|
11
|
-
function asyncGeneratorStep(n, t, e, r, o, a, c) {
|
|
12
|
-
try {
|
|
13
|
-
var i = n[a](c),
|
|
14
|
-
u = i.value;
|
|
15
|
-
} catch (n) {
|
|
16
|
-
return void e(n);
|
|
17
|
-
}
|
|
18
|
-
i.done ? t(u) : Promise.resolve(u).then(r, o);
|
|
19
|
-
}
|
|
20
|
-
function _asyncToGenerator(n) {
|
|
21
|
-
return function () {
|
|
22
|
-
var t = this,
|
|
23
|
-
e = arguments;
|
|
24
|
-
return new Promise(function (r, o) {
|
|
25
|
-
var a = n.apply(t, e);
|
|
26
|
-
function _next(n) {
|
|
27
|
-
asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
|
|
28
|
-
}
|
|
29
|
-
function _throw(n) {
|
|
30
|
-
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
|
|
31
|
-
}
|
|
32
|
-
_next(void 0);
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function _createForOfIteratorHelper(r, e) {
|
|
37
|
-
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
38
|
-
if (!t) {
|
|
39
|
-
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
|
|
40
|
-
t && (r = t);
|
|
41
|
-
var n = 0,
|
|
42
|
-
F = function () {};
|
|
43
|
-
return {
|
|
44
|
-
s: F,
|
|
45
|
-
n: function () {
|
|
46
|
-
return n >= r.length ? {
|
|
47
|
-
done: true
|
|
48
|
-
} : {
|
|
49
|
-
done: false,
|
|
50
|
-
value: r[n++]
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
e: function (r) {
|
|
54
|
-
throw r;
|
|
55
|
-
},
|
|
56
|
-
f: F
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
60
|
-
}
|
|
61
|
-
var o,
|
|
62
|
-
a = true,
|
|
63
|
-
u = false;
|
|
64
|
-
return {
|
|
65
|
-
s: function () {
|
|
66
|
-
t = t.call(r);
|
|
67
|
-
},
|
|
68
|
-
n: function () {
|
|
69
|
-
var r = t.next();
|
|
70
|
-
return a = r.done, r;
|
|
71
|
-
},
|
|
72
|
-
e: function (r) {
|
|
73
|
-
u = true, o = r;
|
|
74
|
-
},
|
|
75
|
-
f: function () {
|
|
76
|
-
try {
|
|
77
|
-
a || null == t.return || t.return();
|
|
78
|
-
} finally {
|
|
79
|
-
if (u) throw o;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
function _defineProperty(e, r, t) {
|
|
85
|
-
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
86
|
-
value: t,
|
|
87
|
-
enumerable: true,
|
|
88
|
-
configurable: true,
|
|
89
|
-
writable: true
|
|
90
|
-
}) : e[r] = t, e;
|
|
91
|
-
}
|
|
92
|
-
function _iterableToArrayLimit(r, l) {
|
|
93
|
-
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
94
|
-
if (null != t) {
|
|
95
|
-
var e,
|
|
96
|
-
n,
|
|
97
|
-
i,
|
|
98
|
-
u,
|
|
99
|
-
a = [],
|
|
100
|
-
f = true,
|
|
101
|
-
o = false;
|
|
102
|
-
try {
|
|
103
|
-
if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
|
|
104
|
-
} catch (r) {
|
|
105
|
-
o = true, n = r;
|
|
106
|
-
} finally {
|
|
107
|
-
try {
|
|
108
|
-
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
|
|
109
|
-
} finally {
|
|
110
|
-
if (o) throw n;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return a;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function _nonIterableRest() {
|
|
117
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
118
|
-
}
|
|
119
|
-
function ownKeys(e, r) {
|
|
120
|
-
var t = Object.keys(e);
|
|
121
|
-
if (Object.getOwnPropertySymbols) {
|
|
122
|
-
var o = Object.getOwnPropertySymbols(e);
|
|
123
|
-
r && (o = o.filter(function (r) {
|
|
124
|
-
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
|
125
|
-
})), t.push.apply(t, o);
|
|
126
|
-
}
|
|
127
|
-
return t;
|
|
128
|
-
}
|
|
129
|
-
function _objectSpread2(e) {
|
|
130
|
-
for (var r = 1; r < arguments.length; r++) {
|
|
131
|
-
var t = null != arguments[r] ? arguments[r] : {};
|
|
132
|
-
r % 2 ? ownKeys(Object(t), true).forEach(function (r) {
|
|
133
|
-
_defineProperty(e, r, t[r]);
|
|
134
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
|
|
135
|
-
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
return e;
|
|
139
|
-
}
|
|
140
|
-
function _regenerator() {
|
|
141
|
-
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
|
142
|
-
var e,
|
|
143
|
-
t,
|
|
144
|
-
r = "function" == typeof Symbol ? Symbol : {},
|
|
145
|
-
n = r.iterator || "@@iterator",
|
|
146
|
-
o = r.toStringTag || "@@toStringTag";
|
|
147
|
-
function i(r, n, o, i) {
|
|
148
|
-
var c = n && n.prototype instanceof Generator ? n : Generator,
|
|
149
|
-
u = Object.create(c.prototype);
|
|
150
|
-
return _regeneratorDefine(u, "_invoke", function (r, n, o) {
|
|
151
|
-
var i,
|
|
152
|
-
c,
|
|
153
|
-
u,
|
|
154
|
-
f = 0,
|
|
155
|
-
p = o || [],
|
|
156
|
-
y = false,
|
|
157
|
-
G = {
|
|
158
|
-
p: 0,
|
|
159
|
-
n: 0,
|
|
160
|
-
v: e,
|
|
161
|
-
a: d,
|
|
162
|
-
f: d.bind(e, 4),
|
|
163
|
-
d: function (t, r) {
|
|
164
|
-
return i = t, c = 0, u = e, G.n = r, a;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
function d(r, n) {
|
|
168
|
-
for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
|
|
169
|
-
var o,
|
|
170
|
-
i = p[t],
|
|
171
|
-
d = G.p,
|
|
172
|
-
l = i[2];
|
|
173
|
-
r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0));
|
|
174
|
-
}
|
|
175
|
-
if (o || r > 1) return a;
|
|
176
|
-
throw y = true, n;
|
|
177
|
-
}
|
|
178
|
-
return function (o, p, l) {
|
|
179
|
-
if (f > 1) throw TypeError("Generator is already running");
|
|
180
|
-
for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
|
|
181
|
-
i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
|
|
182
|
-
try {
|
|
183
|
-
if (f = 2, i) {
|
|
184
|
-
if (c || (o = "next"), t = i[o]) {
|
|
185
|
-
if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
|
|
186
|
-
if (!t.done) return t;
|
|
187
|
-
u = t.value, c < 2 && (c = 0);
|
|
188
|
-
} else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
|
|
189
|
-
i = e;
|
|
190
|
-
} else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
|
|
191
|
-
} catch (t) {
|
|
192
|
-
i = e, c = 1, u = t;
|
|
193
|
-
} finally {
|
|
194
|
-
f = 1;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return {
|
|
198
|
-
value: t,
|
|
199
|
-
done: y
|
|
200
|
-
};
|
|
201
|
-
};
|
|
202
|
-
}(r, o, i), true), u;
|
|
203
|
-
}
|
|
204
|
-
var a = {};
|
|
205
|
-
function Generator() {}
|
|
206
|
-
function GeneratorFunction() {}
|
|
207
|
-
function GeneratorFunctionPrototype() {}
|
|
208
|
-
t = Object.getPrototypeOf;
|
|
209
|
-
var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () {
|
|
210
|
-
return this;
|
|
211
|
-
}), t),
|
|
212
|
-
u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
|
|
213
|
-
function f(e) {
|
|
214
|
-
return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
|
|
215
|
-
}
|
|
216
|
-
return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine(u), _regeneratorDefine(u, o, "Generator"), _regeneratorDefine(u, n, function () {
|
|
217
|
-
return this;
|
|
218
|
-
}), _regeneratorDefine(u, "toString", function () {
|
|
219
|
-
return "[object Generator]";
|
|
220
|
-
}), (_regenerator = function () {
|
|
221
|
-
return {
|
|
222
|
-
w: i,
|
|
223
|
-
m: f
|
|
224
|
-
};
|
|
225
|
-
})();
|
|
226
|
-
}
|
|
227
|
-
function _regeneratorDefine(e, r, n, t) {
|
|
228
|
-
var i = Object.defineProperty;
|
|
229
|
-
try {
|
|
230
|
-
i({}, "", {});
|
|
231
|
-
} catch (e) {
|
|
232
|
-
i = 0;
|
|
233
|
-
}
|
|
234
|
-
_regeneratorDefine = function (e, r, n, t) {
|
|
235
|
-
function o(r, n) {
|
|
236
|
-
_regeneratorDefine(e, r, function (e) {
|
|
237
|
-
return this._invoke(r, n, e);
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
r ? i ? i(e, r, {
|
|
241
|
-
value: n,
|
|
242
|
-
enumerable: !t,
|
|
243
|
-
configurable: !t,
|
|
244
|
-
writable: !t
|
|
245
|
-
}) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2));
|
|
246
|
-
}, _regeneratorDefine(e, r, n, t);
|
|
247
|
-
}
|
|
248
|
-
function _regeneratorValues(e) {
|
|
249
|
-
if (null != e) {
|
|
250
|
-
var t = e["function" == typeof Symbol && Symbol.iterator || "@@iterator"],
|
|
251
|
-
r = 0;
|
|
252
|
-
if (t) return t.call(e);
|
|
253
|
-
if ("function" == typeof e.next) return e;
|
|
254
|
-
if (!isNaN(e.length)) return {
|
|
255
|
-
next: function () {
|
|
256
|
-
return e && r >= e.length && (e = void 0), {
|
|
257
|
-
value: e && e[r++],
|
|
258
|
-
done: !e
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
throw new TypeError(typeof e + " is not iterable");
|
|
264
|
-
}
|
|
265
|
-
function _slicedToArray(r, e) {
|
|
266
|
-
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
|
|
267
|
-
}
|
|
268
|
-
function _toPrimitive(t, r) {
|
|
269
|
-
if ("object" != typeof t || !t) return t;
|
|
270
|
-
var e = t[Symbol.toPrimitive];
|
|
271
|
-
if (void 0 !== e) {
|
|
272
|
-
var i = e.call(t, r);
|
|
273
|
-
if ("object" != typeof i) return i;
|
|
274
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
275
|
-
}
|
|
276
|
-
return ("string" === r ? String : Number)(t);
|
|
277
|
-
}
|
|
278
|
-
function _toPropertyKey(t) {
|
|
279
|
-
var i = _toPrimitive(t, "string");
|
|
280
|
-
return "symbol" == typeof i ? i : i + "";
|
|
281
|
-
}
|
|
282
|
-
function _typeof(o) {
|
|
283
|
-
"@babel/helpers - typeof";
|
|
284
|
-
|
|
285
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
|
|
286
|
-
return typeof o;
|
|
287
|
-
} : function (o) {
|
|
288
|
-
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
289
|
-
}, _typeof(o);
|
|
290
|
-
}
|
|
291
|
-
function _unsupportedIterableToArray(r, a) {
|
|
292
|
-
if (r) {
|
|
293
|
-
if ("string" == typeof r) return _arrayLikeToArray(r, a);
|
|
294
|
-
var t = {}.toString.call(r).slice(8, -1);
|
|
295
|
-
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
var FaImage = function FaImage(_ref) {
|
|
300
|
-
var className = _ref.className,
|
|
301
|
-
size = _ref.size,
|
|
302
|
-
color = _ref.color,
|
|
303
|
-
style = _ref.style;
|
|
3
|
+
const FaImage = ({
|
|
4
|
+
className,
|
|
5
|
+
size,
|
|
6
|
+
color,
|
|
7
|
+
style
|
|
8
|
+
}) => {
|
|
304
9
|
return /*#__PURE__*/React.createElement("span", {
|
|
305
10
|
className: className,
|
|
306
|
-
style:
|
|
11
|
+
style: {
|
|
307
12
|
display: 'inline-flex',
|
|
308
13
|
alignItems: 'center',
|
|
309
14
|
justifyContent: 'center',
|
|
310
15
|
fontSize: size || '1em',
|
|
311
|
-
color: color || 'inherit'
|
|
312
|
-
|
|
16
|
+
color: color || 'inherit',
|
|
17
|
+
...style
|
|
18
|
+
},
|
|
313
19
|
dangerouslySetInnerHTML: {
|
|
314
|
-
__html:
|
|
20
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>`
|
|
315
21
|
}
|
|
316
22
|
});
|
|
317
23
|
};
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
24
|
+
const FaBold = ({
|
|
25
|
+
className,
|
|
26
|
+
size,
|
|
27
|
+
color,
|
|
28
|
+
style
|
|
29
|
+
}) => {
|
|
323
30
|
return /*#__PURE__*/React.createElement("span", {
|
|
324
31
|
className: className,
|
|
325
|
-
style:
|
|
32
|
+
style: {
|
|
326
33
|
display: 'inline-flex',
|
|
327
34
|
alignItems: 'center',
|
|
328
35
|
justifyContent: 'center',
|
|
329
36
|
fontSize: size || '1em',
|
|
330
|
-
color: color || 'inherit'
|
|
331
|
-
|
|
37
|
+
color: color || 'inherit',
|
|
38
|
+
...style
|
|
39
|
+
},
|
|
332
40
|
dangerouslySetInnerHTML: {
|
|
333
|
-
__html:
|
|
41
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 384 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M333.49 238a122 122 0 0 0 27-65.21C367.87 96.49 308 32 233.42 32H34a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h31.87v288H34a16 16 0 0 0-16 16v48a16 16 0 0 0 16 16h209.32c70.8 0 134.14-51.75 141-122.4 4.74-48.45-16.39-92.06-50.83-119.6zM145.66 112h87.76a48 48 0 0 1 0 96h-87.76zm87.76 288h-87.76V288h87.76a56 56 0 0 1 0 112z"></path></svg>`
|
|
334
42
|
}
|
|
335
43
|
});
|
|
336
44
|
};
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
45
|
+
const FaItalic = ({
|
|
46
|
+
className,
|
|
47
|
+
size,
|
|
48
|
+
color,
|
|
49
|
+
style
|
|
50
|
+
}) => {
|
|
342
51
|
return /*#__PURE__*/React.createElement("span", {
|
|
343
52
|
className: className,
|
|
344
|
-
style:
|
|
53
|
+
style: {
|
|
345
54
|
display: 'inline-flex',
|
|
346
55
|
alignItems: 'center',
|
|
347
56
|
justifyContent: 'center',
|
|
348
57
|
fontSize: size || '1em',
|
|
349
|
-
color: color || 'inherit'
|
|
350
|
-
|
|
58
|
+
color: color || 'inherit',
|
|
59
|
+
...style
|
|
60
|
+
},
|
|
351
61
|
dangerouslySetInnerHTML: {
|
|
352
|
-
__html:
|
|
62
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 320 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M320 48v32a16 16 0 0 1-16 16h-62.76l-80 320H208a16 16 0 0 1 16 16v32a16 16 0 0 1-16 16H16a16 16 0 0 1-16-16v-32a16 16 0 0 1 16-16h62.76l80-320H112a16 16 0 0 1-16-16V48a16 16 0 0 1 16-16h192a16 16 0 0 1 16 16z"></path></svg>`
|
|
353
63
|
}
|
|
354
64
|
});
|
|
355
65
|
};
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
66
|
+
const FaUnderline = ({
|
|
67
|
+
className,
|
|
68
|
+
size,
|
|
69
|
+
color,
|
|
70
|
+
style
|
|
71
|
+
}) => {
|
|
361
72
|
return /*#__PURE__*/React.createElement("span", {
|
|
362
73
|
className: className,
|
|
363
|
-
style:
|
|
74
|
+
style: {
|
|
364
75
|
display: 'inline-flex',
|
|
365
76
|
alignItems: 'center',
|
|
366
77
|
justifyContent: 'center',
|
|
367
78
|
fontSize: size || '1em',
|
|
368
|
-
color: color || 'inherit'
|
|
369
|
-
|
|
79
|
+
color: color || 'inherit',
|
|
80
|
+
...style
|
|
81
|
+
},
|
|
370
82
|
dangerouslySetInnerHTML: {
|
|
371
|
-
__html:
|
|
83
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M32 64h32v160c0 88.22 71.78 160 160 160s160-71.78 160-160V64h32a16 16 0 0 0 16-16V16a16 16 0 0 0-16-16H272a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h32v160a80 80 0 0 1-160 0V64h32a16 16 0 0 0 16-16V16a16 16 0 0 0-16-16H32a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16zm400 384H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"></path></svg>`
|
|
372
84
|
}
|
|
373
85
|
});
|
|
374
86
|
};
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
87
|
+
const FaTextHeight = ({
|
|
88
|
+
className,
|
|
89
|
+
size,
|
|
90
|
+
color,
|
|
91
|
+
style
|
|
92
|
+
}) => {
|
|
380
93
|
return /*#__PURE__*/React.createElement("span", {
|
|
381
94
|
className: className,
|
|
382
|
-
style:
|
|
95
|
+
style: {
|
|
383
96
|
display: 'inline-flex',
|
|
384
97
|
alignItems: 'center',
|
|
385
98
|
justifyContent: 'center',
|
|
386
99
|
fontSize: size || '1em',
|
|
387
|
-
color: color || 'inherit'
|
|
388
|
-
|
|
100
|
+
color: color || 'inherit',
|
|
101
|
+
...style
|
|
102
|
+
},
|
|
389
103
|
dangerouslySetInnerHTML: {
|
|
390
|
-
__html:
|
|
104
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 576 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M304 32H16A16 16 0 0 0 0 48v96a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16v-32h56v304H80a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h160a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-40V112h56v32a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zm256 336h-48V144h48c14.31 0 21.33-17.31 11.31-27.31l-80-80a16 16 0 0 0-22.62 0l-80 80C379.36 126 384.36 144 400 144h48v224h-48c-14.31 0-21.32 17.31-11.31 27.31l80 80a16 16 0 0 0 22.62 0l80-80C580.64 386 575.64 368 560 368z"></path></svg>`
|
|
391
105
|
}
|
|
392
106
|
});
|
|
393
107
|
};
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
108
|
+
const FaAlignCenter = ({
|
|
109
|
+
className,
|
|
110
|
+
size,
|
|
111
|
+
color,
|
|
112
|
+
style
|
|
113
|
+
}) => {
|
|
399
114
|
return /*#__PURE__*/React.createElement("span", {
|
|
400
115
|
className: className,
|
|
401
|
-
style:
|
|
116
|
+
style: {
|
|
402
117
|
display: 'inline-flex',
|
|
403
118
|
alignItems: 'center',
|
|
404
119
|
justifyContent: 'center',
|
|
405
120
|
fontSize: size || '1em',
|
|
406
|
-
color: color || 'inherit'
|
|
407
|
-
|
|
121
|
+
color: color || 'inherit',
|
|
122
|
+
...style
|
|
123
|
+
},
|
|
408
124
|
dangerouslySetInnerHTML: {
|
|
409
|
-
__html:
|
|
125
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M432 160H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0 256H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM108.1 96h231.81A12.09 12.09 0 0 0 352 83.9V44.09A12.09 12.09 0 0 0 339.91 32H108.1A12.09 12.09 0 0 0 96 44.09V83.9A12.1 12.1 0 0 0 108.1 96zm231.81 256A12.09 12.09 0 0 0 352 339.9v-39.81A12.09 12.09 0 0 0 339.91 288H108.1A12.09 12.09 0 0 0 96 300.09v39.81a12.1 12.1 0 0 0 12.1 12.1z"></path></svg>`
|
|
410
126
|
}
|
|
411
127
|
});
|
|
412
128
|
};
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
129
|
+
const FaAlignRight = ({
|
|
130
|
+
className,
|
|
131
|
+
size,
|
|
132
|
+
color,
|
|
133
|
+
style
|
|
134
|
+
}) => {
|
|
418
135
|
return /*#__PURE__*/React.createElement("span", {
|
|
419
136
|
className: className,
|
|
420
|
-
style:
|
|
137
|
+
style: {
|
|
421
138
|
display: 'inline-flex',
|
|
422
139
|
alignItems: 'center',
|
|
423
140
|
justifyContent: 'center',
|
|
424
141
|
fontSize: size || '1em',
|
|
425
|
-
color: color || 'inherit'
|
|
426
|
-
|
|
142
|
+
color: color || 'inherit',
|
|
143
|
+
...style
|
|
144
|
+
},
|
|
427
145
|
dangerouslySetInnerHTML: {
|
|
428
|
-
__html:
|
|
146
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M16 224h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16zm416 192H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm3.17-384H172.83A12.82 12.82 0 0 0 160 44.83v38.34A12.82 12.82 0 0 0 172.83 96h262.34A12.82 12.82 0 0 0 448 83.17V44.83A12.82 12.82 0 0 0 435.17 32zm0 256H172.83A12.82 12.82 0 0 0 160 300.83v38.34A12.82 12.82 0 0 0 172.83 352h262.34A12.82 12.82 0 0 0 448 339.17v-38.34A12.82 12.82 0 0 0 435.17 288z"></path></svg>`
|
|
429
147
|
}
|
|
430
148
|
});
|
|
431
149
|
};
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
150
|
+
const FaAlignLeft = ({
|
|
151
|
+
className,
|
|
152
|
+
size,
|
|
153
|
+
color,
|
|
154
|
+
style
|
|
155
|
+
}) => {
|
|
437
156
|
return /*#__PURE__*/React.createElement("span", {
|
|
438
157
|
className: className,
|
|
439
|
-
style:
|
|
158
|
+
style: {
|
|
440
159
|
display: 'inline-flex',
|
|
441
160
|
alignItems: 'center',
|
|
442
161
|
justifyContent: 'center',
|
|
443
162
|
fontSize: size || '1em',
|
|
444
|
-
color: color || 'inherit'
|
|
445
|
-
|
|
163
|
+
color: color || 'inherit',
|
|
164
|
+
...style
|
|
165
|
+
},
|
|
446
166
|
dangerouslySetInnerHTML: {
|
|
447
|
-
__html:
|
|
167
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M12.83 352h262.34A12.82 12.82 0 0 0 288 339.17v-38.34A12.82 12.82 0 0 0 275.17 288H12.83A12.82 12.82 0 0 0 0 300.83v38.34A12.82 12.82 0 0 0 12.83 352zm0-256h262.34A12.82 12.82 0 0 0 288 83.17V44.83A12.82 12.82 0 0 0 275.17 32H12.83A12.82 12.82 0 0 0 0 44.83v38.34A12.82 12.82 0 0 0 12.83 96zM432 160H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0 256H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"></path></svg>`
|
|
448
168
|
}
|
|
449
169
|
});
|
|
450
170
|
};
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
171
|
+
const FaListOl = ({
|
|
172
|
+
className,
|
|
173
|
+
size,
|
|
174
|
+
color,
|
|
175
|
+
style
|
|
176
|
+
}) => {
|
|
456
177
|
return /*#__PURE__*/React.createElement("span", {
|
|
457
178
|
className: className,
|
|
458
|
-
style:
|
|
179
|
+
style: {
|
|
459
180
|
display: 'inline-flex',
|
|
460
181
|
alignItems: 'center',
|
|
461
182
|
justifyContent: 'center',
|
|
462
183
|
fontSize: size || '1em',
|
|
463
|
-
color: color || 'inherit'
|
|
464
|
-
|
|
184
|
+
color: color || 'inherit',
|
|
185
|
+
...style
|
|
186
|
+
},
|
|
465
187
|
dangerouslySetInnerHTML: {
|
|
466
|
-
__html:
|
|
188
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M61.77 401l17.5-20.15a19.92 19.92 0 0 0 5.07-14.19v-3.31C84.34 356 80.5 352 73 352H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8h22.83a157.41 157.41 0 0 0-11 12.31l-5.61 7c-4 5.07-5.25 10.13-2.8 14.88l1.05 1.93c3 5.76 6.29 7.88 12.25 7.88h4.73c10.33 0 15.94 2.44 15.94 9.09 0 4.72-4.2 8.22-14.36 8.22a41.54 41.54 0 0 1-15.47-3.12c-6.49-3.88-11.74-3.5-15.6 3.12l-5.59 9.31c-3.72 6.13-3.19 11.72 2.63 15.94 7.71 4.69 20.38 9.44 37 9.44 34.16 0 48.5-22.75 48.5-44.12-.03-14.38-9.12-29.76-28.73-34.88zM496 224H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM16 160h64a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H64V40a8 8 0 0 0-8-8H32a8 8 0 0 0-7.14 4.42l-8 16A8 8 0 0 0 24 64h8v64H16a8 8 0 0 0-8 8v16a8 8 0 0 0 8 8zm-3.91 160H80a8 8 0 0 0 8-8v-16a8 8 0 0 0-8-8H41.32c3.29-10.29 48.34-18.68 48.34-56.44 0-29.06-25-39.56-44.47-39.56-21.36 0-33.8 10-40.46 18.75-4.37 5.59-3 10.84 2.8 15.37l8.58 6.88c5.61 4.56 11 2.47 16.12-2.44a13.44 13.44 0 0 1 9.46-3.84c3.33 0 9.28 1.56 9.28 8.75C51 248.19 0 257.31 0 304.59v4C0 316 5.08 320 12.09 320z"></path></svg>`
|
|
467
189
|
}
|
|
468
190
|
});
|
|
469
191
|
};
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
192
|
+
const FaListUl = ({
|
|
193
|
+
className,
|
|
194
|
+
size,
|
|
195
|
+
color,
|
|
196
|
+
style
|
|
197
|
+
}) => {
|
|
475
198
|
return /*#__PURE__*/React.createElement("span", {
|
|
476
199
|
className: className,
|
|
477
|
-
style:
|
|
200
|
+
style: {
|
|
478
201
|
display: 'inline-flex',
|
|
479
202
|
alignItems: 'center',
|
|
480
203
|
justifyContent: 'center',
|
|
481
204
|
fontSize: size || '1em',
|
|
482
|
-
color: color || 'inherit'
|
|
483
|
-
|
|
205
|
+
color: color || 'inherit',
|
|
206
|
+
...style
|
|
207
|
+
},
|
|
484
208
|
dangerouslySetInnerHTML: {
|
|
485
|
-
__html:
|
|
209
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M48 48a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm0 160a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm0 160a48 48 0 1 0 48 48 48 48 0 0 0-48-48zm448 16H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm0-320H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16zm0 160H176a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h320a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16z"></path></svg>`
|
|
486
210
|
}
|
|
487
211
|
});
|
|
488
212
|
};
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
213
|
+
const FaFont = ({
|
|
214
|
+
className,
|
|
215
|
+
size,
|
|
216
|
+
color,
|
|
217
|
+
style
|
|
218
|
+
}) => {
|
|
494
219
|
return /*#__PURE__*/React.createElement("span", {
|
|
495
220
|
className: className,
|
|
496
|
-
style:
|
|
221
|
+
style: {
|
|
497
222
|
display: 'inline-flex',
|
|
498
223
|
alignItems: 'center',
|
|
499
224
|
justifyContent: 'center',
|
|
500
225
|
fontSize: size || '1em',
|
|
501
|
-
color: color || 'inherit'
|
|
502
|
-
|
|
226
|
+
color: color || 'inherit',
|
|
227
|
+
...style
|
|
228
|
+
},
|
|
503
229
|
dangerouslySetInnerHTML: {
|
|
504
|
-
__html:
|
|
230
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M432 416h-23.41L277.88 53.69A32 32 0 0 0 247.58 32h-47.16a32 32 0 0 0-30.3 21.69L39.41 416H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-19.58l23.3-64h152.56l23.3 64H304a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM176.85 272L224 142.51 271.15 272z"></path></svg>`
|
|
505
231
|
}
|
|
506
232
|
});
|
|
507
233
|
};
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
234
|
+
const FaTable = ({
|
|
235
|
+
className,
|
|
236
|
+
size,
|
|
237
|
+
color,
|
|
238
|
+
style
|
|
239
|
+
}) => {
|
|
513
240
|
return /*#__PURE__*/React.createElement("span", {
|
|
514
241
|
className: className,
|
|
515
|
-
style:
|
|
242
|
+
style: {
|
|
516
243
|
display: 'inline-flex',
|
|
517
244
|
alignItems: 'center',
|
|
518
245
|
justifyContent: 'center',
|
|
519
246
|
fontSize: size || '1em',
|
|
520
|
-
color: color || 'inherit'
|
|
521
|
-
|
|
247
|
+
color: color || 'inherit',
|
|
248
|
+
...style
|
|
249
|
+
},
|
|
522
250
|
dangerouslySetInnerHTML: {
|
|
523
|
-
__html:
|
|
251
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M64 448c-35.3 0-64-28.7-64-64V128c0-35.3 28.7-64 64-64H448c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64zm96-288H64v64h96v-64zm0 96H64v64h96v-64zm0 96H64c0 17.7 14.3 32 32 32h64v-32zm128-192h-96v64h96v-64zm0 96h-96v64h96v-64zm0 96h-96v96h96v-96zm160-192h-96v64h96v-64zm0 96h-96v64h96v-64zm0 96h-96v64h64c17.7 0 32-14.3 32-32v-32z"></path></svg>`
|
|
524
252
|
}
|
|
525
253
|
});
|
|
526
254
|
};
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
255
|
+
const FaObjectGroup = ({
|
|
256
|
+
className,
|
|
257
|
+
size,
|
|
258
|
+
color,
|
|
259
|
+
style
|
|
260
|
+
}) => {
|
|
532
261
|
return /*#__PURE__*/React.createElement("span", {
|
|
533
262
|
className: className,
|
|
534
|
-
style:
|
|
263
|
+
style: {
|
|
535
264
|
display: 'inline-flex',
|
|
536
265
|
alignItems: 'center',
|
|
537
266
|
justifyContent: 'center',
|
|
538
267
|
fontSize: size || '1em',
|
|
539
|
-
color: color || 'inherit'
|
|
540
|
-
|
|
268
|
+
color: color || 'inherit',
|
|
269
|
+
...style
|
|
270
|
+
},
|
|
541
271
|
dangerouslySetInnerHTML: {
|
|
542
|
-
__html:
|
|
272
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M480 320h-48v48c0 17.7-14.3 32-32 32h-48v32c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V160c0-26.5 21.5-48 48-48h32v-48c0-17.7 14.3-32 32-32h48V0h32c26.5 0 48 21.5 48 48v48h48c17.7 0 32 14.3 32 32v48h32c26.5 0 48 21.5 48 48v128c0 26.5-21.5 48-48 48z"></path></svg>`
|
|
543
273
|
}
|
|
544
274
|
});
|
|
545
275
|
};
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
276
|
+
const FaTrash = ({
|
|
277
|
+
className,
|
|
278
|
+
size,
|
|
279
|
+
color,
|
|
280
|
+
style
|
|
281
|
+
}) => {
|
|
551
282
|
return /*#__PURE__*/React.createElement("span", {
|
|
552
283
|
className: className,
|
|
553
|
-
style:
|
|
284
|
+
style: {
|
|
554
285
|
display: 'inline-flex',
|
|
555
286
|
alignItems: 'center',
|
|
556
287
|
justifyContent: 'center',
|
|
557
288
|
fontSize: size || '1em',
|
|
558
|
-
color: color || 'inherit'
|
|
559
|
-
|
|
289
|
+
color: color || 'inherit',
|
|
290
|
+
...style
|
|
291
|
+
},
|
|
560
292
|
dangerouslySetInnerHTML: {
|
|
561
|
-
__html:
|
|
293
|
+
__html: `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 448 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z"></path></svg>`
|
|
562
294
|
}
|
|
563
295
|
});
|
|
564
296
|
};
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
297
|
+
const FaVideo = ({
|
|
298
|
+
className,
|
|
299
|
+
size,
|
|
300
|
+
color,
|
|
301
|
+
style
|
|
302
|
+
}) => {
|
|
570
303
|
return /*#__PURE__*/React.createElement("span", {
|
|
571
304
|
className: className,
|
|
572
|
-
style:
|
|
305
|
+
style: {
|
|
573
306
|
display: 'inline-flex',
|
|
574
307
|
alignItems: 'center',
|
|
575
308
|
justifyContent: 'center',
|
|
576
309
|
fontSize: size || '1em',
|
|
577
|
-
color: color || 'inherit'
|
|
578
|
-
|
|
310
|
+
color: color || 'inherit',
|
|
311
|
+
...style
|
|
312
|
+
},
|
|
579
313
|
dangerouslySetInnerHTML: {
|
|
580
|
-
__html:
|
|
314
|
+
__html: '<svg stroke=\"currentColor\" fill=\"currentColor\" stroke-width=\"0\" viewBox=\"0 0 576 512\" height=\"1em\" width=\"1em\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M0 128C0 92.7 28.7 64 64 64H320c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128zM559.1 99.8c10.4 5.6 16.9 16.3 16.9 28.2V384c0 11.9-6.5 22.6-16.9 28.2s-23 5-32.9-1.6l-96-64L416 337.1V174.9l14.2-9.5 96-64c9.9-6.6 22.6-7.1 32.9-1.6z\"></path></svg>'
|
|
581
315
|
}
|
|
582
316
|
});
|
|
583
317
|
};
|
|
584
318
|
|
|
319
|
+
// Basic ID generator
|
|
320
|
+
|
|
585
321
|
// DraftJS helper stubs
|
|
586
322
|
// Since we are removing specific DraftJS dependencies for this package,
|
|
587
323
|
// these serve as placeholders or basic HTML verifiers.
|
|
588
324
|
|
|
589
|
-
|
|
590
|
-
if (
|
|
325
|
+
const isValidDraftFormat = content => {
|
|
326
|
+
if (typeof content !== "object" || content === null) return false;
|
|
591
327
|
return !!(content.blocks && content.entityMap);
|
|
592
328
|
};
|
|
593
329
|
|
|
@@ -595,18 +331,16 @@ var isValidDraftFormat = function isValidDraftFormat(content) {
|
|
|
595
331
|
// Dealing with full DraftJS->HTML conversion without the library is complex.
|
|
596
332
|
// We assume for this package that if the legacy DraftJS format is passed,
|
|
597
333
|
// the user might need to handle it or we expect HTML primarily.
|
|
598
|
-
|
|
334
|
+
const draftBlocksToHTML = content => {
|
|
599
335
|
console.warn("draftBlocksToHTML: DraftJS object detected but full conversion is simplified in this package.");
|
|
600
336
|
// Return empty or try to extract text as a fallback
|
|
601
337
|
if (content && content.blocks) {
|
|
602
|
-
return content.blocks.map(
|
|
603
|
-
return "<p>".concat(b.text, "</p>");
|
|
604
|
-
}).join("");
|
|
338
|
+
return content.blocks.map(b => `<p>${b.text}</p>`).join("");
|
|
605
339
|
}
|
|
606
340
|
return "";
|
|
607
341
|
};
|
|
608
342
|
|
|
609
|
-
|
|
343
|
+
const Spinner = () => {
|
|
610
344
|
return /*#__PURE__*/React.createElement("div", {
|
|
611
345
|
className: "rte-spinner-container"
|
|
612
346
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -614,8 +348,9 @@ var Spinner = function Spinner() {
|
|
|
614
348
|
}));
|
|
615
349
|
};
|
|
616
350
|
|
|
617
|
-
|
|
618
|
-
|
|
351
|
+
const LabelComponent = ({
|
|
352
|
+
children
|
|
353
|
+
}) => {
|
|
619
354
|
if (!children) return null;
|
|
620
355
|
return /*#__PURE__*/React.createElement("label", {
|
|
621
356
|
className: "rte-label",
|
|
@@ -653,191 +388,133 @@ function styleInject(css, ref) {
|
|
|
653
388
|
}
|
|
654
389
|
}
|
|
655
390
|
|
|
656
|
-
var css_248z = ".rte-container{background-color:#fff;border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,.05);overflow:hidden;transition:all .2s cubic-bezier(.4,0,.2,1)}.rte-container:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)}.rte-toolbar{align-items:center;background-color:#f9fafb;border-bottom:1px solid #f3f4f6;display:flex;flex-wrap:wrap;gap:4px;padding:8px}.rte-toolbar-button{align-items:center;background:transparent;border:none;border-radius:6px;color:#4b5563;cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all .15s ease;width:32px}.rte-toolbar-button:hover{background-color:#f3f4f6;color:#111827}.rte-toolbar-button.active{background-color:#eff6ff;color:#2563eb}.rte-toolbar-button:disabled{cursor:not-allowed;opacity:.5}.rte-toolbar-button-danger:hover{background-color:#fef2f2!important;color:#dc2626!important}.rte-toolbar-select{background-color:#fff;border:1px solid #e5e7eb;border-radius:6px;color:#374151;cursor:pointer;font-size:14px;height:32px;outline:none;padding:0 8px;transition:border-color .15s ease}.rte-toolbar-select:hover{border-color:#d1d5db}.rte-toolbar-select:focus{border-color:#3b82f6}.rte-color-picker-label{align-items:center;border-radius:6px;cursor:pointer;display:flex;height:32px;justify-content:center;position:relative;transition:background-color .15s ease;width:32px}.rte-color-picker-label:hover{background-color:#f3f4f6}.rte-color-input{cursor:pointer;height:100%;inset:0;opacity:0;position:absolute;width:100%}.rte-content{color:#1f2937;font-family:inherit;font-size:16px;line-height:1.6;min-height:150px;outline:none;overflow-y:auto;padding:12px;word-break:break-word}.rte-content ul{list-style-type:disc;margin-left:1.5rem}.rte-content ol{list-style-type:decimal;margin-left:1.5rem}.rte-content img{border-radius:8px;display:block;height:auto;max-width:100%}.rte-content table{border-collapse:collapse;margin:16px 0;width:100%}.rte-content td,.rte-content th{border:1px solid #e5e7eb;min-width:40px;padding:12px;word-break:break-word}.video-container{border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1);height:0;margin:16px 0;overflow:hidden;padding-bottom:56.25%;position:relative}.video-container iframe{height:100%;left:0;position:absolute;top:0;width:100%}.rte-modal-overlay{align-items:center;animation:rte-fade-in .2s ease-out;backdrop-filter:blur(4px);background-color:rgba(0,0,0,.5);display:flex;inset:0;justify-content:center;position:fixed;z-index:9999}.rte-modal{animation:rte-zoom-in .2s ease-out;background-color:#fff;border:1px solid #f3f4f6;border-radius:16px;box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);display:flex;flex-direction:column;gap:16px;max-width:400px;padding:0;width:100%}.rte-modal-title{color:#111827;flex:1;font-size:18px;font-weight:600;margin:0;text-align:center}.rte-modal-header{align-items:center;border-bottom:1px solid #f3f4f6;display:flex;justify-content:space-between;padding:20px 24px 16px}.rte-form-group{display:flex;flex-direction:column;gap:8px;padding:16px 24px}.rte-label{color:#374151;font-size:14px;font-weight:600}.rte-input{border:1px solid #d1d5db;border-radius:8px;outline:none;padding:8px 12px;transition:all .15s ease;width:93%}.rte-input:focus{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)}.rte-modal-actions{border-top:1px solid #f3f4f6;display:flex;gap:12px;justify-content:flex-end;padding:16px 24px 20px}.rte-button{border:none;border-radius:8px;cursor:pointer;font-weight:500;padding:8px 16px;transition:all .15s ease}.rte-button-secondary{background-color:#f3f4f6;color:#4b5563}.rte-button-secondary:hover{background-color:#e5e7eb}.rte-button-primary{background-color:#2563eb;box-shadow:0 1px 2px rgba(0,0,0,.05);color:#fff}.rte-button-primary:hover{background-color:#1d4ed8}.rte-button-primary:disabled{cursor:not-allowed;opacity:.5}.rte-spinner-container{align-items:center;display:flex;justify-content:center;padding:16px}.rte-spinner{animation:rte-spin .8s linear infinite;border:3px solid #eff6ff;border-radius:50%;border-top-color:#3b82f6;height:32px;width:32px}@keyframes rte-spin{to{transform:rotate(1turn)}}@keyframes rte-fade-in{0%{opacity:0}to{opacity:1}}@keyframes rte-zoom-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.image-container{
|
|
391
|
+
var css_248z = ".rte-container{background-color:#fff;border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,.05);overflow:hidden;transition:all .2s cubic-bezier(.4,0,.2,1)}.rte-container:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)}.rte-toolbar{align-items:center;background-color:#f9fafb;border-bottom:1px solid #f3f4f6;display:flex;flex-wrap:wrap;gap:4px;padding:8px}.rte-toolbar-button{align-items:center;background:transparent;border:none;border-radius:6px;color:#4b5563;cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all .15s ease;width:32px}.rte-toolbar-button:hover{background-color:#f3f4f6;color:#111827}.rte-toolbar-button.active{background-color:#eff6ff;color:#2563eb}.rte-toolbar-button:disabled{cursor:not-allowed;opacity:.5}.rte-toolbar-button-danger:hover{background-color:#fef2f2!important;color:#dc2626!important}.rte-toolbar-select{background-color:#fff;border:1px solid #e5e7eb;border-radius:6px;color:#374151;cursor:pointer;font-size:14px;height:32px;outline:none;padding:0 8px;transition:border-color .15s ease}.rte-toolbar-select:hover{border-color:#d1d5db}.rte-toolbar-select:focus{border-color:#3b82f6}.rte-color-picker-label{align-items:center;border-radius:6px;cursor:pointer;display:flex;height:32px;justify-content:center;position:relative;transition:background-color .15s ease;width:32px}.rte-color-picker-label:hover{background-color:#f3f4f6}.rte-color-input{cursor:pointer;height:100%;inset:0;opacity:0;position:absolute;width:100%}.rte-content{color:#1f2937;font-family:inherit;font-size:16px;line-height:1.6;min-height:150px;outline:none;overflow-y:auto;padding:12px;word-break:break-word}.rte-content ul{list-style-type:disc;margin-left:1.5rem}.rte-content ol{list-style-type:decimal;margin-left:1.5rem}.rte-content img{border-radius:8px;display:block;height:auto;max-width:100%}.rte-content table{border-collapse:collapse;margin:16px 0;width:100%}.rte-content td,.rte-content th{border:1px solid #e5e7eb;min-width:40px;padding:12px;word-break:break-word}.video-container{border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1);height:0;margin:16px 0;overflow:hidden;padding-bottom:56.25%;position:relative}.video-container iframe{height:100%;left:0;position:absolute;top:0;width:100%}.rte-modal-overlay{align-items:center;animation:rte-fade-in .2s ease-out;backdrop-filter:blur(4px);background-color:rgba(0,0,0,.5);display:flex;inset:0;justify-content:center;position:fixed;z-index:9999}.rte-modal{animation:rte-zoom-in .2s ease-out;background-color:#fff;border:1px solid #f3f4f6;border-radius:16px;box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);display:flex;flex-direction:column;gap:16px;max-width:400px;padding:0;width:100%}.rte-modal-title{color:#111827;flex:1;font-size:18px;font-weight:600;margin:0;text-align:center}.rte-modal-header{align-items:center;border-bottom:1px solid #f3f4f6;display:flex;justify-content:space-between;padding:20px 24px 16px}.rte-form-group{display:flex;flex-direction:column;gap:8px;padding:16px 24px}.rte-label{color:#374151;font-size:14px;font-weight:600}.rte-input{border:1px solid #d1d5db;border-radius:8px;outline:none;padding:8px 12px;transition:all .15s ease;width:93%}.rte-input:focus{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)}.rte-modal-actions{border-top:1px solid #f3f4f6;display:flex;gap:12px;justify-content:flex-end;padding:16px 24px 20px}.rte-button{border:none;border-radius:8px;cursor:pointer;font-weight:500;padding:8px 16px;transition:all .15s ease}.rte-button-secondary{background-color:#f3f4f6;color:#4b5563}.rte-button-secondary:hover{background-color:#e5e7eb}.rte-button-primary{background-color:#2563eb;box-shadow:0 1px 2px rgba(0,0,0,.05);color:#fff}.rte-button-primary:hover{background-color:#1d4ed8}.rte-button-primary:disabled{cursor:not-allowed;opacity:.5}.rte-spinner-container{align-items:center;display:flex;justify-content:center;padding:16px}.rte-spinner{animation:rte-spin .8s linear infinite;border:3px solid #eff6ff;border-radius:50%;border-top-color:#3b82f6;height:32px;width:32px}@keyframes rte-spin{to{transform:rotate(1turn)}}@keyframes rte-fade-in{0%{opacity:0}to{opacity:1}}@keyframes rte-zoom-in{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.image-container{display:inline-block;line-height:0;margin:15px;max-width:100%;position:relative}.image-container.image-align-center{display:block;margin:24px auto;text-align:center}.image-container.image-align-left,.image-container.image-align-right{display:block}.image-container.image-align-left,.image-container.image-align-right{margin:15px 0}.image-container.image-align-left img{margin-left:0!important;margin-right:auto!important}.image-container.image-align-center img{margin-left:auto!important;margin-right:auto!important}.image-container.image-align-right img{margin-left:auto!important;margin-right:0!important}.image-container img{border-radius:12px;display:block;height:auto;margin:0;max-width:100%;width:auto}.image-container.image-small img{width:50%!important}.image-delete-button{align-items:center;background:#ef4444;border:3px solid #fff;border-radius:9999px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);color:#fff;cursor:pointer;display:flex;font-size:18px;font-weight:700;height:26px;justify-content:center;line-height:1;padding:0;position:absolute;right:0;top:0;transform:translate(50%,-50%);transition:all .2s cubic-bezier(.4,0,.2,1);width:26px;z-index:50}.image-delete-button:hover{background:#b91c1c;box-shadow:0 10px 15px -3px rgba(0,0,0,.1);transform:translate(50%,-50%) scale(1.1)}.rte-table-delete-btn,.rte-table-delete-hover{align-items:center;display:flex;justify-content:center}.rte-table-delete-btn{background:#fff;border:1px solid #ef4444;border-radius:6px;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);color:#ef4444;cursor:pointer;height:28px;padding:0;transition:all .2s ease;width:28px}.rte-table-delete-btn:hover{background:#ef4444;color:#fff;transform:scale(1.1)}.rte-table-delete-btn:active{transform:scale(.95)}.rte-image-toolbar{background:#fff!important;border:1px solid #e5e7eb!important;border-radius:8px!important;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06)!important;display:flex;gap:4px!important;padding:4px!important;pointer-events:auto!important}.rte-image-toolbar button{align-items:center;background:transparent;border:none;border-radius:4px;color:#4b5563;cursor:pointer;display:flex;font-size:11px;font-weight:600;height:28px;justify-content:center;min-width:32px;padding:0 4px;transition:all .15s ease}.rte-image-toolbar button:hover{background-color:#f3f4f6;color:#111827}.rte-image-toolbar button.danger{color:#ef4444!important}.rte-image-toolbar button.danger:hover{background-color:#fef2f2!important}.image-container:after{clear:both;content:\"\";display:table}.rte-footer{background-color:#fcfcfd;border-top:1px solid #f3f4f6;display:flex;justify-content:flex-end;padding:6px 16px;user-select:none}.rte-footer-content{align-items:center;color:#9ca3af;display:flex;font-size:11px;gap:10px;letter-spacing:.025em}.rte-footer-separator{color:#e5e7eb;font-size:14px;line-height:1}.rte-footer-item b{color:#6b7280;font-weight:600}";
|
|
657
392
|
styleInject(css_248z);
|
|
658
393
|
|
|
659
394
|
// Helper functions for HTML escaping
|
|
660
|
-
|
|
395
|
+
const escapeHtml = str => {
|
|
661
396
|
if (!str) return "";
|
|
662
397
|
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\"/g, """).replace(/'/g, "'");
|
|
663
398
|
};
|
|
664
|
-
|
|
665
|
-
return escapeHtml(str).replace(/"/g, """);
|
|
666
|
-
};
|
|
399
|
+
const escapeAttr = str => escapeHtml(str).replace(/"/g, """);
|
|
667
400
|
|
|
668
401
|
// URL detection regex
|
|
669
|
-
|
|
670
|
-
function RichTextEditor(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
minHeight = _ref.minHeight,
|
|
687
|
-
maxHeight = _ref.maxHeight,
|
|
688
|
-
onImageUpload = _ref.onImageUpload;
|
|
402
|
+
const URL_REGEX = /(https?:\/\/[^\s]+)/g;
|
|
403
|
+
function RichTextEditor({
|
|
404
|
+
onChange,
|
|
405
|
+
showEditButton,
|
|
406
|
+
onBlur,
|
|
407
|
+
disabled = false,
|
|
408
|
+
editable: initialEditable = false,
|
|
409
|
+
value,
|
|
410
|
+
isLoading,
|
|
411
|
+
isList = false,
|
|
412
|
+
label,
|
|
413
|
+
showBorder = true,
|
|
414
|
+
paddingLeft,
|
|
415
|
+
minHeight,
|
|
416
|
+
maxHeight,
|
|
417
|
+
onImageUpload
|
|
418
|
+
}) {
|
|
689
419
|
if (isLoading) {
|
|
690
420
|
return /*#__PURE__*/React.createElement(Spinner, null);
|
|
691
421
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
linkUrl = _useState6[0],
|
|
706
|
-
setLinkUrl = _useState6[1];
|
|
707
|
-
var _useState7 = useState(""),
|
|
708
|
-
_useState8 = _slicedToArray(_useState7, 2),
|
|
709
|
-
linkText = _useState8[0],
|
|
710
|
-
setLinkText = _useState8[1];
|
|
711
|
-
var selectionRangeRef = useRef(null);
|
|
712
|
-
var _useState9 = useState(defaultEditable),
|
|
713
|
-
_useState0 = _slicedToArray(_useState9, 2),
|
|
714
|
-
editable = _useState0[0],
|
|
715
|
-
setEditable = _useState0[1];
|
|
422
|
+
const editorRef = useRef(null);
|
|
423
|
+
const fileInputRef = useRef(null);
|
|
424
|
+
const scrollTopRef = useRef(0);
|
|
425
|
+
const [html, setHtml] = useState("");
|
|
426
|
+
const [linkModalOpen, setLinkModalOpen] = useState(false);
|
|
427
|
+
const [linkUrl, setLinkUrl] = useState("");
|
|
428
|
+
const [linkText, setLinkText] = useState("");
|
|
429
|
+
const selectionRangeRef = useRef(null);
|
|
430
|
+
const [editable, setEditable] = useState(initialEditable);
|
|
431
|
+
const lastSynchronizedHtmlRef = useRef("");
|
|
432
|
+
useEffect(() => {
|
|
433
|
+
setEditable(initialEditable);
|
|
434
|
+
}, [initialEditable]);
|
|
716
435
|
|
|
717
436
|
// NEW: Track current list type for dropdown
|
|
718
|
-
|
|
719
|
-
_useState10 = _slicedToArray(_useState1, 2),
|
|
720
|
-
currentListType = _useState10[0],
|
|
721
|
-
setCurrentListType = _useState10[1];
|
|
437
|
+
const [currentListType, setCurrentListType] = useState(null);
|
|
722
438
|
|
|
723
439
|
// NEW: Track active styles for toolbar buttons
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
setIsBold = _useState12[1];
|
|
728
|
-
var _useState13 = useState(false),
|
|
729
|
-
_useState14 = _slicedToArray(_useState13, 2),
|
|
730
|
-
isItalic = _useState14[0],
|
|
731
|
-
setIsItalic = _useState14[1];
|
|
732
|
-
var _useState15 = useState(false),
|
|
733
|
-
_useState16 = _slicedToArray(_useState15, 2),
|
|
734
|
-
isUnderline = _useState16[0],
|
|
735
|
-
setIsUnderline = _useState16[1];
|
|
440
|
+
const [isBold, setIsBold] = useState(false);
|
|
441
|
+
const [isItalic, setIsItalic] = useState(false);
|
|
442
|
+
const [isUnderline, setIsUnderline] = useState(false);
|
|
736
443
|
|
|
737
444
|
// NEW: Track current font size
|
|
738
|
-
|
|
739
|
-
_useState18 = _slicedToArray(_useState17, 2),
|
|
740
|
-
currentFontSize = _useState18[0],
|
|
741
|
-
setCurrentFontSize = _useState18[1];
|
|
445
|
+
const [currentFontSize, setCurrentFontSize] = useState("16");
|
|
742
446
|
|
|
743
447
|
// NEW: Track current line height
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
setYoutubeUrl = _useState34[1];
|
|
776
|
-
var _useState35 = useState(false),
|
|
777
|
-
_useState36 = _slicedToArray(_useState35, 2),
|
|
778
|
-
tableModalOpen = _useState36[0],
|
|
779
|
-
setTableModalOpen = _useState36[1];
|
|
780
|
-
var _useState37 = useState(null),
|
|
781
|
-
_useState38 = _slicedToArray(_useState37, 2);
|
|
782
|
-
_useState38[0];
|
|
783
|
-
var setHoveredTable = _useState38[1];
|
|
784
|
-
var _useState39 = useState(3),
|
|
785
|
-
_useState40 = _slicedToArray(_useState39, 2),
|
|
786
|
-
tableRows = _useState40[0],
|
|
787
|
-
setTableRows = _useState40[1];
|
|
788
|
-
var _useState41 = useState(3),
|
|
789
|
-
_useState42 = _slicedToArray(_useState41, 2),
|
|
790
|
-
tableCols = _useState42[0],
|
|
791
|
-
setTableCols = _useState42[1];
|
|
792
|
-
var _useState43 = useState(0),
|
|
793
|
-
_useState44 = _slicedToArray(_useState43, 2);
|
|
794
|
-
_useState44[0];
|
|
795
|
-
var setSelectionVersion = _useState44[1];
|
|
796
|
-
var _useState45 = useState(null),
|
|
797
|
-
_useState46 = _slicedToArray(_useState45, 2),
|
|
798
|
-
selectedImage = _useState46[0],
|
|
799
|
-
setSelectedImage = _useState46[1];
|
|
800
|
-
var _useState47 = useState(null),
|
|
801
|
-
_useState48 = _slicedToArray(_useState47, 2);
|
|
802
|
-
_useState48[0];
|
|
803
|
-
var setResizeData = _useState48[1];
|
|
804
|
-
var openImageModal = function openImageModal(url) {
|
|
448
|
+
const [currentLineHeight, setCurrentLineHeight] = useState("");
|
|
449
|
+
const [activeAlign, setActiveAlign] = useState(null);
|
|
450
|
+
const [imageModalOpen, setImageModalOpen] = useState(false);
|
|
451
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState("");
|
|
452
|
+
const [zoomLevel, setZoomLevel] = useState(1);
|
|
453
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
454
|
+
const [videoModalOpen, setVideoModalOpen] = useState(false);
|
|
455
|
+
const [videoUrl, setVideoUrl] = useState("");
|
|
456
|
+
const [tableModalOpen, setTableModalOpen] = useState(false);
|
|
457
|
+
const [hoveredTable, setHoveredTable] = useState(null);
|
|
458
|
+
const [tableRows, setTableRows] = useState(3);
|
|
459
|
+
const [tableCols, setTableCols] = useState(3);
|
|
460
|
+
const [selectionVersion, setSelectionVersion] = useState(0);
|
|
461
|
+
const [selectedImage, setSelectedImage] = useState(null);
|
|
462
|
+
const [metrics, setMetrics] = useState({
|
|
463
|
+
words: 0,
|
|
464
|
+
chars: 0
|
|
465
|
+
});
|
|
466
|
+
const updateMetrics = useCallback(() => {
|
|
467
|
+
if (!editorRef.current) return;
|
|
468
|
+
// Calculate metrics immediately but outside of render path
|
|
469
|
+
const text = editorRef.current.innerText || "";
|
|
470
|
+
const cleanText = text.replace(/[\n\r]/g, ' ').trim();
|
|
471
|
+
const words = cleanText ? cleanText.split(/\s+/).length : 0;
|
|
472
|
+
const chars = text.length;
|
|
473
|
+
setMetrics({
|
|
474
|
+
words,
|
|
475
|
+
chars
|
|
476
|
+
});
|
|
477
|
+
}, []);
|
|
478
|
+
const openImageModal = url => {
|
|
805
479
|
if (editorRef.current) {
|
|
806
480
|
scrollTopRef.current = editorRef.current.scrollTop;
|
|
807
481
|
}
|
|
808
482
|
setSelectedImageUrl(url);
|
|
809
483
|
setImageModalOpen(true);
|
|
810
484
|
};
|
|
811
|
-
|
|
485
|
+
const closeImageModal = () => {
|
|
812
486
|
setImageModalOpen(false);
|
|
813
487
|
setSelectedImageUrl("");
|
|
814
488
|
setZoomLevel(1);
|
|
815
489
|
};
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
490
|
+
const saveSelection = () => {
|
|
491
|
+
if (typeof window === "undefined") return;
|
|
492
|
+
const sel = window.getSelection();
|
|
493
|
+
if (sel && sel.rangeCount > 0) {
|
|
494
|
+
selectionRangeRef.current = sel.getRangeAt(0).cloneRange();
|
|
495
|
+
}
|
|
820
496
|
};
|
|
821
|
-
|
|
822
|
-
setZoomLevel(
|
|
823
|
-
|
|
824
|
-
|
|
497
|
+
const handleZoomIn = () => {
|
|
498
|
+
setZoomLevel(prevZoom => prevZoom + 0.1);
|
|
499
|
+
};
|
|
500
|
+
const handleZoomOut = () => {
|
|
501
|
+
setZoomLevel(prevZoom => Math.max(0.1, prevZoom - 0.1));
|
|
825
502
|
};
|
|
826
503
|
|
|
827
504
|
// Effect to restore scroll position after modal closes
|
|
828
|
-
useEffect(
|
|
505
|
+
useEffect(() => {
|
|
829
506
|
if (!imageModalOpen && editorRef.current) {
|
|
830
507
|
editorRef.current.scrollTop = scrollTopRef.current;
|
|
831
508
|
}
|
|
832
509
|
}, [imageModalOpen]);
|
|
833
|
-
useEffect(
|
|
510
|
+
useEffect(() => {
|
|
834
511
|
if (!imageModalOpen) return;
|
|
835
|
-
|
|
512
|
+
const handleKeyDown = e => {
|
|
836
513
|
if (e.key === 'Escape') {
|
|
837
514
|
closeImageModal();
|
|
838
515
|
}
|
|
839
516
|
};
|
|
840
|
-
|
|
517
|
+
const handleWheel = e => {
|
|
841
518
|
if (e.ctrlKey) {
|
|
842
519
|
e.preventDefault();
|
|
843
520
|
if (e.deltaY < 0) {
|
|
@@ -851,127 +528,99 @@ function RichTextEditor(_ref) {
|
|
|
851
528
|
window.addEventListener('wheel', handleWheel, {
|
|
852
529
|
passive: false
|
|
853
530
|
});
|
|
854
|
-
return
|
|
531
|
+
return () => {
|
|
855
532
|
document.removeEventListener('keydown', handleKeyDown);
|
|
856
533
|
window.removeEventListener('wheel', handleWheel);
|
|
857
534
|
};
|
|
858
535
|
}, [imageModalOpen]);
|
|
859
|
-
useEffect(
|
|
860
|
-
|
|
536
|
+
useEffect(() => {
|
|
537
|
+
const handleClick = e => {
|
|
861
538
|
// Trigger selection update for toolbar reactivity
|
|
862
|
-
setSelectionVersion(
|
|
863
|
-
|
|
864
|
-
});
|
|
865
|
-
var deleteBtn = e.target.closest('button[title="Remove image"]');
|
|
539
|
+
setSelectionVersion(v => v + 1);
|
|
540
|
+
const deleteBtn = e.target.closest('button[title="Remove image"]');
|
|
866
541
|
if (deleteBtn && editable) {
|
|
867
542
|
e.preventDefault();
|
|
868
543
|
e.stopPropagation();
|
|
869
|
-
|
|
544
|
+
const wrapper = deleteBtn.closest('.image-container');
|
|
870
545
|
if (wrapper && wrapper.parentNode) {
|
|
871
546
|
wrapper.parentNode.removeChild(wrapper);
|
|
872
|
-
triggerChange();
|
|
547
|
+
triggerChange && triggerChange();
|
|
873
548
|
}
|
|
874
549
|
}
|
|
875
550
|
};
|
|
876
|
-
|
|
551
|
+
const editor = editorRef.current;
|
|
877
552
|
if (editor) {
|
|
878
553
|
editor.addEventListener('click', handleClick);
|
|
879
|
-
return
|
|
554
|
+
return () => {
|
|
880
555
|
editor.removeEventListener('click', handleClick);
|
|
881
556
|
};
|
|
882
557
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
});
|
|
558
|
+
// Removed dependency on editable to minimize listener churn
|
|
559
|
+
}, []);
|
|
560
|
+
useEffect(() => {
|
|
561
|
+
if (editorRef.current && value && value !== lastSynchronizedHtmlRef.current) {
|
|
562
|
+
requestAnimationFrame(() => processExistingImages(editorRef.current));
|
|
889
563
|
}
|
|
890
564
|
}, [value]);
|
|
891
565
|
|
|
892
566
|
// Runs whenever editable changes (toggles delete icon visibility)
|
|
893
|
-
useEffect(
|
|
567
|
+
useEffect(() => {
|
|
894
568
|
processExistingImages(editorRef.current);
|
|
895
|
-
}, [
|
|
896
|
-
useEffect(
|
|
897
|
-
// Only update if value is
|
|
898
|
-
if (value) {
|
|
569
|
+
}, [editable]);
|
|
570
|
+
useEffect(() => {
|
|
571
|
+
// Only update if value is different from our last known synced state
|
|
572
|
+
if (value && value !== lastSynchronizedHtmlRef.current) {
|
|
899
573
|
try {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
editorRef.current.innerHTML = htmlContent;
|
|
906
|
-
}
|
|
574
|
+
let newContent = "";
|
|
575
|
+
|
|
576
|
+
// Check if value is a Draft.js content state
|
|
577
|
+
if (isValidDraftFormat(value)) {
|
|
578
|
+
newContent = draftBlocksToHTML(value);
|
|
907
579
|
} else if (typeof value === 'string') {
|
|
908
|
-
//
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
580
|
+
// If value is already what we have in HTML state, skip unescaping
|
|
581
|
+
if (value === html) {
|
|
582
|
+
lastSynchronizedHtmlRef.current = value;
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
newContent = unescapeHtml(value);
|
|
586
|
+
}
|
|
587
|
+
if (newContent && newContent !== html) {
|
|
588
|
+
lastSynchronizedHtmlRef.current = value;
|
|
589
|
+
setHtml(newContent);
|
|
590
|
+
if (editorRef.current && editorRef.current.innerHTML !== newContent) {
|
|
591
|
+
editorRef.current.innerHTML = newContent;
|
|
913
592
|
}
|
|
593
|
+
updateMetrics();
|
|
914
594
|
}
|
|
915
595
|
} catch (e) {
|
|
916
596
|
console.error('Error processing editor content:', e);
|
|
917
|
-
// Fallback to raw value if parsing fails
|
|
918
|
-
var _unescapedValue = typeof value === 'string' ? unescapeHtml(value) : value;
|
|
919
|
-
setHtml(_unescapedValue);
|
|
920
|
-
if (editorRef.current) {
|
|
921
|
-
editorRef.current.innerHTML = _unescapedValue || '';
|
|
922
|
-
}
|
|
923
597
|
}
|
|
924
|
-
} else {
|
|
598
|
+
} else if (!value && html) {
|
|
925
599
|
setHtml('');
|
|
600
|
+
lastSynchronizedHtmlRef.current = "";
|
|
926
601
|
if (editorRef.current) {
|
|
927
602
|
editorRef.current.innerHTML = '';
|
|
603
|
+
updateMetrics();
|
|
928
604
|
}
|
|
929
605
|
}
|
|
930
|
-
}, [
|
|
606
|
+
}, [value, initialEditable, updateMetrics]);
|
|
931
607
|
|
|
932
|
-
// Call onChange whenever html state updates
|
|
933
|
-
useEffect(function () {
|
|
934
|
-
onChange && onChange(html);
|
|
935
|
-
}, [html, onChange]);
|
|
936
608
|
// Trigger change manually
|
|
937
|
-
|
|
938
|
-
|
|
609
|
+
const triggerChange = useCallback(() => {
|
|
610
|
+
const next = getCleanHtml();
|
|
939
611
|
setHtml(next);
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
var detectListType = function detectListType() {
|
|
944
|
-
var sel = window.getSelection();
|
|
945
|
-
if (!sel || !sel.rangeCount) {
|
|
946
|
-
setCurrentListType(null);
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
var node = sel.anchorNode;
|
|
950
|
-
while (node && node !== editorRef.current) {
|
|
951
|
-
if (node.nodeName === "OL") {
|
|
952
|
-
setCurrentListType("ordered");
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
if (node.nodeName === "UL") {
|
|
956
|
-
setCurrentListType("unordered");
|
|
957
|
-
return;
|
|
958
|
-
}
|
|
959
|
-
node = node.parentNode;
|
|
960
|
-
}
|
|
961
|
-
setCurrentListType(null);
|
|
962
|
-
};
|
|
612
|
+
lastSynchronizedHtmlRef.current = next;
|
|
613
|
+
onChange && onChange(next);
|
|
614
|
+
}, [onChange]);
|
|
963
615
|
|
|
964
616
|
// Helper to walk up DOM to find style tags or CSS style:
|
|
965
|
-
|
|
966
|
-
for (var _len = arguments.length, tagNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
967
|
-
tagNames[_key - 1] = arguments[_key];
|
|
968
|
-
}
|
|
617
|
+
const isParentStyle = (node, ...tagNames) => {
|
|
969
618
|
while (node && node !== editorRef.current) {
|
|
970
619
|
if (node.nodeType === 1 && tagNames.includes(node.tagName)) return true;
|
|
971
620
|
|
|
972
621
|
// Also check inline style for bold and italic:
|
|
973
622
|
if (node.nodeType === 1 && node.style) {
|
|
974
|
-
|
|
623
|
+
const style = node.style;
|
|
975
624
|
if (tagNames.includes("bold") && (style.fontWeight === "bold" || Number(style.fontWeight) >= 600)) return true;
|
|
976
625
|
if (tagNames.includes("italic") && style.fontStyle === "italic") return true;
|
|
977
626
|
if (tagNames.includes("underline") && style.textDecoration.includes("underline")) return true;
|
|
@@ -989,100 +638,92 @@ function RichTextEditor(_ref) {
|
|
|
989
638
|
return false;
|
|
990
639
|
};
|
|
991
640
|
|
|
992
|
-
// Update style states based on selection or cursor position
|
|
993
|
-
var updateStyleStates = function updateStyleStates() {
|
|
994
|
-
var sel = window.getSelection();
|
|
995
|
-
if (!sel || !sel.rangeCount) {
|
|
996
|
-
setIsBold(false);
|
|
997
|
-
setIsItalic(false);
|
|
998
|
-
setIsUnderline(false);
|
|
999
|
-
setFontColor("#000000"); // default
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1002
|
-
var container = sel.anchorNode.nodeType === 3 ? sel.anchorNode.parentNode : sel.anchorNode;
|
|
1003
|
-
var computedAlign = window.getComputedStyle(container).textAlign;
|
|
1004
|
-
setActiveAlign(computedAlign);
|
|
1005
|
-
var range = sel.getRangeAt(0);
|
|
1006
|
-
if (range.collapsed) {
|
|
1007
|
-
// Cursor only, check parent nodes
|
|
1008
|
-
var _container = sel.anchorNode.nodeType === 3 ? sel.anchorNode.parentNode : sel.anchorNode;
|
|
1009
|
-
window.getComputedStyle(_container);
|
|
1010
|
-
setIsBold(isParentStyle(_container, "B", "STRONG", "bold"));
|
|
1011
|
-
setIsItalic(isParentStyle(_container, "I", "EM", "italic"));
|
|
1012
|
-
setIsUnderline(isParentStyle(_container, "U", "underline"));
|
|
1013
|
-
|
|
1014
|
-
// ✅ Get computed color from container
|
|
1015
|
-
var computedColor = window.getComputedStyle(_container).color;
|
|
1016
|
-
setFontColor(rgbToHex(computedColor));
|
|
1017
|
-
} else {
|
|
1018
|
-
// Text selected, use execCommand state
|
|
1019
|
-
setIsBold(document.queryCommandState("bold"));
|
|
1020
|
-
setIsItalic(document.queryCommandState("italic"));
|
|
1021
|
-
setIsUnderline(document.queryCommandState("underline"));
|
|
1022
|
-
|
|
1023
|
-
// ✅ For selection, get color from selection's start container
|
|
1024
|
-
var _container2 = sel.anchorNode.nodeType === 3 ? sel.anchorNode.parentNode : sel.anchorNode;
|
|
1025
|
-
var _computedColor = window.getComputedStyle(_container2).color;
|
|
1026
|
-
setFontColor(rgbToHex(_computedColor));
|
|
1027
|
-
}
|
|
1028
|
-
};
|
|
1029
|
-
|
|
1030
641
|
// Helper to convert rgb() to hex
|
|
1031
642
|
function rgbToHex(rgb) {
|
|
1032
|
-
|
|
643
|
+
const result = rgb.match(/\d+/g);
|
|
1033
644
|
if (!result) return "#000000";
|
|
1034
|
-
return "#" + result.slice(0, 3).map(
|
|
1035
|
-
|
|
645
|
+
return "#" + result.slice(0, 3).map(x => {
|
|
646
|
+
const hex = parseInt(x, 10).toString(16);
|
|
1036
647
|
return hex.length === 1 ? "0" + hex : hex;
|
|
1037
648
|
}).join("");
|
|
1038
649
|
}
|
|
1039
650
|
|
|
1040
|
-
// Listen for selection changes globally to update styles and list type
|
|
1041
|
-
useEffect(
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
if (!
|
|
1047
|
-
|
|
1048
|
-
|
|
651
|
+
// Listen for selection changes globally to update styles and list type in one pass
|
|
652
|
+
useEffect(() => {
|
|
653
|
+
const handleGlobalSelectionSync = () => {
|
|
654
|
+
var _editorRef$current;
|
|
655
|
+
// Only sync if the editor has focus
|
|
656
|
+
const sel = window.getSelection();
|
|
657
|
+
if (!sel || !sel.rangeCount || !((_editorRef$current = editorRef.current) !== null && _editorRef$current !== void 0 && _editorRef$current.contains(sel.anchorNode))) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// 1. Detect List Type
|
|
662
|
+
let node = sel.anchorNode;
|
|
663
|
+
let listFound = null;
|
|
664
|
+
while (node && node !== editorRef.current) {
|
|
665
|
+
if (node.nodeName === "OL") {
|
|
666
|
+
listFound = "ordered";
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
if (node.nodeName === "UL") {
|
|
670
|
+
listFound = "unordered";
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
node = node.parentNode;
|
|
674
|
+
}
|
|
675
|
+
setCurrentListType(listFound);
|
|
676
|
+
|
|
677
|
+
// 2. Update Style States
|
|
678
|
+
const container = sel.anchorNode.nodeType === 3 ? sel.anchorNode.parentNode : sel.anchorNode;
|
|
679
|
+
const computedAlign = window.getComputedStyle(container).textAlign;
|
|
680
|
+
setActiveAlign(computedAlign);
|
|
681
|
+
const range = sel.getRangeAt(0);
|
|
682
|
+
if (range.collapsed) {
|
|
683
|
+
setIsBold(isParentStyle(container, "B", "STRONG", "bold"));
|
|
684
|
+
setIsItalic(isParentStyle(container, "I", "EM", "italic"));
|
|
685
|
+
setIsUnderline(isParentStyle(container, "U", "underline"));
|
|
686
|
+
const computedColor = window.getComputedStyle(container).color;
|
|
687
|
+
setFontColor(rgbToHex(computedColor));
|
|
688
|
+
} else {
|
|
689
|
+
setIsBold(document.queryCommandState("bold"));
|
|
690
|
+
setIsItalic(document.queryCommandState("italic"));
|
|
691
|
+
setIsUnderline(document.queryCommandState("underline"));
|
|
692
|
+
const computedColor = window.getComputedStyle(container).color;
|
|
693
|
+
setFontColor(rgbToHex(computedColor));
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// 3. Current Font Size
|
|
697
|
+
const element = range.startContainer.parentElement.closest('[style*="font-size"]');
|
|
1049
698
|
if (element) {
|
|
1050
|
-
|
|
1051
|
-
|
|
699
|
+
const fontSize = window.getComputedStyle(element).fontSize;
|
|
700
|
+
const sizeValue = fontSize ? parseInt(fontSize) : 16;
|
|
1052
701
|
setCurrentFontSize(sizeValue.toString());
|
|
1053
702
|
} else {
|
|
1054
|
-
setCurrentFontSize("16");
|
|
703
|
+
setCurrentFontSize("16");
|
|
1055
704
|
}
|
|
1056
705
|
};
|
|
1057
|
-
document.addEventListener(
|
|
1058
|
-
return
|
|
1059
|
-
document.removeEventListener("selectionchange",
|
|
1060
|
-
document.removeEventListener("selectionchange", updateStyleStates);
|
|
1061
|
-
document.removeEventListener('selectionchange', handleSelectionChange);
|
|
706
|
+
document.addEventListener("selectionchange", handleGlobalSelectionSync);
|
|
707
|
+
return () => {
|
|
708
|
+
document.removeEventListener("selectionchange", handleGlobalSelectionSync);
|
|
1062
709
|
};
|
|
1063
710
|
}, []);
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
};
|
|
1067
|
-
var exec = function exec(command) {
|
|
1068
|
-
var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
711
|
+
const focus = () => editorRef.current && editorRef.current.focus();
|
|
712
|
+
const exec = (command, value = null) => {
|
|
1069
713
|
document.execCommand(command, false, value);
|
|
1070
714
|
triggerChange();
|
|
1071
715
|
focus();
|
|
1072
716
|
};
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
fontColor = _useState50[0],
|
|
1076
|
-
setFontColor = _useState50[1];
|
|
1077
|
-
var handleColorChange = function handleColorChange(color) {
|
|
717
|
+
const [fontColor, setFontColor] = useState("#000000");
|
|
718
|
+
const handleColorChange = color => {
|
|
1078
719
|
setFontColor(color);
|
|
1079
720
|
exec("foreColor", color);
|
|
1080
721
|
};
|
|
1081
|
-
|
|
1082
|
-
|
|
722
|
+
const addLink = () => {
|
|
723
|
+
const sel = window.getSelection();
|
|
1083
724
|
if (!sel || sel.rangeCount === 0) return;
|
|
1084
725
|
selectionRangeRef.current = sel.getRangeAt(0).cloneRange();
|
|
1085
|
-
|
|
726
|
+
const selectedText = sel.toString();
|
|
1086
727
|
if (selectedText.length > 0) {
|
|
1087
728
|
setLinkText(selectedText);
|
|
1088
729
|
setLinkUrl("");
|
|
@@ -1093,112 +734,108 @@ function RichTextEditor(_ref) {
|
|
|
1093
734
|
setLinkModalOpen(true);
|
|
1094
735
|
}
|
|
1095
736
|
};
|
|
1096
|
-
|
|
737
|
+
const findParentTag = (node, tagName) => {
|
|
1097
738
|
if (!node) return null;
|
|
1098
|
-
|
|
739
|
+
let curr = node;
|
|
1099
740
|
while (curr && curr !== editorRef.current) {
|
|
1100
741
|
if (curr.tagName === tagName) return curr;
|
|
1101
742
|
curr = curr.parentNode;
|
|
1102
743
|
}
|
|
1103
744
|
return null;
|
|
1104
745
|
};
|
|
1105
|
-
|
|
1106
|
-
|
|
746
|
+
const tableAction = action => {
|
|
747
|
+
const sel = window.getSelection();
|
|
1107
748
|
if (!sel || !sel.rangeCount) return;
|
|
1108
|
-
|
|
749
|
+
const cell = findParentTag(sel.anchorNode, 'TD') || findParentTag(sel.anchorNode, 'TH');
|
|
1109
750
|
if (!cell) return;
|
|
1110
|
-
|
|
1111
|
-
|
|
751
|
+
const row = cell.parentNode;
|
|
752
|
+
const table = row.parentNode.closest('table');
|
|
1112
753
|
switch (action) {
|
|
1113
754
|
case 'addRowAbove':
|
|
1114
|
-
|
|
1115
|
-
for (
|
|
1116
|
-
|
|
755
|
+
const newRowAbove = table.insertRow(row.rowIndex);
|
|
756
|
+
for (let i = 0; i < row.cells.length; i++) {
|
|
757
|
+
const newCell = newRowAbove.insertCell(i);
|
|
1117
758
|
newCell.style.border = "1px solid #e5e7eb";
|
|
1118
759
|
newCell.style.padding = "12px";
|
|
1119
760
|
newCell.innerHTML = " ";
|
|
1120
761
|
}
|
|
1121
762
|
break;
|
|
1122
763
|
case 'addRowBelow':
|
|
1123
|
-
|
|
1124
|
-
for (
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
764
|
+
const newRowBelow = table.insertRow(row.rowIndex + 1);
|
|
765
|
+
for (let i = 0; i < row.cells.length; i++) {
|
|
766
|
+
const newCell = newRowBelow.insertCell(i);
|
|
767
|
+
newCell.style.border = "1px solid #e5e7eb";
|
|
768
|
+
newCell.style.padding = "12px";
|
|
769
|
+
newCell.innerHTML = " ";
|
|
1129
770
|
}
|
|
1130
771
|
break;
|
|
1131
772
|
case 'addColBefore':
|
|
1132
|
-
|
|
1133
|
-
for (
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
773
|
+
const cellIndex = cell.cellIndex;
|
|
774
|
+
for (let i = 0; i < table.rows.length; i++) {
|
|
775
|
+
const newCell = table.rows[i].insertCell(cellIndex);
|
|
776
|
+
newCell.style.border = "1px solid #e5e7eb";
|
|
777
|
+
newCell.style.padding = "12px";
|
|
778
|
+
newCell.innerHTML = " ";
|
|
1138
779
|
}
|
|
1139
780
|
break;
|
|
1140
781
|
case 'addColAfter':
|
|
1141
|
-
|
|
1142
|
-
for (
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
782
|
+
const cellIndexAfter = cell.cellIndex + 1;
|
|
783
|
+
for (let i = 0; i < table.rows.length; i++) {
|
|
784
|
+
const newCell = table.rows[i].insertCell(cellIndexAfter);
|
|
785
|
+
newCell.style.border = "1px solid #e5e7eb";
|
|
786
|
+
newCell.style.padding = "12px";
|
|
787
|
+
newCell.innerHTML = " ";
|
|
1147
788
|
}
|
|
1148
789
|
break;
|
|
1149
790
|
case 'deleteRow':
|
|
1150
791
|
{
|
|
1151
|
-
|
|
1152
|
-
|
|
792
|
+
const rowIndex = row.rowIndex;
|
|
793
|
+
const cellIndex = cell.cellIndex;
|
|
1153
794
|
table.deleteRow(rowIndex);
|
|
1154
795
|
if (table.rows.length === 0) {
|
|
1155
796
|
table.remove();
|
|
1156
797
|
} else {
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
798
|
+
const targetRowIndex = Math.min(rowIndex, table.rows.length - 1);
|
|
799
|
+
const targetRow = table.rows[targetRowIndex];
|
|
800
|
+
const targetCell = targetRow.cells[Math.min(cellIndex, targetRow.cells.length - 1)];
|
|
1160
801
|
if (targetCell) {
|
|
1161
|
-
|
|
802
|
+
const range = document.createRange();
|
|
1162
803
|
range.selectNodeContents(targetCell);
|
|
1163
804
|
range.collapse(true);
|
|
1164
805
|
sel.removeAllRanges();
|
|
1165
806
|
sel.addRange(range);
|
|
1166
|
-
setSelectionVersion(
|
|
1167
|
-
return v + 1;
|
|
1168
|
-
});
|
|
807
|
+
setSelectionVersion(v => v + 1);
|
|
1169
808
|
}
|
|
1170
809
|
}
|
|
1171
810
|
break;
|
|
1172
811
|
}
|
|
1173
812
|
case 'deleteCol':
|
|
1174
813
|
{
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
for (
|
|
1178
|
-
table.rows[
|
|
814
|
+
const idx = cell.cellIndex;
|
|
815
|
+
const rowIndex = row.rowIndex;
|
|
816
|
+
for (let i = 0; i < table.rows.length; i++) {
|
|
817
|
+
table.rows[i].deleteCell(idx);
|
|
1179
818
|
}
|
|
1180
819
|
if (table.rows[0].cells.length === 0) {
|
|
1181
820
|
table.remove();
|
|
1182
821
|
} else {
|
|
1183
|
-
var _table$rows$
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
if (
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
822
|
+
var _table$rows$rowIndex;
|
|
823
|
+
const targetColIndex = Math.min(idx, table.rows[0].cells.length - 1);
|
|
824
|
+
const targetCell = ((_table$rows$rowIndex = table.rows[rowIndex]) === null || _table$rows$rowIndex === void 0 ? void 0 : _table$rows$rowIndex.cells[targetColIndex]) || table.rows[0].cells[targetColIndex];
|
|
825
|
+
if (targetCell) {
|
|
826
|
+
const range = document.createRange();
|
|
827
|
+
range.selectNodeContents(targetCell);
|
|
828
|
+
range.collapse(true);
|
|
1190
829
|
sel.removeAllRanges();
|
|
1191
|
-
sel.addRange(
|
|
1192
|
-
setSelectionVersion(
|
|
1193
|
-
return v + 1;
|
|
1194
|
-
});
|
|
830
|
+
sel.addRange(range);
|
|
831
|
+
setSelectionVersion(v => v + 1);
|
|
1195
832
|
}
|
|
1196
833
|
}
|
|
1197
834
|
break;
|
|
1198
835
|
}
|
|
1199
836
|
case 'mergeRight':
|
|
1200
837
|
if (cell.nextElementSibling) {
|
|
1201
|
-
|
|
838
|
+
const nextCell = cell.nextElementSibling;
|
|
1202
839
|
cell.colSpan = (cell.colSpan || 1) + (nextCell.colSpan || 1);
|
|
1203
840
|
nextCell.remove();
|
|
1204
841
|
}
|
|
@@ -1209,20 +846,20 @@ function RichTextEditor(_ref) {
|
|
|
1209
846
|
}
|
|
1210
847
|
triggerChange && triggerChange();
|
|
1211
848
|
};
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
for (
|
|
849
|
+
const insertTable = () => {
|
|
850
|
+
const rows = parseInt(tableRows) || 3;
|
|
851
|
+
const cols = parseInt(tableCols) || 3;
|
|
852
|
+
let tableHtml = '<table style="width: 100%; border-collapse: collapse; border: 1px solid #e5e7eb; margin: 16px 0;"><tbody>';
|
|
853
|
+
for (let i = 0; i < rows; i++) {
|
|
1217
854
|
tableHtml += '<tr>';
|
|
1218
|
-
for (
|
|
855
|
+
for (let j = 0; j < cols; j++) {
|
|
1219
856
|
tableHtml += '<td style="border: 1px solid #e5e7eb; padding: 12px; min-height: 20px;"> </td>';
|
|
1220
857
|
}
|
|
1221
858
|
tableHtml += '</tr>';
|
|
1222
859
|
}
|
|
1223
860
|
tableHtml += '</tbody></table><p> </p>';
|
|
1224
861
|
if (selectionRangeRef.current) {
|
|
1225
|
-
|
|
862
|
+
const sel = window.getSelection();
|
|
1226
863
|
sel.removeAllRanges();
|
|
1227
864
|
sel.addRange(selectionRangeRef.current);
|
|
1228
865
|
}
|
|
@@ -1230,51 +867,85 @@ function RichTextEditor(_ref) {
|
|
|
1230
867
|
setTableModalOpen(false);
|
|
1231
868
|
triggerChange && triggerChange();
|
|
1232
869
|
};
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
870
|
+
const parseVideoUrl = url => {
|
|
871
|
+
url = url.trim();
|
|
872
|
+
if (!url) return null;
|
|
873
|
+
|
|
874
|
+
// YouTube
|
|
875
|
+
const ytRegExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|watch\?vi=|\&vi=)([^#\&\?]*).*/;
|
|
876
|
+
const ytMatch = url.match(ytRegExp);
|
|
877
|
+
if (ytMatch && ytMatch[2].length === 11) {
|
|
878
|
+
return `https://www.youtube.com/embed/${ytMatch[2]}`;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Vimeo
|
|
882
|
+
const vimeoRegExp = /vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/;
|
|
883
|
+
const vimeoMatch = url.match(vimeoRegExp);
|
|
884
|
+
if (vimeoMatch && vimeoMatch[3]) {
|
|
885
|
+
return `https://player.vimeo.com/video/${vimeoMatch[3]}`;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// DailyMotion
|
|
889
|
+
const dmRegExp = /dailymotion\.com\/video\/([a-zA-Z0-9]+)/;
|
|
890
|
+
const dmMatch = url.match(dmRegExp);
|
|
891
|
+
if (dmMatch && dmMatch[1]) {
|
|
892
|
+
return `https://www.dailymotion.com/embed/video/${dmMatch[1]}`;
|
|
893
|
+
}
|
|
894
|
+
return null;
|
|
895
|
+
};
|
|
896
|
+
const insertVideo = () => {
|
|
897
|
+
const embedUrl = parseVideoUrl(videoUrl);
|
|
898
|
+
if (embedUrl) {
|
|
1240
899
|
if (editorRef.current) {
|
|
1241
900
|
editorRef.current.focus();
|
|
1242
901
|
}
|
|
1243
902
|
if (selectionRangeRef.current) {
|
|
1244
|
-
|
|
903
|
+
const sel = window.getSelection();
|
|
1245
904
|
sel.removeAllRanges();
|
|
1246
905
|
sel.addRange(selectionRangeRef.current);
|
|
1247
906
|
}
|
|
1248
|
-
|
|
907
|
+
const embedHtml = `<div class="video-container">
|
|
908
|
+
<iframe
|
|
909
|
+
src="${embedUrl}"
|
|
910
|
+
frameborder="0"
|
|
911
|
+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
912
|
+
allowfullscreen
|
|
913
|
+
></iframe>
|
|
914
|
+
</div><p> </p>`;
|
|
1249
915
|
try {
|
|
1250
916
|
document.execCommand("insertHTML", false, embedHtml);
|
|
1251
917
|
} catch (err) {
|
|
1252
|
-
console.error("Failed to insert
|
|
1253
|
-
// Fallback: append to the end of the editor
|
|
918
|
+
console.error("Failed to insert Video HTML:", err);
|
|
1254
919
|
if (editorRef.current) {
|
|
1255
|
-
|
|
920
|
+
const div = document.createElement('div');
|
|
1256
921
|
div.innerHTML = embedHtml;
|
|
1257
922
|
editorRef.current.appendChild(div);
|
|
1258
923
|
}
|
|
1259
924
|
}
|
|
925
|
+
setVideoModalOpen(false);
|
|
926
|
+
setVideoUrl("");
|
|
927
|
+
triggerChange && triggerChange();
|
|
1260
928
|
} else {
|
|
1261
|
-
console.warn("Invalid
|
|
929
|
+
console.warn("Invalid Video URL or Platform not supported");
|
|
1262
930
|
}
|
|
1263
|
-
setYoutubeModalOpen(false);
|
|
1264
|
-
setYoutubeUrl("");
|
|
1265
|
-
triggerChange && triggerChange();
|
|
1266
931
|
};
|
|
1267
|
-
|
|
932
|
+
const processExistingImages = container => {
|
|
1268
933
|
if (!container) return;
|
|
1269
|
-
container.querySelectorAll("img").forEach(
|
|
1270
|
-
//
|
|
1271
|
-
|
|
1272
|
-
if (
|
|
1273
|
-
|
|
934
|
+
container.querySelectorAll("img").forEach(img => {
|
|
935
|
+
// ONLY wrap if it's not already inside a wrapper
|
|
936
|
+
const existingWrapper = img.closest(".image-container");
|
|
937
|
+
if (existingWrapper) {
|
|
938
|
+
// Just update existing wrapper state if needed
|
|
939
|
+
existingWrapper.style.cursor = editable ? 'pointer' : 'default';
|
|
940
|
+
const deleteBtn = existingWrapper.querySelector('.image-delete-button');
|
|
941
|
+
if (deleteBtn) {
|
|
942
|
+
deleteBtn.style.display = editable ? 'flex' : 'none';
|
|
943
|
+
}
|
|
944
|
+
return;
|
|
1274
945
|
}
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
wrapper.className =
|
|
946
|
+
const wrapper = document.createElement("div");
|
|
947
|
+
const align = img.getAttribute('data-align') || 'center';
|
|
948
|
+
wrapper.className = `image-container image-align-${align}`;
|
|
1278
949
|
wrapper.style.cursor = editable ? 'pointer' : 'default';
|
|
1279
950
|
img.className = "rte-image";
|
|
1280
951
|
img.style.cssText = ""; // Reset inline styles
|
|
@@ -1282,26 +953,26 @@ function RichTextEditor(_ref) {
|
|
|
1282
953
|
img.dataset.hasDeleteButton = "true";
|
|
1283
954
|
|
|
1284
955
|
// Add click listener to open modal
|
|
1285
|
-
img.addEventListener("click",
|
|
1286
|
-
|
|
1287
|
-
});
|
|
1288
|
-
var deleteBtn = document.createElement("button");
|
|
956
|
+
img.addEventListener("click", () => openImageModal(img.src));
|
|
957
|
+
const deleteBtn = document.createElement("button");
|
|
1289
958
|
deleteBtn.innerHTML = "×";
|
|
1290
959
|
deleteBtn.className = "image-delete-button";
|
|
1291
960
|
deleteBtn.style.display = editable ? 'flex' : 'none';
|
|
1292
961
|
deleteBtn.style.pointerEvents = editable ? 'auto' : 'none';
|
|
1293
962
|
deleteBtn.title = "Remove image";
|
|
1294
|
-
deleteBtn.onclick =
|
|
963
|
+
deleteBtn.onclick = e => {
|
|
1295
964
|
e.preventDefault();
|
|
1296
965
|
e.stopPropagation();
|
|
1297
|
-
|
|
966
|
+
const wrapper = e.currentTarget.closest(".image-container");
|
|
1298
967
|
if (wrapper && wrapper.parentNode) {
|
|
1299
968
|
wrapper.parentNode.removeChild(wrapper);
|
|
1300
969
|
triggerChange && triggerChange();
|
|
1301
970
|
}
|
|
1302
971
|
};
|
|
1303
|
-
|
|
1304
|
-
|
|
972
|
+
const {
|
|
973
|
+
parentNode,
|
|
974
|
+
nextSibling
|
|
975
|
+
} = img;
|
|
1305
976
|
if (parentNode) {
|
|
1306
977
|
parentNode.removeChild(img);
|
|
1307
978
|
wrapper.appendChild(img);
|
|
@@ -1314,111 +985,86 @@ function RichTextEditor(_ref) {
|
|
|
1314
985
|
}
|
|
1315
986
|
});
|
|
1316
987
|
};
|
|
1317
|
-
useEffect(
|
|
988
|
+
useEffect(() => {
|
|
1318
989
|
if (editorRef.current && value) {
|
|
1319
|
-
requestAnimationFrame(
|
|
1320
|
-
return processExistingImages(editorRef.current);
|
|
1321
|
-
});
|
|
990
|
+
requestAnimationFrame(() => processExistingImages(editorRef.current));
|
|
1322
991
|
}
|
|
1323
992
|
}, [value]);
|
|
1324
|
-
var insertImage = /*#__PURE__*/function () {
|
|
1325
|
-
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(dataUrl, fileName) {
|
|
1326
|
-
var container, img;
|
|
1327
|
-
return _regenerator().w(function (_context) {
|
|
1328
|
-
while (1) switch (_context.n) {
|
|
1329
|
-
case 0:
|
|
1330
|
-
try {
|
|
1331
|
-
if (editable) {
|
|
1332
|
-
// Create container for the image
|
|
1333
|
-
container = document.createElement('div');
|
|
1334
|
-
container.className = 'image-container';
|
|
1335
993
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
994
|
+
/*
|
|
995
|
+
Advanced Tip: Use the 'onImageUpload' prop to handle file uploads to a server
|
|
996
|
+
instead of using base64. If 'onImageUpload' is provided, it should return a URL string.
|
|
997
|
+
*/
|
|
998
|
+
const insertImage = async (dataUrl, fileName) => {
|
|
999
|
+
try {
|
|
1000
|
+
if (editable) {
|
|
1001
|
+
// Create container for the image
|
|
1002
|
+
const container = document.createElement('div');
|
|
1003
|
+
container.className = 'image-container';
|
|
1343
1004
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1005
|
+
// Create image element
|
|
1006
|
+
const img = document.createElement('img');
|
|
1007
|
+
img.src = dataUrl;
|
|
1008
|
+
img.alt = fileName || "image";
|
|
1009
|
+
img.addEventListener("click", () => openImageModal(dataUrl));
|
|
1346
1010
|
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
triggerChange();
|
|
1011
|
+
// Add elements to container
|
|
1012
|
+
container.appendChild(img);
|
|
1350
1013
|
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}));
|
|
1364
|
-
return function insertImage(_x, _x2) {
|
|
1365
|
-
return _ref2.apply(this, arguments);
|
|
1366
|
-
};
|
|
1367
|
-
}();
|
|
1368
|
-
var readFileAsDataURL = function readFileAsDataURL(file) {
|
|
1369
|
-
return new Promise(function (res, rej) {
|
|
1370
|
-
var reader = new FileReader();
|
|
1371
|
-
reader.onload = function (ev) {
|
|
1372
|
-
return res(ev.target.result);
|
|
1373
|
-
};
|
|
1374
|
-
reader.onerror = rej;
|
|
1375
|
-
reader.readAsDataURL(file);
|
|
1376
|
-
});
|
|
1014
|
+
// Insert at cursor position
|
|
1015
|
+
insertNodeAtCursor(container);
|
|
1016
|
+
triggerChange();
|
|
1017
|
+
|
|
1018
|
+
// Immediately process newly inserted image so delete button appears
|
|
1019
|
+
requestAnimationFrame(() => {
|
|
1020
|
+
processExistingImages(editorRef.current);
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
} catch (err) {
|
|
1024
|
+
console.error('Error inserting image:', err);
|
|
1025
|
+
}
|
|
1377
1026
|
};
|
|
1378
|
-
|
|
1379
|
-
|
|
1027
|
+
const readFileAsDataURL = file => new Promise((res, rej) => {
|
|
1028
|
+
const reader = new FileReader();
|
|
1029
|
+
reader.onload = ev => res(ev.target.result);
|
|
1030
|
+
reader.onerror = rej;
|
|
1031
|
+
reader.readAsDataURL(file);
|
|
1032
|
+
});
|
|
1033
|
+
const handlePaste = useCallback(e => {
|
|
1034
|
+
const clipboardData = e.clipboardData || window.clipboardData;
|
|
1380
1035
|
if (!clipboardData) return;
|
|
1381
1036
|
|
|
1382
1037
|
// Check for image in clipboard
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
}
|
|
1404
|
-
return {
|
|
1405
|
-
v: void 0
|
|
1406
|
-
};
|
|
1038
|
+
const items = clipboardData.items || [];
|
|
1039
|
+
for (let i = 0; i < items.length; i++) {
|
|
1040
|
+
const item = items[i];
|
|
1041
|
+
if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {
|
|
1042
|
+
e.preventDefault();
|
|
1043
|
+
const file = item.getAsFile();
|
|
1044
|
+
if (file) {
|
|
1045
|
+
setIsUploading(true);
|
|
1046
|
+
const uploadPromise = onImageUpload ? onImageUpload(file) : readFileAsDataURL(file);
|
|
1047
|
+
uploadPromise.then(url => {
|
|
1048
|
+
if (url) {
|
|
1049
|
+
// if the user's onImageUpload resolves to `{ mediaUrl: '...' }` like the previous MediaUpload, handle it
|
|
1050
|
+
const finalUrl = typeof url === 'object' && url !== null && url.mediaUrl ? url.mediaUrl : url;
|
|
1051
|
+
insertImage(finalUrl, file.name || 'pasted-image');
|
|
1052
|
+
}
|
|
1053
|
+
setIsUploading(false);
|
|
1054
|
+
}).catch(error => {
|
|
1055
|
+
console.error('Error uploading pasted image:', error);
|
|
1056
|
+
setIsUploading(false);
|
|
1057
|
+
});
|
|
1407
1058
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
for (var i = 0; i < items.length; i++) {
|
|
1411
|
-
_ret = _loop();
|
|
1412
|
-
if (_ret) return _ret.v;
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1413
1061
|
}
|
|
1414
|
-
|
|
1062
|
+
const htmlData = clipboardData.getData('text/html');
|
|
1415
1063
|
if (htmlData && htmlData.trim()) {
|
|
1416
1064
|
e.preventDefault();
|
|
1417
|
-
|
|
1065
|
+
const tempDiv = document.createElement('div');
|
|
1418
1066
|
tempDiv.innerHTML = htmlData;
|
|
1419
|
-
tempDiv.querySelectorAll('script, meta, link').forEach(
|
|
1420
|
-
return el.remove();
|
|
1421
|
-
});
|
|
1067
|
+
tempDiv.querySelectorAll('script, meta, link').forEach(el => el.remove());
|
|
1422
1068
|
document.execCommand('styleWithCSS', false, true);
|
|
1423
1069
|
document.execCommand('insertHTML', false, tempDiv.innerHTML);
|
|
1424
1070
|
document.execCommand('styleWithCSS', false, false);
|
|
@@ -1426,13 +1072,13 @@ function RichTextEditor(_ref) {
|
|
|
1426
1072
|
focus();
|
|
1427
1073
|
return;
|
|
1428
1074
|
}
|
|
1429
|
-
|
|
1075
|
+
const plainText = clipboardData.getData('text/plain');
|
|
1430
1076
|
if (plainText) {
|
|
1431
1077
|
e.preventDefault();
|
|
1432
|
-
|
|
1433
|
-
htmlToInsert = htmlToInsert.replace(URL_REGEX,
|
|
1434
|
-
|
|
1435
|
-
return
|
|
1078
|
+
let htmlToInsert = escapeHtml(plainText);
|
|
1079
|
+
htmlToInsert = htmlToInsert.replace(URL_REGEX, url => {
|
|
1080
|
+
const safeUrl = escapeAttr(url.trim());
|
|
1081
|
+
return `<a href="${safeUrl}" target="_blank" rel="noopener noreferrer" style="color: blue; text-decoration: underline;">${escapeHtml(url)}</a>`;
|
|
1436
1082
|
});
|
|
1437
1083
|
htmlToInsert = htmlToInsert.replace(/\n/g, '<br>');
|
|
1438
1084
|
document.execCommand('insertHTML', false, htmlToInsert);
|
|
@@ -1440,94 +1086,37 @@ function RichTextEditor(_ref) {
|
|
|
1440
1086
|
focus();
|
|
1441
1087
|
}
|
|
1442
1088
|
}, [insertImage, triggerChange]);
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
return _regenerator().w(function (_context2) {
|
|
1472
|
-
while (1) switch (_context2.n) {
|
|
1473
|
-
case 0:
|
|
1474
|
-
file = _step.value;
|
|
1475
|
-
try {
|
|
1476
|
-
setIsUploading(true);
|
|
1477
|
-
uploadPromise = onImageUpload ? onImageUpload(file) : readFileAsDataURL(file);
|
|
1478
|
-
uploadPromise.then(function (url) {
|
|
1479
|
-
if (url) {
|
|
1480
|
-
var finalUrl = _typeof(url) === 'object' && url !== null && url.mediaUrl ? url.mediaUrl : url;
|
|
1481
|
-
insertImage(finalUrl, file.name);
|
|
1482
|
-
}
|
|
1483
|
-
setIsUploading(false);
|
|
1484
|
-
})["catch"](function (error) {
|
|
1485
|
-
console.error('Error processing image:', error);
|
|
1486
|
-
setIsUploading(false);
|
|
1487
|
-
});
|
|
1488
|
-
} catch (error) {
|
|
1489
|
-
console.error('Error processing image:', error);
|
|
1490
|
-
setIsUploading(false);
|
|
1491
|
-
}
|
|
1492
|
-
case 1:
|
|
1493
|
-
return _context2.a(2);
|
|
1494
|
-
}
|
|
1495
|
-
}, _loop2);
|
|
1496
|
-
});
|
|
1497
|
-
_iterator.s();
|
|
1498
|
-
case 4:
|
|
1499
|
-
if ((_step = _iterator.n()).done) {
|
|
1500
|
-
_context3.n = 6;
|
|
1501
|
-
break;
|
|
1502
|
-
}
|
|
1503
|
-
return _context3.d(_regeneratorValues(_loop2()), 5);
|
|
1504
|
-
case 5:
|
|
1505
|
-
_context3.n = 4;
|
|
1506
|
-
break;
|
|
1507
|
-
case 6:
|
|
1508
|
-
_context3.n = 8;
|
|
1509
|
-
break;
|
|
1510
|
-
case 7:
|
|
1511
|
-
_context3.p = 7;
|
|
1512
|
-
_t = _context3.v;
|
|
1513
|
-
_iterator.e(_t);
|
|
1514
|
-
case 8:
|
|
1515
|
-
_context3.p = 8;
|
|
1516
|
-
_iterator.f();
|
|
1517
|
-
return _context3.f(8);
|
|
1518
|
-
case 9:
|
|
1519
|
-
return _context3.a(2);
|
|
1520
|
-
}
|
|
1521
|
-
}, _callee2, null, [[3, 7, 8, 9]]);
|
|
1522
|
-
}));
|
|
1523
|
-
return function handleDrop(_x3) {
|
|
1524
|
-
return _ref3.apply(this, arguments);
|
|
1525
|
-
};
|
|
1526
|
-
}();
|
|
1527
|
-
var insertNodeAtCursor = function insertNodeAtCursor(node) {
|
|
1089
|
+
const handleDrop = async e => {
|
|
1090
|
+
if (!editable) return;
|
|
1091
|
+
e.preventDefault();
|
|
1092
|
+
e.stopPropagation();
|
|
1093
|
+
const files = e.dataTransfer.files;
|
|
1094
|
+
if (!files || files.length === 0) return;
|
|
1095
|
+
const imageFiles = Array.from(files).filter(file => file.type.startsWith("image/"));
|
|
1096
|
+
for (const file of imageFiles) {
|
|
1097
|
+
try {
|
|
1098
|
+
setIsUploading(true);
|
|
1099
|
+
const uploadPromise = onImageUpload ? onImageUpload(file) : readFileAsDataURL(file);
|
|
1100
|
+
uploadPromise.then(url => {
|
|
1101
|
+
if (url) {
|
|
1102
|
+
const finalUrl = typeof url === 'object' && url !== null && url.mediaUrl ? url.mediaUrl : url;
|
|
1103
|
+
insertImage(finalUrl, file.name);
|
|
1104
|
+
}
|
|
1105
|
+
setIsUploading(false);
|
|
1106
|
+
}).catch(error => {
|
|
1107
|
+
console.error('Error processing image:', error);
|
|
1108
|
+
setIsUploading(false);
|
|
1109
|
+
});
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
console.error('Error processing image:', error);
|
|
1112
|
+
setIsUploading(false);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
const insertNodeAtCursor = node => {
|
|
1528
1117
|
try {
|
|
1529
|
-
|
|
1530
|
-
|
|
1118
|
+
const sel = window.getSelection();
|
|
1119
|
+
let range;
|
|
1531
1120
|
if (!sel || sel.rangeCount === 0 || !editorRef.current.contains(sel.anchorNode)) {
|
|
1532
1121
|
editorRef.current.focus();
|
|
1533
1122
|
|
|
@@ -1542,7 +1131,7 @@ function RichTextEditor(_ref) {
|
|
|
1542
1131
|
}
|
|
1543
1132
|
range.deleteContents();
|
|
1544
1133
|
range.insertNode(node);
|
|
1545
|
-
|
|
1134
|
+
const space = document.createTextNode("\u00A0");
|
|
1546
1135
|
if (node.parentNode) {
|
|
1547
1136
|
node.parentNode.insertBefore(space, node.nextSibling);
|
|
1548
1137
|
}
|
|
@@ -1557,36 +1146,36 @@ function RichTextEditor(_ref) {
|
|
|
1557
1146
|
}
|
|
1558
1147
|
}
|
|
1559
1148
|
};
|
|
1560
|
-
|
|
1149
|
+
const getCleanHtml = () => {
|
|
1561
1150
|
if (!editorRef.current) return "";
|
|
1562
1151
|
return editorRef.current.innerHTML;
|
|
1563
1152
|
};
|
|
1564
1153
|
|
|
1565
1154
|
// Helper function to unescape HTML entities
|
|
1566
|
-
|
|
1155
|
+
const unescapeHtml = html => {
|
|
1567
1156
|
if (!html) return '';
|
|
1568
|
-
|
|
1157
|
+
const txt = document.createElement("textarea");
|
|
1569
1158
|
txt.innerHTML = html;
|
|
1570
1159
|
return txt.value;
|
|
1571
1160
|
};
|
|
1572
|
-
|
|
1161
|
+
const handleKeyDown = useCallback(e => {
|
|
1573
1162
|
// Handle Enter key
|
|
1574
1163
|
if (e.key === 'Enter') {
|
|
1575
1164
|
e.preventDefault();
|
|
1576
|
-
|
|
1165
|
+
const selection = window.getSelection();
|
|
1577
1166
|
if (!selection.rangeCount) return;
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1167
|
+
const range = selection.getRangeAt(0);
|
|
1168
|
+
const node = range.startContainer;
|
|
1169
|
+
const parent = node.nodeType === 3 ? node.parentNode : node;
|
|
1581
1170
|
|
|
1582
1171
|
// Check if we're in a list item
|
|
1583
|
-
|
|
1172
|
+
const listItem = parent.closest('li');
|
|
1584
1173
|
if (listItem) {
|
|
1585
|
-
|
|
1174
|
+
const list = listItem.parentNode;
|
|
1586
1175
|
list.tagName === 'OL';
|
|
1587
1176
|
|
|
1588
1177
|
// Create a new list item
|
|
1589
|
-
|
|
1178
|
+
const newItem = document.createElement('li');
|
|
1590
1179
|
|
|
1591
1180
|
// If we're at the end of a list item, add a new one
|
|
1592
1181
|
if (range.collapsed && range.endOffset === node.length) {
|
|
@@ -1594,12 +1183,12 @@ function RichTextEditor(_ref) {
|
|
|
1594
1183
|
if (listItem.textContent.trim() === '') {
|
|
1595
1184
|
document.execCommand('insertHTML', false, '<div><br></div>');
|
|
1596
1185
|
// Move the cursor to the new line
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1186
|
+
const newRange = document.createRange();
|
|
1187
|
+
const newDiv = editorRef.current.lastElementChild;
|
|
1188
|
+
newRange.setStart(newDiv, 0);
|
|
1189
|
+
newRange.collapse(true);
|
|
1601
1190
|
selection.removeAllRanges();
|
|
1602
|
-
selection.addRange(
|
|
1191
|
+
selection.addRange(newRange);
|
|
1603
1192
|
return;
|
|
1604
1193
|
}
|
|
1605
1194
|
|
|
@@ -1611,15 +1200,15 @@ function RichTextEditor(_ref) {
|
|
|
1611
1200
|
}
|
|
1612
1201
|
|
|
1613
1202
|
// Move cursor to the new list item
|
|
1614
|
-
|
|
1203
|
+
const newRange = document.createRange();
|
|
1615
1204
|
newRange.setStart(newItem, 0);
|
|
1616
1205
|
newRange.collapse(true);
|
|
1617
1206
|
selection.removeAllRanges();
|
|
1618
1207
|
selection.addRange(newRange);
|
|
1619
1208
|
} else {
|
|
1620
1209
|
// If we're in the middle of text, split the list item
|
|
1621
|
-
|
|
1622
|
-
|
|
1210
|
+
const textBefore = node.textContent.substring(0, range.startOffset);
|
|
1211
|
+
const textAfter = node.textContent.substring(range.startOffset);
|
|
1623
1212
|
|
|
1624
1213
|
// Update current item
|
|
1625
1214
|
node.textContent = textBefore;
|
|
@@ -1633,11 +1222,11 @@ function RichTextEditor(_ref) {
|
|
|
1633
1222
|
}
|
|
1634
1223
|
|
|
1635
1224
|
// Move cursor to the new list item
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1225
|
+
const newRange = document.createRange();
|
|
1226
|
+
newRange.setStart(newItem.firstChild || newItem, 0);
|
|
1227
|
+
newRange.collapse(true);
|
|
1639
1228
|
selection.removeAllRanges();
|
|
1640
|
-
selection.addRange(
|
|
1229
|
+
selection.addRange(newRange);
|
|
1641
1230
|
}
|
|
1642
1231
|
} else {
|
|
1643
1232
|
// Regular text, insert a new paragraph
|
|
@@ -1659,54 +1248,54 @@ function RichTextEditor(_ref) {
|
|
|
1659
1248
|
exec("underline");
|
|
1660
1249
|
}
|
|
1661
1250
|
}, [exec, triggerChange]);
|
|
1662
|
-
|
|
1251
|
+
const confirmLink = () => {
|
|
1663
1252
|
// Add protocol if missing
|
|
1664
|
-
|
|
1253
|
+
let url = linkUrl.trim();
|
|
1665
1254
|
if (url && !/^(https?:\/\/|mailto:|tel:)/i.test(url)) {
|
|
1666
|
-
url =
|
|
1255
|
+
url = `https://${url}`;
|
|
1667
1256
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1257
|
+
const safeUrl = escapeAttr(url);
|
|
1258
|
+
const safeText = escapeHtml(linkText || linkUrl);
|
|
1259
|
+
const sel = window.getSelection();
|
|
1671
1260
|
sel.removeAllRanges();
|
|
1672
1261
|
if (selectionRangeRef.current) {
|
|
1673
1262
|
sel.addRange(selectionRangeRef.current);
|
|
1674
1263
|
}
|
|
1675
|
-
|
|
1264
|
+
const linkHtml = `<a href="${safeUrl}" target="_blank" rel="noopener noreferrer" style="color: blue;">${safeText}</a>`;
|
|
1676
1265
|
document.execCommand("insertHTML", false, linkHtml);
|
|
1677
1266
|
setLinkModalOpen(false);
|
|
1678
1267
|
triggerChange();
|
|
1679
1268
|
focus();
|
|
1680
1269
|
selectionRangeRef.current = null;
|
|
1681
1270
|
};
|
|
1682
|
-
|
|
1271
|
+
const cancelLink = () => {
|
|
1683
1272
|
setLinkModalOpen(false);
|
|
1684
1273
|
selectionRangeRef.current = null;
|
|
1685
1274
|
};
|
|
1686
|
-
|
|
1275
|
+
const handleSelect = type => {
|
|
1687
1276
|
exec(type === "unordered" ? "insertUnorderedList" : "insertOrderedList");
|
|
1688
1277
|
};
|
|
1689
|
-
|
|
1278
|
+
const onLineHeightChange = value => {
|
|
1690
1279
|
if (!value) return;
|
|
1691
|
-
|
|
1280
|
+
const sel = window.getSelection();
|
|
1692
1281
|
if (!sel || !sel.rangeCount) return;
|
|
1693
|
-
|
|
1694
|
-
|
|
1282
|
+
const range = sel.getRangeAt(0);
|
|
1283
|
+
const editor = editorRef.current;
|
|
1695
1284
|
if (!editor) return;
|
|
1696
|
-
|
|
1697
|
-
acceptNode:
|
|
1285
|
+
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, {
|
|
1286
|
+
acceptNode: node => {
|
|
1698
1287
|
return range.intersectsNode(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
1699
1288
|
}
|
|
1700
1289
|
}, false);
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1290
|
+
let node;
|
|
1291
|
+
const blocksToStyle = new Set();
|
|
1292
|
+
const blockTags = ['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'BLOCKQUOTE'];
|
|
1293
|
+
const tempRange = range.cloneRange();
|
|
1705
1294
|
while (node = walker.nextNode()) {
|
|
1706
1295
|
if (node.nodeType === 1 && blockTags.includes(node.tagName)) {
|
|
1707
1296
|
blocksToStyle.add(node);
|
|
1708
1297
|
} else if (node.nodeType === 3) {
|
|
1709
|
-
|
|
1298
|
+
let parent = node.parentNode;
|
|
1710
1299
|
while (parent && parent !== editor && !blockTags.includes(parent.tagName)) {
|
|
1711
1300
|
parent = parent.parentNode;
|
|
1712
1301
|
}
|
|
@@ -1716,11 +1305,11 @@ function RichTextEditor(_ref) {
|
|
|
1716
1305
|
}
|
|
1717
1306
|
}
|
|
1718
1307
|
if (blocksToStyle.size > 0) {
|
|
1719
|
-
blocksToStyle.forEach(
|
|
1308
|
+
blocksToStyle.forEach(block => {
|
|
1720
1309
|
block.style.lineHeight = value;
|
|
1721
1310
|
});
|
|
1722
1311
|
} else {
|
|
1723
|
-
|
|
1312
|
+
let common = range.commonAncestorContainer;
|
|
1724
1313
|
if (common.nodeType === 3) common = common.parentNode;
|
|
1725
1314
|
while (common && common !== editor && !blockTags.includes(common.tagName)) {
|
|
1726
1315
|
common = common.parentNode;
|
|
@@ -1729,7 +1318,7 @@ function RichTextEditor(_ref) {
|
|
|
1729
1318
|
common.style.lineHeight = value;
|
|
1730
1319
|
} else if (editor) {
|
|
1731
1320
|
document.execCommand('formatBlock', false, 'div');
|
|
1732
|
-
|
|
1321
|
+
let newCommon = window.getSelection().getRangeAt(0).commonAncestorContainer;
|
|
1733
1322
|
if (newCommon.nodeType === 3) newCommon = newCommon.parentNode;
|
|
1734
1323
|
if (newCommon && newCommon !== editor) {
|
|
1735
1324
|
newCommon.style.lineHeight = value;
|
|
@@ -1744,19 +1333,19 @@ function RichTextEditor(_ref) {
|
|
|
1744
1333
|
triggerChange();
|
|
1745
1334
|
focus();
|
|
1746
1335
|
};
|
|
1747
|
-
|
|
1748
|
-
|
|
1336
|
+
const applyFontSize = size => {
|
|
1337
|
+
const sel = window.getSelection();
|
|
1749
1338
|
if (!sel || !sel.rangeCount) return;
|
|
1750
|
-
|
|
1751
|
-
|
|
1339
|
+
const range = sel.getRangeAt(0);
|
|
1340
|
+
const sizePx = `${size}px`;
|
|
1752
1341
|
|
|
1753
1342
|
// Collapsed selection (cursor only): insert a styled zero-width span
|
|
1754
1343
|
if (range.collapsed) {
|
|
1755
|
-
|
|
1344
|
+
const span = document.createElement("span");
|
|
1756
1345
|
span.style.fontSize = sizePx;
|
|
1757
1346
|
span.appendChild(document.createTextNode("\u200B"));
|
|
1758
1347
|
range.insertNode(span);
|
|
1759
|
-
|
|
1348
|
+
const newRange = document.createRange();
|
|
1760
1349
|
newRange.setStart(span.firstChild, 1);
|
|
1761
1350
|
newRange.collapse(true);
|
|
1762
1351
|
sel.removeAllRanges();
|
|
@@ -1768,42 +1357,41 @@ function RichTextEditor(_ref) {
|
|
|
1768
1357
|
|
|
1769
1358
|
// Extended selection (highlighted text)
|
|
1770
1359
|
try {
|
|
1771
|
-
|
|
1360
|
+
const editor = editorRef.current;
|
|
1772
1361
|
if (!editor) return;
|
|
1773
1362
|
|
|
1774
1363
|
// We will iterate through all the text nodes in the selection
|
|
1775
|
-
|
|
1776
|
-
acceptNode:
|
|
1364
|
+
const walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT, {
|
|
1365
|
+
acceptNode: node => {
|
|
1777
1366
|
return range.intersectsNode(node) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
1778
1367
|
}
|
|
1779
1368
|
}, false);
|
|
1780
|
-
|
|
1781
|
-
|
|
1369
|
+
let node;
|
|
1370
|
+
const nodesToStyle = [];
|
|
1782
1371
|
while (node = walker.nextNode()) {
|
|
1783
1372
|
nodesToStyle.push(node);
|
|
1784
1373
|
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1374
|
+
const savedRange = range.cloneRange();
|
|
1375
|
+
let lastInsertedNode = null;
|
|
1787
1376
|
|
|
1788
1377
|
// Iterate through the selected text nodes and wrap them in spans
|
|
1789
|
-
for (
|
|
1790
|
-
|
|
1791
|
-
var parent = textNode.parentNode;
|
|
1378
|
+
for (const textNode of nodesToStyle) {
|
|
1379
|
+
const parent = textNode.parentNode;
|
|
1792
1380
|
|
|
1793
1381
|
// This is important: check if the parent is a block-level element
|
|
1794
1382
|
// like a list item or paragraph. If so, we want to style the block
|
|
1795
1383
|
// itself to avoid breaking its structure.
|
|
1796
|
-
|
|
1384
|
+
const isBlockLevel = ['P', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'BLOCKQUOTE'].includes(parent.tagName);
|
|
1797
1385
|
if (isBlockLevel) {
|
|
1798
1386
|
parent.style.fontSize = sizePx;
|
|
1799
1387
|
} else {
|
|
1800
1388
|
// For inline text, wrap the selected portion in a new span
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1389
|
+
const startOffset = textNode === savedRange.startContainer ? savedRange.startOffset : 0;
|
|
1390
|
+
const endOffset = textNode === savedRange.endContainer ? savedRange.endOffset : textNode.length;
|
|
1391
|
+
const newSpan = document.createElement("span");
|
|
1804
1392
|
newSpan.style.fontSize = sizePx;
|
|
1805
1393
|
newSpan.textContent = textNode.textContent.substring(startOffset, endOffset);
|
|
1806
|
-
|
|
1394
|
+
const tempRange = document.createRange();
|
|
1807
1395
|
tempRange.setStart(textNode, startOffset);
|
|
1808
1396
|
tempRange.setEnd(textNode, endOffset);
|
|
1809
1397
|
tempRange.deleteContents();
|
|
@@ -1814,11 +1402,11 @@ function RichTextEditor(_ref) {
|
|
|
1814
1402
|
|
|
1815
1403
|
// After styling, we need to correctly position the cursor
|
|
1816
1404
|
if (lastInsertedNode) {
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1405
|
+
const newRange = document.createRange();
|
|
1406
|
+
newRange.setStartAfter(lastInsertedNode);
|
|
1407
|
+
newRange.collapse(true);
|
|
1820
1408
|
sel.removeAllRanges();
|
|
1821
|
-
sel.addRange(
|
|
1409
|
+
sel.addRange(newRange);
|
|
1822
1410
|
} else {
|
|
1823
1411
|
// If no nodes were wrapped (e.g., we styled a block), restore the original selection
|
|
1824
1412
|
sel.removeAllRanges();
|
|
@@ -1830,65 +1418,47 @@ function RichTextEditor(_ref) {
|
|
|
1830
1418
|
triggerChange();
|
|
1831
1419
|
focus();
|
|
1832
1420
|
};
|
|
1833
|
-
|
|
1834
|
-
if (
|
|
1835
|
-
|
|
1836
|
-
setHtml(
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
case 1:
|
|
1853
|
-
try {
|
|
1854
|
-
setIsUploading(true);
|
|
1855
|
-
uploadPromise = onImageUpload ? onImageUpload(file) : readFileAsDataURL(file);
|
|
1856
|
-
uploadPromise.then(function (url) {
|
|
1857
|
-
if (url) {
|
|
1858
|
-
var finalUrl = _typeof(url) === 'object' && url !== null && url.mediaUrl ? url.mediaUrl : url;
|
|
1859
|
-
insertImage(finalUrl, file.name);
|
|
1860
|
-
}
|
|
1861
|
-
setIsUploading(false);
|
|
1862
|
-
e.target.value = null;
|
|
1863
|
-
})["catch"](function (error) {
|
|
1864
|
-
console.error('Error uploading image:', error);
|
|
1865
|
-
setIsUploading(false);
|
|
1866
|
-
});
|
|
1867
|
-
} catch (error) {
|
|
1868
|
-
console.error('Error uploading image:', error);
|
|
1869
|
-
setIsUploading(false);
|
|
1870
|
-
}
|
|
1871
|
-
case 2:
|
|
1872
|
-
return _context4.a(2);
|
|
1421
|
+
const handleInput = useCallback(() => {
|
|
1422
|
+
if (editorRef.current) {
|
|
1423
|
+
const next = editorRef.current.innerHTML;
|
|
1424
|
+
setHtml(next);
|
|
1425
|
+
lastSynchronizedHtmlRef.current = next;
|
|
1426
|
+
onChange && onChange(next);
|
|
1427
|
+
updateMetrics();
|
|
1428
|
+
}
|
|
1429
|
+
}, [onChange, updateMetrics]);
|
|
1430
|
+
const handleImageUpload = async e => {
|
|
1431
|
+
const file = e.target.files[0];
|
|
1432
|
+
if (!file) return;
|
|
1433
|
+
try {
|
|
1434
|
+
setIsUploading(true);
|
|
1435
|
+
const uploadPromise = onImageUpload ? onImageUpload(file) : readFileAsDataURL(file);
|
|
1436
|
+
uploadPromise.then(url => {
|
|
1437
|
+
if (url) {
|
|
1438
|
+
const finalUrl = typeof url === 'object' && url !== null && url.mediaUrl ? url.mediaUrl : url;
|
|
1439
|
+
insertImage(finalUrl, file.name);
|
|
1873
1440
|
}
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1441
|
+
setIsUploading(false);
|
|
1442
|
+
e.target.value = null;
|
|
1443
|
+
}).catch(error => {
|
|
1444
|
+
console.error('Error uploading image:', error);
|
|
1445
|
+
setIsUploading(false);
|
|
1446
|
+
});
|
|
1447
|
+
} catch (error) {
|
|
1448
|
+
console.error('Error uploading image:', error);
|
|
1449
|
+
setIsUploading(false);
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
useEffect(() => {
|
|
1881
1453
|
// If disabled is explicitly false, make sure the editor is not editable
|
|
1882
1454
|
if (disabled === true) {
|
|
1883
1455
|
setEditable(false);
|
|
1884
1456
|
}
|
|
1885
1457
|
}, [disabled]);
|
|
1886
|
-
|
|
1887
|
-
setSelectionVersion(
|
|
1888
|
-
return v + 1;
|
|
1889
|
-
});
|
|
1458
|
+
const handleEditorClick = useCallback(e => {
|
|
1459
|
+
setSelectionVersion(v => v + 1);
|
|
1890
1460
|
// Check if the click is on a link
|
|
1891
|
-
|
|
1461
|
+
const clickedLink = e.target.closest('a');
|
|
1892
1462
|
if (clickedLink) {
|
|
1893
1463
|
e.preventDefault();
|
|
1894
1464
|
e.stopPropagation();
|
|
@@ -1897,11 +1467,10 @@ function RichTextEditor(_ref) {
|
|
|
1897
1467
|
}
|
|
1898
1468
|
|
|
1899
1469
|
// NEW: Check if click is on an image for resizing
|
|
1900
|
-
|
|
1470
|
+
const clickedImg = e.target.closest('img');
|
|
1901
1471
|
if (clickedImg && !clickedImg.closest('.rte-modal')) {
|
|
1902
1472
|
setSelectedImage(clickedImg);
|
|
1903
|
-
|
|
1904
|
-
} else if (!e.target.closest('.resize-handle')) {
|
|
1473
|
+
} else if (!e.target.closest('.rte-image-toolbar')) {
|
|
1905
1474
|
setSelectedImage(null);
|
|
1906
1475
|
}
|
|
1907
1476
|
|
|
@@ -1914,119 +1483,81 @@ function RichTextEditor(_ref) {
|
|
|
1914
1483
|
// Only allow setting editable to true if not disabled
|
|
1915
1484
|
if (!editable && disabled !== true) {
|
|
1916
1485
|
setEditable(true);
|
|
1917
|
-
setTimeout(
|
|
1486
|
+
setTimeout(() => {
|
|
1918
1487
|
if (editorRef.current) {
|
|
1919
1488
|
editorRef.current.focus();
|
|
1920
1489
|
}
|
|
1921
1490
|
}, 0);
|
|
1922
1491
|
}
|
|
1923
1492
|
}, [editable, disabled]);
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
img.style.height = "".concat(newHeight, "px");
|
|
1941
|
-
setResizeData({}); // Force re-render of handles
|
|
1942
|
-
};
|
|
1943
|
-
var _onMouseUp = function onMouseUp() {
|
|
1944
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
1945
|
-
document.removeEventListener('mouseup', _onMouseUp);
|
|
1946
|
-
triggerChange();
|
|
1947
|
-
};
|
|
1948
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
1949
|
-
document.addEventListener('mouseup', _onMouseUp);
|
|
1950
|
-
};
|
|
1951
|
-
var renderResizeHandles = function renderResizeHandles() {
|
|
1952
|
-
if (!selectedImage || !editorRef.current) return null;
|
|
1953
|
-
var editorRect = editorRef.current.getBoundingClientRect();
|
|
1954
|
-
var imgRect = selectedImage.getBoundingClientRect();
|
|
1955
|
-
|
|
1956
|
-
// Relative position within editorRef using the more robust BoundingClientRect
|
|
1957
|
-
var top = imgRect.top - editorRect.top + editorRef.current.scrollTop;
|
|
1958
|
-
var left = imgRect.left - editorRect.left + editorRef.current.scrollLeft;
|
|
1959
|
-
var width = imgRect.width;
|
|
1960
|
-
var height = imgRect.height;
|
|
1961
|
-
var handleStyles = {
|
|
1962
|
-
position: 'absolute',
|
|
1963
|
-
width: '10px',
|
|
1964
|
-
height: '10px',
|
|
1965
|
-
background: '#3b82f6',
|
|
1966
|
-
border: '2px solid white',
|
|
1967
|
-
borderRadius: '50%',
|
|
1968
|
-
zIndex: 100
|
|
1969
|
-
};
|
|
1970
|
-
var handles = [{
|
|
1971
|
-
id: 'nw',
|
|
1972
|
-
style: {
|
|
1973
|
-
top: top - 5,
|
|
1974
|
-
left: left - 5,
|
|
1975
|
-
cursor: 'nw-resize'
|
|
1976
|
-
}
|
|
1977
|
-
}, {
|
|
1978
|
-
id: 'ne',
|
|
1979
|
-
style: {
|
|
1980
|
-
top: top - 5,
|
|
1981
|
-
left: left + width - 5,
|
|
1982
|
-
cursor: 'ne-resize'
|
|
1493
|
+
const renderImageToolbar = () => {
|
|
1494
|
+
if (!selectedImage || !editorRef.current || !editable) return null;
|
|
1495
|
+
const editorRect = editorRef.current.getBoundingClientRect();
|
|
1496
|
+
const imgRect = selectedImage.getBoundingClientRect();
|
|
1497
|
+
const top = imgRect.top - editorRect.top + editorRef.current.scrollTop;
|
|
1498
|
+
const left = imgRect.left - editorRect.left + editorRef.current.scrollLeft;
|
|
1499
|
+
const width = imgRect.width;
|
|
1500
|
+
const handleAlignment = align => {
|
|
1501
|
+
const wrapper = selectedImage.closest('.image-container');
|
|
1502
|
+
if (wrapper) {
|
|
1503
|
+
// Remove all alignment classes first
|
|
1504
|
+
wrapper.classList.remove('image-align-left', 'image-align-center', 'image-align-right');
|
|
1505
|
+
// Add the new alignment class
|
|
1506
|
+
wrapper.classList.add(`image-align-${align}`);
|
|
1507
|
+
selectedImage.setAttribute('data-align', align);
|
|
1508
|
+
triggerChange();
|
|
1983
1509
|
}
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1510
|
+
};
|
|
1511
|
+
const removeImage = () => {
|
|
1512
|
+
const wrapper = selectedImage.closest('.image-container');
|
|
1513
|
+
if (wrapper) {
|
|
1514
|
+
wrapper.remove();
|
|
1515
|
+
setSelectedImage(null);
|
|
1516
|
+
triggerChange();
|
|
1990
1517
|
}
|
|
1991
|
-
}
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1518
|
+
};
|
|
1519
|
+
const toggleSize = () => {
|
|
1520
|
+
const wrapper = selectedImage.closest('.image-container');
|
|
1521
|
+
if (wrapper) {
|
|
1522
|
+
const isSmall = wrapper.classList.contains('image-small');
|
|
1523
|
+
if (isSmall) {
|
|
1524
|
+
wrapper.classList.remove('image-small');
|
|
1525
|
+
} else {
|
|
1526
|
+
wrapper.classList.add('image-small');
|
|
1527
|
+
}
|
|
1528
|
+
triggerChange();
|
|
1997
1529
|
}
|
|
1998
|
-
}
|
|
1530
|
+
};
|
|
1999
1531
|
return /*#__PURE__*/React.createElement("div", {
|
|
1532
|
+
className: "rte-image-toolbar",
|
|
2000
1533
|
style: {
|
|
2001
1534
|
position: 'absolute',
|
|
2002
|
-
top: 0,
|
|
2003
|
-
left: 0,
|
|
2004
|
-
|
|
2005
|
-
height: '100%',
|
|
2006
|
-
pointerEvents: 'none'
|
|
2007
|
-
}
|
|
2008
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
2009
|
-
style: {
|
|
2010
|
-
position: 'absolute',
|
|
2011
|
-
top: top,
|
|
2012
|
-
left: left,
|
|
2013
|
-
width: width,
|
|
2014
|
-
height: height,
|
|
2015
|
-
border: '2px solid #3b82f6',
|
|
2016
|
-
pointerEvents: 'none'
|
|
1535
|
+
top: Math.max(0, top - 45),
|
|
1536
|
+
left: Math.max(0, left + width / 2 - 80),
|
|
1537
|
+
zIndex: 1000
|
|
2017
1538
|
}
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
1539
|
+
}, /*#__PURE__*/React.createElement("button", {
|
|
1540
|
+
type: "button",
|
|
1541
|
+
onClick: () => handleAlignment('left'),
|
|
1542
|
+
title: "Align Left"
|
|
1543
|
+
}, "L"), /*#__PURE__*/React.createElement("button", {
|
|
1544
|
+
type: "button",
|
|
1545
|
+
onClick: () => handleAlignment('center'),
|
|
1546
|
+
title: "Align Center"
|
|
1547
|
+
}, "C"), /*#__PURE__*/React.createElement("button", {
|
|
1548
|
+
type: "button",
|
|
1549
|
+
onClick: () => handleAlignment('right'),
|
|
1550
|
+
title: "Align Right"
|
|
1551
|
+
}, "R"), /*#__PURE__*/React.createElement("button", {
|
|
1552
|
+
type: "button",
|
|
1553
|
+
onClick: toggleSize,
|
|
1554
|
+
title: "Toggle 50% Width"
|
|
1555
|
+
}, "50%"), /*#__PURE__*/React.createElement("button", {
|
|
1556
|
+
type: "button",
|
|
1557
|
+
onClick: removeImage,
|
|
1558
|
+
className: "danger",
|
|
1559
|
+
title: "Remove Image"
|
|
1560
|
+
}, "\xD7"));
|
|
2030
1561
|
};
|
|
2031
1562
|
return /*#__PURE__*/React.createElement("div", {
|
|
2032
1563
|
className: "rte-main-wrapper",
|
|
@@ -2040,21 +1571,21 @@ function RichTextEditor(_ref) {
|
|
|
2040
1571
|
},
|
|
2041
1572
|
className: !showBorder ? "" : "rte-container",
|
|
2042
1573
|
onClick: handleEditorClick,
|
|
2043
|
-
onMouseOver:
|
|
2044
|
-
|
|
1574
|
+
onMouseOver: e => {
|
|
1575
|
+
const table = e.target.closest('table');
|
|
2045
1576
|
if (table && editorRef.current.contains(table)) {
|
|
2046
1577
|
setHoveredTable(table);
|
|
2047
1578
|
}
|
|
2048
1579
|
},
|
|
2049
|
-
onMouseOut:
|
|
2050
|
-
|
|
2051
|
-
|
|
1580
|
+
onMouseOut: e => {
|
|
1581
|
+
const table = e.target.closest('table');
|
|
1582
|
+
const related = e.relatedTarget;
|
|
2052
1583
|
if (table && (!related || !table.contains(related)) && !(related !== null && related !== void 0 && related.closest('.rte-table-delete-hover'))) {
|
|
2053
1584
|
setHoveredTable(null);
|
|
2054
1585
|
}
|
|
2055
1586
|
},
|
|
2056
1587
|
onDrop: handleDrop,
|
|
2057
|
-
onDragOver:
|
|
1588
|
+
onDragOver: e => {
|
|
2058
1589
|
e.preventDefault();
|
|
2059
1590
|
e.stopPropagation();
|
|
2060
1591
|
}
|
|
@@ -2063,40 +1594,40 @@ function RichTextEditor(_ref) {
|
|
|
2063
1594
|
}, /*#__PURE__*/React.createElement("button", {
|
|
2064
1595
|
type: "button",
|
|
2065
1596
|
title: "Bold",
|
|
2066
|
-
onClick:
|
|
1597
|
+
onClick: e => {
|
|
2067
1598
|
e.preventDefault();
|
|
2068
1599
|
e.stopPropagation();
|
|
2069
1600
|
document.execCommand("bold");
|
|
2070
1601
|
handleInput();
|
|
2071
1602
|
focus();
|
|
2072
1603
|
},
|
|
2073
|
-
className:
|
|
1604
|
+
className: `rte-toolbar-button ${isBold ? "active" : ""}`
|
|
2074
1605
|
}, /*#__PURE__*/React.createElement(FaBold, {
|
|
2075
1606
|
size: 14
|
|
2076
1607
|
})), /*#__PURE__*/React.createElement("button", {
|
|
2077
1608
|
type: "button",
|
|
2078
1609
|
title: "Italic",
|
|
2079
|
-
onClick:
|
|
1610
|
+
onClick: e => {
|
|
2080
1611
|
e.preventDefault();
|
|
2081
1612
|
e.stopPropagation();
|
|
2082
1613
|
document.execCommand("italic");
|
|
2083
1614
|
handleInput();
|
|
2084
1615
|
focus();
|
|
2085
1616
|
},
|
|
2086
|
-
className:
|
|
1617
|
+
className: `rte-toolbar-button ${isItalic ? "active" : ""}`
|
|
2087
1618
|
}, /*#__PURE__*/React.createElement(FaItalic, {
|
|
2088
1619
|
size: 14
|
|
2089
1620
|
})), /*#__PURE__*/React.createElement("button", {
|
|
2090
1621
|
type: "button",
|
|
2091
1622
|
title: "Underline",
|
|
2092
|
-
onClick:
|
|
1623
|
+
onClick: e => {
|
|
2093
1624
|
e.preventDefault();
|
|
2094
1625
|
e.stopPropagation();
|
|
2095
1626
|
document.execCommand("underline");
|
|
2096
1627
|
handleInput();
|
|
2097
1628
|
focus();
|
|
2098
1629
|
},
|
|
2099
|
-
className:
|
|
1630
|
+
className: `rte-toolbar-button ${isUnderline ? "active" : ""}`
|
|
2100
1631
|
}, /*#__PURE__*/React.createElement(FaUnderline, {
|
|
2101
1632
|
size: 14
|
|
2102
1633
|
})), /*#__PURE__*/React.createElement("div", {
|
|
@@ -2108,13 +1639,11 @@ function RichTextEditor(_ref) {
|
|
|
2108
1639
|
}
|
|
2109
1640
|
}), /*#__PURE__*/React.createElement("select", {
|
|
2110
1641
|
value: currentFontSize,
|
|
2111
|
-
onMouseDown:
|
|
2112
|
-
|
|
2113
|
-
},
|
|
2114
|
-
onChange: function onChange(e) {
|
|
1642
|
+
onMouseDown: e => e.stopPropagation(),
|
|
1643
|
+
onChange: e => {
|
|
2115
1644
|
e.preventDefault();
|
|
2116
1645
|
e.stopPropagation();
|
|
2117
|
-
|
|
1646
|
+
const size = e.target.value;
|
|
2118
1647
|
if (!size) return;
|
|
2119
1648
|
applyFontSize(size);
|
|
2120
1649
|
setCurrentFontSize(size);
|
|
@@ -2124,12 +1653,10 @@ function RichTextEditor(_ref) {
|
|
|
2124
1653
|
style: {
|
|
2125
1654
|
width: '70px'
|
|
2126
1655
|
}
|
|
2127
|
-
}, [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48].map(
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
}, s, "px");
|
|
2132
|
-
})), /*#__PURE__*/React.createElement("label", {
|
|
1656
|
+
}, [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 48].map(s => /*#__PURE__*/React.createElement("option", {
|
|
1657
|
+
key: s,
|
|
1658
|
+
value: s
|
|
1659
|
+
}, s, "px"))), /*#__PURE__*/React.createElement("label", {
|
|
2133
1660
|
title: "Font Color",
|
|
2134
1661
|
className: "rte-color-picker-label"
|
|
2135
1662
|
}, /*#__PURE__*/React.createElement(FaFont, {
|
|
@@ -2140,11 +1667,11 @@ function RichTextEditor(_ref) {
|
|
|
2140
1667
|
}), /*#__PURE__*/React.createElement("input", {
|
|
2141
1668
|
type: "color",
|
|
2142
1669
|
value: fontColor,
|
|
2143
|
-
onMouseDown:
|
|
1670
|
+
onMouseDown: e => {
|
|
2144
1671
|
e.preventDefault();
|
|
2145
1672
|
e.stopPropagation();
|
|
2146
1673
|
},
|
|
2147
|
-
onChange:
|
|
1674
|
+
onChange: e => {
|
|
2148
1675
|
e.stopPropagation();
|
|
2149
1676
|
handleColorChange(e.target.value);
|
|
2150
1677
|
},
|
|
@@ -2159,8 +1686,8 @@ function RichTextEditor(_ref) {
|
|
|
2159
1686
|
}), /*#__PURE__*/React.createElement("button", {
|
|
2160
1687
|
type: "button",
|
|
2161
1688
|
title: "Align Left",
|
|
2162
|
-
className:
|
|
2163
|
-
onMouseDown:
|
|
1689
|
+
className: `rte-toolbar-button ${activeAlign === "left" ? "active" : ""}`,
|
|
1690
|
+
onMouseDown: e => {
|
|
2164
1691
|
e.preventDefault();
|
|
2165
1692
|
exec("justifyLeft");
|
|
2166
1693
|
setActiveAlign("left");
|
|
@@ -2170,8 +1697,8 @@ function RichTextEditor(_ref) {
|
|
|
2170
1697
|
})), /*#__PURE__*/React.createElement("button", {
|
|
2171
1698
|
type: "button",
|
|
2172
1699
|
title: "Align Center",
|
|
2173
|
-
className:
|
|
2174
|
-
onMouseDown:
|
|
1700
|
+
className: `rte-toolbar-button ${activeAlign === "center" ? "active" : ""}`,
|
|
1701
|
+
onMouseDown: e => {
|
|
2175
1702
|
e.preventDefault();
|
|
2176
1703
|
exec("justifyCenter");
|
|
2177
1704
|
setActiveAlign("center");
|
|
@@ -2181,8 +1708,8 @@ function RichTextEditor(_ref) {
|
|
|
2181
1708
|
})), /*#__PURE__*/React.createElement("button", {
|
|
2182
1709
|
type: "button",
|
|
2183
1710
|
title: "Align Right",
|
|
2184
|
-
className:
|
|
2185
|
-
onMouseDown:
|
|
1711
|
+
className: `rte-toolbar-button ${activeAlign === "right" ? "active" : ""}`,
|
|
1712
|
+
onMouseDown: e => {
|
|
2186
1713
|
e.preventDefault();
|
|
2187
1714
|
exec("justifyRight");
|
|
2188
1715
|
setActiveAlign("right");
|
|
@@ -2199,21 +1726,21 @@ function RichTextEditor(_ref) {
|
|
|
2199
1726
|
}), /*#__PURE__*/React.createElement("button", {
|
|
2200
1727
|
type: "button",
|
|
2201
1728
|
title: "Unordered List",
|
|
2202
|
-
onMouseDown:
|
|
1729
|
+
onMouseDown: e => {
|
|
2203
1730
|
e.preventDefault();
|
|
2204
1731
|
handleSelect("unordered");
|
|
2205
1732
|
},
|
|
2206
|
-
className:
|
|
1733
|
+
className: `rte-toolbar-button ${currentListType === "unordered" ? "active" : ""}`
|
|
2207
1734
|
}, /*#__PURE__*/React.createElement(FaListUl, {
|
|
2208
1735
|
size: 14
|
|
2209
1736
|
})), /*#__PURE__*/React.createElement("button", {
|
|
2210
1737
|
type: "button",
|
|
2211
1738
|
title: "Ordered List",
|
|
2212
|
-
onMouseDown:
|
|
1739
|
+
onMouseDown: e => {
|
|
2213
1740
|
e.preventDefault();
|
|
2214
1741
|
handleSelect("ordered");
|
|
2215
1742
|
},
|
|
2216
|
-
className:
|
|
1743
|
+
className: `rte-toolbar-button ${currentListType === "ordered" ? "active" : ""}`
|
|
2217
1744
|
}, /*#__PURE__*/React.createElement(FaListOl, {
|
|
2218
1745
|
size: 14
|
|
2219
1746
|
})), /*#__PURE__*/React.createElement("div", {
|
|
@@ -2224,12 +1751,10 @@ function RichTextEditor(_ref) {
|
|
|
2224
1751
|
}
|
|
2225
1752
|
}, /*#__PURE__*/React.createElement("select", {
|
|
2226
1753
|
value: currentLineHeight,
|
|
2227
|
-
onMouseDown:
|
|
2228
|
-
|
|
2229
|
-
},
|
|
2230
|
-
onChange: function onChange(e) {
|
|
1754
|
+
onMouseDown: e => e.stopPropagation(),
|
|
1755
|
+
onChange: e => {
|
|
2231
1756
|
e.preventDefault();
|
|
2232
|
-
|
|
1757
|
+
const height = e.target.value;
|
|
2233
1758
|
if (height) {
|
|
2234
1759
|
onLineHeightChange(height);
|
|
2235
1760
|
setCurrentLineHeight(height);
|
|
@@ -2244,12 +1769,10 @@ function RichTextEditor(_ref) {
|
|
|
2244
1769
|
}, /*#__PURE__*/React.createElement("option", {
|
|
2245
1770
|
value: "",
|
|
2246
1771
|
disabled: true
|
|
2247
|
-
}, "\u2195"), ['1', '1.15', '1.5', '2'].map(
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
}, h);
|
|
2252
|
-
})), /*#__PURE__*/React.createElement("div", {
|
|
1772
|
+
}, "\u2195"), ['1', '1.15', '1.5', '2'].map(h => /*#__PURE__*/React.createElement("option", {
|
|
1773
|
+
key: h,
|
|
1774
|
+
value: h
|
|
1775
|
+
}, h))), /*#__PURE__*/React.createElement("div", {
|
|
2253
1776
|
style: {
|
|
2254
1777
|
position: 'absolute',
|
|
2255
1778
|
left: '6px',
|
|
@@ -2276,7 +1799,7 @@ function RichTextEditor(_ref) {
|
|
|
2276
1799
|
type: "button",
|
|
2277
1800
|
title: "Add Link",
|
|
2278
1801
|
className: "rte-toolbar-button",
|
|
2279
|
-
onMouseDown:
|
|
1802
|
+
onMouseDown: e => {
|
|
2280
1803
|
e.preventDefault();
|
|
2281
1804
|
addLink();
|
|
2282
1805
|
}
|
|
@@ -2296,7 +1819,7 @@ function RichTextEditor(_ref) {
|
|
|
2296
1819
|
}), /*#__PURE__*/React.createElement("button", {
|
|
2297
1820
|
type: "button",
|
|
2298
1821
|
className: "rte-toolbar-button",
|
|
2299
|
-
onMouseDown:
|
|
1822
|
+
onMouseDown: e => {
|
|
2300
1823
|
var _fileInputRef$current;
|
|
2301
1824
|
e.preventDefault();
|
|
2302
1825
|
if (!isUploading) (_fileInputRef$current = fileInputRef.current) === null || _fileInputRef$current === void 0 || _fileInputRef$current.click();
|
|
@@ -2323,9 +1846,9 @@ function RichTextEditor(_ref) {
|
|
|
2323
1846
|
type: "button",
|
|
2324
1847
|
title: "Insert Table",
|
|
2325
1848
|
className: "rte-toolbar-button",
|
|
2326
|
-
onMouseDown:
|
|
1849
|
+
onMouseDown: e => {
|
|
2327
1850
|
e.preventDefault();
|
|
2328
|
-
|
|
1851
|
+
const sel = window.getSelection();
|
|
2329
1852
|
if (sel && sel.rangeCount > 0) {
|
|
2330
1853
|
selectionRangeRef.current = sel.getRangeAt(0).cloneRange();
|
|
2331
1854
|
}
|
|
@@ -2335,24 +1858,21 @@ function RichTextEditor(_ref) {
|
|
|
2335
1858
|
size: 14
|
|
2336
1859
|
})), /*#__PURE__*/React.createElement("button", {
|
|
2337
1860
|
type: "button",
|
|
2338
|
-
title: "Embed YouTube
|
|
2339
|
-
className:
|
|
2340
|
-
onMouseDown:
|
|
1861
|
+
title: "Embed Video (YouTube, Vimeo, etc.)",
|
|
1862
|
+
className: `rte-toolbar-button ${videoModalOpen ? 'active' : ''}`,
|
|
1863
|
+
onMouseDown: e => {
|
|
2341
1864
|
e.preventDefault();
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
selectionRangeRef.current = sel.getRangeAt(0).cloneRange();
|
|
2345
|
-
}
|
|
2346
|
-
setYoutubeModalOpen(true);
|
|
1865
|
+
saveSelection();
|
|
1866
|
+
setVideoModalOpen(true);
|
|
2347
1867
|
}
|
|
2348
|
-
}, /*#__PURE__*/React.createElement(
|
|
1868
|
+
}, /*#__PURE__*/React.createElement(FaVideo, {
|
|
2349
1869
|
size: 14
|
|
2350
|
-
})),
|
|
1870
|
+
})), (() => {
|
|
2351
1871
|
if (typeof window === "undefined") return null;
|
|
2352
|
-
|
|
1872
|
+
const sel = window.getSelection();
|
|
2353
1873
|
// Robust check: inside cell OR the table itself is selected
|
|
2354
|
-
|
|
2355
|
-
|
|
1874
|
+
const isCell = sel && sel.rangeCount > 0 && sel.anchorNode && (findParentTag(sel.anchorNode, 'TD') || findParentTag(sel.anchorNode, 'TH'));
|
|
1875
|
+
const isTable = sel && sel.rangeCount > 0 && sel.anchorNode && findParentTag(sel.anchorNode, 'TABLE');
|
|
2356
1876
|
if (isCell || isTable) {
|
|
2357
1877
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
2358
1878
|
style: {
|
|
@@ -2365,7 +1885,7 @@ function RichTextEditor(_ref) {
|
|
|
2365
1885
|
type: "button",
|
|
2366
1886
|
title: "Add Row Above",
|
|
2367
1887
|
className: "rte-toolbar-button",
|
|
2368
|
-
onMouseDown:
|
|
1888
|
+
onMouseDown: e => {
|
|
2369
1889
|
e.preventDefault();
|
|
2370
1890
|
tableAction('addRowAbove');
|
|
2371
1891
|
}
|
|
@@ -2373,7 +1893,7 @@ function RichTextEditor(_ref) {
|
|
|
2373
1893
|
type: "button",
|
|
2374
1894
|
title: "Add Row Below",
|
|
2375
1895
|
className: "rte-toolbar-button",
|
|
2376
|
-
onMouseDown:
|
|
1896
|
+
onMouseDown: e => {
|
|
2377
1897
|
e.preventDefault();
|
|
2378
1898
|
tableAction('addRowBelow');
|
|
2379
1899
|
}
|
|
@@ -2381,7 +1901,7 @@ function RichTextEditor(_ref) {
|
|
|
2381
1901
|
type: "button",
|
|
2382
1902
|
title: "Add Col Before",
|
|
2383
1903
|
className: "rte-toolbar-button",
|
|
2384
|
-
onMouseDown:
|
|
1904
|
+
onMouseDown: e => {
|
|
2385
1905
|
e.preventDefault();
|
|
2386
1906
|
tableAction('addColBefore');
|
|
2387
1907
|
}
|
|
@@ -2389,38 +1909,36 @@ function RichTextEditor(_ref) {
|
|
|
2389
1909
|
type: "button",
|
|
2390
1910
|
title: "Add Col After",
|
|
2391
1911
|
className: "rte-toolbar-button",
|
|
2392
|
-
onMouseDown:
|
|
1912
|
+
onMouseDown: e => {
|
|
2393
1913
|
e.preventDefault();
|
|
2394
1914
|
tableAction('addColAfter');
|
|
2395
1915
|
}
|
|
2396
|
-
}, "+C\u2192"), /*#__PURE__*/React.createElement("
|
|
2397
|
-
style: {
|
|
2398
|
-
width: '1px',
|
|
2399
|
-
height: '20px',
|
|
2400
|
-
backgroundColor: '#f3f4f6',
|
|
2401
|
-
margin: '0 4px'
|
|
2402
|
-
}
|
|
2403
|
-
}), /*#__PURE__*/React.createElement("button", {
|
|
1916
|
+
}, "+C\u2192"), /*#__PURE__*/React.createElement("button", {
|
|
2404
1917
|
type: "button",
|
|
2405
1918
|
title: "Merge Cells (Right)",
|
|
2406
1919
|
className: "rte-toolbar-button",
|
|
2407
|
-
onMouseDown:
|
|
1920
|
+
onMouseDown: e => {
|
|
2408
1921
|
e.preventDefault();
|
|
2409
1922
|
tableAction('mergeRight');
|
|
2410
1923
|
}
|
|
2411
1924
|
}, /*#__PURE__*/React.createElement(FaObjectGroup, {
|
|
2412
1925
|
size: 14
|
|
2413
|
-
})), /*#__PURE__*/React.createElement("
|
|
1926
|
+
})), /*#__PURE__*/React.createElement("div", {
|
|
1927
|
+
style: {
|
|
1928
|
+
display: 'flex',
|
|
1929
|
+
gap: '10px'
|
|
1930
|
+
}
|
|
1931
|
+
}, /*#__PURE__*/React.createElement("button", {
|
|
2414
1932
|
type: "button",
|
|
2415
1933
|
title: "Delete Row",
|
|
2416
|
-
className: "rte-toolbar-button rte-toolbar-button-danger
|
|
2417
|
-
onMouseDown:
|
|
1934
|
+
className: "rte-toolbar-button rte-toolbar-button-danger",
|
|
1935
|
+
onMouseDown: e => {
|
|
2418
1936
|
e.preventDefault();
|
|
2419
1937
|
tableAction('deleteRow');
|
|
2420
1938
|
}
|
|
2421
1939
|
}, /*#__PURE__*/React.createElement(FaTrash, {
|
|
2422
1940
|
size: 12
|
|
2423
|
-
}),
|
|
1941
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
2424
1942
|
style: {
|
|
2425
1943
|
fontSize: '10px'
|
|
2426
1944
|
}
|
|
@@ -2428,47 +1946,42 @@ function RichTextEditor(_ref) {
|
|
|
2428
1946
|
type: "button",
|
|
2429
1947
|
title: "Delete Column",
|
|
2430
1948
|
className: "rte-toolbar-button rte-toolbar-button-danger",
|
|
2431
|
-
onMouseDown:
|
|
1949
|
+
onMouseDown: e => {
|
|
2432
1950
|
e.preventDefault();
|
|
2433
1951
|
tableAction('deleteCol');
|
|
2434
1952
|
}
|
|
2435
1953
|
}, /*#__PURE__*/React.createElement(FaTrash, {
|
|
2436
1954
|
size: 12
|
|
2437
|
-
}),
|
|
1955
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
2438
1956
|
style: {
|
|
2439
|
-
fontSize: '10px'
|
|
2440
|
-
marginRight: "5px"
|
|
1957
|
+
fontSize: '10px'
|
|
2441
1958
|
}
|
|
2442
1959
|
}, "Col")), /*#__PURE__*/React.createElement("button", {
|
|
2443
1960
|
type: "button",
|
|
2444
1961
|
title: "Delete Table",
|
|
2445
1962
|
className: "rte-toolbar-button rte-toolbar-button-danger",
|
|
2446
|
-
onMouseDown:
|
|
1963
|
+
onMouseDown: e => {
|
|
2447
1964
|
e.preventDefault();
|
|
2448
1965
|
tableAction('deleteTable');
|
|
2449
1966
|
}
|
|
2450
1967
|
}, /*#__PURE__*/React.createElement(FaTrash, {
|
|
2451
|
-
size:
|
|
2452
|
-
}),
|
|
1968
|
+
size: 12
|
|
1969
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
2453
1970
|
style: {
|
|
2454
|
-
|
|
1971
|
+
fontSize: '10px'
|
|
2455
1972
|
}
|
|
2456
|
-
}, "Table")));
|
|
1973
|
+
}, "Table"))));
|
|
2457
1974
|
}
|
|
2458
1975
|
return null;
|
|
2459
|
-
}()), /*#__PURE__*/React.createElement("div", {
|
|
1976
|
+
})()), /*#__PURE__*/React.createElement("div", {
|
|
2460
1977
|
ref: editorRef,
|
|
2461
1978
|
contentEditable: editable && disabled !== true,
|
|
2462
1979
|
suppressContentEditableWarning: true,
|
|
2463
1980
|
onInput: handleInput,
|
|
2464
1981
|
onPaste: handlePaste,
|
|
2465
1982
|
onDrop: handleDrop,
|
|
2466
|
-
onDragStart:
|
|
2467
|
-
|
|
2468
|
-
},
|
|
2469
|
-
onDragOver: function onDragOver(e) {
|
|
2470
|
-
return e.preventDefault();
|
|
2471
|
-
},
|
|
1983
|
+
onDragStart: e => e.preventDefault(),
|
|
1984
|
+
onDragOver: e => e.preventDefault(),
|
|
2472
1985
|
onKeyDown: handleKeyDown,
|
|
2473
1986
|
onClick: handleEditorClick,
|
|
2474
1987
|
style: {
|
|
@@ -2477,30 +1990,22 @@ function RichTextEditor(_ref) {
|
|
|
2477
1990
|
paddingLeft: paddingLeft || '12px'
|
|
2478
1991
|
},
|
|
2479
1992
|
className: "rte-content"
|
|
2480
|
-
}),
|
|
1993
|
+
}), renderImageToolbar(), /*#__PURE__*/React.createElement("div", {
|
|
2481
1994
|
className: "rte-footer"
|
|
2482
|
-
},
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
}, /*#__PURE__*/React.createElement("b", null, words), " words"), /*#__PURE__*/React.createElement("span", {
|
|
2492
|
-
className: "rte-footer-separator"
|
|
2493
|
-
}, "\u2022"), /*#__PURE__*/React.createElement("span", {
|
|
2494
|
-
className: "rte-footer-item"
|
|
2495
|
-
}, /*#__PURE__*/React.createElement("b", null, chars), " characters"));
|
|
2496
|
-
}()), linkModalOpen && /*#__PURE__*/React.createElement("div", {
|
|
1995
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
1996
|
+
className: "rte-footer-content"
|
|
1997
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
1998
|
+
className: "rte-footer-item"
|
|
1999
|
+
}, /*#__PURE__*/React.createElement("b", null, metrics.words), " words"), /*#__PURE__*/React.createElement("span", {
|
|
2000
|
+
className: "rte-footer-separator"
|
|
2001
|
+
}, "\u2022"), /*#__PURE__*/React.createElement("span", {
|
|
2002
|
+
className: "rte-footer-item"
|
|
2003
|
+
}, /*#__PURE__*/React.createElement("b", null, metrics.chars), " characters"))), linkModalOpen && /*#__PURE__*/React.createElement("div", {
|
|
2497
2004
|
className: "rte-modal-overlay",
|
|
2498
2005
|
onClick: cancelLink
|
|
2499
2006
|
}, /*#__PURE__*/React.createElement("div", {
|
|
2500
2007
|
className: "rte-modal",
|
|
2501
|
-
onClick:
|
|
2502
|
-
return e.stopPropagation();
|
|
2503
|
-
}
|
|
2008
|
+
onClick: e => e.stopPropagation()
|
|
2504
2009
|
}, /*#__PURE__*/React.createElement("h3", {
|
|
2505
2010
|
className: "rte-modal-title"
|
|
2506
2011
|
}, "Insert Link"), /*#__PURE__*/React.createElement("div", {
|
|
@@ -2516,9 +2021,7 @@ function RichTextEditor(_ref) {
|
|
|
2516
2021
|
className: "rte-input",
|
|
2517
2022
|
placeholder: "e.g. Google",
|
|
2518
2023
|
value: linkText,
|
|
2519
|
-
onChange:
|
|
2520
|
-
return setLinkText(e.target.value);
|
|
2521
|
-
}
|
|
2024
|
+
onChange: e => setLinkText(e.target.value)
|
|
2522
2025
|
})), /*#__PURE__*/React.createElement("div", {
|
|
2523
2026
|
className: "rte-form-group"
|
|
2524
2027
|
}, /*#__PURE__*/React.createElement("label", {
|
|
@@ -2528,12 +2031,8 @@ function RichTextEditor(_ref) {
|
|
|
2528
2031
|
className: "rte-input",
|
|
2529
2032
|
placeholder: "https://example.com",
|
|
2530
2033
|
value: linkUrl,
|
|
2531
|
-
onChange:
|
|
2532
|
-
|
|
2533
|
-
},
|
|
2534
|
-
onKeyDown: function onKeyDown(e) {
|
|
2535
|
-
return e.key === 'Enter' && confirmLink();
|
|
2536
|
-
},
|
|
2034
|
+
onChange: e => setLinkUrl(e.target.value),
|
|
2035
|
+
onKeyDown: e => e.key === 'Enter' && confirmLink(),
|
|
2537
2036
|
autoFocus: true
|
|
2538
2037
|
}))), /*#__PURE__*/React.createElement("div", {
|
|
2539
2038
|
className: "rte-modal-divider",
|
|
@@ -2553,14 +2052,10 @@ function RichTextEditor(_ref) {
|
|
|
2553
2052
|
disabled: !linkUrl
|
|
2554
2053
|
}, "Insert")))), tableModalOpen && /*#__PURE__*/React.createElement("div", {
|
|
2555
2054
|
className: "rte-modal-overlay",
|
|
2556
|
-
onClick:
|
|
2557
|
-
return setTableModalOpen(false);
|
|
2558
|
-
}
|
|
2055
|
+
onClick: () => setTableModalOpen(false)
|
|
2559
2056
|
}, /*#__PURE__*/React.createElement("div", {
|
|
2560
2057
|
className: "rte-modal",
|
|
2561
|
-
onClick:
|
|
2562
|
-
return e.stopPropagation();
|
|
2563
|
-
}
|
|
2058
|
+
onClick: e => e.stopPropagation()
|
|
2564
2059
|
}, /*#__PURE__*/React.createElement("h3", {
|
|
2565
2060
|
className: "rte-modal-title"
|
|
2566
2061
|
}, "Insert Table"), /*#__PURE__*/React.createElement("div", {
|
|
@@ -2571,9 +2066,7 @@ function RichTextEditor(_ref) {
|
|
|
2571
2066
|
type: "number",
|
|
2572
2067
|
className: "rte-input",
|
|
2573
2068
|
value: tableRows,
|
|
2574
|
-
onChange:
|
|
2575
|
-
return setTableRows(e.target.value);
|
|
2576
|
-
},
|
|
2069
|
+
onChange: e => setTableRows(e.target.value),
|
|
2577
2070
|
min: "1",
|
|
2578
2071
|
max: "10"
|
|
2579
2072
|
})), /*#__PURE__*/React.createElement("div", {
|
|
@@ -2584,9 +2077,7 @@ function RichTextEditor(_ref) {
|
|
|
2584
2077
|
type: "number",
|
|
2585
2078
|
className: "rte-input",
|
|
2586
2079
|
value: tableCols,
|
|
2587
|
-
onChange:
|
|
2588
|
-
return setTableCols(e.target.value);
|
|
2589
|
-
},
|
|
2080
|
+
onChange: e => setTableCols(e.target.value),
|
|
2590
2081
|
min: "1",
|
|
2591
2082
|
max: "10"
|
|
2592
2083
|
})), /*#__PURE__*/React.createElement("div", {
|
|
@@ -2594,56 +2085,55 @@ function RichTextEditor(_ref) {
|
|
|
2594
2085
|
}, /*#__PURE__*/React.createElement("button", {
|
|
2595
2086
|
type: "button",
|
|
2596
2087
|
className: "rte-button rte-button-secondary",
|
|
2597
|
-
onClick:
|
|
2598
|
-
return setTableModalOpen(false);
|
|
2599
|
-
}
|
|
2088
|
+
onClick: () => setTableModalOpen(false)
|
|
2600
2089
|
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
|
|
2601
2090
|
type: "button",
|
|
2602
2091
|
className: "rte-button rte-button-primary",
|
|
2603
2092
|
onClick: insertTable
|
|
2604
|
-
}, "Insert")))),
|
|
2093
|
+
}, "Insert")))), videoModalOpen && /*#__PURE__*/React.createElement("div", {
|
|
2605
2094
|
className: "rte-modal-overlay",
|
|
2606
|
-
onClick:
|
|
2607
|
-
return setYoutubeModalOpen(false);
|
|
2608
|
-
}
|
|
2095
|
+
onClick: () => setVideoModalOpen(false)
|
|
2609
2096
|
}, /*#__PURE__*/React.createElement("div", {
|
|
2610
2097
|
className: "rte-modal",
|
|
2611
|
-
onClick:
|
|
2612
|
-
return e.stopPropagation();
|
|
2613
|
-
}
|
|
2098
|
+
onClick: e => e.stopPropagation()
|
|
2614
2099
|
}, /*#__PURE__*/React.createElement("div", {
|
|
2615
2100
|
className: "rte-modal-header"
|
|
2616
2101
|
}, /*#__PURE__*/React.createElement("h3", {
|
|
2617
2102
|
className: "rte-modal-title"
|
|
2618
|
-
}, "Embed
|
|
2103
|
+
}, "Embed Video")), /*#__PURE__*/React.createElement("div", {
|
|
2619
2104
|
className: "rte-form-group"
|
|
2620
2105
|
}, /*#__PURE__*/React.createElement("label", {
|
|
2621
2106
|
className: "rte-label"
|
|
2622
|
-
}, "Paste YouTube
|
|
2107
|
+
}, "Paste Video URL (YouTube, Vimeo...) ", /*#__PURE__*/React.createElement("span", {
|
|
2108
|
+
style: {
|
|
2109
|
+
color: '#ef4444'
|
|
2110
|
+
}
|
|
2111
|
+
}, "*")), /*#__PURE__*/React.createElement("input", {
|
|
2623
2112
|
type: "text",
|
|
2624
2113
|
className: "rte-input",
|
|
2625
|
-
value:
|
|
2626
|
-
onChange:
|
|
2627
|
-
|
|
2628
|
-
},
|
|
2629
|
-
placeholder: "https://www.youtube.com/watch?v=...",
|
|
2114
|
+
value: videoUrl,
|
|
2115
|
+
onChange: e => setVideoUrl(e.target.value),
|
|
2116
|
+
placeholder: "Paste URL here...",
|
|
2630
2117
|
autoFocus: true,
|
|
2631
|
-
onKeyDown:
|
|
2632
|
-
if (e.key === 'Enter')
|
|
2633
|
-
if (e.key === 'Escape')
|
|
2118
|
+
onKeyDown: e => {
|
|
2119
|
+
if (e.key === 'Enter' && videoUrl.trim()) insertVideo();
|
|
2120
|
+
if (e.key === 'Escape') setVideoModalOpen(false);
|
|
2634
2121
|
}
|
|
2635
2122
|
})), /*#__PURE__*/React.createElement("div", {
|
|
2636
2123
|
className: "rte-modal-actions"
|
|
2637
2124
|
}, /*#__PURE__*/React.createElement("button", {
|
|
2638
2125
|
type: "button",
|
|
2639
2126
|
className: "rte-button rte-button-secondary",
|
|
2640
|
-
onClick:
|
|
2641
|
-
return setYoutubeModalOpen(false);
|
|
2642
|
-
}
|
|
2127
|
+
onClick: () => setVideoModalOpen(false)
|
|
2643
2128
|
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
|
|
2644
2129
|
type: "button",
|
|
2645
2130
|
className: "rte-button rte-button-primary",
|
|
2646
|
-
onClick:
|
|
2131
|
+
onClick: () => {
|
|
2132
|
+
if (videoUrl.trim()) {
|
|
2133
|
+
insertVideo();
|
|
2134
|
+
}
|
|
2135
|
+
},
|
|
2136
|
+
disabled: !videoUrl.trim()
|
|
2647
2137
|
}, "Embed Video")))), imageModalOpen && /*#__PURE__*/React.createElement("div", {
|
|
2648
2138
|
className: "rte-modal-overlay",
|
|
2649
2139
|
onClick: closeImageModal
|
|
@@ -2653,16 +2143,14 @@ function RichTextEditor(_ref) {
|
|
|
2653
2143
|
maxWidth: "90%",
|
|
2654
2144
|
maxHeight: "90%"
|
|
2655
2145
|
},
|
|
2656
|
-
onClick:
|
|
2657
|
-
return e.stopPropagation();
|
|
2658
|
-
}
|
|
2146
|
+
onClick: e => e.stopPropagation()
|
|
2659
2147
|
}, /*#__PURE__*/React.createElement("img", {
|
|
2660
2148
|
src: selectedImageUrl,
|
|
2661
2149
|
style: {
|
|
2662
2150
|
width: "100%",
|
|
2663
2151
|
maxHeight: "90vh",
|
|
2664
2152
|
borderRadius: '12px',
|
|
2665
|
-
transform:
|
|
2153
|
+
transform: `scale(${zoomLevel})`,
|
|
2666
2154
|
transition: "transform 0.2s ease",
|
|
2667
2155
|
boxShadow: '0 25px 50px -12px rgba(0,0,0,0.5)'
|
|
2668
2156
|
},
|
|
@@ -2677,13 +2165,11 @@ function RichTextEditor(_ref) {
|
|
|
2677
2165
|
}, /*#__PURE__*/React.createElement("button", {
|
|
2678
2166
|
type: "button",
|
|
2679
2167
|
className: "rte-button rte-button-secondary",
|
|
2680
|
-
onClick:
|
|
2681
|
-
return setEditable(false);
|
|
2682
|
-
}
|
|
2168
|
+
onClick: () => setEditable(false)
|
|
2683
2169
|
}, "Cancel"), /*#__PURE__*/React.createElement("button", {
|
|
2684
2170
|
type: "button",
|
|
2685
2171
|
className: "rte-button rte-button-primary",
|
|
2686
|
-
onClick:
|
|
2172
|
+
onClick: () => {
|
|
2687
2173
|
onChange && onChange(html);
|
|
2688
2174
|
setEditable(false);
|
|
2689
2175
|
}
|