@editora/core 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs +475 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs.map +1 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs +340 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs.map +1 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs +449 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs.map +1 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs +48 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs.map +1 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs +45 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs.map +1 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs +79 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs.map +1 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs +153 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs.map +1 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs +27 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs.map +1 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs +1679 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs.map +1 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs +326 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs.map +1 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs +473 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs.map +1 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs +59 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs.map +1 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs +116 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs.map +1 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs +461 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs.map +1 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs +1033 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs.map +1 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs +106 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs.map +1 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs +186 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs.map +1 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs +128 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs.map +1 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs +77 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs.map +1 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs +64 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs.map +1 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs +89 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs.map +1 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs +133 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs.map +1 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs +43 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs.map +1 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs +73 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs.map +1 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs +206 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs.map +1 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs +59 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs.map +1 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs +182 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs.map +1 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs +533 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs.map +1 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs +178 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs.map +1 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs +172 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs.map +1 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs +322 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs.map +1 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs +311 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs.map +1 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs +731 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs.map +1 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs +465 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs.map +1 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs +43 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs.map +1 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs +491 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs.map +1 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs +564 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs.map +1 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs +97 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs.map +1 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs +432 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs.map +1 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs +35 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs.map +1 -0
- package/dist/core.css +1 -0
- package/dist/documentManager-irzj9n3V.mjs +37627 -0
- package/dist/documentManager-irzj9n3V.mjs.map +1 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs +27 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs.map +1 -0
- package/dist/editora.min.js +519 -4
- package/dist/editora.min.js.map +1 -0
- package/dist/editora.umd.js +519 -4
- package/dist/editora.umd.js.map +1 -0
- package/dist/index-BF5RBhL9.js +4 -0
- package/dist/index-BF5RBhL9.js.map +1 -0
- package/dist/index-BPsf460l.mjs +1243 -0
- package/dist/index-BPsf460l.mjs.map +1 -0
- package/dist/index.cjs.js +517 -4
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.es-CuicffkQ.mjs +6665 -0
- package/dist/index.es-CuicffkQ.mjs.map +1 -0
- package/dist/index.esm.js +1403 -122
- package/dist/index.esm.js.map +1 -0
- package/dist/plugin-loader.js +55 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/purify.es-CKpwg8Tk.mjs +471 -0
- package/dist/purify.es-CKpwg8Tk.mjs.map +1 -0
- package/dist/webcomponent-core.js +1243 -0
- package/dist/webcomponent-core.js.map +1 -0
- package/dist/webcomponent-core.min.css +1 -0
- package/dist/webcomponent-core.min.js +597 -0
- package/dist/webcomponent-core.min.js.map +1 -0
- package/dist/webcomponent.cjs.js +2 -0
- package/dist/webcomponent.cjs.js.map +1 -0
- package/dist/webcomponent.esm.js +6 -0
- package/dist/webcomponent.esm.js.map +1 -0
- package/dist/webcomponent.js +1286 -0
- package/dist/webcomponent.js.map +1 -0
- package/dist/webcomponent.min.css +1 -0
- package/dist/webcomponent.min.js +4076 -0
- package/dist/webcomponent.min.js.map +1 -0
- package/package.json +64 -6
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
const u = /* @__PURE__ */ new Map();
|
|
2
|
+
let x = !1, d = null, C = /* @__PURE__ */ new Set(), v = {}, h = null, p = "";
|
|
3
|
+
const w = "User";
|
|
4
|
+
let y = null;
|
|
5
|
+
function R() {
|
|
6
|
+
return Array.from(u.values());
|
|
7
|
+
}
|
|
8
|
+
function S(e, o, t = !1) {
|
|
9
|
+
if (t) {
|
|
10
|
+
const b = `comment-${Date.now()}`, B = {
|
|
11
|
+
id: b,
|
|
12
|
+
anchorId: "",
|
|
13
|
+
selectedText: "",
|
|
14
|
+
author: e,
|
|
15
|
+
text: o,
|
|
16
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17
|
+
resolved: !1,
|
|
18
|
+
replies: []
|
|
19
|
+
};
|
|
20
|
+
return u.set(b, B), s(), b;
|
|
21
|
+
}
|
|
22
|
+
const n = window.getSelection();
|
|
23
|
+
if (!n || n.rangeCount === 0) return "";
|
|
24
|
+
const c = h || n.getRangeAt(0), g = c.toString();
|
|
25
|
+
if (!g) return "";
|
|
26
|
+
const a = `comment-${Date.now()}`, f = `comment-anchor-${Date.now()}`, l = document.createElement("span");
|
|
27
|
+
l.id = f, l.className = "rte-comment-anchor", l.setAttribute("data-comment-id", a), l.style.cssText = `
|
|
28
|
+
background-color: #ffeb3b;
|
|
29
|
+
border-bottom: 2px solid #fbc02d;
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
position: relative;
|
|
32
|
+
`, l.title = "Click to view comment";
|
|
33
|
+
const r = c.cloneRange(), i = r.extractContents();
|
|
34
|
+
l.appendChild(i), r.insertNode(l);
|
|
35
|
+
const m = {
|
|
36
|
+
id: a,
|
|
37
|
+
anchorId: f,
|
|
38
|
+
selectedText: g,
|
|
39
|
+
author: e,
|
|
40
|
+
text: o,
|
|
41
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42
|
+
resolved: !1,
|
|
43
|
+
replies: []
|
|
44
|
+
};
|
|
45
|
+
return u.set(a, m), l.onclick = () => {
|
|
46
|
+
x = !0, k();
|
|
47
|
+
}, s(), h = null, n.removeAllRanges(), a;
|
|
48
|
+
}
|
|
49
|
+
function z(e, o) {
|
|
50
|
+
const t = u.get(e);
|
|
51
|
+
if (t) {
|
|
52
|
+
if (t.resolved = !0, t.resolvedAt = (/* @__PURE__ */ new Date()).toISOString(), t.resolvedBy = o, t.anchorId) {
|
|
53
|
+
const n = document.getElementById(t.anchorId);
|
|
54
|
+
n && (n.style.backgroundColor = "#e0e0e0", n.style.borderBottom = "2px solid #bdbdbd", n.style.opacity = "0.6");
|
|
55
|
+
}
|
|
56
|
+
s();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function L(e) {
|
|
60
|
+
const o = u.get(e);
|
|
61
|
+
if (o) {
|
|
62
|
+
if (o.resolved = !1, o.resolvedAt = void 0, o.resolvedBy = void 0, o.anchorId) {
|
|
63
|
+
const t = document.getElementById(o.anchorId);
|
|
64
|
+
t && (t.style.backgroundColor = "#ffeb3b", t.style.borderBottom = "2px solid #fbc02d", t.style.opacity = "1");
|
|
65
|
+
}
|
|
66
|
+
s();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function N(e) {
|
|
70
|
+
const o = u.get(e);
|
|
71
|
+
if (o) {
|
|
72
|
+
if (o.anchorId) {
|
|
73
|
+
const t = document.getElementById(o.anchorId);
|
|
74
|
+
if (t) {
|
|
75
|
+
const n = t.parentNode;
|
|
76
|
+
for (; t.firstChild; )
|
|
77
|
+
n == null || n.insertBefore(t.firstChild, t);
|
|
78
|
+
t.remove();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
u.delete(e), s();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function T(e, o, t) {
|
|
85
|
+
const n = u.get(e);
|
|
86
|
+
if (!n) return;
|
|
87
|
+
const c = {
|
|
88
|
+
id: `reply-${Date.now()}`,
|
|
89
|
+
author: o,
|
|
90
|
+
text: t,
|
|
91
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
92
|
+
};
|
|
93
|
+
n.replies.push(c), s();
|
|
94
|
+
}
|
|
95
|
+
function E(e, o) {
|
|
96
|
+
const t = u.get(e);
|
|
97
|
+
if (!t || !t.anchorId) return;
|
|
98
|
+
const n = document.getElementById(t.anchorId);
|
|
99
|
+
n && (o ? (n.classList.add("highlighted"), n.style.outline = "2px solid #0066cc", n.style.outlineOffset = "2px") : (n.classList.remove("highlighted"), n.style.outline = "none"));
|
|
100
|
+
}
|
|
101
|
+
function k() {
|
|
102
|
+
if (d) {
|
|
103
|
+
d.style.display = x ? "block" : "none", x ? (s(), I()) : A();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const e = document.createElement("div");
|
|
107
|
+
e.className = "rte-comments-panel", d = e, document.body.appendChild(e), s(), I(), V();
|
|
108
|
+
}
|
|
109
|
+
function I() {
|
|
110
|
+
y || (y = () => {
|
|
111
|
+
const e = window.getSelection();
|
|
112
|
+
e && e.rangeCount > 0 && !e.isCollapsed && (h = e.getRangeAt(0).cloneRange());
|
|
113
|
+
}, document.addEventListener("selectionchange", y));
|
|
114
|
+
}
|
|
115
|
+
function A() {
|
|
116
|
+
y && (document.removeEventListener("selectionchange", y), y = null), h = null;
|
|
117
|
+
}
|
|
118
|
+
function s() {
|
|
119
|
+
if (!d) return;
|
|
120
|
+
const e = R();
|
|
121
|
+
d.innerHTML = `
|
|
122
|
+
<div class="comments-header" style="display: flex; justify-content: space-between; align-items: center;">
|
|
123
|
+
<h3 style="margin: 0;">Comments (${e.length})</h3>
|
|
124
|
+
<button class="rte-comments-close" aria-label="Close comments panel">✕</button>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div class="comment-add-box">
|
|
128
|
+
<textarea class="new-comment-textarea" placeholder="Add a new comment..." rows="2"></textarea>
|
|
129
|
+
<button class="rte-button-small add-comment-btn">Add Comment</button>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
${e.length === 0 ? '<div class="comments-empty">No comments yet</div>' : '<div class="comments-list"></div>'}
|
|
133
|
+
`;
|
|
134
|
+
const o = d.querySelector(".rte-comments-close");
|
|
135
|
+
o && o.addEventListener("click", () => {
|
|
136
|
+
x = !1, d && (d.style.display = "none"), A();
|
|
137
|
+
});
|
|
138
|
+
const t = d.querySelector(".new-comment-textarea"), n = d.querySelector(".add-comment-btn");
|
|
139
|
+
if (t && n && (t.value = p, t.oninput = () => {
|
|
140
|
+
p = t.value, n.disabled = !p.trim(), n.style.opacity = p.trim() ? "1" : "0.5";
|
|
141
|
+
}, n.disabled = !p.trim(), n.style.opacity = p.trim() ? "1" : "0.5", n.onclick = () => {
|
|
142
|
+
if (!p.trim()) {
|
|
143
|
+
alert("Comment cannot be empty"), t.focus();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
h ? S(w, p.trim()) : S(w, p.trim(), !0), p = "", t.value = "", s();
|
|
147
|
+
}), e.length > 0) {
|
|
148
|
+
const c = d.querySelector(".comments-list");
|
|
149
|
+
c && e.forEach((g) => {
|
|
150
|
+
const a = D(g);
|
|
151
|
+
c.appendChild(a);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function D(e) {
|
|
156
|
+
const o = C.has(e.id), t = document.createElement("div");
|
|
157
|
+
t.className = `comment-item${e.resolved ? " resolved" : ""}`;
|
|
158
|
+
const n = document.createElement("div");
|
|
159
|
+
n.className = "comment-header", n.innerHTML = `
|
|
160
|
+
<div class="comment-meta">
|
|
161
|
+
<strong>${e.author}</strong>
|
|
162
|
+
<span class="comment-date">${new Date(e.createdAt).toLocaleDateString()}</span>
|
|
163
|
+
</div>
|
|
164
|
+
<button class="comment-expand" aria-label="Toggle comment">${o ? "▼" : "▶"}</button>
|
|
165
|
+
`;
|
|
166
|
+
const c = n.querySelector(".comment-expand");
|
|
167
|
+
c && c.addEventListener("click", () => {
|
|
168
|
+
C.has(e.id) ? C.delete(e.id) : C.add(e.id), s();
|
|
169
|
+
}), t.appendChild(n);
|
|
170
|
+
const g = document.createElement("div");
|
|
171
|
+
if (g.className = "comment-text", g.textContent = e.text, t.appendChild(g), e.selectedText) {
|
|
172
|
+
const a = document.createElement("div");
|
|
173
|
+
a.className = "comment-selection", a.textContent = `"${e.selectedText}"`, t.appendChild(a);
|
|
174
|
+
}
|
|
175
|
+
if (o) {
|
|
176
|
+
const a = document.createElement("div");
|
|
177
|
+
if (a.className = "comment-expanded", e.replies.length > 0) {
|
|
178
|
+
const r = document.createElement("div");
|
|
179
|
+
r.className = "comment-replies", e.replies.forEach((i) => {
|
|
180
|
+
const m = document.createElement("div");
|
|
181
|
+
m.className = "comment-reply", m.innerHTML = `
|
|
182
|
+
<div class="reply-header">
|
|
183
|
+
<strong>${i.author}</strong>
|
|
184
|
+
<span class="reply-date">${new Date(i.createdAt).toLocaleDateString()}</span>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="reply-text">${i.text}</div>
|
|
187
|
+
`, r.appendChild(m);
|
|
188
|
+
}), a.appendChild(r);
|
|
189
|
+
}
|
|
190
|
+
if (!e.resolved) {
|
|
191
|
+
const r = document.createElement("div");
|
|
192
|
+
r.className = "comment-reply-input";
|
|
193
|
+
const i = document.createElement("textarea");
|
|
194
|
+
i.placeholder = "Add a reply...", i.rows = 2, i.value = v[e.id] || "", i.oninput = () => {
|
|
195
|
+
v[e.id] = i.value;
|
|
196
|
+
};
|
|
197
|
+
const m = document.createElement("button");
|
|
198
|
+
m.className = "rte-button-small", m.textContent = "Reply", m.onclick = () => {
|
|
199
|
+
var b;
|
|
200
|
+
(b = v[e.id]) != null && b.trim() && (T(e.id, w, v[e.id]), v[e.id] = "", s());
|
|
201
|
+
}, r.appendChild(i), r.appendChild(m), a.appendChild(r);
|
|
202
|
+
}
|
|
203
|
+
const f = document.createElement("div");
|
|
204
|
+
if (f.className = "comment-actions", e.resolved) {
|
|
205
|
+
const r = document.createElement("button");
|
|
206
|
+
r.className = "action-button reopen", r.textContent = "↻ Reopen", r.onclick = () => L(e.id), f.appendChild(r);
|
|
207
|
+
} else {
|
|
208
|
+
const r = document.createElement("button");
|
|
209
|
+
r.className = "action-button resolve", r.textContent = "✓ Resolve", r.onclick = () => z(e.id, w), f.appendChild(r);
|
|
210
|
+
}
|
|
211
|
+
const l = document.createElement("button");
|
|
212
|
+
l.className = "action-button delete", l.textContent = "🗑 Delete", l.onclick = () => {
|
|
213
|
+
confirm("Delete this comment?") && N(e.id);
|
|
214
|
+
}, f.appendChild(l), a.appendChild(f), t.appendChild(a);
|
|
215
|
+
}
|
|
216
|
+
return t.onmouseenter = () => E(e.id, !0), t.onmouseleave = () => E(e.id, !1), t;
|
|
217
|
+
}
|
|
218
|
+
function V() {
|
|
219
|
+
if (document.getElementById("rte-comments-panel-styles")) return;
|
|
220
|
+
const e = document.createElement("style");
|
|
221
|
+
e.id = "rte-comments-panel-styles", e.textContent = `
|
|
222
|
+
.rte-comments-close:hover {
|
|
223
|
+
color: #d32f2f;
|
|
224
|
+
}
|
|
225
|
+
.rte-comments-panel {
|
|
226
|
+
position: fixed;
|
|
227
|
+
right: 0;
|
|
228
|
+
top: 0;
|
|
229
|
+
width: 350px;
|
|
230
|
+
height: 100%;
|
|
231
|
+
background: white;
|
|
232
|
+
border-left: 1px solid #ddd;
|
|
233
|
+
box-shadow: -2px 0 4px rgba(0,0,0,0.1);
|
|
234
|
+
overflow-y: auto;
|
|
235
|
+
z-index: 1000;
|
|
236
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
237
|
+
display: flex;
|
|
238
|
+
flex-direction: column;
|
|
239
|
+
}
|
|
240
|
+
.comments-header {
|
|
241
|
+
padding: 16px;
|
|
242
|
+
border-bottom: 1px solid #eee;
|
|
243
|
+
background-color: #fafafa;
|
|
244
|
+
}
|
|
245
|
+
.comments-header h3 {
|
|
246
|
+
margin: 0;
|
|
247
|
+
font-size: 14px;
|
|
248
|
+
font-weight: 600;
|
|
249
|
+
}
|
|
250
|
+
.rte-comments-close {
|
|
251
|
+
background: none;
|
|
252
|
+
border: none;
|
|
253
|
+
font-size: 22px;
|
|
254
|
+
cursor: pointer;
|
|
255
|
+
color: #888;
|
|
256
|
+
margin-left: 8px;
|
|
257
|
+
padding: 0;
|
|
258
|
+
}
|
|
259
|
+
.comment-add-box {
|
|
260
|
+
padding: 12px;
|
|
261
|
+
border-bottom: 1px solid #eee;
|
|
262
|
+
background: #fafafa;
|
|
263
|
+
display: flex;
|
|
264
|
+
flex-direction: column;
|
|
265
|
+
gap: 8px;
|
|
266
|
+
}
|
|
267
|
+
.new-comment-textarea {
|
|
268
|
+
font-size: 13px;
|
|
269
|
+
padding: 8px;
|
|
270
|
+
border-radius: 3px;
|
|
271
|
+
border: 1px solid #ddd;
|
|
272
|
+
resize: vertical;
|
|
273
|
+
font-family: inherit;
|
|
274
|
+
}
|
|
275
|
+
.comments-empty {
|
|
276
|
+
padding: 16px;
|
|
277
|
+
text-align: center;
|
|
278
|
+
color: #999;
|
|
279
|
+
font-size: 13px;
|
|
280
|
+
}
|
|
281
|
+
.comments-list {
|
|
282
|
+
padding: 12px;
|
|
283
|
+
}
|
|
284
|
+
.comment-item {
|
|
285
|
+
padding: 12px;
|
|
286
|
+
margin-bottom: 12px;
|
|
287
|
+
border: 1px solid #eee;
|
|
288
|
+
border-radius: 4px;
|
|
289
|
+
background-color: white;
|
|
290
|
+
transition: all 0.2s;
|
|
291
|
+
}
|
|
292
|
+
.comment-item:hover {
|
|
293
|
+
border-color: #ddd;
|
|
294
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
295
|
+
}
|
|
296
|
+
.comment-item.resolved {
|
|
297
|
+
opacity: 0.6;
|
|
298
|
+
background-color: #f5f5f5;
|
|
299
|
+
}
|
|
300
|
+
.comment-header {
|
|
301
|
+
display: flex;
|
|
302
|
+
justify-content: space-between;
|
|
303
|
+
align-items: center;
|
|
304
|
+
margin-bottom: 8px;
|
|
305
|
+
}
|
|
306
|
+
.comment-meta {
|
|
307
|
+
display: flex;
|
|
308
|
+
flex-direction: column;
|
|
309
|
+
gap: 2px;
|
|
310
|
+
}
|
|
311
|
+
.comment-meta strong {
|
|
312
|
+
font-size: 13px;
|
|
313
|
+
color: #333;
|
|
314
|
+
}
|
|
315
|
+
.comment-date {
|
|
316
|
+
font-size: 11px;
|
|
317
|
+
color: #999;
|
|
318
|
+
}
|
|
319
|
+
.comment-expand {
|
|
320
|
+
background: none;
|
|
321
|
+
border: none;
|
|
322
|
+
cursor: pointer;
|
|
323
|
+
color: #666;
|
|
324
|
+
font-size: 12px;
|
|
325
|
+
padding: 0;
|
|
326
|
+
}
|
|
327
|
+
.comment-text {
|
|
328
|
+
font-size: 13px;
|
|
329
|
+
line-height: 1.4;
|
|
330
|
+
color: #333;
|
|
331
|
+
margin-bottom: 8px;
|
|
332
|
+
}
|
|
333
|
+
.comment-selection {
|
|
334
|
+
font-size: 12px;
|
|
335
|
+
color: #666;
|
|
336
|
+
font-style: italic;
|
|
337
|
+
background-color: #f9f9f9;
|
|
338
|
+
padding: 6px;
|
|
339
|
+
border-radius: 3px;
|
|
340
|
+
margin-bottom: 8px;
|
|
341
|
+
}
|
|
342
|
+
.comment-expanded {
|
|
343
|
+
margin-top: 12px;
|
|
344
|
+
padding-top: 12px;
|
|
345
|
+
border-top: 1px solid #eee;
|
|
346
|
+
}
|
|
347
|
+
.comment-replies {
|
|
348
|
+
margin-bottom: 12px;
|
|
349
|
+
}
|
|
350
|
+
.comment-reply {
|
|
351
|
+
padding: 8px;
|
|
352
|
+
background-color: #fafafa;
|
|
353
|
+
border-radius: 3px;
|
|
354
|
+
margin-bottom: 8px;
|
|
355
|
+
font-size: 12px;
|
|
356
|
+
}
|
|
357
|
+
.reply-header {
|
|
358
|
+
display: flex;
|
|
359
|
+
gap: 8px;
|
|
360
|
+
margin-bottom: 4px;
|
|
361
|
+
}
|
|
362
|
+
.reply-header strong {
|
|
363
|
+
font-size: 12px;
|
|
364
|
+
color: #333;
|
|
365
|
+
}
|
|
366
|
+
.reply-date {
|
|
367
|
+
font-size: 11px;
|
|
368
|
+
color: #999;
|
|
369
|
+
}
|
|
370
|
+
.reply-text {
|
|
371
|
+
font-size: 12px;
|
|
372
|
+
color: #666;
|
|
373
|
+
line-height: 1.3;
|
|
374
|
+
}
|
|
375
|
+
.comment-reply-input {
|
|
376
|
+
display: flex;
|
|
377
|
+
flex-direction: column;
|
|
378
|
+
gap: 6px;
|
|
379
|
+
margin-bottom: 12px;
|
|
380
|
+
}
|
|
381
|
+
.comment-reply-input textarea {
|
|
382
|
+
font-size: 12px;
|
|
383
|
+
padding: 6px;
|
|
384
|
+
border: 1px solid #ddd;
|
|
385
|
+
border-radius: 3px;
|
|
386
|
+
font-family: inherit;
|
|
387
|
+
resize: vertical;
|
|
388
|
+
}
|
|
389
|
+
.rte-button-small {
|
|
390
|
+
font-size: 12px;
|
|
391
|
+
padding: 4px 8px;
|
|
392
|
+
background-color: #1976d2;
|
|
393
|
+
color: white;
|
|
394
|
+
border: none;
|
|
395
|
+
border-radius: 3px;
|
|
396
|
+
cursor: pointer;
|
|
397
|
+
align-self: flex-end;
|
|
398
|
+
}
|
|
399
|
+
.rte-button-small:hover {
|
|
400
|
+
background-color: #1565c0;
|
|
401
|
+
}
|
|
402
|
+
.rte-button-small:disabled {
|
|
403
|
+
opacity: 0.5;
|
|
404
|
+
pointer-events: none;
|
|
405
|
+
}
|
|
406
|
+
.comment-actions {
|
|
407
|
+
display: flex;
|
|
408
|
+
gap: 6px;
|
|
409
|
+
justify-content: flex-end;
|
|
410
|
+
}
|
|
411
|
+
.action-button {
|
|
412
|
+
font-size: 12px;
|
|
413
|
+
padding: 4px 8px;
|
|
414
|
+
background-color: #f5f5f5;
|
|
415
|
+
border: 1px solid #ddd;
|
|
416
|
+
border-radius: 3px;
|
|
417
|
+
cursor: pointer;
|
|
418
|
+
transition: all 0.2s;
|
|
419
|
+
}
|
|
420
|
+
.action-button:hover {
|
|
421
|
+
background-color: #eeeeee;
|
|
422
|
+
}
|
|
423
|
+
.action-button.resolve {
|
|
424
|
+
color: #2e7d32;
|
|
425
|
+
}
|
|
426
|
+
.action-button.delete {
|
|
427
|
+
color: #c62828;
|
|
428
|
+
}
|
|
429
|
+
.rte-comment-anchor {
|
|
430
|
+
position: relative;
|
|
431
|
+
}
|
|
432
|
+
.rte-comment-anchor.highlighted {
|
|
433
|
+
background-color: #ffeb3b !important;
|
|
434
|
+
border-radius: 3px;
|
|
435
|
+
}
|
|
436
|
+
`, document.head.appendChild(e);
|
|
437
|
+
}
|
|
438
|
+
const H = () => ({
|
|
439
|
+
name: "comments",
|
|
440
|
+
toolbar: [
|
|
441
|
+
{
|
|
442
|
+
label: "Add Comment",
|
|
443
|
+
command: "addComment",
|
|
444
|
+
type: "button",
|
|
445
|
+
icon: '<svg fill="#000000" width="24px" height="24px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><defs><style>.cls-1{fill:none;}</style></defs><title>add-comment</title><path d="M17.74,30,16,29l4-7h6a2,2,0,0,0,2-2V8a2,2,0,0,0-2-2H6A2,2,0,0,0,4,8V20a2,2,0,0,0,2,2h9v2H6a4,4,0,0,1-4-4V8A4,4,0,0,1,6,4H26a4,4,0,0,1,4,4V20a4,4,0,0,1-4,4H21.16Z" transform="translate(0 0)"></path><polygon points="17 9 15 9 15 13 11 13 11 15 15 15 15 19 17 19 17 15 21 15 21 13 17 13 17 9"></polygon><rect id="_Transparent_Rectangle_" data-name="<Transparent Rectangle>" class="cls-1" width="32" height="32"></rect></g></svg>'
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
label: "Show / Hide Comments",
|
|
449
|
+
command: "toggleComments",
|
|
450
|
+
type: "button",
|
|
451
|
+
icon: '<svg width="24px" height="24px" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M16 1H4V11H8L10 13L12 11H16V1Z" fill="#000000"></path> <path d="M2 5V13H7.17157L8.70711 14.5355L7.29289 15.9497L6.34315 15H0V5H2Z" fill="#000000"></path> </g></svg>'
|
|
452
|
+
}
|
|
453
|
+
],
|
|
454
|
+
commands: {
|
|
455
|
+
addComment: () => {
|
|
456
|
+
const e = window.getSelection();
|
|
457
|
+
return e && e.rangeCount > 0 && !e.isCollapsed ? h = e.getRangeAt(0).cloneRange() : h = null, x = !0, k(), !0;
|
|
458
|
+
},
|
|
459
|
+
toggleComments: () => (x = !x, k(), !0)
|
|
460
|
+
},
|
|
461
|
+
keymap: {}
|
|
462
|
+
});
|
|
463
|
+
export {
|
|
464
|
+
H as CommentsPlugin,
|
|
465
|
+
S as addCommentCommand,
|
|
466
|
+
N as deleteComment,
|
|
467
|
+
R as getAllComments,
|
|
468
|
+
E as highlightComment,
|
|
469
|
+
L as reopenComment,
|
|
470
|
+
T as replyToComment,
|
|
471
|
+
z as resolveComment
|
|
472
|
+
};
|
|
473
|
+
//# sourceMappingURL=CommentsPlugin.native-2zQV8Ia4.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommentsPlugin.native-2zQV8Ia4.mjs","sources":["../../plugins/comments/src/CommentsPlugin.native.ts"],"sourcesContent":["import { Plugin } from '@editora/core';\n\n/**\n * Comments Plugin - Native Implementation with Complete UI Parity\n * \n * Matches React CommentsPluginProvider exactly:\n * - Expandable/collapsible comments\n * - Always-on \"Add Comment\" textarea at top\n * - Selection preservation with selectionRef\n * - Comment count in header\n * - Inline reply textareas in expanded view\n * - Complete CSS styling\n * - Selection change tracking\n * - General comments support\n */\n\ninterface CommentReply {\n id: string;\n author: string;\n text: string;\n createdAt: string;\n}\n\ninterface Comment {\n id: string;\n anchorId: string;\n selectedText: string;\n author: string;\n text: string;\n createdAt: string;\n resolved: boolean;\n resolvedAt?: string;\n resolvedBy?: string;\n replies: CommentReply[];\n}\n\n// State\nconst commentRegistry = new Map<string, Comment>();\nlet commentsPanelVisible = false;\nlet commentsPanelElement: HTMLElement | null = null;\nlet expandedComments = new Set<string>();\nlet replyTexts: { [key: string]: string } = {};\nlet savedSelection: Range | null = null;\nlet newCommentText = '';\nconst commentAuthor = 'User';\n\n// Track selection changes while panel is open\nlet selectionChangeListener: (() => void) | null = null;\n\n/**\n * Get all comments\n */\nexport function getAllComments(): Comment[] {\n return Array.from(commentRegistry.values());\n}\n\n/**\n * Add comment (with or without selection)\n */\nexport function addCommentCommand(author: string, text: string, general = false): string {\n if (general) {\n const commentId = `comment-${Date.now()}`;\n const comment: Comment = {\n id: commentId,\n anchorId: '',\n selectedText: '',\n author,\n text,\n createdAt: new Date().toISOString(),\n resolved: false,\n replies: []\n };\n commentRegistry.set(commentId, comment);\n refreshCommentsPanel();\n return commentId;\n }\n\n // Use saved selection if available\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return '';\n \n const range = savedSelection || selection.getRangeAt(0);\n const selectedText = range.toString();\n \n if (!selectedText) return '';\n\n const commentId = `comment-${Date.now()}`;\n const anchorId = `comment-anchor-${Date.now()}`;\n\n // Create anchor span\n const anchor = document.createElement('span');\n anchor.id = anchorId;\n anchor.className = 'rte-comment-anchor';\n anchor.setAttribute('data-comment-id', commentId);\n anchor.style.cssText = `\n background-color: #ffeb3b;\n border-bottom: 2px solid #fbc02d;\n cursor: pointer;\n position: relative;\n `;\n anchor.title = 'Click to view comment';\n\n // Wrap selection\n const clonedRange = range.cloneRange();\n const contents = clonedRange.extractContents();\n anchor.appendChild(contents);\n clonedRange.insertNode(anchor);\n\n // Create comment\n const comment: Comment = {\n id: commentId,\n anchorId,\n selectedText,\n author,\n text,\n createdAt: new Date().toISOString(),\n resolved: false,\n replies: []\n };\n\n commentRegistry.set(commentId, comment);\n\n // Add click handler\n anchor.onclick = () => {\n commentsPanelVisible = true;\n createCommentsPanel();\n };\n\n refreshCommentsPanel();\n \n // Clear selection\n savedSelection = null;\n selection.removeAllRanges();\n \n return commentId;\n}\n\n/**\n * Resolve comment\n */\nexport function resolveComment(commentId: string, author: string) {\n const comment = commentRegistry.get(commentId);\n if (!comment) return;\n\n comment.resolved = true;\n comment.resolvedAt = new Date().toISOString();\n comment.resolvedBy = author;\n\n if (comment.anchorId) {\n const anchor = document.getElementById(comment.anchorId);\n if (anchor) {\n anchor.style.backgroundColor = '#e0e0e0';\n anchor.style.borderBottom = '2px solid #bdbdbd';\n anchor.style.opacity = '0.6';\n }\n }\n\n refreshCommentsPanel();\n}\n\n/**\n * Reopen comment\n */\nexport function reopenComment(commentId: string) {\n const comment = commentRegistry.get(commentId);\n if (!comment) return;\n\n comment.resolved = false;\n comment.resolvedAt = undefined;\n comment.resolvedBy = undefined;\n\n if (comment.anchorId) {\n const anchor = document.getElementById(comment.anchorId);\n if (anchor) {\n anchor.style.backgroundColor = '#ffeb3b';\n anchor.style.borderBottom = '2px solid #fbc02d';\n anchor.style.opacity = '1';\n }\n }\n\n refreshCommentsPanel();\n}\n\n/**\n * Delete comment\n */\nexport function deleteComment(commentId: string) {\n const comment = commentRegistry.get(commentId);\n if (!comment) return;\n\n if (comment.anchorId) {\n const anchor = document.getElementById(comment.anchorId);\n if (anchor) {\n const parent = anchor.parentNode;\n while (anchor.firstChild) {\n parent?.insertBefore(anchor.firstChild, anchor);\n }\n anchor.remove();\n }\n }\n\n commentRegistry.delete(commentId);\n refreshCommentsPanel();\n}\n\n/**\n * Reply to comment\n */\nexport function replyToComment(commentId: string, author: string, text: string) {\n const comment = commentRegistry.get(commentId);\n if (!comment) return;\n\n const reply: CommentReply = {\n id: `reply-${Date.now()}`,\n author,\n text,\n createdAt: new Date().toISOString()\n };\n\n comment.replies.push(reply);\n refreshCommentsPanel();\n}\n\n/**\n * Highlight comment\n */\nexport function highlightComment(commentId: string, highlight: boolean) {\n const comment = commentRegistry.get(commentId);\n if (!comment || !comment.anchorId) return;\n\n const anchor = document.getElementById(comment.anchorId);\n if (anchor) {\n if (highlight) {\n anchor.classList.add('highlighted');\n anchor.style.outline = '2px solid #0066cc';\n anchor.style.outlineOffset = '2px';\n } else {\n anchor.classList.remove('highlighted');\n anchor.style.outline = 'none';\n }\n }\n}\n\n/**\n * Create Comments Panel with exact React UI\n */\nfunction createCommentsPanel() {\n if (commentsPanelElement) {\n commentsPanelElement.style.display = commentsPanelVisible ? 'block' : 'none';\n if (commentsPanelVisible) {\n refreshCommentsPanel();\n startSelectionTracking();\n } else {\n stopSelectionTracking();\n }\n return;\n }\n\n const panel = document.createElement('div');\n panel.className = 'rte-comments-panel';\n \n commentsPanelElement = panel;\n document.body.appendChild(panel);\n \n refreshCommentsPanel();\n startSelectionTracking();\n addCommentsPanelStyles();\n}\n\n/**\n * Start tracking selection changes\n */\nfunction startSelectionTracking() {\n if (selectionChangeListener) return;\n \n selectionChangeListener = () => {\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0 && !sel.isCollapsed) {\n savedSelection = sel.getRangeAt(0).cloneRange();\n }\n };\n \n document.addEventListener('selectionchange', selectionChangeListener);\n}\n\n/**\n * Stop tracking selection changes\n */\nfunction stopSelectionTracking() {\n if (selectionChangeListener) {\n document.removeEventListener('selectionchange', selectionChangeListener);\n selectionChangeListener = null;\n }\n savedSelection = null;\n}\n\n/**\n * Refresh Comments Panel Content\n */\nfunction refreshCommentsPanel() {\n if (!commentsPanelElement) return;\n\n const comments = getAllComments();\n \n commentsPanelElement.innerHTML = `\n <div class=\"comments-header\" style=\"display: flex; justify-content: space-between; align-items: center;\">\n <h3 style=\"margin: 0;\">Comments (${comments.length})</h3>\n <button class=\"rte-comments-close\" aria-label=\"Close comments panel\">✕</button>\n </div>\n\n <div class=\"comment-add-box\">\n <textarea class=\"new-comment-textarea\" placeholder=\"Add a new comment...\" rows=\"2\"></textarea>\n <button class=\"rte-button-small add-comment-btn\">Add Comment</button>\n </div>\n\n ${comments.length === 0 ? \n '<div class=\"comments-empty\">No comments yet</div>' :\n '<div class=\"comments-list\"></div>'\n }\n `;\n\n // Close button handler\n const closeBtn = commentsPanelElement.querySelector('.rte-comments-close');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n commentsPanelVisible = false;\n if (commentsPanelElement) commentsPanelElement.style.display = 'none';\n stopSelectionTracking();\n });\n }\n\n // New comment handler\n const textarea = commentsPanelElement.querySelector('.new-comment-textarea') as HTMLTextAreaElement;\n const addBtn = commentsPanelElement.querySelector('.add-comment-btn') as HTMLButtonElement;\n \n if (textarea && addBtn) {\n textarea.value = newCommentText;\n textarea.oninput = () => {\n newCommentText = textarea.value;\n addBtn.disabled = !newCommentText.trim();\n addBtn.style.opacity = newCommentText.trim() ? '1' : '0.5';\n };\n \n addBtn.disabled = !newCommentText.trim();\n addBtn.style.opacity = newCommentText.trim() ? '1' : '0.5';\n \n addBtn.onclick = () => {\n if (!newCommentText.trim()) {\n alert('Comment cannot be empty');\n textarea.focus();\n return;\n }\n \n if (savedSelection) {\n addCommentCommand(commentAuthor, newCommentText.trim());\n } else {\n addCommentCommand(commentAuthor, newCommentText.trim(), true);\n }\n \n newCommentText = '';\n textarea.value = '';\n refreshCommentsPanel();\n };\n }\n\n // Render comment cards\n if (comments.length > 0) {\n const commentsList = commentsPanelElement.querySelector('.comments-list');\n if (commentsList) {\n comments.forEach(comment => {\n const card = createCommentCard(comment);\n commentsList.appendChild(card);\n });\n }\n }\n}\n\n/**\n * Create Comment Card\n */\nfunction createCommentCard(comment: Comment): HTMLElement {\n const isExpanded = expandedComments.has(comment.id);\n \n const card = document.createElement('div');\n card.className = `comment-item${comment.resolved ? ' resolved' : ''}`;\n \n // Header\n const header = document.createElement('div');\n header.className = 'comment-header';\n header.innerHTML = `\n <div class=\"comment-meta\">\n <strong>${comment.author}</strong>\n <span class=\"comment-date\">${new Date(comment.createdAt).toLocaleDateString()}</span>\n </div>\n <button class=\"comment-expand\" aria-label=\"Toggle comment\">${isExpanded ? '▼' : '▶'}</button>\n `;\n \n const expandBtn = header.querySelector('.comment-expand');\n if (expandBtn) {\n expandBtn.addEventListener('click', () => {\n if (expandedComments.has(comment.id)) {\n expandedComments.delete(comment.id);\n } else {\n expandedComments.add(comment.id);\n }\n refreshCommentsPanel();\n });\n }\n \n card.appendChild(header);\n \n // Comment text\n const text = document.createElement('div');\n text.className = 'comment-text';\n text.textContent = comment.text;\n card.appendChild(text);\n \n // Selected text\n if (comment.selectedText) {\n const selection = document.createElement('div');\n selection.className = 'comment-selection';\n selection.textContent = `\"${comment.selectedText}\"`;\n card.appendChild(selection);\n }\n \n // Expanded content\n if (isExpanded) {\n const expanded = document.createElement('div');\n expanded.className = 'comment-expanded';\n \n // Replies\n if (comment.replies.length > 0) {\n const repliesDiv = document.createElement('div');\n repliesDiv.className = 'comment-replies';\n \n comment.replies.forEach(reply => {\n const replyDiv = document.createElement('div');\n replyDiv.className = 'comment-reply';\n replyDiv.innerHTML = `\n <div class=\"reply-header\">\n <strong>${reply.author}</strong>\n <span class=\"reply-date\">${new Date(reply.createdAt).toLocaleDateString()}</span>\n </div>\n <div class=\"reply-text\">${reply.text}</div>\n `;\n repliesDiv.appendChild(replyDiv);\n });\n \n expanded.appendChild(repliesDiv);\n }\n \n // Reply input\n if (!comment.resolved) {\n const replyInput = document.createElement('div');\n replyInput.className = 'comment-reply-input';\n \n const replyTextarea = document.createElement('textarea');\n replyTextarea.placeholder = 'Add a reply...';\n replyTextarea.rows = 2;\n replyTextarea.value = replyTexts[comment.id] || '';\n replyTextarea.oninput = () => {\n replyTexts[comment.id] = replyTextarea.value;\n };\n \n const replyBtn = document.createElement('button');\n replyBtn.className = 'rte-button-small';\n replyBtn.textContent = 'Reply';\n replyBtn.onclick = () => {\n if (replyTexts[comment.id]?.trim()) {\n replyToComment(comment.id, commentAuthor, replyTexts[comment.id]);\n replyTexts[comment.id] = '';\n refreshCommentsPanel();\n }\n };\n \n replyInput.appendChild(replyTextarea);\n replyInput.appendChild(replyBtn);\n expanded.appendChild(replyInput);\n }\n \n // Actions\n const actions = document.createElement('div');\n actions.className = 'comment-actions';\n \n if (!comment.resolved) {\n const resolveBtn = document.createElement('button');\n resolveBtn.className = 'action-button resolve';\n resolveBtn.textContent = '✓ Resolve';\n resolveBtn.onclick = () => resolveComment(comment.id, commentAuthor);\n actions.appendChild(resolveBtn);\n } else {\n const reopenBtn = document.createElement('button');\n reopenBtn.className = 'action-button reopen';\n reopenBtn.textContent = '↻ Reopen';\n reopenBtn.onclick = () => reopenComment(comment.id);\n actions.appendChild(reopenBtn);\n }\n \n const deleteBtn = document.createElement('button');\n deleteBtn.className = 'action-button delete';\n deleteBtn.textContent = '🗑 Delete';\n deleteBtn.onclick = () => {\n if (confirm('Delete this comment?')) {\n deleteComment(comment.id);\n }\n };\n actions.appendChild(deleteBtn);\n \n expanded.appendChild(actions);\n card.appendChild(expanded);\n }\n \n // Hover highlighting\n card.onmouseenter = () => highlightComment(comment.id, true);\n card.onmouseleave = () => highlightComment(comment.id, false);\n \n return card;\n}\n\n/**\n * Add Comments Panel Styles (matching React CSS exactly)\n */\nfunction addCommentsPanelStyles() {\n if (document.getElementById('rte-comments-panel-styles')) return;\n \n const style = document.createElement('style');\n style.id = 'rte-comments-panel-styles';\n style.textContent = `\n .rte-comments-close:hover {\n color: #d32f2f;\n }\n .rte-comments-panel {\n position: fixed;\n right: 0;\n top: 0;\n width: 350px;\n height: 100%;\n background: white;\n border-left: 1px solid #ddd;\n box-shadow: -2px 0 4px rgba(0,0,0,0.1);\n overflow-y: auto;\n z-index: 1000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n display: flex;\n flex-direction: column;\n }\n .comments-header {\n padding: 16px;\n border-bottom: 1px solid #eee;\n background-color: #fafafa;\n }\n .comments-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n }\n .rte-comments-close {\n background: none;\n border: none;\n font-size: 22px;\n cursor: pointer;\n color: #888;\n margin-left: 8px;\n padding: 0;\n }\n .comment-add-box {\n padding: 12px;\n border-bottom: 1px solid #eee;\n background: #fafafa;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n .new-comment-textarea {\n font-size: 13px;\n padding: 8px;\n border-radius: 3px;\n border: 1px solid #ddd;\n resize: vertical;\n font-family: inherit;\n }\n .comments-empty {\n padding: 16px;\n text-align: center;\n color: #999;\n font-size: 13px;\n }\n .comments-list {\n padding: 12px;\n }\n .comment-item {\n padding: 12px;\n margin-bottom: 12px;\n border: 1px solid #eee;\n border-radius: 4px;\n background-color: white;\n transition: all 0.2s;\n }\n .comment-item:hover {\n border-color: #ddd;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n }\n .comment-item.resolved {\n opacity: 0.6;\n background-color: #f5f5f5;\n }\n .comment-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n }\n .comment-meta {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .comment-meta strong {\n font-size: 13px;\n color: #333;\n }\n .comment-date {\n font-size: 11px;\n color: #999;\n }\n .comment-expand {\n background: none;\n border: none;\n cursor: pointer;\n color: #666;\n font-size: 12px;\n padding: 0;\n }\n .comment-text {\n font-size: 13px;\n line-height: 1.4;\n color: #333;\n margin-bottom: 8px;\n }\n .comment-selection {\n font-size: 12px;\n color: #666;\n font-style: italic;\n background-color: #f9f9f9;\n padding: 6px;\n border-radius: 3px;\n margin-bottom: 8px;\n }\n .comment-expanded {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid #eee;\n }\n .comment-replies {\n margin-bottom: 12px;\n }\n .comment-reply {\n padding: 8px;\n background-color: #fafafa;\n border-radius: 3px;\n margin-bottom: 8px;\n font-size: 12px;\n }\n .reply-header {\n display: flex;\n gap: 8px;\n margin-bottom: 4px;\n }\n .reply-header strong {\n font-size: 12px;\n color: #333;\n }\n .reply-date {\n font-size: 11px;\n color: #999;\n }\n .reply-text {\n font-size: 12px;\n color: #666;\n line-height: 1.3;\n }\n .comment-reply-input {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-bottom: 12px;\n }\n .comment-reply-input textarea {\n font-size: 12px;\n padding: 6px;\n border: 1px solid #ddd;\n border-radius: 3px;\n font-family: inherit;\n resize: vertical;\n }\n .rte-button-small {\n font-size: 12px;\n padding: 4px 8px;\n background-color: #1976d2;\n color: white;\n border: none;\n border-radius: 3px;\n cursor: pointer;\n align-self: flex-end;\n }\n .rte-button-small:hover {\n background-color: #1565c0;\n }\n .rte-button-small:disabled {\n opacity: 0.5;\n pointer-events: none;\n }\n .comment-actions {\n display: flex;\n gap: 6px;\n justify-content: flex-end;\n }\n .action-button {\n font-size: 12px;\n padding: 4px 8px;\n background-color: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 3px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .action-button:hover {\n background-color: #eeeeee;\n }\n .action-button.resolve {\n color: #2e7d32;\n }\n .action-button.delete {\n color: #c62828;\n }\n .rte-comment-anchor {\n position: relative;\n }\n .rte-comment-anchor.highlighted {\n background-color: #ffeb3b !important;\n border-radius: 3px;\n }\n `;\n document.head.appendChild(style);\n}\n\nexport const CommentsPlugin = (): Plugin => ({\n name: 'comments',\n \n toolbar: [\n {\n label: 'Add Comment',\n command: 'addComment',\n type: 'button',\n icon: '<svg fill=\"#000000\" width=\"24px\" height=\"24px\" viewBox=\"0 0 32 32\" id=\"icon\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"><defs><style>.cls-1{fill:none;}</style></defs><title>add-comment</title><path d=\"M17.74,30,16,29l4-7h6a2,2,0,0,0,2-2V8a2,2,0,0,0-2-2H6A2,2,0,0,0,4,8V20a2,2,0,0,0,2,2h9v2H6a4,4,0,0,1-4-4V8A4,4,0,0,1,6,4H26a4,4,0,0,1,4,4V20a4,4,0,0,1-4,4H21.16Z\" transform=\"translate(0 0)\"></path><polygon points=\"17 9 15 9 15 13 11 13 11 15 15 15 15 19 17 19 17 15 21 15 21 13 17 13 17 9\"></polygon><rect id=\"_Transparent_Rectangle_\" data-name=\"<Transparent Rectangle>\" class=\"cls-1\" width=\"32\" height=\"32\"></rect></g></svg>',\n },\n {\n label: 'Show / Hide Comments',\n command: 'toggleComments',\n type: 'button',\n icon: '<svg width=\"24px\" height=\"24px\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"> <path d=\"M16 1H4V11H8L10 13L12 11H16V1Z\" fill=\"#000000\"></path> <path d=\"M2 5V13H7.17157L8.70711 14.5355L7.29289 15.9497L6.34315 15H0V5H2Z\" fill=\"#000000\"></path> </g></svg>',\n },\n ],\n \n commands: {\n addComment: () => {\n // Save current selection\n const sel = window.getSelection();\n if (sel && sel.rangeCount > 0 && !sel.isCollapsed) {\n savedSelection = sel.getRangeAt(0).cloneRange();\n } else {\n savedSelection = null;\n }\n \n commentsPanelVisible = true;\n createCommentsPanel();\n return true;\n },\n \n toggleComments: () => {\n commentsPanelVisible = !commentsPanelVisible;\n createCommentsPanel();\n return true;\n }\n },\n \n keymap: {}\n});\n"],"names":["commentRegistry","commentsPanelVisible","commentsPanelElement","expandedComments","replyTexts","savedSelection","newCommentText","commentAuthor","selectionChangeListener","getAllComments","addCommentCommand","author","text","general","commentId","comment","refreshCommentsPanel","selection","range","selectedText","anchorId","anchor","clonedRange","contents","createCommentsPanel","resolveComment","reopenComment","deleteComment","parent","replyToComment","reply","highlightComment","highlight","startSelectionTracking","stopSelectionTracking","panel","addCommentsPanelStyles","sel","comments","closeBtn","textarea","addBtn","commentsList","card","createCommentCard","isExpanded","header","expandBtn","expanded","repliesDiv","replyDiv","replyInput","replyTextarea","replyBtn","_a","actions","reopenBtn","resolveBtn","deleteBtn","style","CommentsPlugin"],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const o = ["P", "DIV", "H1", "H2", "H3", "H4", "H5", "H6", "LI", "BLOCKQUOTE"], i = () => ({
|
|
2
|
+
name: "direction",
|
|
3
|
+
toolbar: [
|
|
4
|
+
{
|
|
5
|
+
label: "Left to Right",
|
|
6
|
+
command: "setDirectionLTR",
|
|
7
|
+
icon: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M21 18H3M21 18L18 21M21 18L18 15M13 3V12M13 3H7M13 3C13.4596 3 13.9148 3.0776 14.3394 3.22836C14.764 3.37913 15.1499 3.6001 15.4749 3.87868C15.7999 4.15726 16.0577 4.48797 16.2336 4.85195C16.4095 5.21593 16.5 5.60603 16.5 6C16.5 6.39397 16.4095 6.78407 16.2336 7.14805C16.0577 7.51203 15.7999 7.84274 15.4749 8.12132C15.1499 8.3999 14.764 8.62087 14.3394 8.77164C13.9148 8.9224 13.4596 9 13 9V3ZM9 3V12" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>',
|
|
8
|
+
shortcut: "Mod-Shift-l"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
label: "Right to Left",
|
|
12
|
+
command: "setDirectionRTL",
|
|
13
|
+
icon: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <path d="M3 18H21M3 18L6 21M3 18L6 15M11 12V3H17M15 3V12M10.5 3C10.0404 3 9.58525 3.0776 9.16061 3.22836C8.73597 3.37913 8.35013 3.6001 8.02513 3.87868C7.70012 4.15726 7.44231 4.48797 7.26642 4.85195C7.09053 5.21593 7 5.60603 7 6C7 6.39397 7.09053 6.78407 7.26642 7.14805C7.44231 7.51203 7.70012 7.84274 8.02513 8.12132C8.35013 8.3999 8.73597 8.62087 9.16061 8.77164C9.58525 8.9224 10.0404 9 10.5 9L10.5 3Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg>',
|
|
14
|
+
shortcut: "Mod-Shift-r"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
commands: {
|
|
18
|
+
setDirectionLTR: () => {
|
|
19
|
+
try {
|
|
20
|
+
const t = window.getSelection();
|
|
21
|
+
if (!t || t.rangeCount === 0) return !1;
|
|
22
|
+
let e = t.getRangeAt(0).commonAncestorContainer;
|
|
23
|
+
for (e && e.nodeType === Node.TEXT_NODE && (e = e.parentElement); e && e !== document.body; ) {
|
|
24
|
+
const r = e;
|
|
25
|
+
if (r.tagName && o.includes(r.tagName))
|
|
26
|
+
return r.removeAttribute("dir"), !0;
|
|
27
|
+
e = r.parentElement;
|
|
28
|
+
}
|
|
29
|
+
return !1;
|
|
30
|
+
} catch (t) {
|
|
31
|
+
return console.error("Failed to set LTR direction:", t), !1;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
setDirectionRTL: () => {
|
|
35
|
+
try {
|
|
36
|
+
const t = window.getSelection();
|
|
37
|
+
if (!t || t.rangeCount === 0) return !1;
|
|
38
|
+
let e = t.getRangeAt(0).commonAncestorContainer;
|
|
39
|
+
for (e && e.nodeType === Node.TEXT_NODE && (e = e.parentElement); e && e !== document.body; ) {
|
|
40
|
+
const r = e;
|
|
41
|
+
if (r.tagName && o.includes(r.tagName))
|
|
42
|
+
return r.setAttribute("dir", "rtl"), !0;
|
|
43
|
+
e = r.parentElement;
|
|
44
|
+
}
|
|
45
|
+
return !1;
|
|
46
|
+
} catch (t) {
|
|
47
|
+
return console.error("Failed to set RTL direction:", t), !1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
keymap: {
|
|
52
|
+
"Mod-Shift-l": "setDirectionLTR",
|
|
53
|
+
"Mod-Shift-r": "setDirectionRTL"
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
export {
|
|
57
|
+
i as DirectionPlugin
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=DirectionPlugin.native-Be7wCzkI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectionPlugin.native-Be7wCzkI.mjs","sources":["../../plugins/direction/src/DirectionPlugin.native.ts"],"sourcesContent":["import type { Plugin } from '@editora/core';\n\n/**\n * DirectionPlugin - Native implementation for text direction (LTR/RTL)\n * \n * Features:\n * - Set text direction to Left-to-Right (LTR) - removes dir attribute (default)\n * - Set text direction to Right-to-Left (RTL) - sets dir=\"rtl\"\n * - Essential for multilingual content (Arabic, Hebrew, Persian, Urdu, etc.)\n * \n * Commands:\n * - setDirectionLTR: Remove dir attribute (default LTR behavior)\n * - setDirectionRTL: Set dir=\"rtl\" on nearest block element\n * \n * UI/UX Features:\n * - Detailed SVG icons matching React implementation\n * - Works on block-level elements (P, DIV, H1-H6, LI, BLOCKQUOTE)\n * - Keyboard shortcuts: Cmd/Ctrl+Shift+L (LTR), Cmd/Ctrl+Shift+R (RTL)\n * - Clean attribute-only approach (no inline styles)\n */\n\n// List of block-level elements that can have direction attributes\nconst BLOCK_LEVEL_TAGS = ['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'BLOCKQUOTE'];\n\nexport const DirectionPlugin = (): Plugin => {\n return {\n name: 'direction',\n \n toolbar: [\n {\n label: 'Left to Right',\n command: 'setDirectionLTR',\n icon: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"> <path d=\"M21 18H3M21 18L18 21M21 18L18 15M13 3V12M13 3H7M13 3C13.4596 3 13.9148 3.0776 14.3394 3.22836C14.764 3.37913 15.1499 3.6001 15.4749 3.87868C15.7999 4.15726 16.0577 4.48797 16.2336 4.85195C16.4095 5.21593 16.5 5.60603 16.5 6C16.5 6.39397 16.4095 6.78407 16.2336 7.14805C16.0577 7.51203 15.7999 7.84274 15.4749 8.12132C15.1499 8.3999 14.764 8.62087 14.3394 8.77164C13.9148 8.9224 13.4596 9 13 9V3ZM9 3V12\" stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path> </g></svg>`,\n shortcut: 'Mod-Shift-l'\n },\n {\n label: 'Right to Left',\n command: 'setDirectionRTL',\n icon: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g id=\"SVGRepo_bgCarrier\" stroke-width=\"0\"></g><g id=\"SVGRepo_tracerCarrier\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></g><g id=\"SVGRepo_iconCarrier\"> <path d=\"M3 18H21M3 18L6 21M3 18L6 15M11 12V3H17M15 3V12M10.5 3C10.0404 3 9.58525 3.0776 9.16061 3.22836C8.73597 3.37913 8.35013 3.6001 8.02513 3.87868C7.70012 4.15726 7.44231 4.48797 7.26642 4.85195C7.09053 5.21593 7 5.60603 7 6C7 6.39397 7.09053 6.78407 7.26642 7.14805C7.44231 7.51203 7.70012 7.84274 8.02513 8.12132C8.35013 8.3999 8.73597 8.62087 9.16061 8.77164C9.58525 8.9224 10.0404 9 10.5 9L10.5 3Z\" stroke=\"#000000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path> </g></svg>`,\n shortcut: 'Mod-Shift-r'\n }\n ],\n\n commands: {\n setDirectionLTR: () => {\n try {\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return false;\n\n const range = selection.getRangeAt(0);\n let element: Node | null = range.commonAncestorContainer;\n\n // If it's a text node, get the parent element\n if (element && element.nodeType === Node.TEXT_NODE) {\n element = element.parentElement;\n }\n\n // Find the nearest block-level element\n while (element && element !== document.body) {\n const htmlElement = element as HTMLElement;\n if (htmlElement.tagName && BLOCK_LEVEL_TAGS.includes(htmlElement.tagName)) {\n // Remove the dir attribute - browser defaults to LTR\n htmlElement.removeAttribute('dir');\n return true;\n }\n element = htmlElement.parentElement;\n }\n \n return false;\n } catch (error) {\n console.error('Failed to set LTR direction:', error);\n return false;\n }\n },\n\n setDirectionRTL: () => {\n try {\n const selection = window.getSelection();\n if (!selection || selection.rangeCount === 0) return false;\n\n const range = selection.getRangeAt(0);\n let element: Node | null = range.commonAncestorContainer;\n\n // If it's a text node, get the parent element\n if (element && element.nodeType === Node.TEXT_NODE) {\n element = element.parentElement;\n }\n\n // Find the nearest block-level element\n while (element && element !== document.body) {\n const htmlElement = element as HTMLElement;\n if (htmlElement.tagName && BLOCK_LEVEL_TAGS.includes(htmlElement.tagName)) {\n // Set the dir attribute to \"rtl\"\n htmlElement.setAttribute('dir', 'rtl');\n return true;\n }\n element = htmlElement.parentElement;\n }\n \n return false;\n } catch (error) {\n console.error('Failed to set RTL direction:', error);\n return false;\n }\n }\n },\n\n keymap: {\n 'Mod-Shift-l': 'setDirectionLTR',\n 'Mod-Shift-r': 'setDirectionRTL'\n }\n };\n};\n"],"names":["BLOCK_LEVEL_TAGS","DirectionPlugin","selection","element","htmlElement","error"],"mappings":"AAsBA,MAAMA,IAAmB,CAAC,KAAK,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,YAAY,GAE/EC,IAAkB,OACtB;AAAA,EACL,MAAM;AAAA,EAEN,SAAS;AAAA,IACP;AAAA,MACE,OAAO;AAAA,MACP,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,IAEZ;AAAA,MACE,OAAO;AAAA,MACP,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,EACZ;AAAA,EAGF,UAAU;AAAA,IACR,iBAAiB,MAAM;AACrB,UAAI;AACF,cAAMC,IAAY,OAAO,aAAA;AACzB,YAAI,CAACA,KAAaA,EAAU,eAAe,EAAG,QAAO;AAGrD,YAAIC,IADUD,EAAU,WAAW,CAAC,EACH;AAQjC,aALIC,KAAWA,EAAQ,aAAa,KAAK,cACvCA,IAAUA,EAAQ,gBAIbA,KAAWA,MAAY,SAAS,QAAM;AAC3C,gBAAMC,IAAcD;AACpB,cAAIC,EAAY,WAAWJ,EAAiB,SAASI,EAAY,OAAO;AAEtE,mBAAAA,EAAY,gBAAgB,KAAK,GAC1B;AAET,UAAAD,IAAUC,EAAY;AAAA,QACxB;AAEA,eAAO;AAAA,MACT,SAASC,GAAO;AACd,uBAAQ,MAAM,gCAAgCA,CAAK,GAC5C;AAAA,MACT;AAAA,IACF;AAAA,IAEA,iBAAiB,MAAM;AACrB,UAAI;AACF,cAAMH,IAAY,OAAO,aAAA;AACzB,YAAI,CAACA,KAAaA,EAAU,eAAe,EAAG,QAAO;AAGrD,YAAIC,IADUD,EAAU,WAAW,CAAC,EACH;AAQjC,aALIC,KAAWA,EAAQ,aAAa,KAAK,cACvCA,IAAUA,EAAQ,gBAIbA,KAAWA,MAAY,SAAS,QAAM;AAC3C,gBAAMC,IAAcD;AACpB,cAAIC,EAAY,WAAWJ,EAAiB,SAASI,EAAY,OAAO;AAEtE,mBAAAA,EAAY,aAAa,OAAO,KAAK,GAC9B;AAET,UAAAD,IAAUC,EAAY;AAAA,QACxB;AAEA,eAAO;AAAA,MACT,SAASC,GAAO;AACd,uBAAQ,MAAM,gCAAgCA,CAAK,GAC5C;AAAA,MACT;AAAA,IACF;AAAA,EAAA;AAAA,EAGF,QAAQ;AAAA,IACN,eAAe;AAAA,IACf,eAAe;AAAA,EAAA;AACjB;"}
|