6.0.1 • Published 6 months ago

airr-react v6.0.1

Weekly downloads
7
License
MIT
Repository
github
Last release
6 months ago

Build Status Maintainability Known Vulnerabilities

airr-react

This library is set of several components that helps building Single Page Apps with ReactJS.
airr-react defines few basic UI classes and features that every app needs. The core component is responsible for maintaining navigation in the app. All of it when minified and gzipped weights ~11.8kB (bundlephobia.com).

Library can be used for:

  • creating unique looking and behaving apps,
  • creating PWA or standard responsive web apps for dektop, phone and tablet browsers,
  • rapidly designing prototypes showing your ideas.

Table of contents

Installation

npm i airr-react

Usage

Here's a simple code usage that provides a viewport with two views.

Edit airr-react-example

import React from "react";
import ReactDOM from "react-dom";
import { Scene, View, Sidepanel } from "airr-react";
import "airr-react/dist/airr-react.css";
import "./styles.css";

const BlueViewName = "blue-view";
const RedViewName = "red-view";

class BlueView extends View {
    content() {
        return (
            <div className={BlueViewName}>
                BlueView
                <br />
                <button onClick={this.props.goToRedView}>go to red</button>
                <button onClick={this.props.openSidepanel}>open sidepanel</button>
                <button onClick={this.props.openMayer}>open modal</button>
            </div>
        );
    }
}
class RedView extends View {
    content() {
        return (
            <div className={RedViewName}>
                RedView
                <br />
                <button onClick={this.props.goToBlueView}>go to blue</button>
            </div>
        );
    }
}

class Viewport extends Scene {
    viewsConfig = {
        [BlueViewName]: {
            type: BlueView,
            props: {
                name: BlueViewName,
                goToRedView: () => this.changeView(RedViewName),
                openSidepanel: this.openSidepanel,
                openMayer: () =>
                    this.openMayer({
                        name: "foo-mayer",
                        content: (
                            <div>
                                Hello! I am modal layer!
                                <br />
                                <button onClick={() => this.closeMayer("foo-mayer")}>
                                    close me
                                </button>
                            </div>
                        )
                    })
            }
        },
        [RedViewName]: {
            type: RedView,
            props: {
                name: RedViewName,
                goToBlueView: () => this.changeView(BlueViewName)
            }
        }
    };

    constructor(props) {
        super(props);

        this.state = {
            ...this.state,
            activeViewName: BlueViewName,
            sidepanel: {
                type: Sidepanel,
                props: {
                    children: "Hello! I'm sidepanel!"
                }
            },
            views: [this.getFreshViewConfig(BlueViewName), this.getFreshViewConfig(RedViewName)]
        };
    }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Viewport />, rootElement);

Concept

View class component is responsible for your single view instance. Put all other components that creates you view inside it and render with content() method.

Other props and functions that will manage changing of your views can be pass to View class from Scene class. The Scene is a views container, core class that can fill view with proper methods to navigate between views, open popups and define sidepanel.

PureComponents

From version 3.0.0 of airr-react all components are implementing PureComponents approach. So remember that your views will not be updated unless you provide them with different props.

View's life-cycles

Airr library provides easy to implement views life-cycles methods. When you develop apps divided into certain views you have to deal with many tasks before or after certain view is activated and animated into the screen.

Like React's componentDidMount method, Airr provides self explanatory methods that can be used by Components that extends View or Scene component. These methods are:

  • viewBeforeActivation
  • viewAfterActivation
  • viewBeforeDeactivation
  • viewAfterDeactivation

Scene or View can:

class JustView extends View {
    viewBeforeActivation() {
        console.log("JustView will be active soon");
    }
    viewAfterActivation() {
        console.log("JustView was activated soon");
    }
    viewBeforeDeactivation() {
        console.log("JustView will be deactivated");
    }
    viewAfterDeactivation() {
        console.log("JustView is now inactive");
    }
    componentDidUpdate() {
        console.log("JustView was updated");
    }
}

Additionaly Scene has:

  • viewsAnimationEnd(oldViewName: string, newViewName: string)
