All Projects → mikevercoelen → redux-signal

mikevercoelen / redux-signal

Licence: MIT license
A scalable solution for modals using React and Redux

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to redux-signal

Jalert
jQuery alert/modal/lightbox plugin
Stars: ✭ 73 (+114.71%)
Mutual labels:  modals
Accessible modal window
Accessible modal dialogs
Stars: ✭ 196 (+476.47%)
Mutual labels:  modals
ember-modal-service
An ember-cli addon to manage modals as promises
Stars: ✭ 27 (-20.59%)
Mutual labels:  modals
Vuedals
Vue modals with a single component
Stars: ✭ 102 (+200%)
Mutual labels:  modals
Izimodal
Elegant, responsive, flexible and lightweight modal plugin with jQuery.
Stars: ✭ 2,122 (+6141.18%)
Mutual labels:  modals
React Native Modalfy
🥞 Modal citizen of React Native.
Stars: ✭ 212 (+523.53%)
Mutual labels:  modals
Ngx Bootstrap
Fast and reliable Bootstrap widgets in Angular (supports Ivy engine)
Stars: ✭ 5,343 (+15614.71%)
Mutual labels:  modals
react-portalgun
Lightweight portal system for React. Mega seeds included 🔫
Stars: ✭ 75 (+120.59%)
Mutual labels:  modals
Decktransition
A library to recreate the iOS Apple Music now playing transition
Stars: ✭ 2,207 (+6391.18%)
Mutual labels:  modals
vue-modal
Reusable Modal component, supports own custom HTML, text and classes.
Stars: ✭ 29 (-14.71%)
Mutual labels:  modals
V Dialogs
A simple and clean instructional dialog plugin for Vue2, dialog type including Modal, Alert, Mask and Toast
Stars: ✭ 121 (+255.88%)
Mutual labels:  modals
Featherlight
Featherlight is a very lightweight jQuery lightbox plugin. It's simple yet flexible and easy to use. Featherlight has minimal css and uses no inline styles, everything is name-spaced, it's completely customizable via config object and offers image, ajax and iframe support out of the box. Featherlights small footprint weights about 4kB – in total.
Stars: ✭ 2,037 (+5891.18%)
Mutual labels:  modals
Focus Layers
Tiny React hooks for isolating focus within subsections of the DOM.
Stars: ✭ 238 (+600%)
Mutual labels:  modals
Modals
Simple modal dialogue windows
Stars: ✭ 85 (+150%)
Mutual labels:  modals
redux-promising-modals
A middleware, reducer and actions for manipulating modal windows using Redux.
Stars: ✭ 23 (-32.35%)
Mutual labels:  modals
Django Admin Interface
django's default admin interface made customizable. popup windows replaced by modals. :mage: ⚡️
Stars: ✭ 717 (+2008.82%)
Mutual labels:  modals
Heyui
🎉UI Toolkit for Web, Vue2.0 http://www.heyui.top
Stars: ✭ 2,373 (+6879.41%)
Mutual labels:  modals
corner-popup
jQuery pop-up script displaying various types of content in corner of browser
Stars: ✭ 23 (-32.35%)
Mutual labels:  popups
PopUpOFF
Chrome extension, providing better web experience.
Stars: ✭ 65 (+91.18%)
Mutual labels:  popups
laravel-livewire-modals
Dynamic Laravel Livewire Bootstrap modals.
Stars: ✭ 63 (+85.29%)
Mutual labels:  modals

Redux Signal

Flexible, scalable library for creating modals with React and Redux.

  • signals: small, quick notification modals (confirmations, alerts etc.)
  • modals: fully customizable modals for your forms etc.

Demo

mikevercoelen.github.io/redux-signal

Example

import React from 'react'
import { withSignal, SignalTypes } from 'redux-signal'

// As an example, this app has a ProfileView. The user can upload an avatar,
// and if the avatar file is too large, we want to display a notification popup

class ProfileView extends React.Component {
  onAvatarFileUpload = () => {
    if (avatarIsToLarge) { // use your imagination...
      this.props.createSignal({
        type: SignalTypes.OK,
        title: 'Warning',
        message: 'The file was too large'
      })
    }
  }

