1.8.4 • Published 3 years ago

musalleen-react-theme v1.8.4

Weekly downloads
56
License
MIT
Repository
github
Last release
3 years ago

musalleen-react-theme.

npm version npm MIT Licence

https://musalleen-react-theme.herokuapp.com/

A set of common UI components and theme for Musalleen's web apps written in React.js. It was ported from an already built bootstrap 4 theme called ERact.

Along with theme colors, it has the following set of components.

  • Button
  • DescriptionList
  • FormInput
  • Image
  • ImageModal
  • InfoCard
  • Loader
  • Logo
  • PaymentWidget
  • Table

It also has these set of custom hooks.

  • useForm
  • useBoolean

It also has resuable alerts and dialogs that are triggered through redux actions.

Prerequisites.

To use this theme in a project, following conditions must be met.

  • The project must be capable to load SCSS files as the theme uses only scss files. This is enabled by default if you've used create-react-app V2 to generate the boilerplate. Otherwise if you're using Webpack, you need to use sass-loader which includes node_modules.

  • This package has these peerDependencies that must also be installed in the project. (Really sorry for such narrow version ranges. I'm really picky and paranoid about semver! :) )

    "immer": "^1.8.0",
    "react": "16.7.0-alpha.2",
    "react-dom": "16.7.0-alpha.2",
    "react-icons": "2.2.5",
    "react-redux": "^5.1.1",
    "react-router": "3.0.5",
    "reactstrap": "6.5.0",
    "redux": "^4.0.1" 

If you ever want to update these dependencies in your project, consider updating these here first and bumping the version of this package. If there are any breaking changes, bump the major version and archive the branch.

Instructions.

  • yarn add musalleen-react-theme.

  • In your App.js. (Import theme)

import 'musalleen-react-theme/lib/theme/theme.scss';
  • Redux setup. (This package is tightly coupled with Redux and you need to use to if you want to use this package.)
import { Provider } from 'react-redux';
import { Provider as MusallenProvider } from 'musallen-react-theme';
// Import store from wherever you like.
import store from './store';

<Provider store={store}>
    {/* The ORDER for this providers is important. MusalleenProvider needs to be inside Provider as it needs redux context */}
    <MusalleenProvider>
            {children}
    </MusalleenProvider>
</Provider>
+ import { store } from 'musalleen-react-theme';
- import { combineReducers } from 'redux';
import reducer1 from './reducer1';
import reducer2 from './reducer2';

// Use this to create your store.
+ const reducers = store.combineReducers({
+    reducer1,
+    reducer2
+ });
- const reducers = combineReducers({
-    reducer1,
-    reducer2
- });
  • To use alerts and dialogs anywhere in your project.
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { store } from 'musalleen-react-theme';

const {
    hideAlert, 
    showBadRequestAlert,
    showNoInternetAlert,
    showServerErrorAlert,
    showSuccessAlert,
    showWarningAlert,
    showDangerAlert

    showDialog,
    hideDialog
} = store.actions;

function Component({ dispatch }) {

    function handleShowDangerAlert() {
        dispatch(showAlert('Oops!', 'Something broke.', 'danger', true, new Error('Fatal Error.')));
        // or just...
        dispatch(showDangerAlert('Something broke.'));
        // The last two arguments are auto hide and an optional error.
    }

    function handleShowWarningAlert() {
        dispatch(showAlert('Caution!', 'Something is wrong.', 'warning', true, null));
        // or just...
        dispatch(showWarningAlert('Something is wrong.'));
    }

    function handleShowSuccessAlert() {
        dispatch(showAlert('Huraay!', 'Task is finished.', 'success', true, null));
        // or just...
        dispatch(showSuccessAlert('Task is finished.'));
    }

    async function handleShowDialog() {
        // Let's wait for the user to press a button by waiting for the promise to resolve.
        const confirm = await dispatch(showDialog('Are you sure?', 'Do you really want to do this?' 'Okay', 'Cancel'));
        // or just...
        const [confirm, { note }] = await dispatch(
            showDialog(
                    'Are you sure?',
                    'Do you really want to do this?',      
                    'Okay',
                    'Cancel',
                    // This will create a input in the dialog
                    // with the label "Note".
                    {
                        note: {
                            type: 'textarea',
                            label: 'Note',
                            placeholder: 'Add a note you want to add to this action.'
                        }
                        // Similarly we can add another input.
                        // The keys for this JSON can be inferred by looking
                        // at the props for FormInput. Almost all the keys will
                        // be passed on the FormInput as props.
                        // name: {
                        //     type: 'text',
                        //     label: 'Name',
                        // }
                    }
            )
        );
        if (confirm) {
            // User pressed the 'Okay' button.
            // "note" will hold what the user typed in the input.
            console.log(note);
        } else {
            // User pressed the 'Cancel' button.
        }
    }
    
    return (
        <button onClick={handleShowDangerAlert}>
            Show Danger Alert
        </button>
        <button onClick={handleShowWarningAlert}>
            Show Warning Alert
        </button>
        <button onClick={handleShowSuccessAlert}>
            Show Success Alert
        </button>
        <button onClick={handleShowDialog}>
            Show Dialog
        </button>
    );
}

Component.propTypes = {
    dispatch: PropTypes.func.isRequired
}

export default connect(Component);
  • To use UI components.
import React, { useState } from 'react';
import { Components } from 'musalleen-react-theme';

const {
    FormInput,
    DescriptionList 
    // the rest of the components.
} = Components;

function Component({ dispatch }) {

    const [value, setValue] = useState(value);
    
    return (
        <FormInput 
            label="My Input"
            value={value}
            onChangeValue={setValue}
            // ...Rest of the props.
        />

    );
}

export default Component;
  • To use custom hooks. More on hooks.
import React from 'react';
import { Components, hooks } from 'musalleen-react-theme';

const {
    FormInput,
    DescriptionList,
    ImageModal,
    Button
    // the rest of the components.
} = Components;

const { 
    useBoolean,
    useForm
} = hooks;

function Component() {

    // Boolean helper.
    // [value, setValueTrue, setValueFalse]
    const [modalVisible, showModal, hideModal] = useBoolean(false);

    // Form and validation helper.
    const [values, errors, handleInputChange, setError, validate, resetForm] = useForm(
        // Initial state.
        {
            firstName: '',
            lastName: '',
            email: '', // email is optional.
        },
        // Required values.
        ['firstName', 'lastName']
    );

    function submitForm() {
        const formHasErrors = validate();
        if (formHasErrors) {
            // Any empty value error messages will automatically be set.
            return;
        }
        const { firstName, lastName, email } = values;

        // Perform custom validation.
        if (!email.includes('@')) {
            // Set a custom error message.
            // setError takes the state name and the error messsage as arguments.
            setError('email', 'Error is not of proper format.');
            return;
        }

        // Form values are valid. Do what you have to do and then reset form.
        // API.post({
        //     firstName,
        //     lastName,
        //     email
        // });

        // Resets form to default values.
        resetForm();
    }
    
    return (
        <div>
            <Button onClick={showModal}>
                Show Modal
            </Button>

            <ImageModal
                show={modalVisible}
                onClose={hideModal}
                title="Sample Image"
                url="https://unsplash.com/photos/4KsPeWWNXY0/download?force=true"
                description="Here's a sample image."
            />
            {/* Use the values from useForm inside FormInputs */}
            <FormInput 
                label="First Name"
                value={values.firstName}
                onChangeValue={handleInputChange('firstName')}
                state={errors.firstName ? 'danger' : 'default'}
                message={errors.firstName}
            />

            <FormInput 
                label="Last Name"
                value={values.lastName}
                onChangeValue={handleInputChange('lastName')}
                state={errors.lastName ? 'danger' : 'default'}
                message={errors.lastName}
            />

            <FormInput 
                label="Email"
                value={values.email}
                onChangeValue={handleInputChange('email')}
                state={errors.email ? 'danger' : 'default'}
                message={errors.email}
            />

            <Button onClick={submitForm}>
                Submit Form
            </Button>

        </div>
    );
}

Setup.

  • Styling is done using scss. These files are imported directly and are transpiled on the fly using sass-loader.
  • Webpack is used for bundling and transpiling.
  • Component level documentation is done using react-styleguidist.
  • To checkout each components with live examples and their props; Clone repo, download dependencies and do a npm run styleguide or yarn styleguide to start the react styleguidist server. (Examples for the components should live inside the lib/components/examples directory)
  • Yarn should be used as the package manager of choice and a yarn.lock file has also been committed.
1.8.4

3 years ago

1.8.2

4 years ago

1.8.3

4 years ago

1.8.1

4 years ago

1.8.0

4 years ago

1.7.0

4 years ago

1.6.0

4 years ago

1.5.0

4 years ago

1.4.1

4 years ago

1.4.0

4 years ago

1.3.0

4 years ago

1.2.0

4 years ago

1.1.0

4 years ago

0.8.5

4 years ago

0.8.4

4 years ago

0.8.3

4 years ago

0.7.3

5 years ago

0.7.2

5 years ago

0.7.1

5 years ago

0.7.0

5 years ago

0.6.2

5 years ago

0.6.1

5 years ago

0.6.0

5 years ago

0.5.0

5 years ago

0.4.5

5 years ago

0.4.4

5 years ago

0.4.3

5 years ago

0.4.2

5 years ago

0.4.1

5 years ago

0.4.0

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.9

5 years ago

0.2.8

5 years ago

0.2.7

5 years ago

0.2.6

5 years ago

0.2.5

5 years ago

0.2.4

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago