# @sinchlabs/composer

Latest version **1.25.0** (published 2024-04-04) · 0 weekly downloads

## Install

```sh
npm install @sinchlabs/composer
pnpm add @sinchlabs/composer
yarn add @sinchlabs/composer
bun add @sinchlabs/composer
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: esm support; no vulnerabilities.

Warnings: low downloads; no types.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.25.0 |
| Published | 2024-04-04 |
| First published | 2021-09-07 |
| Weekly downloads | 0 |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 29 |
| Unpacked size | 3.7 MB |
| Known vulnerabilities | 0 (+25 in 3 direct dependencies) |
| Install scripts | yes |
| Maintainers | joaysi, szymonryczeksinch, viktorklangsinch |

## Links

- npm: https://www.npmjs.com/package/@sinchlabs/composer
- Repository: https://gitlab.com/composer/messagecomposer
- Homepage: https://gitlab.com/composer/messagecomposer#readme
- Issues: https://gitlab.com/composer/messagecomposer/issues
- npm.io page: https://npm.io/package/@sinchlabs/composer

## Dependencies (29)

- [utif](https://npm.io/package/utif.md) ^3.1.0
- [uuid](https://npm.io/package/uuid.md) ^8.3.2
- [axios](https://npm.io/package/axios.md) ^0.26.1
- [immer](https://npm.io/package/immer.md) ^9.0.12
- [core-js](https://npm.io/package/core-js.md) ^3.21.1
- [graphql](https://npm.io/package/graphql.md) ^16.3.0
- [i18next](https://npm.io/package/i18next.md) ^21.6.12
- [emoji-mart](https://npm.io/package/emoji-mart.md) ^3.0.1
- [lodash.get](https://npm.io/package/lodash.get.md) ^4.4.2
- [lodash.merge](https://npm.io/package/lodash.merge.md) ^4.6.2
- [monaco-editor](https://npm.io/package/monaco-editor.md) ^0.33.0
- [react-i18next](https://npm.io/package/react-i18next.md) ^11.15.6
- [@apollo/client](https://npm.io/package/@apollo/client.md) ^3.5.10
- [lodash.isequal](https://npm.io/package/lodash.isequal.md) ^4.5.0
- [react-dropzone](https://npm.io/package/react-dropzone.md) ^12.0.4
- [textarea-caret](https://npm.io/package/textarea-caret.md) ^3.1.0
- [lodash.debounce](https://npm.io/package/lodash.debounce.md) ^4.0.8
- [@material-ui/lab](https://npm.io/package/@material-ui/lab.md) ^4.0.0-alpha.61
- [react-image-crop](https://npm.io/package/react-image-crop.md) ^10.0.4
- [styled-components](https://npm.io/package/styled-components.md) ^5.3.3
- [@sinchlabs/distcry](https://npm.io/package/@sinchlabs/distcry.md) ^1.0.4
- [react-number-format](https://npm.io/package/react-number-format.md) ^4.9.1
- [@monaco-editor/react](https://npm.io/package/@monaco-editor/react.md) ^4.3.1
- [i18next-http-backend](https://npm.io/package/i18next-http-backend.md) ^1.3.2
- [react-error-boundary](https://npm.io/package/react-error-boundary.md) ^3.1.4
- [react-swipeable-views](https://npm.io/package/react-swipeable-views.md) ^0.14.0
- [i18next-chained-backend](https://npm.io/package/i18next-chained-backend.md) ^3.0.2
- [resize-observer-polyfill](https://npm.io/package/resize-observer-polyfill.md) ^1.5.1
- [i18next-resources-to-backend](https://npm.io/package/i18next-resources-to-backend.md) ^1.0.0

## Recent versions

- 1.25.0 (latest) — 2024-04-04
- 1.14.6 — 2023-06-07
- 1.14.5 — 2023-05-31
- 1.14.4 — 2023-05-31
- 1.14.3 — 2023-05-31
- 1.14.2 — 2023-05-31
- 1.14.1 — 2023-05-31
- 1.14.0 — 2023-03-14
- 1.10.1 — 2022-10-05
- 1.10.0 — 2022-10-05
- 1.5.3 — 2022-05-13
- 1.5.2 — 2022-05-11
- 1.5.1 — 2022-04-28
- 1.0.0-alpha.12 — 2021-10-22
- 1.0.0-alpha.11 — 2021-10-21
- … 2 more at https://npm.io/package/@sinchlabs/composer/versions

## README

<div align="center">
  <img src="https://1vxc0v12qhrm1e72gq1mmxkf-wpengine.netdna-ssl.com/wp-content/uploads/2020/04/cropped-Sinch-PR-1000-300x141-1.png" width="320" alt="Sinch Logo" />
</div>

<div align="center">
  <h1>Message Composer</h1>
  <h2>Composing messages compatible with Sinch Conversation API</h2>
</div>

## Getting Started

1. Create an `.env ` file and paste the key to decrypt the package.
   **Example below is just that and real keys needs to be provided by Sinch.**

> `.env`
>
>     DISTCRY = { "composer": "p455w0rd" }

2. Install the Composer package

```bash
$ yarn add @sinchlabs/composer
```

3. Install dependencies:

- @material-ui/core version 4
- @material-ui/icons version 4

## How To Use

Composer provides 5 editors.

- `Inline Editor` allows for visual composing of messages.
- `Code Editor` which makes it possible to create messages by directly editing message as json.
- `Form Editor` which allows creation of message in standard form format.
- `WhatsApp Editor`
  - `WhatsApp Template Editor` allows for composing of messages in WhatsApp templates format.
  - `WhatsApp Samples Editor` allows to add preview values to WhatsApp template samples.
- `KakaoTalk Template Editor` allows for composing of messages in KakaoTalk templates format.

`Inline`, `Code` and `Form` editors has by default a dropdown for selecting type of message.
Default dropdown can be removed using `disableMessageTypeDropdown` props and standalone component, `MessageTypeCard`, or own implimentation can be used instead.

**Inline, Form, Code Editor Props:**

- `message`: The message accepts a message compatible with the conversation API omni format.
- `onChange`: Callback to which is passes the current message in the editor state.
- `onFileUpload` (optional): Function for uploading attachements, needs to return url of attachement.
- `variables` (optional): Quick suggestions of variables to use in message.
- `disabledMessageTypes` (optional): Exclude certain message types.
- `disableMessageTypeDropdown` (optional): Exclude the message type dropdown.
- `theme` (optional): MaterialUI theme object that overrides default values.

**WhatsApp Template Editor Props:**

- `components`: object with WhatsApp Template.
- `onComponentsChange`: Callback to which is passes the current template components state.
- `onError` (optional): Fires when `errors` object changes.
- `theme` (optional): MaterialUI theme object that overrides default values.
- `disabled` (optional): disabling every field in the form.

**WhatsApp Samples Editor Props:**

It has the same props like WhatsApp Template Editor with one extra:

- `onFileUpload`: Function for uploading files, needs to return url of file.

**KakaoTalk Template Editor Props:**

- `template`: object with KakaoTalk Template.
- `onTemplateChange`: Callback to which is passes the current template components state.
- `onError` (optional): Fires when `errors` object changes.
- `theme` (optional): MaterialUI theme object that overrides default values.
- `disabled` (optional): disabling every field in the form.
- `onFileUpload` (optional): Function for uploading files, needs to return url of file.

### Inline Editor

```tsx
import { useState } from 'react';
import { InlineEditor, MessageTypeCard } from '@sinchlabs/composer';

