andycmaj / react-chat-renderer

React JSX factory implementation for Slack
15 stars 0 forks source link
async chat chatbot conversational-ui jsx react react-components react-renderer slack slack-blockkit

React-chat-renderer

npm version

I wanted to build rich, interactive Slack and Discord workflows in a familiar idiom. Hence, a custom React renderer for declarative chat interactions.

Design Principles

Upcoming

Inspirations

Example

Asynchronous components

/** @jsx slack.h */
/** @jsxFrag slack.Fragment */
import {
  slack,
  render,
  ContextBlock,
  ImageElement,
  PlainText,
  FC,
} from 'react-chat-renderer';

  const DeltaIndicator: FC<{delta: number}, any> = async ({ delta }) => {
    await fakePromise();

    return delta > 0 ? (
      <ImageElement
        altText="improved"
        imageUrl="https://user-images.githubusercontent.com/97470/75739421-a7138180-5cb9-11ea-9547-e64acf86eb59.png"
      />
    ) : delta === 0 ? (
      'okay!'
    ) : (
      <ImageElement
        altText="declined"
        imageUrl="https://user-images.githubusercontent.com/97470/75739424-a7ac1800-5cb9-11ea-969a-e1ac9f12a41a.png"
      />
    );
  };

  it('renders contextblock with component children', async () => {
    const message = (
      <ContextBlock>
        <PlainText emoji>Hello, world</PlainText>
        <DeltaIndicator delta={-3} />
        <DeltaIndicator delta={0} />
      </ContextBlock>
    );

    expect(await render(message)).toMatchSnapshot();
  });

JSX Message

/** @jsx slack.h */
import {
  slack,
  DividerBlock,
  SectionBlock,
  ButtonElement,
  PlainText,
  MarkdownText,
  ProgressBar,
  Message,
} from '..';

const message = (
  <Message responseType="in_channel">
    <SectionBlock
      accessory={<ButtonElement actionId="doAThing">Go!</ButtonElement>}
    >
      <PlainText emoji>section text :sadkeanu:</PlainText>
    </SectionBlock>
    <DividerBlock />
    <SectionBlock blockId="section1">
      <MarkdownText>
        section ```code``` *progress:*{' '}
        <ProgressBar color="red" columnWidth="10" total="300" value="200" />
      </MarkdownText>
    </SectionBlock>
  </Message>
);

Rendered JSON Message

slack message

{
  "response_type": "in_channel",
  "as_user": false,
  "blocks": [
    {
      "type": "section",
      "accessory": {
        "type": "button",
        "text": {
          "type": "plain_text",
          "emoji": true,
          "text": "Go!"
        },
        "action_id": "doAThing"
      },
      "text": {
        "type": "plain_text",
        "text": "section text :sadkeanu:",
        "emoji": true
      }
    },
    {
      "type": "divider"
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "section ```code``` *progress:* `▓▓▓▓▓▓▓░░░`",
        "verbatim": false
      },
      "block_id": "section1"
    }
  ]
}