diff --git a/packages/module/src/MessageBar/MessageBar.scss b/packages/module/src/MessageBar/MessageBar.scss index 87c80fa82..72fc72f93 100644 --- a/packages/module/src/MessageBar/MessageBar.scss +++ b/packages/module/src/MessageBar/MessageBar.scss @@ -34,26 +34,23 @@ &-actions { display: flex; justify-content: end; - padding-block-start: var(--pf-chatbot__message-bar-child--PaddingBlockStart); + padding-block-start: var(--pf-t--global--spacer--sm); padding-block-end: var(--pf-t--global--spacer--sm); gap: var(--pf-t--global--spacer--xs); } &-input { flex: 1 1 auto; - padding-block-start: var(--pf-chatbot__message-bar-child--PaddingBlockStart); - padding-block-end: var(--pf-chatbot__message-bar-child--PaddingBlockEnd); + padding-block-start: var(--pf-t--global--spacer--sm); + padding-block-end: var(--pf-t--global--spacer--sm); } } // - Form control textarea .pf-chatbot__message-textarea { - padding-block-start: var(--pf-t--global--spacer--md); - padding-block-end: var(--pf-t--global--spacer--md); - padding-inline-start: var(--pf-t--global--spacer--md); - padding-inline-end: var(--pf-t--global--spacer--md); --pf-v6-c-form-control--before--BorderStyle: none; --pf-v6-c-form-control--after--BorderStyle: none; + resize: none; background-color: transparent; font-size: var(--pf-t--global--font--size--md); line-height: 1.5rem; @@ -64,4 +61,29 @@ .pf-v6-c-form-control__textarea:focus-visible { outline: none; } + textarea { + outline-offset: 0px; + --pf-v6-c-form-control--PaddingBlockStart: 0; + --pf-v6-c-form-control--PaddingBlockEnd: 0; + --pf-v6-c-form-control--BorderRadius: 0; + } + textarea:focus-visible { + outline: none; + } +} + +@media screen and (max-width: 359px) { + .pf-chatbot__message-textarea { + margin-top: var(--pf-t--global--spacer--md) !important; + margin-bottom: var(--pf-t--global--spacer--md) !important; + } +} + +.pf-chatbot--embedded { + @media screen and (max-width: 415px) { + .pf-chatbot__message-textarea { + margin-top: var(--pf-t--global--spacer--md) !important; + margin-bottom: var(--pf-t--global--spacer--md) !important; + } + } } diff --git a/packages/module/src/MessageBar/MessageBar.tsx b/packages/module/src/MessageBar/MessageBar.tsx index e772fab76..d190d36fc 100644 --- a/packages/module/src/MessageBar/MessageBar.tsx +++ b/packages/module/src/MessageBar/MessageBar.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { ButtonProps, DropEvent, TextAreaProps } from '@patternfly/react-core'; -import { AutoTextArea } from 'react-textarea-auto-witdth-height'; +import { ButtonProps, DropEvent, TextArea, TextAreaProps } from '@patternfly/react-core'; // Import Chatbot components import SendButton from './SendButton'; @@ -8,6 +7,7 @@ import MicrophoneButton from './MicrophoneButton'; import { AttachButton } from './AttachButton'; import AttachMenu from '../AttachMenu'; import StopButton from './StopButton'; +import { ChatbotDisplayMode } from '../Chatbot'; export interface MessageBarWithAttachMenuProps { /** Flag to enable whether attach menu is open */ @@ -63,6 +63,8 @@ export interface MessageBarProps extends TextAreaProps { }; /** A callback for when the text area value changes. */ onChange?: (event: React.ChangeEvent, value: string) => void; + /** Display mode of chatbot, if you want to message bar to resize when the display mode changes */ + displayMode?: ChatbotDisplayMode; } export const MessageBar: React.FunctionComponent = ({ @@ -78,18 +80,149 @@ export const MessageBar: React.FunctionComponent = ({ hasStopButton, buttonProps, onChange, + displayMode, ...props }: MessageBarProps) => { // Text Input // -------------------------------------------------------------------------- const [message, setMessage] = React.useState(''); const [isListeningMessage, setIsListeningMessage] = React.useState(false); - - const textareaRef = React.useRef(null); + const [hasSentMessage, setHasSentMessage] = React.useState(false); + const textareaRef = React.useRef(null); const attachButtonRef = React.useRef(null); + const setInitialLineHeight = (field: HTMLTextAreaElement) => { + field.style.setProperty('line-height', '1rem'); + const parent = field.parentElement; + if (parent) { + parent.style.setProperty('margin-top', `0rem`); + parent.style.setProperty('margin-bottom', `0rem`); + parent.style.setProperty('height', 'inherit'); + + const grandparent = parent.parentElement; + if (grandparent) { + grandparent.style.setProperty('flex-basis', 'auto'); + } + } + }; + + const setAutoHeight = (field: HTMLTextAreaElement) => { + const parent = field.parentElement; + if (parent) { + parent.style.setProperty('height', 'inherit'); + const computed = window.getComputedStyle(field); + // Calculate the height + const height = + parseInt(computed.getPropertyValue('border-top-width')) + + parseInt(computed.getPropertyValue('padding-top')) + + field.scrollHeight + + parseInt(computed.getPropertyValue('padding-bottom')) + + parseInt(computed.getPropertyValue('border-bottom-width')); + parent.style.setProperty('height', `${height}px`); + + if (height > 32 || window.innerWidth <= 507) { + parent.style.setProperty('margin-bottom', `1rem`); + parent.style.setProperty('margin-top', `1rem`); + } + } + }; + + const textIsLongerThan2Lines = (field: HTMLTextAreaElement) => { + const lineHeight = parseFloat(window.getComputedStyle(field).lineHeight); + const lines = field.scrollHeight / lineHeight; + return lines > 2; + }; + + const setAutoWidth = (field: HTMLTextAreaElement) => { + const parent = field.parentElement; + if (parent) { + const grandparent = parent.parentElement; + if (textIsLongerThan2Lines(field) && grandparent) { + grandparent.style.setProperty('flex-basis', `100%`); + } + } + }; + + const handleNewLine = (field: HTMLTextAreaElement) => { + const parent = field.parentElement; + if (parent) { + parent.style.setProperty('margin-bottom', `1rem`); + parent.style.setProperty('margin-top', `1rem`); + } + }; + + const handleMobileHeight = (field: HTMLTextAreaElement) => { + const parent = field.parentElement; + if (parent) { + parent.style.setProperty('margin-bottom', `1rem`); + parent.style.setProperty('margin-top', `1rem`); + } + }; + + React.useEffect(() => { + const field = textareaRef.current; + if (field) { + if (field.value === '') { + if (window.innerWidth > 507) { + setInitialLineHeight(field); + } else { + handleMobileHeight(field); + } + } else { + setAutoHeight(field); + setAutoWidth(field); + } + } + const resetHeight = () => { + if (field) { + if (field.value === '') { + if (window.innerWidth > 507) { + setInitialLineHeight(field); + } else { + handleMobileHeight(field); + } + } else { + setAutoHeight(field); + setAutoWidth(field); + } + } + }; + window.addEventListener('resize', resetHeight); + + return () => { + window.removeEventListener('resize', resetHeight); + }; + }, []); + + React.useEffect(() => { + const field = textareaRef.current; + if (field) { + if (field.value === '') { + setInitialLineHeight(textareaRef.current); + } else { + setAutoHeight(textareaRef.current); + setAutoWidth(field); + } + } + }, [displayMode, message]); + + React.useEffect(() => { + const field = textareaRef.current; + if (field) { + setInitialLineHeight(field); + setHasSentMessage(false); + } + }, [hasSentMessage]); + const handleChange = React.useCallback((event) => { onChange && onChange(event, event.target.value); + if (textareaRef.current) { + if (event.target.value === '') { + setInitialLineHeight(textareaRef.current); + } else { + setAutoHeight(textareaRef.current); + } + } setMessage(event.target.value); }, []); @@ -97,6 +230,7 @@ export const MessageBar: React.FunctionComponent = ({ const handleSend = React.useCallback(() => { setMessage((m) => { onSendMessage(m); + setHasSentMessage(true); return ''; }); }, [onSendMessage]); @@ -109,6 +243,11 @@ export const MessageBar: React.FunctionComponent = ({ handleSend(); } } + if (event.key === 'Enter' && event.shiftKey) { + if (textareaRef.current) { + handleNewLine(textareaRef.current); + } + } }, [handleSend] ); @@ -173,14 +312,14 @@ export const MessageBar: React.FunctionComponent = ({ const messageBarContents = ( <>
-