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}
}