class BarScene extends Scene {
    viewsAnimationEnd(oldViewName, newViewName) {
        console.log(
            `[BarScene::viewsAnimationEnd] oldViewName: ${oldViewName}, newViewName: ${newViewName}`
        );
    }

    componentDidMount() {
        super.componentDidMount();
        console.log("Scene did mount");
    }
}

React Component's life-cycles

You can use all well known React's life-cycles methods when extending airr-react's components.
Only when using componentDidMount in the class that extends Scene you must also invoke super's method like:

  componentDidMount() {
    super.componentDidMount()
    console.log("Scene did mount")
  }

Rendering View's content

In the classes that extends View (which will be all your views) to render children elements use content method instead of render:

class FooView extends View {
    content() {
        return <div>Hello Foo world!</div>;
    }
}

You have to do it this way because core class must set correct properties to the inner view component:

export default class View<P extends ViewProps = ViewProps, S = {}> extends PureComponent<P, S>
    render(): ReactNode {
        const content: ReactNode = getProperContent(this.content(), this.props.children);

        return <ViewRenderer {...this.getViewProps()}>{content}</ViewRenderer>;
    }
}

If you would like to overwrite this behaviour, you must do it like this:

import { getViewProps } from "airr-react/dist/CommonViewHelpers";
import ViewRenderer from "airr-react/dist/ViewRenderer";

class FooView extends View {
    render(): ReactNode {
        return (
            <ViewRenderer {...this.getViewProps()}>
                {() => this.myCustomRenderMethodCall()}
            </ViewRenderer>
        );
    }
}

TypeScript support

Library is fully typed in TypeScript from version 6.0.0. The declarations files are included in library. Check the corespoding examples below to find out how to use certain types and interfaces with library components. Proper summary of this usage will be added here soon.

Examples

Kitchen sink app

Go to example: Standard, Typescript

Demon app showing all library features.

Infinite viewport

Go to example: Standard, Typescript

In this example you can push unlimited views and play with Scene properties.

Simple Scene

Go to example: Standard, Typescript

Very simple app from 'Usage' chapter.

Scene API

Scene class has many helpfull methods to navigate through views and modify Scene properties. Some properties needs to be modify only by using coresponding methods. Which properties requires this approach is described in Props documentation in 'change with method' column.

viewsConfig

viewsConfig: ViewsConfig

Class member that keep information about views configuration objects. Every key in this object describes view config. That configuration later will be used to create new view and add it to state views array. Used by ::getFreshViewConfig to deliver new view config. This variable is mainly used in crucial components's ::changeView method.

Example:

  viewsConfig = {
    "login-view": {
      type: LoginView,
      props: {
          handleLoginBtnClick: this.handleLoginBtnClick
      }
    },
    "home-view": {
      type: HomeView,
      props: {
          showPopup: this.showNewUserPopup
      }
    }
  }

view

changeView

async changeView( view: string | ViewConfig<CommonViewProps>, viewProps: CommonViewProps | {} = {}, sceneProps: SceneProps | {} = {} ): Promise<string | void>

Crucial method of the scene component for manipalutaing views and scene properties and performing animations. Can change active view with animation or just update view and scene properties. Change view by:

  • string name kept in state views array which will lead to view change (with animation) or just update if currently active
  • string name kept in this.viewsConfig which will lead to view push (with animation)
  • new view config wich will lead to view change

Examples:

openSidepanel

openSidepanel(): Promise<boolean | void>

Opens sidepanel if was previously defined

Example:

hideSidepanel

hideSidepanel(): Promise<boolean | void>

Hides sidepanel

Example:

openMayer

openMayer(config: MayerProps): Promise<void>

Add new mayer to this.state.mayers configurations array. This will immediatelly open new mayer.

Example:

closeMayer

closeMayer(name: string): Promise<void>

Close mayer by its name.

Examples:

Other methods

For more detailed documentation of these methods please go to lib/Scene.tsx file. As everything is typescripted now I hope finding good information will not be a problem.

getFreshViewConfig - very usefull for getting new view config from viewsConfig variable.

filterViews - removes views that are not pointed in array.

popView - go back one view and removes currently active view.

