Code Monkey home page Code Monkey logo

react-chat-renderer's Introduction

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

  • Support Slack's new Block-kit and Interactive Messaging Workflows.
    • Attachments considered legacy/obsolete
  • Each Component is a pure function with a parent-agnostic view of a Slack message entity (eg. a layout block). It's responsible for rendering its own JSON shape.
    • these FCs should always return a JSON entity that is a subtree of a Slack message.
  • Should be able to build USEFUL, self-contained components that can do asynchronous things. Don't need a full-blown hooks implementation, but you CAN make the JSX factory asynchronous.

Upcoming

  • Microsoft Teams support
  • more out-of-the-box elements

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"
    }
  ]
}

react-chat-renderer's People

Contributors

andycmaj avatar davemeyer avatar dependabot[bot] avatar mshende avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

react-chat-renderer's Issues

make `BlockQuote` a SPAN instead of extending `MarkdownText` so that it can be a child of `MarkdownText`

we currently have:

<SectionBlock>
        <MarkdownText>{triggeringActivity.data.comment}</MarkdownText>
</SectionBlock>

// OR


<SectionBlock>
        <BlockQuote>{commentBody}</BlockQuote>
</SectionBlock>

we should be able to put BlockQuotes INTO markdown blocks.

<SectionBlock>
        <MarkdownText>
			Here's a comment from Dave: 

			<BlockQuote>{commentBody}</BlockQuote>
		</MarkdownText>
</SectionBlock>

hmmm can a BlockQuote be a CHILD of MarkdownText? practically, i thikn you'd sometimes want to be able to have markdown sections that CONTAIN block quotes and other things as well...

Originally posted by @andycmaj in https://github.com/asynchronous-dev/botany/pull/973

add Link component for creating markdown formatted links

currently you would have to do something like

<MarkdownText>
  {`<${'thing.url}|${thing.name}>`}
</MarkdownText>

to create a slack link with alt text

it would be simpler to have a

<MarkdownLink url={thing.url} text={thing.name} />

add text input components

example of input block:

"blocks": [
  {
    "type": "input",
    "element": {
      "type": "plain_text_input",
      "multiline": true,
        "placeholder": {
          "type": "plain_text",
          "text": "eff"
        }
    },
    "label": {
      "type": "plain_text",
      "text": "Label",
      "emoji": true
    }
  },
]

persisted interaction workflow state (redux sessions)

Summary

use a redux-like state-persistence and updating mechanism.
hydrate and dehydrate state before and after each action runs.

so an HTTP request ~= a redux action.

Idea

Here's an interaction message sent from Slack and handled by a lambda:

{
  "type": "block_actions",
  "team": { ... },
  "user": { ... },
  "api_app_id": "API_APP_ID",
  "token": "MESSAGE_TOKEN",
  "container": {
    "type": "message",
    "message_ts": "1561776627.000500",
    "channel_id": "CHANNEL_ID",
    "is_ephemeral": false
  },
  "trigger_id": "679602909028.575391407056.10172fae809593326ff92c15c4db964d",
  "channel": { ... },
  "message": {
    "type": "message",
    "subtype": "bot_message",
    "text": "This+content+can't+be+displayed.",
    "ts": "1561776627.000500",
    "bot_id": "BOT_ID",
    "blocks": [
      {
        "type": "section",
        "block_id": "P4NT",
        "text": {
          "type": "mrkdwn",
          "text": "Progress:+\u2593\u2593\u2591\u2591\u2591",
          "verbatim": false
        },
        "accessory": {
          "type": "button",
          "action_id": "doAThing",
          "text": { "type": "plain_text", "text": "Go!", "emoji": true }
        }
      }
    ]
  },
  "response_url": "RESPONSE_URL",
  "actions": [
    {
      "action_id": "doAThing",
      "block_id": "P4NT",
      "text": { "type": "plain_text", "text": "Go!", "emoji": true },
      "type": "button",
      "action_ts": "1561776635.121684"
    }
  ]
}
  • slack do interaction
  • handle request
  • hydrate state into store
    • look up current state in distributed cache using previous message's identifiers. block_id
  • dispatch action action_id + block_id or some combination of things from actions payload
  • run reducers to compute new state
  • persist new state with block_id
    • use trigger_id as new block_id
  • render message with new block_id

add newline element

there doesn't seem to be a way to insert a newline in a generated slack message. so we should create an explicit newline element for easy message formatting

add option_groups to select element props

single and multi select elements can take a list of options or a list of option_groups. right now we only support options.

option groups allow distinct labeled groups of options
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.