npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

iot-react-grid

v1.0.27

Published

An implementation of the react-grid-layout that accepts different widgets to displayed inside the grid items and enables widget communication at the grid level.

Downloads

3

Readme

Initilizing the Grid

The required props to initlize the grid are its initial dimensions and an array containing the widgets that may be added to the grid. The Grid component must be wrapped in a which with the controller state (its redux store), should be imported and passed as a prop as such:

 <Provider store={store}>
        <ReactGrid 
            onChange={(elements, layout, controller, state) => {console.log('UPDATE OCCURRED', state)}}
            initState={{
                dashboard: [
                    {
                        element: {id: 'Widget1', gridId: '0'},
                        layout: {i: '0', x: 0, y: 0, w: 11, h: 4}
                    },
                    {
                        element: {id: 'Widget2', gridId: '1'},
                        layout: {i: '1', x: 0, y: 4, w: 6, h: 4}
                    },
                ],
                controller: {
                    abc: 'xxx'
                },
            }}
            components={[ReactGridViewWidget1, ReactGridViewWidget2]}
            width={1724}
            height={800}
            rowHeight={50}
            isDroppable={true}/>
</Provider>

Its optional props extended react-grid-layout props. Some of the more relevant include:

  • onChange - You may pass a custom function, it will be called whenever there in a change in either the grid layout or the controller state, triggering a rerender. It receives the grid elements array, the grid layout, the controller and the current state.
  • onLayoutChange - Similiar as above but only triggers on a layout change. Receives the new layout.
  • iniState - Initial grid state. The dashboard array should contain objects that contain an element field indicating the id of widget (must match an id provided by one of the components in the components array) and a gridId. This gridId must match the one (i) in its layout field. The controller field is the initial state of the controller.
  • width - Initial grid width in pixels. Required.
  • heigth - Initial grid height in pixels. Required.
  • isDroppable - If elements may be draggable into the grid. Boolean, default is false.
  • overflow - When true grid, height will remain static and allowed to overflow. A scroll bar will be added. When false the grid expands downwards to accomodate for new elements. Default is false.
  • rowHeight - Row height in pixels.
  • compactType - Accepts 'vertical', 'horizontal', null or undefined. When set to vertical the grid will automatically align items vertically, if horizontal horizontally. If null, the grid elements will always remains as they are.
  • margin - Defines the margins for the grid. [horizontalMargin: number, verticalMargin: number].
  • itemCreation - Function to create the grid item. You may provided your own function to create the items on the grid. It must return a div element use key property match the element's gridId. It accepts the grid element, the grid's remove function, the controller, the grid state and it's index position on the array. Example:
function createItem(el: GridComp, removeFunction: (i: string | undefined) => void, _controller: GridControllerObject, state: {[key: string]: any}, index: number){
        return (
            <div id={'widget-'+ el.id + index} key={el.gridId} className={"d-flex flex-column rounded border border-secondary-subtle bg-white overflow-hidden"}>
                <div className={"d-flex flex-row w-100"}>
                    <div className={"bg-secondary flex-inline-flex mr-auto drag-handle"}
                         style={{borderTopLeftRadius: '5px', borderBottomRightRadius: '5px', cursor: 'pointer'}}>
                        {el.title}
                    </div>
                    <div className={"d-inline-flex ml-auto align-items-center"} style={{cursor: 'pointer'}}>
                        <GearWide width={20} fill={"grey"} onClick={() => {el?.optionsMenu? controller?.updateWidgetOptions(gridElements, setGridElements, layout, setLayout, index, el?.optionsMenu(gridElements[index])) : null}}/>
                        <XCircle width={20} fill={"red"} onClick={() => {removeFunction(el.gridId)}}/>
                    </div>
                </div>

                <div className={"d-flex overflow-auto h-100 w-100 overflow-auto"}>
                    {el?.render? el.render(state) : null}
                </div>
            </div>
        )
    }

Widgets

Widgets are functions that receive the controller as a prop so they can interact with the grid. Example:

function ReactGridViewWidget1(controller: GridControllerObject): GridComp{
    const options = {
        title: 'React Grid Widget',
        Icon: '',
        id: 'Widget1',
        minW:3,
        isBounded: true,
        publishesTo: ['shipData'],
        subscribesTo: [],
    }

    React.useEffect(() => {
        console.log('WIDGET 1 USEEFFECT')
    }, [])

    function optionsMenu(element: GridComp){
        return {...options, title: 'xxxx'}
    }

    function onInit(state: ControllerState){
        console.log('Widget 1 init', state)
    }

    function render(state: ControllerState){
        return <div className={"d-flex flex-row w-100 h-100 justify-content-center align-items-center"} onClick={() => {controller?.publishInfo(options.publishesTo[0], ['yyy', '1111'])}}>React Widget1 {state.shipData}</div>
    }

    function onRemove(state: ControllerState){
        console.log('Widget 1 removed', state);
    }

    return {render, onInit, onRemove, optionsMenu,...options}
}

Each widget should inclue a render method that accepts a controller state as an argument. This method will be called whenever there is a layout change or state change and it should return a JSX.Element to display inside the grid item.

Optinal methods such as onInit and onRemove may be added to for the widget to do something whenever it is added to the grid or removed from it. An optional optionsMenu functional may be added allow for editing of its options. Its options object declares its default settings these include:

  • minW: Number - Minimum width in grid units. 1 unit is 1 column, by default the grid has 12 in lg screen size.
  • maxW: Number - Maximum height in grid units.
  • minH: Number - Minimum height in grid units. 1 unit will be correspond to the size declared in the rowSize grid property.
  • maxH: Number - Max height in grid units.
  • title: String. - Widget title that may be displayed on it.
  • id: String - The widget it for the grid to know which widget to initialize. Required
  • subscribesTo: String[] - Indicates the controller state fields to which the widget should react to. This should be used with the controller method compareStateChanges to see which, if any, of its subscriptions changed and act accordingly.
  • publishesTo: String[] - The controller fields to which its writes to.

Controller

The controller provides a set of functions to interact with the grid an other utilities. Some of the most important are:

  • publishInfo: (field: string, value: any) - Accepts a string indicating the controller state field to write to and the value to write. Publishes the new data on the controller state.
  • resetState: (newState: {[key: string]: any}) - Resets the controller state to the provided one.
  • getControllerState - Return the current controller state.
  • compareStateChanges: (subscriptions: string[], prevState: {[key: string]: any}, currentState: {[key: string]: any}) - Checks if any of the fields in the subscriptions array and changed between states and returns an array with the names of the fields which have changes. Usage example:
export default function ReactGridViewWidget1(controller: GridControllerObject): GridComp{
    const options = WidgetConfiguration()

    let currentState: {[key: string]: any};

    React.useEffect(() => {
        console.log('WIDGET 1 USEEFFECT')
    }, [])

    function optionsMenu(element: GridComp){
        return {...options, title: 'xxxx'}
    }

    function onInit(state: ControllerState){
        console.log('Widget 1 init', state)
    }

    function render(state: ControllerState){
        let prevState = currentState;
        currentState = state;

        if(controller?.compareStateChanges(options.subscribesTo, prevState, currentState).length > 0){
            //do something
        }

        return <div className={"d-flex flex-row w-100 h-100 justify-content-center align-items-center"} onClick={() => {controller?.publishInfo(options.publishesTo[0], ['yyy', '1111'])}}>React Widget1 {state.shipData}</div>
    }

    function onRemove(state: ControllerState){
        console.log('Widget 1 removed', state);
    }

    return {render, onInit, onRemove, optionsMenu,...options}
}