@svar-ui/react-comments
Version:
Lightweight React component for adding a modern-looking comments section to your app
463 lines (462 loc) • 14.3 kB
JavaScript
import { jsx as a, jsxs as y, Fragment as oe } from "react/jsx-runtime";
import { useMemo as p, useRef as W, useContext as $, useCallback as V, useEffect as Q, createContext as re, useState as P } from "react";
import { context as I, TextArea as ae, Button as ie, Locale as se, Willow as O, WillowDark as U } from "@svar-ui/react-core";
import { useWritableProp as E } from "@svar-ui/lib-react";
import { ActionMenu as le } from "@svar-ui/react-menu";
import { uid as ce } from "@svar-ui/lib-state";
import { dateToString as ue } from "@svar-ui/lib-dom";
import { en as de } from "@svar-ui/comments-locales";
import { en as fe } from "@svar-ui/core-locales";
function me(e) {
if (e.startsWith("hsl"))
return xe(e)[2] > 55 ? "dark" : "light";
if (e.startsWith("#") || e.startsWith("rgb")) {
const t = we(e, !0);
return Math.round(
(t[0] * 299 + t[1] * 587 + t[2] * 114) / 1e3
) > 180 ? "dark" : "light";
}
return "light";
}
function xe(e) {
return e.match(/\d+/g).map(Number);
}
function we(e, t = !1) {
if (e.startsWith("rgb"))
return t ? he(e) : e;
let n = 0, o = 0, i = 0;
return e.length == 4 ? (n = "0x" + e[1] + e[1], o = "0x" + e[2] + e[2], i = "0x" + e[3] + e[3]) : e.length == 7 && (n = "0x" + e[1] + e[2], o = "0x" + e[3] + e[4], i = "0x" + e[5] + e[6]), n = +n, o = +o, i = +i, t ? { r: n, g: o, b: i } : "rgb(" + n + "," + o + "," + i + ")";
}
function he(e) {
const t = e.indexOf(",") > -1 ? "," : " ", n = e.substring(4).split(")")[0].split(t), o = (+n[0]).toString(16), i = (+n[1]).toString(16), m = (+n[2]).toString(16);
return { r: +o, g: +i, b: +m };
}
function R({
data: e = {
name: "",
avatar: "",
color: ""
},
noTransform: t = !1,
size: n = "small",
border: o = !0
}) {
const i = p(
() => e.name.split(" ").map((s) => s[0]).join(""),
[e.name]
), m = p(
() => e.color ? { background: e.color } : void 0,
[e.color]
), c = p(
() => e.color ? `wx-comments-avatar-color-${me(e.color)}` : "",
[e.color]
);
return /* @__PURE__ */ a(
"div",
{
className: `wx-cyzBpibr wx-user wx-${n} ${c} ${o ? "wx-border" : ""}`,
style: m,
children: e.avatar ? /* @__PURE__ */ a("img", { src: e.avatar, alt: e.name }) : t ? e.name : i
}
);
}
function G(e) {
const {
focus: t = !1,
buttonLabel: n = "Send",
flow: o = !1,
value: i,
author: m,
onPost: c
} = e, [s, l] = E(i || ""), v = W(null), u = W(null), N = W(null), h = $(I.i18n), f = p(() => h.getGroup("comments"), [h]);
return N.current = V(
(d) => {
d && (c && c({ value: d }), l(""), u.current && u.current.focus());
},
[c, s]
), Q(() => {
v.current && (u.current = v.current.querySelector("textarea"), t && u.current && u.current.focus(), u.current.onkeydown = (d) => {
d.key === "Enter" && (d.ctrlKey || d.metaKey) && (d.preventDefault(), N.current(s));
});
}, []), /* @__PURE__ */ y(
"div",
{
className: `wx-v2rD0VHO wx-comments-textarea${o ? " wx-flow" : ""}`,
"data-focus": "yes",
ref: v,
children: [
/* @__PURE__ */ y("div", { className: "wx-v2rD0VHO wx-textarea-wrapper", children: [
m ? /* @__PURE__ */ a("div", { className: "wx-v2rD0VHO wx-textarea-avatar", children: /* @__PURE__ */ a(R, { data: m }) }) : null,
/* @__PURE__ */ a(
ae,
{
placeholder: f("Add a comment..."),
value: s,
onChange: ({ value: d }) => l(d)
}
)
] }),
/* @__PURE__ */ a("div", { className: "wx-v2rD0VHO wx-textarea-bottombar", children: /* @__PURE__ */ a(ie, { type: "primary", onClick: () => N.current(s), children: f(n) }) })
]
}
);
}
const Z = re({
dateStr: (e) => e.toString()
});
function ve({ owned: e, author: t, date: n, edit: o, children: i }) {
const c = $(Z).dateStr;
return /* @__PURE__ */ a("div", { className: `wx-aluyyvxH wx-bubble ${e ? "wx-owned" : ""}`, children: /* @__PURE__ */ y("div", { className: "wx-aluyyvxH wx-bubble-wrapper", children: [
/* @__PURE__ */ a("div", { className: "wx-aluyyvxH wx-avatar", children: /* @__PURE__ */ a(R, { data: t }) }),
/* @__PURE__ */ y("div", { className: "wx-aluyyvxH wx-main-bubble", children: [
/* @__PURE__ */ a("span", { className: "wx-aluyyvxH wx-author-name", children: t.name }),
e ? /* @__PURE__ */ y("div", { className: "wx-aluyyvxH wx-agent-message", children: [
/* @__PURE__ */ y("div", { className: "wx-aluyyvxH wx-message", children: [
i,
o !== e ? /* @__PURE__ */ a("div", { className: "wx-aluyyvxH wx-comment-date", children: c(n) }) : null
] }),
/* @__PURE__ */ a(
"div",
{
className: "wx-aluyyvxH wx-menu-icon",
"data-comment-menu-id": e,
children: /* @__PURE__ */ a("i", { className: "wx-aluyyvxH wx-icon wxi-dots-v" })
}
)
] }) : /* @__PURE__ */ y("div", { className: "wx-aluyyvxH wx-message", children: [
i,
/* @__PURE__ */ a("div", { className: "wx-aluyyvxH wx-comment-date", children: c(n) })
] })
] })
] }) });
}
function ge(e) {
const { owned: t, author: n, date: o, edit: i, children: m } = e, c = $(Z).dateStr;
return /* @__PURE__ */ y("div", { className: `wx-N2LqQbZL wx-flow${t ? " wx-owned" : ""}`, children: [
/* @__PURE__ */ y("div", { className: "wx-N2LqQbZL wx-flow-toolbar", children: [
/* @__PURE__ */ a(R, { data: n }),
/* @__PURE__ */ a("span", { className: "wx-N2LqQbZL wx-author-name", children: n.name }),
t && t !== i && /* @__PURE__ */ a(
"div",
{
className: "wx-N2LqQbZL wx-menu-icon",
"data-comment-menu-id": t,
children: /* @__PURE__ */ a("i", { className: "wx-N2LqQbZL wx-icon wxi-dots-v" })
}
)
] }),
/* @__PURE__ */ a("div", { className: "wx-N2LqQbZL wx-comment-date", children: c(o) }),
/* @__PURE__ */ a("div", { className: "wx-N2LqQbZL wx-message", children: m })
] });
}
function pe(e, t, n) {
let o, i, m, c, s, l, v, u;
if (t ? {
linestart: v,
headerlevel: m,
checkbehind: s,
unsurepoint: l,
content: o,
ctype: i,
newLineCounter: c,
i: u
} = t.state : (t = {
nodes: [{ d: [], t: "p", f: !1, i: 0 }],
length: 0,
state: {}
}, v = 0, m = 0, s = -1, l = -1, o = "", i = "", c = 0, u = 0), l) {
const f = t.nodes[t.nodes.length - 1];
f.d.length && (t.length -= f.d[f.d.length - 1].c.length, f.d.pop());
}
const N = (f) => {
o !== "" && h("", f);
const d = t.nodes[t.nodes.length - 1];
d.f = f !== 1, d.i = u, m > 0 && (d.t = `h${m}`, m = -1), f === 0 && t.nodes.push({ d: [], t: "p", f: !1, i: 0 });
}, h = (f, d = 2) => {
const D = t.nodes[t.nodes.length - 1], C = D.d[D.d.length - 1], L = d === 2 ? i : "";
if (C && C.t === L && l < 0) {
const k = C;
t.length += o.length, k.c = k.c + o, k.i = u;
} else {
const k = L === "" && l >= 0 ? e.substring(l) : o;
t.length += k.length, D.d.push({ c: k, t: L, f: d !== 1, i: u });
}
d === 2 && (f ? l = s : l = -1), d !== 1 && (o = "", i = f, s = -1);
};
for (; u < e.length; u++) {
const f = e[u];
if (f === `
`) {
c++, v = u + 1;
continue;
}
if (!((f === " " || f === " ") && c > 0))
if (c > 0 && (c > 1 ? N(0) : o += `
`, c = 0), f == "*" || f == "`" || f == "#")
e[u - 1] == "\\" ? o += f : s === -1 && (s = u);
else {
if (s >= 0) {
const d = u - s;
if (e[u - 1] == "*")
d === 2 ? h(i === "strong" ? "" : "strong") : d === 1 && h(i === "em" ? "" : "em"), s = -1;
else if (e[u - 1] == "`" && d == 1)
h(i === "code" ? "" : "code"), s = -1;
else if (e[u - 1] == "#" && e[u] === " " && s === v && u - s <= 6) {
m = u - s, s = -1;
continue;
}
}
s !== -1 && (o += e.substring(s, u), s = -1), o += f;
}
}
return N(-1), t.state = {}, t;
}
function _(e) {
let t = "";
for (const n of e)
typeof n.d < "u" ? (t += "<" + n.t + ">", t += _(n.d), t += "</" + n.t + ">") : (n.t && (t += "<" + n.t + ">"), t += n.c, n.t && (t += "</" + n.t + ">"));
return t;
}
function be(e) {
return _(pe(e).nodes);
}
function ye({ content: e }) {
return /* @__PURE__ */ a("div", { dangerouslySetInnerHTML: { __html: be(e) } });
}
function Ne({ content: e }) {
return /* @__PURE__ */ a(oe, { children: e });
}
const ke = {
bubbles: ve,
flow: ge
}, Ce = {
markdown: ye,
text: Ne
};
function Le({
content: e,
date: t,
owned: n,
render: o,
format: i = "text",
author: m,
edit: c,
onPost: s,
onCancel: l
}) {
const v = p(
() => typeof o == "string" ? ke[o] : o,
[o]
), u = p(
() => typeof i == "string" ? Ce[i] : i,
[i]
);
return /* @__PURE__ */ a(v, { owned: n, edit: c, author: m, date: t, children: c && c === n ? /* @__PURE__ */ a(
G,
{
focus: !0,
onPost: s,
onCancel: l,
value: e
}
) : /* @__PURE__ */ a(u, { content: e }) });
}
function He({
data: e,
render: t = "blocks",
format: n,
author: o,
edit: i,
onPost: m,
onCancel: c
}) {
const s = p(
() => typeof t == "string" ? t : "blocks",
[t]
);
return /* @__PURE__ */ a("div", { className: `wx-6HAxmtjJ wx-messages wx-${s}`, children: e.map((l) => /* @__PURE__ */ a(
Le,
{
content: l.content,
date: l.date,
author: l.author,
owned: l.author.id === o.id ? l.id : null,
render: t,
edit: i,
format: l.format || n,
onPost: m,
onCancel: c
},
l.id
)) });
}
function De(e) {
let {
onAction: t,
onChange: n,
readonly: o = !1,
render: i = "flow",
format: m = "text",
users: c,
data: s,
activeUser: l,
focus: v = !1
} = e;
const u = $(I.i18n), { calendar: N, comments: h, formats: f } = u.getRaw(), d = u.getGroup("comments"), D = p(
() => ue(h.dateFormat || f.dateFormat, N),
[N, h, f]
), [C, L] = P(null), [k, q] = P(""), [b, M] = E(s);
Q(() => {
q(""), L(null);
}, [b]);
const j = { id: 0, name: d("Unknown"), color: "hsl(0, 0%, 85%)" }, S = p(() => c ? c.map((r) => r.color ? r : {
...r,
color: "hsl(" + K(r.id + r.name) + ", 100%, 85%)"
}) : [], [c]), T = p(() => {
if (typeof l == "object") return l;
const r = S.find((x) => x.id === l) || j;
return r || {
id: l || -1,
name: d("Me"),
color: "hsl(225, 76%, 67%)"
};
}, [l, S, d]), B = p(() => b ? b.map((r) => {
if (typeof r.author == "object") return r;
const x = S ? S.find((w) => w.id === r.user) : null;
return {
...r,
author: x || j
};
}) : [], [b, S]);
function K(r) {
let x = 0;
for (let w = 0; w < r.length; w++)
x = r.charCodeAt(w) + ((x << 5) - x);
return x % 60 * 6;
}
function X(r) {
const x = {
id: ce(),
content: r,
author: T,
user: T.id,
date: /* @__PURE__ */ new Date()
}, w = [...B, x];
if (M(w), n) {
const g = n({ value: w, comment: x, action: "add" });
g && typeof g == "object" && (g.then ? g.then((H) => {
F(x.id, H);
}) : F(x.id, g));
}
}
function F(r, x) {
const w = b ? b.findIndex((H) => H.id === r) : -1;
if (w === -1) return;
const g = [...b];
g[w] = { ...b[w], ...x }, M(g);
}
function z(r) {
const x = (b || []).filter((w) => w.id !== r);
M(x), n && n({ value: x, id: r, action: "delete" });
}
function J(r, x) {
let w;
const g = (b || []).map((H) => H.id === r ? (w = { ...H, content: x }, w) : H);
M(g), n && n({ value: g, id: r, action: "update", comment: w });
}
function Y() {
L(null);
}
function ee(r) {
const { context: x, action: w } = r;
if (w)
switch (t && t({ action: "menu-clicked" }), w.id) {
case "edit-comment":
L(x);
break;
case "delete-comment":
z(x);
break;
}
}
const te = [
{
id: "edit-comment",
text: d("Edit"),
icon: "wxi-edit-outline"
},
{
id: "delete-comment",
text: d("Delete"),
icon: "wxi-delete-outline"
}
], A = W(null), ne = V(
(r) => {
A.current && typeof A.current.show == "function" && A.current.show(r);
},
[A]
);
return /* @__PURE__ */ a(
Z.Provider,
{
value: {
dateStr: (r) => D(r)
},
children: /* @__PURE__ */ y("div", { className: "wx-8ZGHQX6e wx-comments-list", children: [
/* @__PURE__ */ a(
le,
{
at: "bottom",
ref: A,
options: te,
resolver: (r) => r,
dataKey: "commentMenuId",
onClick: ee
}
),
/* @__PURE__ */ a("div", { className: "wx-8ZGHQX6e wx-list", onClick: ne, children: /* @__PURE__ */ a(
He,
{
author: T,
render: i,
data: B,
format: m,
edit: C,
onPost: (r) => J(C, r.value),
onCancel: Y
}
) }),
!o && !C && /* @__PURE__ */ a(
G,
{
author: T,
flow: i === "flow",
focus: v,
onPost: (r) => X(r.value),
buttonLabel: "Add",
value: k,
onChange: ({ value: r }) => q(r)
}
)
] })
}
);
}
function Re(e) {
const { onData: t, onChange: n, value: o, ...i } = e;
let [m, c] = P([]);
Q(() => {
t && o ? Promise.resolve(t(o)).then((l) => c(l)) : c(o || []);
}, [t, o]);
const s = V(
(l) => (l.originalValue = o, n && n(l)),
[n, o]
);
return /* @__PURE__ */ a(se, { words: { ...fe, ...de }, optional: !0, children: /* @__PURE__ */ a(De, { data: m, ...i, onChange: s }) });
}
const Ze = ({ children: e, fonts: t }) => e ? /* @__PURE__ */ a(O, { fonts: t, children: e }) : /* @__PURE__ */ a(O, { fonts: t }), qe = ({ children: e, fonts: t }) => e ? /* @__PURE__ */ a(U, { fonts: t, children: e }) : /* @__PURE__ */ a(U, { fonts: t });
export {
Re as Comments,
Ze as Willow,
qe as WillowDark
};