@pinkairship/use-messenger

2.0.0 • Public • Published

useMessenger

A react library that provides a context and hook to add and remove messages from your application.

Create a simple hook to add toast notifications, screenreadernotifications, or whatever app notifications you need with a simple, easy to use api.

Install

With npm

npm install @pinkairship/useMessenger

With yarn

yarn add @pinkairship/useMessenger

Usage

Wrap the tree you wish to add and remove messages with a MessagesProvider:

function App () {
  return (
    <MessagesProvider>
      // children here
    </MessagesProvider>
  )
}

Then create a component that will hook into adding a message:

function MakeMessage () {
  const { addMessage } = useMessenger()
  return (
    <input type="button" onClick={() => addMessage(nanoid(), 'err')} value="Add Message" />
  )
}

Then create a component that will display the message and hook into removing the message:

function Message ({ message }) {
  const { removeMessage } = useMessenger()
  return (
    <div>
      {message.message} |  {message.options.status}
      <input type="button" onClick={() => removeMessage(message.id)} value="Remove Message" />
    </div>
  )
}

Then put them altogether (full example below):

import React from 'react'

import { MessagesProvider, useMessenger } from '@pinkairship/useMessenger'
import { nanoid } from 'nanoid'

export default function App () {
  return (
    <MessagesProvider>
      <div>
        <MakeMessage />
        <MessageDisplay />
      </div>
    </MessagesProvider>
  )
}

function MakeMessage () {
  const { addMessage } = useMessenger()
  return (
    <input type="button" onClick={() => addMessage(nanoid(), 'err')} value="Add Message" />
  )
}

function MessageDisplay () {
  const { messages } = useMessenger()

  return (
    <div>
      {
        Object.values(messages).map((m) => <Message message={m} key={m.id} />)
      }
    </div>
  )
}

function Message ({ message }) {
  const { removeMessage } = useMessenger()
  return (
    <div>
      {message.message} |  {message.options.status}
      <input type="button" onClick={() => removeMessage(message.id)} value="Remove Message" />
    </div>
  )
}

Dismissable Alerts

If you want to use dismissable alerts, use the following function when creating an alert:

(message) => {
  const messageId = addMessage('my message')
  // Will be removed in five seconds
  setTimeout(() => removeMessage(messageId), 5000)
}

Add this to your addMessage component:

function MakeMessage () {
  const { addMessage, removeMessage } = useMessenger()

  const dismissableAddMessage = (message) => {
    const messageId = addMessage('my message')
    // Will be removed in five seconds
    setTimeout(() => removeMessage(messageId), 5000)
  }
  return (
    <input type="button" onClick={() => dismissableAddMessage(nanoid())} value="Add Message" />
  )
}

Screen Reader Alerts

To add screen reader alerts (which you should - read more here) pass in a function that accepts the message id, message, and the options of the message (i.e. 'status': 'error').

Also, to remove the message, pass in a removeScreenReaderAlert function that accepts the id of the function. You can use the id of the message to remove the alert when the message is removed.

//index.html
<div role="region" id="screenReaderAlert" aria-live="polite">
</div>

// App.js
export default function App () {
  return (
    <MessagesProvider
      screenReaderAlert={(id, message, options) => myScreenReaderAlertFunction(id, message, options)}
      removeScreenReaderAlert={(id) => myScreenReaderAlertRemovalFunction(messageId)}
    >
      <div>
        <MakeMessage />
        <MessageDisplay />
      </div>
    </MessagesProvider>
  )
}

** Note that you may have components that automatically hook into your screen reader alert when they are created, so be sure to not add a function to add and remove alerts for screen readers if this is the case.

Initial Messages

Initial messages can be set to the MessagesProvider on initial mount.

const intialMessages = ['message1', 'message2']

function App () {
  return (
    <MessagesProvider initialMessages={intialMessages}>
      ...
    </MessagesProvider>
  )
}

initialMessages assumes that the messages being passed are an array of strings, but if they are not you can pass a transform function called initialMessageTransform that will format the messages into a way that MessagesProvider can understand. This format is {message: string, options: object}.

const intialMessages = [{message: nanoid(), customStatus: 'mine', id: 'will be ignored'}]
const transformer = m => ({message: m.message, options:{status: m.customStatus}, id: m.id})

function App () {
  return (
    <MessagesProvider initialMessages={intialMessages} initialMessageTransform={transformer}>
      ...
    </MessagesProvider>
  )
}

Note that the id property will be overwritten by any transforms as it is used internally to track messages in state. If you have a message that has an id, transform it.

** Note that messages set in this manner will not alert screen readers and it is up to the application to still alert screen readers of these messages.

Development

To run a development environment:

npm run start

You can then navigate to http://localhost:8080 and see the example app running. Using webpack serve, any changes you make to the src/ files will automatically be reflected.

Testing

Tests should be included in the __test__ file. To help in writing tests, a wrapper function has been provided in __tests__/index.js. See __tests__/index.js for examples on how to write tests.

Running Tests

To run tests:

npm run test

Troubleshooting

  1. If you install into another project locally (using npm install <folder>) be sure to follow the advice found here https://stackoverflow.com/questions/56021112/react-hooks-in-react-library-giving-invalid-hook-call-error

Readme

Keywords

Package Sidebar

Install

npm i @pinkairship/use-messenger

Weekly Downloads

372

Version

2.0.0

License

MIT

Unpacked Size

34.1 kB

Total Files

23

Last publish

Collaborators

  • pinkairship