  render () {
    // ...
  }
}

export default withSignal(ProfileView)

More example code available here

Table of Contents

Installation

npm install redux-signal --save

Introduction

The problem

Setting up a flexible solution for modals with Redux is hard. Our apps mostly need 2 types of modals: simple modals (such as confirms / warnings etc.) and custom modals.

We might need multiple modals open at once, so we need some stacking order and we only want to display one overlay component. We also want our Redux state to be clean and serializable.

So meet Redux Signal, hi.

In Redux Signal there are 2 types of modals: signals and modals. Signals are simple notifications: like warnings when things go wrong, confirmations when a user tries to removing an item, or user feedback when an item has been removed etc. Modals are fully customizable, modals. Like login popups etc.

NOTE:

Redux Signal is not a library for the styling of your modals, that is your responsibility, however we made react-modal-construction-kit for making your life even easier.

Check out the examples for more info.

How does it work?

Redux Signal uses an event / feedback queue mechanism for signals so we handle events in a clean way, without cluttering our app state with functions etc. See Handling events for more info.

Setup

Reducer setup

The first thing you need to do is to include the signal reducer in your rootReducer. Please make sure it's mounted at your rootReducer as signal, we are working on making this flexible in the future.

reducers/index.js

import { combineReducers } from 'redux'
import { reducer as signalReducer } from 'redux-signal'

export const rootReducer = combineReducers({
  signal: signalReducer
})

SignalContainer setup

The second thing you need to do, is to create a SignalContainer. Again: Redux-signal is not responsible for your Modal look and feel, you need your own Modal component (react-modal-construction-kit)

The SignalContainer is the link between signal and your modal component

So let's create a SignalContainer component:

containers/SignalContainer.js

import React from 'react'
import PropTypes from 'prop-types'

// These are your application specific components we use in this demo example
import Button from '../components/Button/Button'
import Modal from '../components/Modal/Modal'

import {
  createContainer,
  SignalEvents,
  SignalTypes
} from 'redux-signal'

const SignalContainer = ({
  event,
  destroy,
  close,
  modal
}) => {
  // modal contains all the properties you submit when calling `createSignal`, so you have all the freedom
  // to do whatever you want (title, message, isRequired) only isFirst and isVisible are required.

  return (
    <Modal
      isOpen={modal.isVisible}
      title={modal.title}
      onClosed={close}
      footer={getFooter(modal, eventType => event(modal, eventType))}>
      {modal.message}
    </Modal>
  )
}

SignalContainer.propTypes = {
  event: PropTypes.func,
  destroy: PropTypes.func,
  close: PropTypes.func,
  modal: PropTypes.object
}

function getModalLabel (modal, labelType, otherwise) {
  return (modal.labels && modal.labels[labelType]) || <span>{otherwise}</span>
}

function getFooter (modal, onModalEvent) {
  switch (modal.type) {
    case SignalTypes.YES_NO:
      return [
        <Button
          key='no'
          reject
          onClick={() => onModalEvent(SignalEvents.BTN_NO)}>
          {getModalLabel(modal, 'no', 'Nope')}
        </Button>,
        <Button
          key='yes'
          primary
          onClick={() => onModalEvent(SignalEvents.BTN_YES)}>
          {getModalLabel(modal, 'yes', 'Yep')}
        </Button>
      ]
    case SignalTypes.YES_NO_CANCEL:
      return [
        <Button
          key='cancel'
          onClick={() => onModalEvent(SignalEvents.BTN_CANCEL)}>
          {getModalLabel(modal, 'cancel', 'Cancel')}
        </Button>,
        <Button
          key='no'
          reject
          onClick={() => onModalEvent(SignalEvents.BTN_NO)}>
          {getModalLabel(modal, 'no', 'Nope')}
        </Button>,
        <Button
          key='yes'
          reject
          onClick={() => onModalEvent(SignalEvents.BTN_YES)}>
          {getModalLabel(modal, 'yes', 'Yep')}
        </Button>
      ]

    case SignalTypes.OK_CANCEL:
      return [
        <Button
          key='cancel'
          onClick={() => onModalEvent(SignalEvents.BTN_CANCEL)}>
          {getModalLabel(modal, 'cancel', 'Cancel')}
        </Button>,
        <Button
          key='ok'
          primary
          onClick={() => onModalEvent(SignalEvents.BTN_OK)}>
          {getModalLabel(modal, 'ok', 'Ok')}
        </Button>
      ]
    case SignalTypes.OK:
      return (
        <Button
          primary
          onClick={() => onModalEvent(SignalEvents.BTN_OK)}>
          {getModalLabel(modal, 'ok', 'Ok')}
        </Button>
      )
  }

  return null
}