destroyView - removes view from Scene views property.

handleBackButton - utility function. Overwrite it in your Scene class to define back button click behaviour. On default it pops view out.

setSidepanelConfig - special function for enabling sidepanel config after mounting of scene. It will ensure proper sidepanel size (width,height) after incjeting it into DOM.

disableSidepanel - self explanatory.

enableSidepanel - self explanatory.

goToView - action dispatcher method. It will return a function ready to fire view change.

isValidViewConfig - checks wheter object is valid view config and can be added to view's array.

hasViewInConfig - checks if view's name is described by some config in this.viewsConfig object.

hasViewInState - checks if view recognized by name argument is present in state.

getViewIndex - self explanatory.

Props documentation

Scene Props

propertytypedescriptionchange with method
namestring (required)The name of the scene. Must be unique among others views in parent scene. Will be used as identification stringsetState
activeViewNamestringName of the active viewsetState
GUIDisabledbooleanBoolean telling if GUI should be disabled meaning no user actions, events are allowed. GUI is disabled via absolute positioned, not visible div that has the biggest z-IndexsetState
GUIDisableCover?ReactNodeReact element to be placed in GUI disabling divsetState
animationAnimationTypeType of animation to perform when switching viewssetState
animationTimenumberTime of views changing animation in milisecondssetState
navbar1 / true / -1 / 0 / falseSpecify if navbar is present (1,true) or not (0,false). Or maybe hidden (-1)setState
navbarHeightnumberHeight of the navbar in pixelssetState
navbarMenu?NavbarMenuNavbar menu is placed on the right most side. Might contain "toggleSidepanel" button or any custom buttons list.setState
navbarClassstringExtra, space separated, navbar's class listsetState
backButtonbooleanBoolean specifing if navbar renders BackButton. Placed by default on the left side of navbar.setState
backButtonOnFirstViewbooleanDo you need to still show backButton even if scene is rendering first view from stack?setState
handleBackButton?(e: SyntheticEvent) => voidFunction that will handle back button click eventssetState
handleBackBehaviourOnFirstView?() => voidFunction that will handle back button clicks events on when first view in stack is activesetState
sidepanel?SidepanelConfigSidepanels configuration declaration. Must contain two properties: type and propssetState (for side, sizeFactor, animationTime,bgLayerOpacity), openSidepanel and hideSidepanel (for isShown), enableSidepanel and disableSidepanel (for enabled)
sidepanelVisibilityCallback?(isShown: boolean) => voidThis function will be called when sidepanel changes it's visibility. It's argument will be isShown bool.setState
viewsViewConfig[]Array of views. Every view object declaration must contain two properties: type and props.changeView
mayersMayerProps[]Array of mayers objects that will be render into this Scene. Must contain special AirrMayer class properties.openMayer, closeMayer
titleReactNodeTitle that will be use in parent Scene navbar title sectionsetState
classNamestringExtra, space separated classes names to use upon first div element.setState
childrenReactNodeChildren to be render in Scene's container. Might be useful for creating navigation UI.setState
stackModebooleanThis propety changes behaviour of views animation when overlay animation is setsetState
activebooleanDetermine if this scene is active. Set by parent scene. Readonly.none

View Props

propertytypedescription
namestring (required)The name of the view. Must be unique among others views in scene. Will be used as identification string
titleReactNodeTitlebar name. If parent scene navbar is enabled, this title will be showed there. Might be string or React element.
activebooleanDetermine if this view is active. Set by parent scene. Readonly.
classNamestringExtra classes to use. Space separetad string list.
style?CSSPropertiesExtra styles to use upon root DOM element of view.

Sidepanel Props

propertynamedescription
sidePlacementSide to which sidepanel will be attached
isShownbooleanBool determining if sidepanel is shown or not. Use Scene's methods (openSidepanel,closeSidepanel) to manipulate this bool. Do no set manually.
enabledbooleanBool determining if sidepanel is enabled.
sizeFactornumberNumber between 0 and 1 determining how much size of whole screen sidepanel will take
animationTimenumberAnimation time in miliseconds
bgLayerOpacitynumberOpacity between 0 and 1