export const Default = () => {
  const [message, setMessage] = useState({ text_message: { text: 'Hej!' } });

  const handleOnChange = (value) => {
    setMessage(value);
  };

  const handleFileUpload = () => {
    // Upload attachement and return url to attachement.
    return new Promise((resolve) => resolve('path-to-attachement'));
  };

  return (
    <>
      <MessageTypeCard message={message} onChange={setMessage} />
      <InlineEditor
        message={message}
        onChange={handleOnChange}
        onFileUpload={handleFileUpload}
        disableMessageTypeDropdown
      />
    </>
  );
};
```

### Code Editor

```tsx
import { useState } from 'react';
import { CodeEditor } from '@sinchlabs/composer';

export const Default = () => {
  const [message, setMessage] = useState({ text_message: { text: 'Hej!' } });

  const handleOnChange = (value) => {
    setMessage(value);
  };

  return <CodeEditor message={message} onChange={handleOnChange} />;
};
```

### Form Editor

```tsx
import { useState } from 'react';
import { CodeEditor } from '@sinchlabs/composer';

export const Default = () => {
  const [message, setMessage] = useState({ text_message: { text: 'Hej!' } });

  const handleOnChange = (value) => {
    setMessage(value);
  };

  const handleFileUpload = () => {
    // Upload attachement and return url to attachement.
    return new Promise((resolve) => resolve('path-to-attachement'));
  };

  return (
    <FormEditor
      message={message}
      onChange={handleOnChange}
      onFileUpload={handleFileUpload}
    />
  );
};
```

### WhatsApp Template Editor

#### Basic example

```tsx
import { WhatsAppTemplateEditor } from '@sinchlabs/composer';

export const Default: FunctionComponent<Props> = () => {
  const [messageComponents, setMessageComponents] = useState(DEFAULT_TEMPLATE);

  const handleChange = (newComponents) => {
    setMessageComponents(newComponents);
  };

  /*
   * Function that as arguments takes errors object and summary count of errors found in the Editor
   */
  const handleError = (errors, errorsCount) => {
    /* ... */
  };

  return (
    <WhatsAppTemplateEditor
      components={messageComponents}
      onComponentsChange={handleChange}
      onError={handleError}
    />
  );
};
```

#### Themed example (in this case override button color to yellow and use custom font)

```tsx
import { WhatsAppTemplateEditor } from '@sinchlabs/composer';

