@progress/kendo-react-conversational-ui
Version:
React Chat component allows the user to participate in chat sessions with users or chat bots. KendoReact Conversational UI components
173 lines (170 loc) • 4.93 kB
JavaScript
/**
* @license
*-------------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the package root for more information
*-------------------------------------------------------------------------------------------
*/
import * as c from "react";
const A = 50, _ = 250, h = 50, m = 100, B = ({
viewItemsWrapperRef: n,
isKeyboardNavigationActiveRef: S,
processedMessages: a,
suggestions: f
}) => {
const s = c.useCallback(() => {
n.current && (n.current.scrollTop = n.current.scrollHeight - n.current.clientHeight);
}, [n]), u = c.useCallback(() => {
if (!n.current)
return !0;
const t = n.current, { scrollTop: e, scrollHeight: r, clientHeight: l } = t, i = A + 25;
return r - e - l < i;
}, [n]), b = c.useCallback((t) => t === 0 ? 16 : t <= 2 ? 32 * t : Math.min(50 * t, 200), []), C = c.useCallback(
(t, e) => {
const r = b(t);
setTimeout(() => {
!u() && n.current && e(t + 1);
}, r);
},
[b, u, n]
), d = c.useCallback(() => {
const t = (e = 0) => {
e > 5 || requestAnimationFrame(() => {
s(), C(e, t);
});
};
t();
}, [s, C]), y = c.useCallback(() => {
s(), setTimeout(() => {
!u() && n.current && s();
}, 50);
}, [s, u, n]), E = c.useCallback(() => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
requestAnimationFrame(y);
});
});
}, [y]), L = c.useCallback(() => {
s(), setTimeout(() => {
!u() && n.current && d();
}, 25);
}, [s, u, n, d]), o = c.useCallback(
(t = !1) => {
if (!n.current || S.current)
return;
u() && (t ? L() : E());
},
[
u,
L,
E,
n,
S
]
);
c.useEffect(() => {
const t = window.setTimeout(() => s(), _);
return () => {
clearTimeout(t);
};
}, [s]), c.useEffect(() => {
d();
}, [a.length, d]);
const k = c.useRef(/* @__PURE__ */ new Map());
c.useEffect(() => {
const t = /* @__PURE__ */ new Map();
let e = !1;
a.forEach((r) => {
if (r.id !== void 0) {
const l = r.id, i = !!r.typing, T = k.current.get(l);
t.set(l, i), T === !0 && i === !1 && (e = !0);
}
}), k.current = t, e && d();
}, [a, d]), c.useEffect(() => {
const t = window.setTimeout(() => {
o();
}, h);
return () => {
clearTimeout(t);
};
}, [a, o]), c.useEffect(() => {
if (a.length > 0) {
const t = a[a.length - 1], e = (t == null ? void 0 : t.text) || "";
(e.includes("```") || e.includes(`
`) || e.includes("<pre>") || e.includes("<code>") || e.includes("<table>") || e.length > 500) && o(!0);
}
}, [a, o]), c.useEffect(() => {
if (f && f.length > 0) {
const t = window.setTimeout(() => {
o();
}, m);
return () => {
clearTimeout(t);
};
}
}, [f, o]), c.useEffect(() => {
if (!n.current)
return () => {
};
let t;
const e = new ResizeObserver(() => {
t && clearTimeout(t), t = window.setTimeout(() => {
o();
}, h);
}), r = n.current.querySelector(".k-message-list-content");
return r && e.observe(r), () => {
e.disconnect();
};
}, [o, n]);
const g = c.useCallback((t) => {
var r;
if (t.type !== "characterData" && t.type !== "childList")
return !1;
const e = (r = t.target.textContent) != null ? r : "";
return e.includes("```") || e.includes(`
`) || e.includes("<pre>") || e.includes("<code>") || e.includes("<table>") || t.addedNodes && t.addedNodes.length > 2;
}, []), O = c.useCallback(
(t) => {
let e = !1, r = !1;
return t.forEach((l) => {
var i;
(l.type === "childList" || l.type === "characterData" || l.type === "attributes" && ["class", "style"].includes((i = l.attributeName) != null ? i : "")) && (e = !0, g(l) && (r = !0));
}), { shouldScroll: e, hasSignificantChange: r };
},
[g]
), D = c.useCallback(
(t, e) => {
e.current && clearTimeout(e.current), t ? o(!0) : e.current = window.setTimeout(() => {
o();
}, h);
},
[o]
);
c.useEffect(() => {
if (!n.current)
return () => {
};
const t = { current: void 0 };
let e = 0;
const r = new MutationObserver((l) => {
const i = Date.now();
if (i - e < 16)
return;
e = i;
const { shouldScroll: T, hasSignificantChange: x } = O(l);
T && u() && D(x, t);
});
return r.observe(n.current, {
childList: !0,
subtree: !0,
characterData: !0,
attributes: !0,
attributeFilter: ["class", "style"]
}), () => {
r.disconnect(), t.current && clearTimeout(t.current);
};
}, [u, O, D, n]);
};
export {
B as useChatScroll
};