export default createContainer(SignalContainer)

Once you've created the SignalContainer (which, again, is the link between your Modal and redux-signal) you have to use it somewhere in your application. The most logical place would be your main layout, use it like so:

<SignalContainer />

Now you've setup everything you need for redux-signal and can start using createSignal to show signals.

Signals

Showing a signal

  1. Wrap the component where you want to show a signal with withSignal, which injects the component with a few props from which one is called: createSignal.
  2. Use createSignal to show a signal.

Example:

components/Demo.js

import React from 'react'

import {
  withSignal,
  withSignalPropTypes,
  SignalTypes
} from 'redux-signal'

const Demo = ({ createSignal }) => {
  return (
    <div>
      <button
        onClick={() => {
          createSignal({
            type: SignalTypes.OK,
            title: 'hi',
            message: 'Hello world'
          })
        }}>
        Show ok
      </button>
    </div>
  )
}

Demo.propTypes = {
  ...withSignalPropTypes
}

export default withSignal(Demo)

Signal types

There are 4 SignalTypes:

  • OK
  • OK_CANCEL
  • YES_NO
  • YES_NO_CANCEL

It's your responsibility for handling the signal type in the SignalContainer, in our example SignalContainer you can see the type is being used to show different buttons.

More info see createSignal API

Handling events

Lets say you want to have a confirmation popup when a user wants to remove an item. You want to handle the events when clicked on the yes button or no button. You can do so by using eventHandler

import React from 'react'

import {
  withSignal,
  withSignalPropTypes,
  SignalTypes,
  eventHandler
} from 'redux-signal'

const KillTheWorldEvents = eventHandler()

const Demo = ({ createSignal }) => {
  return (
    <div>
      <button
        onClick={() => {
          createSignal({
            type: SignalTypes.YES_NO,
            eventHandler: KillTheWorldEvents,
            title: 'Please confirm',
            message: 'Are you sure you want to kill the world?'
          })
        }}>
        Kill the world
      </button>
      <KillTheWorldEvents
        onYes={() => window.alert("You have killed the world.")}
        onNo={() => window.alert("Thank god, you are a good kid."} />
    </div>
  )
}

Demo.propTypes = {
  ...withSignalPropTypes
}

export default withSignal(Demo)

Modals

TODO: for now check out the modal examples code.

Overlay

TODO: for now check out the SignalOverlayContainer in the examples code.

API

createContainer

The following props will be available once a component has been wrapped with createContainer:

Property Type Description
event function Dispatch a signal event
close function Closes the signal, not to be confused with destroy, which removes the DOM element. Close should be used to close, destroy on transition end
destroy function Destroys the signal, should be used on transition end when using a transitioned modal, see examples for more info on it's use
modal object All the props passed to createSignal

withSignal

The following props will be available once a component has been wrapped with withSignal:

Property Type Description
createSignal function({ type, ...props }) See createSignal
signalEvent function Dispatch a signal event
setModalState function(modalId, ModalState) Set the state of a modal
showModal function(modalId) Shows a modal
hideModal function(modalId) Hides a modal

createSignal

This method will be available in the props of a component wrapped with withSignal

The method expects an object with the following parameters:

Property Type Default Description
type SignalType (enum) - The type of Signal see: Signal types
eventHandler EventHandler - (optional) pass in an EventHandler to handle events
...props - - All other props passed to createSignal can be accessed in your SignalContainer's modal object prop, see createContainer

getHasVisibleModal

This is a selector, and returns true or false if a modal OR signal is visible, this can be used to render an overlay component

Property Type Default Description
state object - Your application state
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].