export const Default: FunctionComponent<Props> = () => {
  const [messageComponents, setMessageComponents] = useState(DEFAULT_TEMPLATE);

  const handleChange = (newComponents) => {
    setMessageComponents(newComponents);
  };

  /*
   * Function that as arguments takes errors object and summary count of errors found in the Editor
   */
  const handleError = (errors, errorsCount) => {
    /* ... */
  };

  /*
   * You can extend default fonts by passing them to the theme.
   * Be aware that Message Composer does not provide font files, you can just change default `CSS` `font-family`
   * property and provide all necessary resources like font files or `@font-family`
   */
  const customFonts = 'AtlasGroteskWeb, Helvetica';

  const customTheme = {
    typography: {
      fontFamily: customFonts,
    },
    overrides: {
      MuiButton: {
        containedPrimary: {
          color: '#000000',
          backgroundColor: '#ffc658',

          '&:hover': {
            backgroundColor: '#ffc658',
          },
        },
      },
    },
  };

  return (
    <WhatsAppTemplateEditor
      components={messageComponents}
      onComponentsChange={handleChange}
      theme={customTheme}
      onError={handleError}
    />
  );
};
```

### WhatsApp Template Components

```tsx
import {
  WhatsAppTemplateBodySolo,
  WhatsAppTemplateButtonsSolo,
  WhatsAppTemplateFooterSolo,
  WhatsAppTemplateHeaderSolo,
} from '@sinchlabs/composer';

export const Header: FunctionComponent<Props> = ({ disabled = false }) => {
  const [format, setFormat] = useState<WAMessageTemplateComponentFormat>();
  const [text, setText] = useState<string>();

  const handleChange = (payload: {
    text?: WAMessageTemplateComponent['text'];
    format?: WAMessageTemplateComponent['format'];
  }) => {
    typeof payload.format !== 'undefined' && setFormat(payload.format);
    typeof payload.text !== 'undefined' && setText(payload.text);
  };

  return (
    <WhatsAppTemplateHeaderSolo
      disabled={disabled}
      format={format}
      onChange={handleChange}
      text={text}
    />
  );
};

export const Body: FunctionComponent<Props> = ({ disabled = false }) => {
  const [bodySamples, setBodySamples] = useState<string[]>();
  const [text, setText] = useState<string>();

  const handleChange = (payload: {
    text?: WAMessageTemplateComponent['text'];
    bodySamples?: WAMessageTemplateComponent['bodySamples'];
  }) => {
    typeof payload.bodySamples !== 'undefined' &&
      setBodySamples(payload.bodySamples);
    typeof payload.text !== 'undefined' && setText(payload.text);
  };

  return (
    <WhatsAppTemplateBodySolo
      bodySamples={bodySamples}
      disabled={disabled}
      onChange={handleChange}
      text={text}
    />
  );
};

export const Footer: FunctionComponent<Props> = ({ disabled = false }) => {
  const [text, setText] = useState<string>();

  const handleChange = (payload: {
    text?: WAMessageTemplateComponent['text'];
  }) => {
    typeof payload.text !== 'undefined' && setText(payload.text);
  };

  return (
    <WhatsAppTemplateFooterSolo
      disabled={disabled}
      onChange={handleChange}
      text={text}
    />
  );
};

export const Buttons: FunctionComponent<Props> = ({ disabled = false }) => {
  const [buttons, setButtons] = useState<WAMessageTemplateComponent['buttons']>(
    []
  );

  const handleChange = (payload: {
    buttons?: WAMessageTemplateComponent['buttons'];
  }) => {
    typeof payload.buttons !== 'undefined' && setButtons(payload.buttons);
  };

  return (
    <WhatsAppTemplateButtonsSolo
      buttons={buttons}
      disabled={disabled}
      onChange={handleChange}
    />
  );
};
```

### KakaoTalk Template Editor

Optionally you can wrap `<KakaoTalkTemplateEditor />` with `<KakaoTalkTemplateProvider />` and consume it with `useKakaoTalkTemplate()` hook which returns
object with `validateTemplate()` function that allows to trigger manual template validation.

#### Basic example

```tsx
import { KakaoTalkTemplateEditor } from '@sinchlabs/composer';

export const Default: FunctionComponent<Props> = () => {
  const [template, setTemplate] = useState<KakaoTalkTemplate>();

  const handleChange = (newTemplate: KakaoTalkTemplate) => {
    setTemplate(newTemplate);
  };

  /*
   * Function that as arguments takes errors object and summary count of errors found in the Editor
   */
  const handleError = (errors, errorsCount) => {
    /* ... */
  };

  return (
    <KakaoTalkTemplateEditor
      onError={handleError}
      onTemplateChange={handleChange}
      template={template}
    />
  );
};
```

---
_Source: https://npm.io/package/@sinchlabs/composer · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
