UNPKG

isomtrik-quickchat

Version:

isomtrik-quickchat is a lightweight, real-time chat component built with Stencil JS. It is designed to be seamlessly integrated into web applications, offering customizable and responsive chat functionalities. The module supports both CommonJS and ES modu

1,191 lines (1,102 loc) 77.5 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const index = require('./index-e1c67530.js'); const DocumentMessageBubble = require('./DocumentMessageBubble-a17c8aa2.js'); require('./ImageMessageBubble-1efdd496.js'); require('./VideoMessageBubble-db9efd68.js'); const ClockMark = require('./ClockMark-6b4b6198.js'); const index_m = require('./index.m-6869e521.js'); const Image = require('./Image-6ad8d97b.js'); const Text = ({ content = '', color = '', fontSize = '16px', textAlign = 'center', fontWeight = 'normal', fontStyle = 'normal', backgroundColor = 'transparent', borderColor = 'transparent', borderWidth = '1px', borderStyle = 'solid', borderRadius = '4px', fontFamily = '', width = "", height = "auto", }) => { return ClockMark.ke` <div class="storybook-text" style=${ClockMark.se({ color, fontSize, textAlign, fontWeight, fontStyle, backgroundColor, borderColor, borderWidth, borderStyle, borderRadius, fontFamily, width, height })} > ${content} </div> `; }; class IncomingTextMessageBubble extends ClockMark.h { static properties = { bgColor: { type: String }, msgTextColor: { type: String }, msgTextTimeColor: { type: String }, borderWidth: { type: String }, borderColor: { type: String }, borderStyle: { type: String }, borderRadius: { type: String }, padding: { type: String }, height: { type: String }, width: { type: String }, time: { type: String }, textContent: { type: String }, alignSelf: {type: String}, fontFamily: {type: String} }; static styles = ClockMark.i$1` .message-container { position: relative; width:fit-content; max-width:80% !important; align-self: center; overflow-wrap: break-word; } .image-container { cursor: pointer; } .full-screen-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.8); display: flex; justify-content: center; align-items: center; z-index: 9999; } .full-screen-image { max-width: 90%; max-height: 90%; object-fit: cover; } .close-button { position: absolute; top: 20px; right: 20px; font-size: 2rem; color: white; cursor: pointer; background: transparent; border: none; } `; openFullScreen() { this.isFullScreen = true; } closeFullScreen() { this.isFullScreen = false; } render() { return ClockMark.ke` <div class="message-container" style="padding:${this.padding || "10px"}; border-width: ${this.borderWidth}; border-color: ${this.borderColor}; border-style:${this.borderStyle}; border-radius:${this.borderRadius || '7px'}; height:${this.height}; background-color:${this.bgColor || "#EFF1FA"}; align-self: ${this.alignSelf || 'left'} font-family: ${this.fontFamily} " > ${Text({ content: this.textContent || 'some incoming message some somesomesomesome', // width: '90%', textAlign: 'left', fontFamily: this.fontFamily, color: this.msgTextColor })} <timestamp-element .time="${this.time || new Date().toISOString()}" .color="${this.msgTextTimeColor}"></timestamp-element> </div> `; } } customElements.define('incoming-text-message-bubble', IncomingTextMessageBubble); class OutgoingTextMessageBubble extends ClockMark.h { static properties = { bgColor: { type: String }, msgTextColor: { type: String }, msgTextTimeColor: { type: String }, borderWidth: { type: String }, borderColor: { type: String }, borderStyle: { type: String }, borderRadius: { type: String }, padding: { type: String }, height: { type: String }, width: { type: String }, time: { type: String }, textContent: { type: String }, alignSelf: { type: String }, isRead: { type: Boolean }, isPopupOpen: { type: Boolean }, fontFamily: { type: String }, isDelivered: { type: String }, }; constructor() { super(); this.isPopupOpen = false; } static styles = ClockMark.i$1` .message-container { position: relative; width: fit-content; max-width: 80% !important; align-self: center; overflow-wrap: break-word; } .message-footer { display: flex; flex-direction: row; align-items: center; justify-content: end; gap: 2px; } .actions { position: absolute; left: -15px; cursor: pointer; top: 5px; } .popup { position: absolute; top: 0px; left: -100px; background-color: white; border: 1px solid #eef1fa; border-radius: 5px; padding: 10px; box-shadow: 0 2px 10px #eef1fa; z-index: 10; display: flex; flex-items: column; align-items: center; justify-content: center; } .popup div { cursor: pointer; } `; openPopup() { this.isPopupOpen = !this.isPopupOpen; } openFullScreen() { this.isFullScreen = true; } closeFullScreen() { this.isFullScreen = false; } render() { return ClockMark.ke` <div class="message-container" style="padding:${this.padding || '10px'}; border-width: ${this.borderWidth}; border-color: ${this.borderColor } border-style:${this.borderStyle || 'solid'}; border-radius:${this.borderRadius || '10px'}; height:${this.height}; background-color:${this.bgColor || '#FFF'}; align-self: ${this.alignSelf || 'right'} font-family: ${this.fontFamily} " > ${Text({ content: this.textContent || 'some outgoing message sssj sj sj ssj ssj some some smosk ajabfa bfa bfhjab ome somesomesomesome', textAlign: 'left', fontFamily: this.fontFamily, color: this.msgTextColor })} <div class="message-footer"> <div><timestamp-element .time="${this.time || new Date().toISOString()}" .color="${this.msgTextTimeColor}"></timestamp-element></div> ${this.isRead == true ? ClockMark.ke`<blue-read-mark></blue-read-mark>` : this.isDelivered == 'true' ? ClockMark.ke`<double-mark></double-mark>` : this.isDelivered == 'pending' ? ClockMark.ke`<clock-mark></clock-mark>` : ClockMark.ke`<single-mark></single-mark>`} </div> </div> `; } } customElements.define('outgoing-text-message-bubble', OutgoingTextMessageBubble); const formatMessageDateFromTimestamp = (timestamp) => { if (!timestamp) { return ''; } const messageDate = new Date(timestamp); const today = new Date(); today.setHours(0, 0, 0, 0); const yesterday = new Date(today); yesterday.setDate(today.getDate() - 1); const day = messageDate.getDate(); const month = messageDate.toLocaleString(undefined, { month: 'long' }); // Function to determine the ordinal suffix (st, nd, rd, th) const getOrdinalSuffix = (day) => { if (day > 3 && day < 21) return 'th'; switch (day % 10) { case 1: return 'st'; case 2: return 'nd'; case 3: return 'rd'; default: return 'th'; } }; const formattedDate = `${day}${getOrdinalSuffix(day)} ${month}`; if (messageDate >= today) { return 'Today'; } else if (messageDate >= yesterday && messageDate < today) { return 'Yesterday'; } else { return formattedDate; } }; class MessageDatePill extends ClockMark.h { static properties = { bgColor: { type: String }, textColor: { type: String }, width: { type: String }, padding: { type: String }, borderRadius: { type: String }, borderWidth: { type: String }, borderColor: { type: String }, fontSize: { type: String }, fontWeight: { type: String }, fontFamily: { type: String }, content: { type: String }, }; render() { return ClockMark.ke` <div style="background-color: ${this.bgColor || '#F9E3FF'}; width: ${this.width}; border-radius: ${this.borderRadius}; border-width: ${this.borderWidth}; border-color: ${this.borderColor}; padding: ${this.padding}; color: ${this.textColor}; font-family: ${this.fontFamily}; font-size: ${this.fontSize}; font-weight: ${this.fontWeight}; " > ${this.content} </div> `; } } customElements.define('message-date-pill', MessageDatePill); class SpinnerLoader extends ClockMark.h { static properties = { height: { type: String }, width: { type: String }, spinTime: { type: String }, spinnerPrimaryColor: { type: String }, spinnerSecondaryColor: { type: String }, spinnerBorderWidth: { type: String }, }; static styles = ClockMark.i$1` .spinner { border-radius: 50%; z-index: 10; } .main-container { position: relative; width: 100%; display: flex; align-items: center; justify-content: center; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; render() { return ClockMark.ke` <div class="main-container"> <div class="spinner" style=" border-color: ${this.spinnerSecondaryColor}; border-width: ${this.spinnerBorderWidth}; border-style: solid; border-top-color: ${this.spinnerPrimaryColor}; height: ${this.height}; width: ${this.width}; animation: spin ${this.spinTime} linear infinite; " ></div> </div> `; } } customElements.define('spinner-loader', SpinnerLoader); const ChatBody = class { constructor(hostRef) { index.registerInstance(this, hostRef); this.openPopup = (event, messageId) => { event.stopPropagation(); this.isPopupOpen = this.isPopupOpen === messageId ? null : messageId; }; // Function to handle scroll event and trigger API call when scrolled near the bottom this.handleScroll = () => { const chatBodyDiv = this.chatBodyElement.shadowRoot.querySelector('.chat-body'); if (chatBodyDiv) { const scrollTop = chatBodyDiv.scrollTop; if (scrollTop === 0 && !this.isMessageLimitEnd) { this.updateSkip(); } // if (this.scrollTimeout) { // clearTimeout(this.scrollTimeout); // } // this.scrollTimeout = setTimeout(() => { // }, 300); this.onScrollEnd(); } }; this.onScrollEnd = () => { const chatBodyDiv = this.chatBodyElement.shadowRoot.querySelector('.chat-body'); const scrollTop = chatBodyDiv.scrollTop; this.previousTotalScrollHeight = chatBodyDiv.scrollHeight - scrollTop; }; // Function to scroll the chat body to the bottom this.scrollToBottom = () => { const chatBodyDiv = this.chatBodyElement.shadowRoot.querySelector('.chat-body'); const scrollTop = chatBodyDiv.scrollTop; if (chatBodyDiv) { setTimeout(() => { chatBodyDiv.scrollTop = chatBodyDiv.scrollHeight; // Scroll to the bottom this.previousTotalScrollHeight = chatBodyDiv.scrollHeight - scrollTop; }, 200); } }; this.scrollToTop = () => { const chatBodyDiv = this.chatBodyElement.shadowRoot.querySelector('.chat-body'); if (chatBodyDiv) { setTimeout(() => { const toScroll = chatBodyDiv.scrollHeight - this.previousTotalScrollHeight; chatBodyDiv.scrollTop = toScroll; this.previousTotalScrollHeight = chatBodyDiv.scrollHeight; }, 0); } }; this.putReadAll = async () => { var _a; const hasUnreadMessages = this.allMessages.some(message => { var _a, _b; return ((message === null || message === void 0 ? void 0 : message.senderId) || ((_a = message === null || message === void 0 ? void 0 : message.senderInfo) === null || _a === void 0 ? void 0 : _a.userId)) != ((_b = this.userMetaData) === null || _b === void 0 ? void 0 : _b.userId) && !message.readByAll; }); if (hasUnreadMessages) { await index_m.w.getInstance().message.putRead({ conversationId: this.conversationId }); const newUpdatedAllMessages = (_a = this.allMessages) === null || _a === void 0 ? void 0 : _a.map(message => { var _a, _b; return (message === null || message === void 0 ? void 0 : message.readByAll) != true && ((message === null || message === void 0 ? void 0 : message.senderId) || ((_a = message === null || message === void 0 ? void 0 : message.senderInfo) === null || _a === void 0 ? void 0 : _a.userId)) != ((_b = this.userMetaData) === null || _b === void 0 ? void 0 : _b.userId) ? Object.assign(Object.assign({}, message), { readByAll: true }) : message; }); this.updateAllMessages(newUpdatedAllMessages); } }; this.handleVisibilityChange = async () => { if (document.visibilityState === 'visible') { this.isTabActive = true; this.putReadAll(); } else { this.isTabActive = false; } }; // Add a new method to handle document clicks this.handleDocumentClick = (event) => { const target = event.target; if (!target.closest('.popup') && !target.closest('.kebab-menu')) { this.isPopupOpen = null; } }; this.isSelf = false; this.conversationId = undefined; this.skip = undefined; this.isDark = undefined; this.allMessages = undefined; this.userMetaData = undefined; this.isMessagesLoading = undefined; this.isMessageSending = undefined; this.isMessageLimitEnd = undefined; this.updateSkip = undefined; this.isScrollToBottom = undefined; this.isScrollToTop = undefined; this.deleteForAll = undefined; this.deleteForSelf = undefined; this.changeScrollToBottomState = undefined; this.changeScrollToTopState = undefined; this.updateAllMessages = undefined; this.isChatClosed = undefined; this.isChatMinimized = undefined; this.previousTotalScrollHeight = 0; this.deviceId = ''; this.scrollTimeout = null; this.isPopupOpen = null; this.deletedMessages = new Set(); this.isTabActive = true; } deleteMessageForSelf(messageId) { this.deleteForSelf({ conversationId: this.conversationId, messageIds: messageId }); this.isPopupOpen = null; } deleteMessageForEveryone(messageId) { this.deleteForAll({ conversationId: this.conversationId, messageIds: messageId }); this.isPopupOpen = null; } async componentWillLoad() { const deviceId = await index_m.getDeviceID(); this.deviceId = deviceId; } // Attach the scroll listener after the component has loaded async componentDidLoad() { document.addEventListener('visibilitychange', this.handleVisibilityChange); document.addEventListener('click', this.handleDocumentClick); const chatBodyDiv = this.chatBodyElement.shadowRoot.querySelector('.chat-body'); if (chatBodyDiv) { chatBodyDiv.addEventListener('scroll', this.handleScroll); // Listen to the scroll event } this.scrollToBottom(); this.putReadAll(); } async handleDataChange() { var _a, _b; if (this.isScrollToBottom && this.allMessages.length > 0 && ((_a = this.userMetaData) === null || _a === void 0 ? void 0 : _a.userId)) { this.scrollToBottom(); this.changeScrollToBottomState(false); } else if (this.allMessages.length > 0 && ((_b = this.userMetaData) === null || _b === void 0 ? void 0 : _b.userId) && !this.isScrollToBottom && this.isScrollToTop) { this.scrollToTop(); this.changeScrollToTopState(false); } if (!this.isChatMinimized && !this.isChatClosed && this.isTabActive) { this.putReadAll(); } } // Clean up the scroll listener when the component is removed disconnectedCallback() { document.removeEventListener('visibilitychange', this.handleVisibilityChange); document.removeEventListener('click', this.handleDocumentClick); const chatBodyDiv = this.chatBodyElement.shadowRoot.querySelector('.chat-body'); if (chatBodyDiv) { chatBodyDiv.removeEventListener('scroll', this.handleScroll); // Remove the scroll listener } } render() { var _a; const backgroundImage = index.getAssetPath('https://isometrik-website-bucket.s3.ap-south-1.amazonaws.com/chat_BG_8a53348931.png'); return (index.h(index.Host, { key: '3986d01d3b846ad517b2c61f6fe716bf7503b394' }, index.h("div", { key: '05072e8c6db5067a8176f1aaaed88fe4239326f7', id: 'lol', class: "chat-body chat-body-bg", style: { backgroundColor: 'var(--chat-body-bg)', backgroundImage: `url(${backgroundImage})`, display: 'flex', flexGrow: '1', flexDirection: 'column', gap: '20px', padding: '10px 15px 35px 10px', overflowY: 'scroll', } }, this.isMessagesLoading && (index.h("spinner-loader", { key: '95f62ae1152616164dba87849942e87d4c16cc0a', height: "20px", width: "20px", spinTime: "1s", spinnerPrimaryColor: "#000", spinnerSecondaryColor: "#F9E3FF", spinnerBorderWidth: "3px" })), this.allMessages.length > 0 && ((_a = this.userMetaData) === null || _a === void 0 ? void 0 : _a.userId) && this.allMessages.map((message, index$1) => { var _a, _b, _c; const currentMessageDate = formatMessageDateFromTimestamp(this.allMessages[index$1].sentAt); const previousMessageDate = formatMessageDateFromTimestamp(((_a = this.allMessages[index$1 - 1]) === null || _a === void 0 ? void 0 : _a.sentAt) || ''); const showDatePill = currentMessageDate !== previousMessageDate; if (message.attachments) { return (index.h("div", { style: { display: 'flex', width: '100%', flexDirection: 'column', gap: '15px' } }, showDatePill && (index.h("div", { style: { display: 'flex', width: '100%', justifyContent: 'center' } }, index.h("message-date-pill", { borderRadius: '9px', textColor: 'var(--chat-date-pill-text)', bgColor: 'var(--chat-date-pill-bg)', padding: '5px 20px', content: currentMessageDate }))), message.attachments.map((attachment) => { var _a, _b; if (((message === null || message === void 0 ? void 0 : message.senderId) || ((_a = message === null || message === void 0 ? void 0 : message.senderInfo) === null || _a === void 0 ? void 0 : _a.userId)) == ((_b = this.userMetaData) === null || _b === void 0 ? void 0 : _b.userId)) { return (index.h("div", { id: "outgoing-message", style: { position: 'relative', display: 'flex', width: '100%', justifyContent: 'right' } }, attachment.mimeType.startsWith('application/') ? (index.h("document-message", { docType: attachment.mimeType, fileName: attachment.name, href: attachment.mediaUrl, bgColor: 'var(--chat-outgoing-msg-bg)', width: "220px", padding: "10px 10px 30px 10px", borderRadius: "6px", time: message === null || message === void 0 ? void 0 : message.sentAt, docName: attachment.name, isRead: message.readByAll, isSelf: true, isDelivered: `${message === null || message === void 0 ? void 0 : message.deliveredToAll}` })) : attachment.mimeType.startsWith('video/') ? (index.h("video-message", { height: '180px', width: '200px', padding: "10px 10px 20px 10px", bgColor: 'var(--chat-outgoing-msg-bg)', isSelf: true, borderRadius: "6px", time: message === null || message === void 0 ? void 0 : message.sentAt, type: attachment.mimeType, videoSrc: attachment.mediaUrl, isRead: message.readByAll, isDelivered: `${message === null || message === void 0 ? void 0 : message.deliveredToAll}` })) : attachment.mimeType.startsWith('image/') ? (index.h("image-message", { bgColor: 'var(--chat-outgoing-msg-bg)', padding: "10px 10px 20px 10px", isSelf: true, borderRadius: "6px", time: message === null || message === void 0 ? void 0 : message.sentAt, imageSrc: attachment.mediaUrl, height: '150px', width: '150px', isRead: message.readByAll, borderWidth: '5px', borderColor: 'var(--chat-outgoing-msg-bg)', borderStyle: 'solid', isDelivered: `${message === null || message === void 0 ? void 0 : message.deliveredToAll}` })) : (''), index.h("span", { class: "kebab-menu", style: { cursor: 'pointer', position: 'absolute', right: '-12px ', top: '5px' }, onClick: e => this.openPopup(e, message === null || message === void 0 ? void 0 : message.messageId) }, index.h("svg", { width: "14px", height: "14px", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", fill: 'var(--chat-msg-info-icon)', class: "bi bi-three-dots-vertical" }, index.h("g", { id: "SVGRepo_bgCarrier", "stroke-width": "0" }), index.h("g", { id: "SVGRepo_tracerCarrier", "stroke-linecap": "round", "stroke-linejoin": "round" }), index.h("g", { id: "SVGRepo_iconCarrier" }, index.h("path", { d: "M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z" })))), this.isPopupOpen === (message === null || message === void 0 ? void 0 : message.messageId) ? (index.h("div", { class: "popup" }, index.h("span", { class: "deleteText", onClick: () => this.deleteMessageForSelf(message === null || message === void 0 ? void 0 : message.messageId) }, "Delete For Me"), index.h("span", { class: "deleteText", onClick: () => this.deleteMessageForEveryone(message === null || message === void 0 ? void 0 : message.messageId) }, "Delete For All"))) : null)); } else { return (index.h("div", { style: { display: 'flex', width: '100%', justifyContent: 'left' } }, attachment.mimeType.startsWith('application/') ? (index.h("document-message", { docType: attachment.mimeType, fileName: attachment.name, href: attachment.mediaUrl, bgColor: 'var(--chat-incoming-msg-bg)', width: "220px", padding: "10px 10px 30px 10px", borderRadius: "6px", time: message === null || message === void 0 ? void 0 : message.sentAt, docName: attachment.name, isSelf: false })) : attachment.mimeType.startsWith('video/') ? (index.h("video-message", { height: '180px', width: '200px', bgColor: 'var(--chat-incoming-msg-bg)', padding: "10px 10px 20px 10px", borderRadius: "6px", isSelf: false, time: message === null || message === void 0 ? void 0 : message.sentAt, type: attachment.mimeType, videoSrc: attachment.mediaUrl })) : attachment.mimeType.startsWith('image/') ? (index.h("image-message", { bgColor: 'var(--chat-incoming-msg-bg)', padding: "10px 10px 20px 10px", borderRadius: "6px", isSelf: false, time: message === null || message === void 0 ? void 0 : message.sentAt, imageSrc: attachment.mediaUrl, height: '150px', width: '150px', borderWidth: '5px', borderColor: 'var(--chat-incoming-msg-bg)', borderStyle: 'solid' })) : (''))); } }))); } else if (message.body) { if (((message === null || message === void 0 ? void 0 : message.senderId) || ((_b = message === null || message === void 0 ? void 0 : message.senderInfo) === null || _b === void 0 ? void 0 : _b.userId)) == ((_c = this.userMetaData) === null || _c === void 0 ? void 0 : _c.userId)) { return (index.h("div", { style: { display: 'flex', width: '100%', flexDirection: 'column', gap: '15px' } }, showDatePill && (index.h("div", { style: { display: 'flex', width: '100%', justifyContent: 'center' } }, index.h("message-date-pill", { borderRadius: '9px', textColor: 'var(--chat-date-pill-text)', bgColor: 'var(--chat-date-pill-bg)', padding: '5px 20px', content: currentMessageDate }))), index.h("div", { id: "outgoing-message", style: { position: 'relative', display: 'flex', width: '100%', justifyContent: 'end' } }, index.h("outgoing-text-message-bubble", { msgTextColor: 'var(--chat-outgoing-msg-text)', msgTextTimeColor: 'var(--chat-outgoing-msg-time-text)', isRead: message.readByAll, padding: "10px 10px 1px 10px", borderRadius: "10px 10px 0 10px", textContent: message === null || message === void 0 ? void 0 : message.body, time: message === null || message === void 0 ? void 0 : message.sentAt, bgColor: 'var(--chat-outgoing-msg-bg)', isDelivered: `${message === null || message === void 0 ? void 0 : message.deliveredToAll}` }), index.h("span", { class: "kebab-menu", style: { cursor: 'pointer', position: 'absolute', right: '-12px ', top: '5px' }, onClick: e => this.openPopup(e, message === null || message === void 0 ? void 0 : message.messageId) }, index.h("svg", { width: "14px", height: "14px", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", fill: 'var(--chat-msg-info-icon, #000)', class: "bi bi-three-dots-vertical" }, index.h("g", { id: "SVGRepo_bgCarrier", "stroke-width": "0" }), index.h("g", { id: "SVGRepo_tracerCarrier", "stroke-linecap": "round", "stroke-linejoin": "round" }), index.h("g", { id: "SVGRepo_iconCarrier" }, index.h("path", { d: "M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z" })))), this.isPopupOpen === (message === null || message === void 0 ? void 0 : message.messageId) ? (index.h("div", { class: "popup" }, index.h("span", { class: "deleteText", onClick: () => this.deleteMessageForSelf(message === null || message === void 0 ? void 0 : message.messageId) }, "Delete For Me"), index.h("span", { class: "deleteText", onClick: () => this.deleteMessageForEveryone(message === null || message === void 0 ? void 0 : message.messageId) }, "Delete For All"))) : null))); } else { return (index.h("div", { style: { display: 'flex', width: '100%', flexDirection: 'column', gap: '15px' } }, showDatePill && (index.h("div", { style: { display: 'flex', width: '100%', justifyContent: 'center' } }, index.h("message-date-pill", { borderRadius: '9px', textColor: 'var(--chat-date-pill-text)', bgColor: 'var(--chat-date-pill-bg)', padding: '5px 20px', content: currentMessageDate }))), index.h("incoming-text-message-bubble", { bgColor: 'var(--chat-incoming-msg-bg)', msgTextTimeColor: 'var(--chat-incoming-msg-time-text)', msgTextColor: 'var(--chat-incoming-msg-text)', borderRadius: "10px 10px 10px 0", time: message === null || message === void 0 ? void 0 : message.sentAt, textContent: message === null || message === void 0 ? void 0 : message.body }))); } } else if (message.action == 'conversationCreated') { return (index.h("div", { style: { display: 'flex', width: '100%', justifyContent: 'center' } }, showDatePill && index.h("message-date-pill", { borderRadius: '9px', textColor: 'var(--chat-date-pill-text)', bgColor: 'var(--chat-date-pill-bg)', padding: '5px 20px', content: currentMessageDate }))); } })))); } get chatBodyElement() { return index.getElement(this); } static get watchers() { return { "allMessages": ["handleDataChange"], "userMetaData": ["handleDataChange"] }; } }; ChatBody.style = ":host {\n flex-grow: 1;\n overflow: hidden;\n display: flex;\n background-color: var(--chat-body-bg);\n}\n \n\n #outgoing-message > * {\n display: flex;\n width: 100%;\n justify-content: end;\n }\n\n ::-webkit-scrollbar {\n width: 5px;\n }\n\n ::-webkit-scrollbar-track {\n background: transparent;\n }\n ::-webkit-scrollbar-thumb {\n background-color: #F9E3FF !important;\n border-radius: 10px;\n }\n .popup {\n position: absolute;\n bottom: 100%;\n box-shadow: 0px 0px 10px 0px GRAY;\n z-index: 10;\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n justify-content: center !important;\n width: 30% !important;\n gap: 16px !important;\n background-color: #FFFFFF;\n font-family: 'Roboto';\n padding: 10px;\n font-weight:500;\n border-radius: 8px;\n }\n\n .popup span {\n cursor: pointer;\n }\n #outgoing-message .kebab-menu {\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n\n #outgoing-message:hover .kebab-menu {\n opacity: 1;\n }\n\n .deleteText {\n font-size: 14px;\n font-weight: 700;\n }"; class Input extends ClockMark.h { static properties = { value: { type: String }, placeholder: { type: String }, width: { type: String }, height: { type: String }, borderColor: { type: String }, borderRadius: { type: String }, backgroundColor: { type: String }, fontSize: { type: String }, padding: { type: String }, color: { type: String }, placeholderColor: { type: String }, borderWidth: { type: String }, inputHeight: { type: String }, minHeight: { type: String }, maxHeight: { type: String }, }; static styles = ClockMark.i$1` :host { display: block; } textarea { width: var(--input-width, 100%); max-height: var(--input-max-height, 100px); min-height: var(--input-min-height, 45px); height: var(--input-height, 45px); border: var(--input-border-width, 1px) solid var(--input-border-color, gray); border-radius: var(--input-border-radius, 4px); background-color: var(--input-background-color, white); font-size: var(--input-font-size, 16px); padding: var(--input-padding, 12px); color: var(--input-color); box-sizing: border-box; resize: none; overflow-y: auto; outline: none; border-width: none; font-family: 'Roboto'; transition: height 0.2s ease; } textarea::-webkit-scrollbar { width: 5px; } textarea::-webkit-scrollbar-track { background: #eff1fa; } textarea::-webkit-scrollbar-thumb { background-color: gray; border-radius: 10px; } textarea::-webkit-scrollbar-thumb:hover { background-color: #555; } textarea::placeholder { color: var(--input-placeholder-color, #aaa); font-family: sans-serif; } textarea:focus { border-color: transparent; outline: none; } `; constructor() { super(); this.value = ''; this.placeholder = 'Enter your text here...'; this.width = '100%'; this.minHeight = '45px'; this.maxHeight = '105px'; this.inputHeight = '45px'; this.borderColor = 'gray'; this.borderRadius = '4px'; this.backgroundColor = 'white'; this.fontSize = '16px'; this.padding = '12px'; this.placeholderColor = '#aaa'; this.borderWidth = '1px'; } render() { return ClockMark.ke` <textarea .value=${this.value} placeholder=${this.placeholder} style=${ClockMark.se({ '--input-width': this.width, '--input-min-height': this.minHeight, '--input-max-height': this.maxHeight, '--input-height': this.inputHeight, '--input-border-color': this.borderColor, '--input-border-radius': this.borderRadius, '--input-background-color': this.backgroundColor, '--input-font-size': this.fontSize, '--input-padding': this.padding, '--input-color': this.color || '#202020', '--input-placeholder-color': this.placeholderColor, '--input-border-width': this.borderWidth, })} @input=${this.handleInputChange} ></textarea> `; } handleInputChange(event) { this.value = event.target.value; this.adjustTextareaHeight(event.target); this.dispatchEvent( new CustomEvent('input', { detail: { value: this.value }, bubbles: true, composed: true, }), ); } // adjustTextareaHeight(textarea) { if (textarea.value.length === 0) { this.inputHeight = '45px'; } else { textarea.style.height = '45px'; const scrollHeight = textarea.scrollHeight; if (scrollHeight <= 45) { this.inputHeight = '45px'; } else if (scrollHeight > 45 && scrollHeight <= 105) { this.inputHeight = `${scrollHeight}px`; } else { this.inputHeight = '105px'; } } textarea.style.height = this.inputHeight; } resetHeight() { const textarea = this.shadowRoot.querySelector('textarea'); if (textarea) { this.inputHeight = '45px'; textarea.style.height = this.inputHeight; } } // } customElements.define('my-input', Input); class AttachmentBox extends ClockMark.h { static properties = { bgColor: { type: String }, textColor: { type: String }, documentIcon: { type: String }, mediaIcon: { type: String }, documentIconHeight: { type: String }, documentIconWidth: { type: String }, mediaIconHeight: { type: String }, mediaIconWidth: { type: String }, containerBorderWidth: { type: String }, containerBorderColor: { type: String }, containerBorderStyle: { type: String }, width: { type: String }, flexDirection: { type: String }, padding: { type: String }, iconGap: { type: String }, containerBorderRadius: { type: String }, onFileUploaded: {type: String} }; static styles = ClockMark.i$1` .attachment-box-container { display: flex; gap: 2px; color: white; align-items: center; } .document-container, .media-container { cursor: pointer !important; position: relative; display: flex; align-items: center; justify-content: center; } input[type="file"] { opacity: 0; position: absolute; width: 100%; height: 100%; top: 0; left: 0; cursor: pointer; } `; handleFileChange(event, fileType) { const file = event.target.files[0]; if (file) { console.log(`${fileType} uploaded:`, file); this.dispatchEvent(new CustomEvent('file-uploaded', { detail: {fileType, file}, bubbles: true, composed: true })); } } render() { return ClockMark.ke` <div class='attachment-box-container' style='background-color: ${this.bgColor}; border-width: ${this.containerBorderWidth}; border-color: ${this.containerBorderColor}; border-style: ${this.containerBorderStyle}; border-radius: ${this.containerBorderRadius || '10px'}; width: ${this.width}; flex-direction: ${this.flexDirection}; padding: ${this.padding}; gap: ${this.iconGap}; '> <div class='document-container'> ${this.documentIcon ? Image.Image({ src: this.documentIcon, alt: 'document icon', width: this.documentIconWidth, height: this.documentIconHeight, }) : ''} <input id="documentUpload" type="file" accept="application/" @change="${(e) => this.handleFileChange(e, 'Document')}" /> </div> <div class='media-container'> ${this.mediaIcon ? Image.Image({ src: this.mediaIcon, alt: 'media icon', width: this.mediaIconWidth, height: this.mediaIconHeight, }) : ''} <!-- Hidden file input for media --> <input id="mediaUpload" type="file" accept="image/*,video/*" @change="${(e) => this.handleFileChange(e, 'Media')}" /> </div> </div> `; } } customElements.define('attachment-box', AttachmentBox); class TestFooter extends ClockMark.h { constructor() { super(); (this.isAttachmentMenuVisible = false), (this.inputBorderColor = 'transparent'), (this.inputBorderWidth = '1px'); (this.inputBorderStyle = 'dashed'), (this.inputPlaceholder = 'Type in your message here'), (this.sendButtonIcon = 'https://flexcrew.s3.us-west-1.amazonaws.com/Group_1171280804_28e21ab22f.svg'), (this.attachmentIcon = 'https://flexcrew.s3.us-west-1.amazonaws.com/gallery_add_4272954ac0.svg'), (this.attachmentIconHeight = '34px'), (this.attachmentIconWidth = '34px'), (this.sendButtonIconHeight = '50px'), (this.sendButtonIconWidth = '50px'), (this.sendButtonIconRadius = '50%'), (this.inputFontSize = '16px'), (this.containerPadding = '10px'), (this.inputBorderRadius = '20px'), (this.inputContainerBorderWidth = '1px'), (this.inputContainerBorderRadius = '10px'), (this.inputContainerBorderStyle = 'solid'), (this.inputPlaceholderColor = '#D4D8EB'), (this.inputContainerPadding = '0 10px'), (this.onSendClick = null); } static properties = { bgColor: { type: String }, inputBorderColor: { type: String }, inputBorderWidth: { type: String }, inputBorderStyle: { type: String }, inputPlaceholder: { type: String }, inputBgColor: { type: String }, inputFontSize: { type: String }, inputFontColor: { type: String }, inputBorderRadius: { type: String }, attachmentIcon: { type: String }, attachmentIconColor: { type: String }, sendButtonIcon: { type: String }, sendButtonIconHeight: { type: String }, sendButtonIconWidth: { type: String }, attachmentIconHeight: { type: String }, attachmentIconWidth: { type: String }, sendButtonIconRadius: { type: String }, containerPadding: { type: String }, containerBoxShadow: { type: String }, inputContainerBorderColor: { type: String }, inputContainerBorderWidth: { type: String }, inputContainerBorderRadius: { type: String }, inputPlaceholderColor: { type: String }, inputContainerPadding: { type: String }, isAttachmentMenuVisible: { type: Boolean }, onSendClick: { type: Function }, inputValue: { type: String }, onMediaIconClick: { type: Function }, onDocumentClick: { type: Function }, onFileUploaded: { type: Function }, }; static styles = ClockMark.i$1` .footer-container { display: flex; align-items: end; gap: 10px; position: relative; box-shadow: 0 -4px 6px rgba(0, 0, 0, 0.1); } .input-container { flex: 1; display: flex; align-items: end; } .attachment-container { width: fit-content; margin-right: 10px; cursor: pointer; } .input-box-container { width: 100%; } .send-container { width: fit-content; } .focused-input { border: none !important; outline: none !important; } .attachment-menu { position: absolute; background-color: white; border: 1px solid #d4d8eb; bottom: 65px; left: 12px; padding: 10px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; gap: 10px; border-radius: 10px; } `; toggleAttachmentMenu() { this.isAttachmentMenuVisible = !this.isAttachmentMenuVisible; } handleInputChange(event) { this.inputValue = event.target.value; this.dispatchEvent( new CustomEvent('input-change', { detail: { value: this.inputValue }, bubbles: true, composed: true, }), ); } handleMediaIconClick() { console.log('inputclicked'); } resetInputHeight() { const inputElement = this.shadowRoot.querySelector('my-input'); if (inputElement) { inputElement.resetHeight(); } } fileUploadHandler(event) { this.onFileUploaded(event); this.isAttachmentMenuVisible = !this.isAttachmentMenuVisible; } render() { return ClockMark.ke` <div class='footer-container' style='padding: ${this.containerPadding}; box-shadow: ${this.containerBoxShadow}; background-color:${this.bgColor || '#000'}' > <div class='input-container' style='border-color: ${this.inputContainerBorderColor || 'D4D8EB'}; border-width: ${this.inputContainerBorderWidth}; border-radius: ${this.inputContainerBorderRadius}; border-style: solid; padding: ${this.inputContainerPadding}' background-color: ${this.inputBgColor || '#ffffff'} > <div class='attachment-container' @click="${this.toggleAttachmentMenu}"> <svg width="36px" height="36px" viewBox="0 0 24.00 24.00" 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="M13 4H8.8C7.11984 4 6.27976 4 5.63803 4.32698C5.07354 4.6146 4.6146 5.07354 4.32698 5.63803C4 6.27976 4 7.11984 4 8.8V15.2C4 16.8802 4 17.7202 4.32698 18.362C4.6146 18.9265 5.07354 19.3854 5.63803 19.673C6.27976 20 7.11984 20 8.8 20H15.2C16.8802 20 17.7202 20 18.362 19.673C18.9265 19.3854 19.3854 18.9265 19.673 18.362C20 17.7202 20 16.8802 20 15.2V11" stroke=${this.attachmentIconColor || '#000'} stroke-width="1.536" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M4 16L8.29289 11.7071C8.68342 11.3166 9.31658 11.3166 9.70711 11.7071L13 15M13 15L15.7929 12.2071C16.1834 11.8166 16.8166 11.8166 17.2071 12.2071L20 15M13 15L15.25 17.25" stroke=${this.attachmentIconColor || '#000'} stroke-width="1.536" stroke-linecap="round" stroke-linejoin="round"></path> <path d="M18.5 3V5.5M18.5 8V5.5M18.5 5.5H16M18.5 5.5H21" stroke=${this.attachmentIconColor || '#000'} stroke-width="1.536" stroke-linecap="round" stroke-linejoin="round"></path> </g></svg> </div> ${ this.isAttachmentMenuVisible ? ClockMark.ke` <div class="attachment-menu"> <attachment-box .documentIcon=${'https://flexcrew.s3.us-west-1.amazonaws.com/document_text_svgrepo_com_1_2583e4b5fc.svg'} .mediaIcon=${'https://flexcrew.s3.us-west-1.amazonaws.com/image_svgrepo_com_2f478c0a9b.svg'} .mediaIconHeight=${'25px'} .mediaIconWidth=${'25px'} .documentIconHeight=${'25px'} .documentIconWidth=${'25px'} .flexDirection=${'column'} .bgColor=${'white'} .onMediaIconClick="${this.mediaIconHandler}" .onDocumentIconClick="${this.onDocumentClick}" .onFileUploaded="${this.onFileUploaded}" @file-uploaded="${event => this.fileUploadHandler(event)}" > </attachment-box> </div> ` : '' } <div class='input-box-container som'> <my-input .value="${this.inputValue}" .borderColor="${this.inputBorderColor || 'gray'}" .borderWidth="${this.inputBorderWidth || '1px'}" .borderRadius="${this.inputBorderRadius} || "10px" .backgroundColor=${this.inputBgColor || '#ffffff'} .fontSize="${this.inputFontSize || '14px'}" .padding="10px" .placeholder="${this.inputPlaceholder || 'Type your message'}" .color=${this.inputFontColor} .placeholderColor=${this.inputPlaceholderColor || '#000'} @input="${this.handleInputChange}" ></my-input> </div> </div> <div class='send-container' > ${ this.sendButtonIcon ? DocumentMessageBubble.Button({ backgroundImage: this.sendButtonIcon, width: this.sendButtonIconWidth, height: this.sendButtonIconHeight, borderWidth: '0px', borderColor: 'transparent', borderRadius: this.sendButtonIconRadius, onClick: () => { this.onSendClick(); this.resetInputHeight(); }, }) : '' } </div> </div> `; } } customElements.define('my-test-footer', TestFooter); class AttachmentPreview extends ClockMark.h { static properties = { bgColor: { type: String }, textColor: { type: String }, width: { type: String }, padding: { type: String }, borderRadius: { type: String }, borderWidth: { type: String }, borderColor: { type: String }, onClose: { type: Function }, fontSize: { type: String }, fontWeight: { type: String }, fontFamily: { type: String }, content: { type: String }, // Can be a media URL or document name height: { type: String }, contentType: { type: String }, // Type of content (e.g., 'image', 'video', 'document') }; static styles = ClockMark.i$1` .close-button { cursor: pointer; background: none; border: none; font-size: 20px; position: absolute; right: -5px; top: -5px; padding: 0px; border-radius: 50%; height: 14px; width: 14px; aspect-ratio: 1:1 } .attachment-preview-container { display: flex; align-items: center; position: absolute; bottom:70px; margin-left: 10px; } .document-preview { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; width: 100%; } .document-name { max-width: 90%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } `; render() { return ClockMark.ke` <div class="attachment-preview-container" style="background-color: ${this.bgColor}; width: ${this.width}; border-radius: ${this.borderRadius}; border-width: ${this.borderWidth}; border-color: ${this.borderColor}; padding: ${this.padding}; height: ${this.height};" > <div class="attachment-details" style="height: ${this.height}; width: ${this.width}"> ${ this.contentType === 'image' ? Image.Image({ src: this.content, alt: 'attachment-preview', height: '100%', width: '100%', objectFit: 'cover', }) : this.contentType === 'video' ? ClockMark.ke`<video src="${this.content}" controls width="100%" height="100%" style="object-fit: cover;"></video>` : ClockMark.ke` <div class="document-preview"> <span class="document-icon"> <svg width="64px" height="64px" viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#000000" data-darkreader-inline-fill="" style="--darkreader-inline-fill: #000000;" > <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="M719.8 651.8m-10 0a10 10 0 1 0 20 0 10 10 0 1 0-20 0Z" fill="#EFF1FA" style="--darkreader-inline-fill: #cddcef;" data-darkreader-inline-fill="" ></path> <path