UNPKG

@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

209 lines (208 loc) 7.59 kB
/** * @license *------------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the package root for more information *------------------------------------------------------------------------------------------- */ import { Keys as n, dispatchEvent as l, validatePackage as p, WatermarkOverlay as h, classNames as u } from "@progress/kendo-react-common"; import o from "prop-types"; import * as i from "react"; import { convertMsgsToViewItems as d } from "../ViewItem.mjs"; import g from "./ActionGroup.mjs"; import f from "./AttachmentGroup.mjs"; import I from "./DateMarker.mjs"; import T from "./MessageGroup.mjs"; import w from "./NewMessage.mjs"; import { ChatMessage as k } from "./ChatMessage.mjs"; import { packageMetadata as y } from "../package-metadata.mjs"; import { ariaLabelMessageList as c, messages as S } from "../messages/index.mjs"; import { provideLocalizationService as x } from "@progress/kendo-react-intl"; const a = class a extends i.Component { constructor(s) { super(s), this.viewItems = [], this.isDirectionRightToLeft = !1, this.scrollToBottomOnLoadingData = !0, this.showLicenseWatermark = !1, this.onFocus = () => { clearTimeout(this.timeoutIdForChatLosingFocus); }, this.onBlur = () => { this.timeoutIdForChatLosingFocus = window.setTimeout(() => { this.setState({ selectedItemIndex: null }); }, 0); }, this.onSelectionRequested = (e) => { this.setState({ selectedItemIndex: e }); }, this.onKeyDown = (e) => { let t = null; const r = this.state.selectedItemIndex !== null ? this.state.selectedItemIndex : this.viewItems.lastSelectionIndex; e.keyCode === n.up ? r === null ? t = 0 : r > 0 && (t = r - 1) : e.keyCode === n.down && (r === null ? t = 0 : r < this.viewItems.lastSelectionIndex && (t = r + 1)), t !== null && (this.setState({ selectedItemIndex: t }), e.preventDefault()); }, this.onMessageSend = (e, t) => { l(this.props.onMessageSend, t, this, { message: e }); }, this.onActionExecute = (e, t) => { if (l(this.props.onActionExecute, t, this, { action: e }), !t.isDefaultPrevented()) { switch (e.type) { case "reply": this.onMessageSend( { author: this.props.user, text: e.value, timestamp: /* @__PURE__ */ new Date() }, t ); break; case "call": window.open("tel:" + e.value); break; case "openUrl": window.open(e.value); break; } this.newMsgComp.focusInput(); } }, this.showLicenseWatermark = !p(y, { component: "Chat" }), this.state = { selectedItemIndex: null, isFirstRender: !0 }; } /** * @hidden */ render() { this.viewItems = this.getViewItemsFromMsgs(this.props.messages), this.isDirectionRightToLeft = this.checkIsDirectionRightToLeft(this.props); const s = x(this); return /* @__PURE__ */ i.createElement( "div", { style: { width: this.props.width, position: "relative" }, onKeyDown: this.onKeyDown, className: this.getClassNames(), ref: (e) => this.chatWrapperEl = e }, /* @__PURE__ */ i.createElement( "div", { className: "k-message-list k-avatars", onBlur: this.onBlur, onFocus: this.onFocus, role: "log", "aria-label": s.toLanguageString( c, S[c] ), "aria-live": "polite", onScroll: (e) => { this.scrollToBottomOnLoadingData = e.currentTarget.scrollTop === e.currentTarget.scrollHeight - e.currentTarget.clientHeight; }, ref: (e) => this.viewItemsWrapperEl = e }, /* @__PURE__ */ i.createElement("div", { className: "k-message-list-content" }, this.renderViewItems()) ), /* @__PURE__ */ i.createElement( w, { user: this.props.user, onMessageSend: this.onMessageSend, isDirectionRightToLeft: this.isDirectionRightToLeft, ref: (e) => this.newMsgComp = e, placeholder: this.props.placeholder, MessageBox: this.props.messageBox, toolbar: this.props.toolbar, onToolbarActionButtonClick: this.props.onToolbarActionExecute, showToolbar: this.props.showToolbar } ), this.showLicenseWatermark && /* @__PURE__ */ i.createElement(h, null) ); } /** * @hidden */ componentDidMount() { this.setState({ isFirstRender: !1 }, () => { this.nextTickId = window.setTimeout(() => this.scrollViewItemsToBottom(), 250); }); } /** * @hidden */ componentWillUnmount() { clearTimeout(this.nextTickId); } /** * @hidden */ componentDidUpdate(s) { s.messages.length !== this.props.messages.length && this.scrollToBottomOnLoadingData && this.scrollViewItemsToBottom(); } getClassNames() { return u("k-chat", this.props.className, { "k-rtl": this.isDirectionRightToLeft }); } checkIsDirectionRightToLeft(s) { return !!(s.dir !== void 0 ? s.dir === "rtl" : this.chatWrapperEl && getComputedStyle(this.chatWrapperEl).direction === "rtl"); } renderViewItems() { const s = this.viewItems.length - 1; return this.viewItems.map((e, t) => { if (e.type === "date-marker") return /* @__PURE__ */ i.createElement(I, { item: e, key: t }); if (e.type === "message-group") return /* @__PURE__ */ i.createElement( T, { group: e, itemTemplate: this.props.messageTemplate, attachmentTemplate: this.props.attachmentTemplate, user: this.props.user, selectedItemIndex: this.state.selectedItemIndex, onRequestSelection: this.onSelectionRequested, isLastGroup: t === s, key: t, message: this.props.message || a.defaultProps.message } ); if (e.type === "attachment-group") return /* @__PURE__ */ i.createElement( f, { group: e, itemTemplate: this.props.attachmentTemplate, onRequestSelection: this.onSelectionRequested, selected: e.selectionIndex === this.state.selectedItemIndex, isLastGroup: t === s, key: t } ); if (e.type === "action-group") return /* @__PURE__ */ i.createElement( g, { group: e, onActionExecute: this.onActionExecute, onRequestSelection: this.onSelectionRequested, selected: e.selectionIndex === this.state.selectedItemIndex, isLastGroup: t === s, key: t } ); }); } scrollViewItemsToBottom() { this.viewItemsWrapperEl && (this.viewItemsWrapperEl.scrollTop = this.viewItemsWrapperEl.scrollHeight - this.viewItemsWrapperEl.clientHeight); } getViewItemsFromMsgs(s) { return s.length > 0 ? d(s) : []; } }; a.propTypes = { messages: o.arrayOf(o.object), user: o.object, messageTemplate: o.any, attachmentTemplate: o.any, width: o.oneOfType([o.string, o.number]), onMessageSend: o.func, onActionExecute: o.func, dir: o.string, messageBox: o.any }, a.defaultProps = { messages: [], dateFormat: "g", message: k }; let m = a; export { m as Chat };