Mayer Props

propertynamedescription
namestring (required)The name of the mayer. Must be unique among others mayers in scene. Will be used as identification.
style?CSSPropertiesExtra styles to apply on Mayer's DOM element
appearFromPlacementSide from which mayer content box will enter
leaveToPlacementSide to which mayer content box will leave
content?ReactNodeContent of mayer
buttons?MayerButtonProps[]Array with buttons configuration
animationTimenumberTime in miliseconds of mayer's appear/disappear animation

Common types

AnimationType

"slide" | "overlay" | "fade"

NavbarMenu

"toggleSidepanel" | ReactNode[]

SidepanelConfig

Object defined with:

property nametypedescription
typeComponentClass<SidepanelProps, any>Reference to class or function that will render AirrSidepanel. Might be AirrSidepanel itself
propsSidepanelPropsSpecial properties of AirrSidepanel class. Go to class declaration for further properties documenation.

ViewConfig

Object defined with:

property nametypedescription
typeComponentClass<ViewProps, any>Refference to class or function that will render AirrView. The most common and adviced approach is to specify class that extends AirrView.
propsViewPropsSpecial properties of AirrView class. Go to class declaration for further properties documenation.

Placement

"top" | "bottom" | "left" | "right"

MayerButtonProps

propertynamedescription
classNamestringExtra class names to use upon button
attrs?CSSPropertiesExtra attributes to apply on HTML element
style?CSSPropertiesAdditional inline styles
closebooleanOptional bool that will automatically add close functionality to the button
handler?(e: SyntheticEvent) => voidOnClick function handler
children?ReactNodeContent to render inside button element

License

Licensed under the MIT License. Copyright (c) 2019 Rafal Rajtar

6.0.1

6 months ago

6.0.0

5 years ago

5.0.0

5 years ago

4.0.2

6 years ago

4.0.1

6 years ago

4.0.0

6 years ago

3.1.4

6 years ago

3.1.3

6 years ago

3.1.2

6 years ago

3.1.1

6 years ago

3.1.0

6 years ago

3.0.1

6 years ago

3.0.0

6 years ago

2.1.2

6 years ago

2.1.1

6 years ago

2.1.0

6 years ago

2.0.21

6 years ago

2.0.20

6 years ago

2.0.19

6 years ago

2.0.18

6 years ago

2.0.17

6 years ago

2.0.16

6 years ago

2.0.15

6 years ago

2.0.14

6 years ago

2.0.13

6 years ago

2.0.12

6 years ago

2.0.11

6 years ago

2.0.10

6 years ago

2.0.9

6 years ago

2.0.8

7 years ago

2.0.7

7 years ago

2.0.6

7 years ago

2.0.5

7 years ago

2.0.4

7 years ago

2.0.3

7 years ago

2.0.2

7 years ago

2.0.1

7 years ago

2.0.0

7 years ago

1.5.10

7 years ago

1.5.9

7 years ago

1.5.8

7 years ago

1.5.7

7 years ago

1.5.6

7 years ago

1.5.5

7 years ago

1.5.4

7 years ago

1.5.3

7 years ago

1.5.2

7 years ago

1.5.1

7 years ago

1.5.0

7 years ago

1.4.1

7 years ago

1.4.0

7 years ago

1.3.9

7 years ago

1.3.8

7 years ago

1.3.6

7 years ago

1.3.5

7 years ago

1.3.4

7 years ago

1.3.3

7 years ago

1.3.2

7 years ago

1.3.1

7 years ago

1.3.0

7 years ago

1.2.5

7 years ago

1.2.4

7 years ago

1.2.3

7 years ago

1.2.2

7 years ago

1.2.1

7 years ago

1.2.0

7 years ago

1.1.2

7 years ago

1.1.1

7 years ago

1.1.0

7 years ago

1.0.11

7 years ago

1.0.10

7 years ago

1.0.9

7 years ago

1.0.8

7 years ago

1.0.7

7 years ago

1.0.6

7 years ago

1.0.5

7 years ago

1.0.4

7 years ago

1.0.3

7 years ago

1.0.2

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago