Messagebar React Component

Messagebar React component represents Framework7's Messagebar component.

Messagebar Components

There are following components included:

  • Messagebar / F7Messagebar - main messagebar element
  • MessagebarSheet / F7MessagebarSheet - messagebar sheet element
  • MessagebarSheetImage / F7MessagebarSheetImage - messagebar sheet image item
  • MessagebarSheetItem / F7MessagebarSheetItem - messagebar sheet item
  • MessagebarAttachments / F7MessagebarAttachments - messagebar attachments element
  • MessagebarAttachment / F7MessagebarAttachment - single messagebar attachment element

Messagebar Properties

PropTypeDefaultDescription
<Messagebar> properties
initbooleantrueInitializes Messagebar
namestringTextarea "name" attribute
textareaIdstring
number
Textarea "id" attribute
placeholderstringMessageTextarea placeholder text
valuestring
number
Textarea value
readonlybooleanfalseSets "readonly" textarea attribute
disabledbooleanfalseSets "disbled" textarea attribute
sendLinkstringEnables Send link and specifies its text. This property will be ignored in case you use send-link slot
maxHeightnumberDefines resizeable textarea max height
resizableboleantrueEnables resizeable textarea
sheetVisiblebooleanfalseMakes messagebar sheet visible/active
attachmentsVisiblebooleanfalseMakes messagebar attachments visible/active
resizePagebooleantrueWhen enabled, it will resize messages page when messagebar textarea size changed
<MessagebarSheetImage> properties
imagestringSheet image URL
checkedbooleanfalseIndicates whether this sheet image-item is checked or not
<MessagebarAttachment> properties
imagestringAttachment image URL
deletablebooleantrueDefines whether the attachment is deletable or not. In case of deletable the additional delete button will be rendered

Messagebar Methods

<Messagebar> methods
.clear()Clear textarea and update/reset its size
.setValue(newValue)Set messagebar textarea value/text
.getValue()Return messagebar textarea value
.resize()Force Messagebar to resize messages page depending on messagebar height/size
.focus()Focus messagebar textarea
.blur()Remove focus from messagebar textarea

Messagebar Events

EventArgumentsDescription
<Messagebar> events
change(event)Event will be triggered when "change" event occurs on messagebar textarea element
input(event)Event will be triggered when "input" event occurs on messagebar textarea element
focus(event)Event will be triggered when "focus" event occurs on messagebar textarea element
blur(event)Event will be triggered when "blur" event occurs on messagebar textarea element
submit
send
(value, clear)Event will be triggered when user clicks on messagebar "send link"
<MessagebarSheetImage> events
change(event)Event will be triggered on sheet item checkbox change
<MessagebarAttachment> events
attachmentClick(event)Event will be triggered on attachment click
attachmentDelete(event)Event will be triggered on attachment delete button click

Messagebar Slots

Messagebar React component has additional slots for custom elements:

  • default - element will be inserted in the end of <div class="toolbar-inner">. element
  • before-area - element will be inserted right before textarea. Messagebar attachments go here
  • after-area - element will be inserted right after textarea
  • send-link - element will be inserted inside of send link
  • before-inner - element will be inserted right before <div class="toolbar-inner">. element
  • after-inner - element will be inserted right after <div class="toolbar-inner">. element. Messagebar sheet goes here
  • inner-start - element will be inserted in the beginning of <div class="toolbar-inner">. element
  • inner-end - element will be inserted in the end of <div class="toolbar-inner">. element. Same as default slot
<Messagebar placeholder="Message" onSubmit="this.onSubmit">
  <div slot="before-inner">Before inner</div>
  <div slot="after-inner">After inner</div>
  <div slot="before-area">Before textarea</div>
  <div slot="after-area">After textarea</div>
  <Icon ios="f7:arrow_up_fill" aurora="f7:arrow_up_fill" md="material:send" slot="send-link"></Icon>
  <div>Default slot</div>
</Messagebar>

Renders to:

<div class="toolbar messagebar">
  <div>Before inner</div>
  <div class="toolbar-inner">
    <div class="messagebar-area">
      <div>Before textarea</div>
      <textarea placeholder="Message"></textarea>
      <div>After textarea</div>
    </div>
    <a href="#" class="link"><i class="icon f7-icons">arrow_up_fill</i></a>
    <div>Default slot</div>
  </div>
  <div>After inner</div>
</div>

Access To Messagebar Instance

If you use automatic initalization to init Messagebar (with init={true} prop) and need to use its Methods and Properties you can access its initialized instance by accessing .f7Messagebar component's property.

Examples

Here is how the full example of Messages page where it can be used together with Messages:

export default class extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      attachments: [],
      sheetVisible: false,
      typingMessage: null,
      messagesData: [
        {
          type: 'sent',
          text: 'Hi, Kate',
        },
        {
          type: 'sent',
          text: 'How are you?',
        },
        {
          name: 'Kate',
          type: 'received',
          text: 'Hi, I am good!',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
          name: 'Blue Ninja',
          type: 'received',
          text: 'Hi there, I am also fine, thanks! And how are you?',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
        },
        {
          type: 'sent',
          text: 'Hey, Blue Ninja! Glad to see you ;)',
        },
        {
          type: 'sent',
          text: 'Hey, look, cutest kitten ever!',
        },
        {
          type: 'sent',
          image: 'https://cdn.framework7.io/placeholder/cats-200x260-4.jpg',

        },
        {
          name: 'Kate',
          type: 'received',
          text: 'Nice!',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
          name: 'Kate',
          type: 'received',
          text: 'Like it very much!',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
          name: 'Blue Ninja',
          type: 'received',
          text: 'Awesome!',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
        },
      ],
      images: [
        'https://cdn.framework7.io/placeholder/cats-300x300-1.jpg',
        'https://cdn.framework7.io/placeholder/cats-200x300-2.jpg',
        'https://cdn.framework7.io/placeholder/cats-400x300-3.jpg',
        'https://cdn.framework7.io/placeholder/cats-300x150-4.jpg',
        'https://cdn.framework7.io/placeholder/cats-150x300-5.jpg',
        'https://cdn.framework7.io/placeholder/cats-300x300-6.jpg',
        'https://cdn.framework7.io/placeholder/cats-300x300-7.jpg',
        'https://cdn.framework7.io/placeholder/cats-200x300-8.jpg',
        'https://cdn.framework7.io/placeholder/cats-400x300-9.jpg',
        'https://cdn.framework7.io/placeholder/cats-300x150-10.jpg',
      ],
      people: [
        {
          name: 'Kate Johnson',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-9.jpg',
        },
        {
          name: 'Blue Ninja',
          avatar: 'https://cdn.framework7.io/placeholder/people-100x100-7.jpg',
        },
      ],
      answers: [
        'Yes!',
        'No',
        'Hm...',
        'I am not sure',
        'And what about you?',
        'May be ;)',
        'Lorem ipsum dolor sit amet, consectetur',
        'What?',
        'Are you sure?',
        'Of course',
        'Need to think about it',
        'Amazing!!!',
      ],
      responseInProgress: false,
    }
  }
  render() {
    return (
      <Page>
        <Navbar title="Messages"></Navbar>

        <Messagebar
          placeholder={this.placeholder}
          ref={(el) => {this.messagebarComponent = el}}
          attachmentsVisible={this.attachmentsVisible}
          sheetVisible={this.state.sheetVisible}
        >
          <Link
            iconIos="f7:camera_fill"
            iconAurora="f7:camera_fill"
            iconMd="material:camera_alt"
            slot="inner-start"
            onClick={() => {this.setState({sheetVisible: !this.state.sheetVisible})}}
          ></Link>
          <Link
            iconIos="f7:arrow_up_fill"
            iconAurora="f7:arrow_up_fill"
            iconMd="material:send"
            slot="inner-end"
            onClick={this.sendMessage.bind(this)}
          ></Link>
          <MessagebarAttachments>
            {this.state.attachments.map((image, index) => (
              <MessagebarAttachment
                key={index}
                image={image}
                onAttachmentDelete={() => this.deleteAttachment(image)}
              ></MessagebarAttachment>
            ))}
          </MessagebarAttachments>
          <MessagebarSheet>
            {this.state.images.map((image, index) => (
              <MessagebarSheetImage
                key={index}
                image={image}
                checked={this.state.attachments.indexOf(image) >= 0}
                onChange={this.handleAttachment.bind(this)}
              ></MessagebarSheetImage>
            ))}
          </MessagebarSheet>
        </Messagebar>

        <Messages ref={(el) => {this.messagesComponent = el}}>
          <MessagesTitle><b>Sunday, Feb 9,</b> 12:58</MessagesTitle>

          {this.state.messagesData.map((message, index) => (
            <Message
              key={index}
              type={message.type}
              image={message.image}
              name={message.name}
              avatar={message.avatar}
              first={this.isFirstMessage(message, index)}
              last={this.isLastMessage(message, index)}
              tail={this.isTailMessage(message, index)}
            >
              {message.text && (
                <span slot="text" dangerouslySetInnerHTML={{__html: message.text}} />
              )}
            </Message>
          ))}
          {this.state.typingMessage && (
            <Message
              type="received"
              typing={true}
              first={true}
              last={true}
              tail={true}
              header={`${this.state.typingMessage.name} is typing`}
              avatar={this.state.typingMessage.avatar}
            ></Message>
          )}
        </Messages>
      </Page>
    )
  }

  get attachmentsVisible() {
    const self = this;
    return self.state.attachments.length > 0;
  }
  get placeholder() {
    const self = this;
    return self.state.attachments.length > 0 ? 'Add comment or Send' : 'Message';
  }
  componentDidMount() {
    const self = this;
    self.$f7ready(() => {
      self.messagebar = self.messagebarComponent.f7Messagebar;
      self.messages = self.messagesComponent.f7Messages;
    });
  }
  isFirstMessage(message, index) {
    const self = this;
    const previousMessage = self.state.messagesData[index - 1];
    if (message.isTitle) return false;
    if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
    return false;
  }
  isLastMessage(message, index) {
    const self = this;
    const nextMessage = self.state.messagesData[index + 1];
    if (message.isTitle) return false;
    if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
    return false;
  }
  isTailMessage(message, index) {
    const self = this;
    const nextMessage = self.state.messagesData[index + 1];
    if (message.isTitle) return false;
    if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
    return false;
  }
  deleteAttachment(image) {
    const self = this;
    const attachments = self.state.attachments;
    const index = attachments.indexOf(image);
    attachments.splice(index, 1);
    self.setState({ attachments });
  }
  handleAttachment(e) {
    const self = this;
    const attachments = self.state.attachments;
    const index = self.$$(e.target).parents('label.checkbox').index();
    const image = self.state.images[index];
    if (e.target.checked) {
      // Add to attachments
      attachments.unshift(image);
    } else {
      // Remove from attachments
      attachments.splice(attachments.indexOf(image), 1);
    }
    self.setState({ attachments });
  }
  sendMessage() {
    const self = this;
    const text = self.messagebar.getValue().replace(/\n/g, '<br>').trim();
    const messagesToSend = [];
    self.state.attachments.forEach((attachment) => {
      messagesToSend.push({
        image: attachment,
      });
    });
    if (text.trim().length) {
      messagesToSend.push({
        text,
      });
    }
    if (messagesToSend.length === 0) {
      return;
    }

    self.setState({
      // Reset attachments
      attachments: [],
      // Hide sheet
      sheetVisible: false,
      // Send message
      messagesData: [...self.state.messagesData, ...messagesToSend],
    });
    self.messagebar.clear();

    // Focus area
    if (text.length) self.messagebar.focus();

    // Mock response
    if (self.state.responseInProgress) return;
    self.setState({
      responseInProgress: true,
    })
    setTimeout(() => {
      const answer = self.state.answers[Math.floor(Math.random() * self.state.answers.length)];
      const person = self.state.people[Math.floor(Math.random() * self.state.people.length)];
      self.setState({
        typingMessage: {
          name: person.name,
          avatar: person.avatar,
        },
      });
      setTimeout(() => {
        self.setState({
          messagesData: [...self.state.messagesData, {
            text: answer,
            type: 'received',
            name: person.name,
            avatar: person.avatar,
          }],
          typingMessage: null,
          responseInProgress: false,
        });
      }, 4000);
    }, 1000);
  }
};