Giter VIP home page Giter VIP logo

react-spreadsheet-grid's Introduction

React Spreadsheet Grid

An Excel-like grid component for React with custom cell editors, performant scroll & resizable columns

react-spreadsheet-grid in action

The key features

This is an Excel-like Spreadsheet Grid component that supports:

✅ Custom cell editors (use built-in Input and Select, or any other components) & header content

✅ Performant scroll for as many rows as you need

✅ Resizable columns

✅ Control by mouse & from keyboard

✅ Flexible setting of disabled cells

✅ Lazy loading support

✅ Customizable CSS styling

✅ Hooks compatible

✅ TypeScript compatible

Table of contents

Live playground

For examples of the grid in action, you can run the demo on your own computer:

Installation

This module is distributed via npm and should be installed as one of your project's dependencies:

npm install --save react-spreadsheet-grid

⚠️ IMPORTANT! This package also depends on react, react-dom and prop-types. Please make sure you have those installed as well.

A primitive example

import React, { useState } from 'react'
import { Grid, Input, Select } from 'react-spreadsheet-grid'

const rows = [
    { id: 'user1', name: 'John Doe', positionId: 'position1' },
    // and so on...
];

const MyAwesomeGrid = () => {
  return (
    <Grid
      columns={[
        {
          title: () => 'Name',
          value: (row, { focus }) => {
              return (
                  <Input
                    value={row.name}
                    focus={focus}
                  />
              );
          }
        }, {
          title: () => 'Position',
          value: (row, { focus }) => {
              return (
                  <Select
                    value={row.positionId}
                    isOpen={focus}
                    items={somePositions}
                  />
              );
          }
        }
      ]}
      rows={rows}
      getRowKey={row => row.id}
    />
  )
}

The pattern of regular usage

Take a closer look at 2 main thing: a declaration of columns and work with the state of the parent component.

To get the correct behavior of the grid you should:

  • Store rows and columns of the grid in the state of the parent component.
  • Describe how the grid renders values of the cells.
  • Have a callback that changes values of the rows in the state of the parent component.

Let's see how it works:

import { Grid, Input, Select } from 'react-spreadsheet-grid'
import AwesomeAutocomplete from 'awesome-autocomplete'

const rows = [
    { id: 'user1', name: 'John Doe', positionId: 'position1', managerId: 'manager1' },
    // and so on...
];

const MyAwesomeGrid = () => {
    // Rows are stored in the state.
    const [rows, setRows] = useState(rows);

    // A callback called every time a value changed.
    // Every time it save a new value to the state.
    const onFieldChange = (rowId, field) => (value) => {
        // Find the row that is being changed
        const row = rows.find({ id } => id === rowId);
        
        // Change a value of a field
        row[field] = value;
        setRows([].concat(rows))
    }
    
    const initColumns = () => [
      {
        title: () => 'Name',
        value: (row, { focus }) => {
          // You can use the built-in Input.
          return (
            <Input
              value={row.name}
              focus={focus}
              onChange={onFieldChange(row.id, 'name')}
            />
          );
        }
      }, {
        title: () => 'Position',
        value: (row, { focus }) => {
            // You can use the built-in Select.
            return (
                <Select
                  value={row.positionId}
                  isOpen={focus}
                  items={somePositions}
                  onChange={onFieldChange(row.id, 'positionId')}
                />
            );
        }
      }, {
        title: () => 'Manager',
        value: (row, { active, focus }) => {
          // You can use whatever component you want to change a value.
          return (
            <AwesomeAutocomplete
              value={row.managerId}
              active={active}
              focus={focus}
              onSelectItem={onFieldChange(row.id, 'managerId')}
            />
          );
        }
      }
    ]

    return (
        <Grid
            columns={initColumns()}
            rows={rows}
            isColumnsResizable
            onColumnResize={onColumnResize}
            getRowKey={row => row.id}
        />
    )
}

Props

columns

arrayOf({
    id: string / number,
    title: string / func,
    value: string / func(row, { active, focus, disabled }),
    width: number,
    getCellClassName: func(row)
})

defaults to []

required

This is the most important prop that defines columns of the table. Every item of the array is responsible for the corresponding column.

key Required Mission
id yes An identifier of a row.
title yes This is what you want to put in the header of the column, it could be passed as a string or as a func returning a React element.
value yes This is content of the cell. Works the same way as title, but func receives row and current state of the cell ({ active, focus, disabled }) as parameters, so you can create an output based on them.
width no Pass this property if you want to initialize the width of a column. You can set width not for all the columns, then the rest of the table width would be distributed between the columns with unspecified width. Also, you can get width of the columns from onColumnResize callback to store somewhere and use for the next render to make columns stay the same width.
getCellClassName no An additional class name getter for a row.

rows

arrayOf(any) | defaults to []

required

This is an array of rows for the table. Every row will be passed to a column.value func (if you use it).

getRowKey

func(row)

required

This is a func that must return unique key for a row based on this row in a parameter.

placeholder

string | defaults to "There are no rows"

Used as a placeholder text when the rows array is empty.

disabledCellChecker

func(row, columnId): bool

Use this func to define what cells are disabled in the table. It gets row and columnId (defined as column.id in a columns array) as parameters and identifiers of a cell. It should return boolean true / false. A disabled cell gets special CSS-class and styles. Also, you can define a column.value output based on the disabled state parameter.

onCellClick

func(row, columnId)

A click handler function for a cell. It gets row and columnId (defined as column.id in the columns array) as parameters and identifiers of a cell.

onActiveCellChanged

func({ x, y })

A callback called every time the active cell is changed. It gets { x, y } coordinates of the new active cell as parameters.

headerHeight

number | defaults to 40

The height of the header of the table in pixels.

⚠️ Define it as a prop, not in CSS styles to not broke the scroll of the table. ⚠️

rowHeight

number | defaults to 48

The height of a row of the table in pixels.

⚠️ Define it as a prop, not in CSS styles to not broke the scroll of the table. ⚠️

focusOnSingleClick

boolean

defaults to false

By default, double clicking a cell sets the focus on the cell's input. Pass true if you want to set the focus on the cell's input upon single clicking it.

isColumnsResizable

bool | defaults to false

Switch this on if you want the table provides an opportunity to resize column width.

onColumnResize

func(widthValues: object)

A callback called every time the width of a column was resized. Gets widthValues object as a parameter. widthValues is a map of values of width for all the columns in percents (columnId - value).

isScrollable

boolean

defaults to true

This defines should a grid has a scrollable container inside of a DOM-element where it was rendered, or not. When it turned on (by default), only visible rows are rendered and that improves performance. If you pass false, all the rows will be rendered at once (that is not a good way to handle with a big amount of them), but you will have opportunity to set up a scroll area where you want it to be and have other components (before or after the grid) included in this area.

onScroll

func(scrollPosition: number)

A callback called every time the position of the scroll of the grid was changed.

onScrollReachesBottom

func()

A callback called when the scroll of the grid reaches its bottom value. Usually, it could be used to implement the lazy loading feature in your grid (see the Lazy loading support section for details).

Public methods

Use public methods via a grid's ref:

const GridWrapper = () => {
  const gridRef = React.createRef()

  React.useEffect(() => {
    gridRef.current.resetScroll()
  })

  return (
    <Grid
      ref={gridRef}
      // other props
    />
  )
}

resetScroll()

Call to reset the scroll to the top of the container.

focusCell({ x: number, y: number })

Call to make the cell with this x, y coordinates (starting from 0) active and focused.

Customizing cells & header content

You can customize content of titles and cells using title and value keys of elements of the columns property. Setting these components using row and { active, focus, disabled } parameters of the functions.

title could be a string or a func returning any React element.

value works the same way, but func receives current row and current state of the cell ({ active, focused, disabled }) as parameters, so you can create an output based on them.

For the basic usage, the library provide 2 default components that you can use out-of-the-box: Input and Select. Perhaps, they will be enough for you. However, you can use any other React components for that purpose: autocompletes, checkboxes, etc.

Built-in Input

Input prop types:

Prop Type Mission
value string The value of the input
placeholder string Placeholder displaying when there is no value
focus bool Should the input has focus or not
selectTextOnFocus bool Should the input content be selected when focused or not
onChange func Blur callback. Use it to catch a changed value

Usage:

import { Grid, Input } from 'react-spreadsheet-grid'

 <Grid
    columns={[
      {
        id: 'name',
        title: () => {
            return <span>Name</span>
        },
        value: (row, { focus }) => {
          return (
            <Input
              value={row.name}
              focus={focus}
              onChange={onFieldChange(row.id, 'name')}
            />
          );
        }
      }
   ]}
/>

Built-in Select

Select prop types:

Prop Type Mission
items arrayOf({ id: string / number, name: string }) Items for select
selectedId string / number Id of a selected item
placeholder string Placeholder displaying when there is no selected item
isOpen bool Should the select be open or not
onChange func Change item callback. Use it to catch a changed value

Usage:

import { Grid, Select } from 'react-spreadsheet-grid'

const positions = [{
    id: 1,
    name: 'Frontend developer'
}, {
    id: 2,
    name: 'Backend developer'
}];

 <Grid
    columns={[
      {
        id: 'position',
        title: () => {
            return <span>Position</span>
        },
        value: (row, { focus }) => {
          return (
            <Select
              items={positions}
              selectedId={row.positionId}
              isOpen={focus}
              onChange={onFieldChange(row.id, 'positionId')}
            />
          );
        }
      }
   ]}
/>

Another component

Let's suggest you need to use an autocomplete as a content of a cell. This is how it could be done:

import { Grid } from 'react-spreadsheet-grid'
import AwesomeAutocomplete from 'awesome-autocomplete'

<Grid
  columns={[
    {
      id: 'manager',
      title: () => {
        return <span>Manager</span>
      },
      value: (row, { focus, active }) => {
        return (
          <AwesomeAutocomplete
            value={row.managerId}
            active={active}
            focus={focus}
            onSelectItem={onFieldChange(row.id, 'managerId')}
          />
        );
      }
    }
  ]}
/>

Performant scroll

A behavior of scroll depends on the isScrollable prop.

If isScrollable is false, the grid renders all the passed rows without a scroll. Probably, this would be useful for small amount of the rows.

If isScrollable is true, the height of the grid is equal to the height of its container, it has a scroll and renders only the rows that are visible. Therefore, you can pass to it as many rows as you want - it will work fine without any problems with rendering and scroll. This would be useful for big amount of the rows.

This is an example, how we could make a 500px height scrollable grid:

<div style={{ height: '500px' }}>
    <Grid
        isScrollable
        /* other props */
    />
</div>

Resizable columns

react-spreadsheet-grid provides the opportunity to set initial width values for columns, to resize them from the UI and to react on these changes. Use relevant columnWidthValues, isColumnsResizable and onColumnResize properties for that purpose.

This is how it could be done:

import React, { useState } from 'react'
import { Grid } from 'react-spreadsheet-grid'

const ResizableGrid = () => {
    // Put columns to the state to be able to store there their width values.
    const [columns, setColumns] = useState(initColumns())

    // Change columns width values in the state to not lose them.
    const onColumnResize = (widthValues) => {
        const newColumns = [].concat(columns)
        Object.keys(widthValues).forEach((columnId) => {
            newColumns[columnId].width = widthValues[columnId]
        })
        setColumns(newColumns)
    }

    return (
        <Grid
            columns={columns}
            isColumnsResizable
            onColumnResize={onColumnResize}
            rows={/* some rows here */}
            getRowKey={row => row.id}
        />
    )
}

Control by mouse & from keyboard

react-spreadsheet-grid could be controlled by a mouse and from keyboard (just like Excel-table could). When a mouse is used, single click make a cell active, double click make a cell focused. When a keyboard used, move active cell, ENTER and TAB make a cell focused.

Customizing CSS styles

Right now, the easiest way to tweak react-spreadsheet-grid is to create another stylesheet to override the default styles. For example, you could create a file named react_spreadsheet_grid_overrides.css with the following contents:

.SpreadsheetGrid__cell_active {
    box-shadow: inset 0 0 0 2px green;
}

This would override the color of borders for the table active cell.

⚠️ The only exception, that you have to use headerHeight and rowHeight props to redefine height of the header and rows to not broke the scroll of the table.

Lazy loading support

react-spreadsheet-grid provides the opportunity to implement the lazy loading feature in your grid. Use the onScrollReachesBottom callback to handle a situation when the scroll position reaches its bottom. Load a new portion of the rows and put them in the state of a high-order component.

This is how it could be done:

import React, { useState } from 'react'
import { Grid } from 'react-spreadsheet-grid'

const LazyLoadingGrid = () => {
  /* Init the state with the initial portion of the rows */
  const [rows, setRows] = useState(initialRows);

  const onScrollReachesBottom = () => {
     loadNewPortionOfRows().then((newRows) => {
        setRows(rows.concat(newRows));
     });
  }

  const loadNewPortionOfRows = () => {
    /* an ajax request here */
  }

  return (
      <Grid
        columns={/* some columns here */}
        row={rows}
        getRowKey={row => row.id}
        onScrollReachesBottom={onScrollReachesBottom}
      />
    )
}

react-spreadsheet-grid's People

Contributors

denisraslov avatar dependabot[bot] avatar josemco avatar kasbah avatar marcobiedermann avatar markronquillo avatar tbroadley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-spreadsheet-grid's Issues

blurCurrentFocus use in example doesn't work

  • react-spreadsheet-grid version: 1.4.3
  • React version: 16.x
  • Operating System:

Relevant code or config: https://codesandbox.io/s/objective-kapitsa-ejlcw

I converted the example to a sandbox (few other small mistakes in there). When you edit and press enter, the focus doesn't shift. I expect it to go the next row. I suspect I am supposed to toggle the blurCurrentFocus?

Suggested solution:

Handle the focus internally in react-spreadsheet-grid and get rid of blurCurrentFocus. (The blurCurrentFocus prop is a little awkward.)

Add support for React Hooks

How can I use this awesome lib with react hooks?
I'm stuck with onFieldChange:

  function onFieldChange(rowId, field, value) {
    // Find a row that is being changed
    const row = rows.find((id) => id === rowId);
    // Change a value of a field
    row[field] = value;
    setRows([].concat(rows));
    // Blurring focus from the current cell is necessary for a correct behavior of the Grid.
    setBlur(true);
    return null;
  }
            <Input
              value={make_date_string(row.date)}
              onChange={onFieldChange(row.id, "date")}
              focus={focus}
            />

image

copy value ranges

i'd like to be able copy & paste a range of rows and columns, similar to what you can do in Excel at the moment.

this could be copying between cell ranges on the same grid, between two separate grid instances, or from somewhere off-grid (e.g. Excel).
3fc45d68-70ca-11e5-907a-38d63878d50a

Add row in the middle of two rows

How do you approach adding a row in the middle of two rows? I've read there's a system of key of each cell, so if you add a row in the middle of two, you probably need to change every key, no?

Context menu and pining column

Hi admin, first of all, thank you for this super useful packaging.

How to plan the support context menu in the roadmap?

Looking forward to hearing from you!

Thank you!

Cannot build with Parcel: Unterminated regular expression

$ PRODUCT_TYPE=webapp parcel entry/src/index.html --open
Server running at http://localhost:1234 
⚠️  Could not load existing sourcemap of "../../node_modules/react-spreadsheet-grid/lib/bundle.js".
🚨  /node_modules/react-spreadsheet-grid/lib/bundle.js:520:83: Unterminated regular expression (520:83)
  518 |         if (sourceMap) {
  519 |                 // http://stackoverflow.com/a/26603875
> 520 |                 css += "\n + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
      |                                                                                                 ^
  521 |         }
  522 | 
  523 |         var blob = new Blob([css], { type: "text/css" });
  • react-spreadsheet-grid version: 1.4.3
  • parcel-bundler version: 1.12.4

Feature request: height property

I am getting an extra scrollbars on my page sometimes. I have other components on the top of the page.

image

I think this could be solved by letting me set a height property. I could then get the height from something like react-virtualized-auto-sizer and use that.

Customizing CSS is not working when react build was done

  • react-spreadsheet-grid version: ^2.0.0
  • React version: 17.0.2
  • Operating System: windows 10

Relevant code or config

Development output
image

Build output
image

What you did: I just follow the rules of customizing CSS.

What happened: I try to override the background color of the header, it works on dev but when I npm run build. the color was not changed.

Problem description:

Suggested solution:

Select Target Cell Text on Click

Hi,

I'm looking to select the target cell text using onClick or onFocus (i.e. when user single clicks on a cell, all text is highlighted)

{
                title: () => 'Order',
                value: (row, { active }) => {
                    return (
                        <Input
                        ref="orderInput"
                        value={row.order || 0}
                        onClick={this.handleClick.bind(this)}
                        onChange={this.onFieldChange.bind(this, row.plu[0], 'order')}
                        />
                    )
                }
 
```}

If I do onClick={console.log("clicked")}, I get a console log. 

if I do onClick={this.handleClick.bind(this)} or onClick={this.handleClick} and try to console.log inside the handleClick function, I get no response. 

Any ideas on how I could get this to work? 

Thanks in advance

Small mistake in the example in the Readme

  • react-spreadsheet-grid version: 1.3.1
  • React version: 16.3.1
  • Operating System: Ubuntu 17.10

What I did:
I tried to follow the example given in the readme and when I changed the content of a cell I got this error:

TypeError: rows[rowId] is undefined

Suggested solution:
Is there maybe a small mistake in the readme to make the example work out of the box?
In the dummy content for the rows:

const rows=[
    { id: 'user1', name: 'John Doe', positionId: 'position1' },
    // and so on...
];

I needed to change the ids to 0, 1, 2... to make the example work for me.

SpreadsheetRow.shouldComponentUpdate(): Returned undefined instead of a boolean value

  • react-spreadsheet-grid version: 1.3.1
  • Operating System: Windows 7 64bits

Relevant code or config

<Grid
        rows={this.state.rows}
        columns={this.columns}
        getRowKey={row => row.id}
      />

What happened:

Warning: SpreadsheetRow.shouldComponentUpdate(): Returned undefined instead of a boolean value. Make sure to return true or false.

Problem description:

React warns about SpreadsheetRow.shouldComponentUpdate not returning true or false

Suggested solution:

If SpreadsheetRow.shouldComponentUpdate returns undefined, return false or true

Does it has sticky header option?

I was wondering whether it has sticky headers option. I did not seen it in documentation. When there is long list of data it will be very helpful.

Cells need unique key property

  • react-spreadsheet-grid:1.4.3
  • React version: 16.8.2

Running the basic example I get this warning:

index.js:1446 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `SpreadsheetGrid`. See https://fb.me/react-warning-keys for more information.
    in SpreadsheetRow (created by SpreadsheetGrid)

Feature request: go to cell below on enter, next cell on tab

I was expecting it to go to cell below on pressing enter and go to cell to the right on pressing tab. This is how spreadsheets normally do it, no?

(One weird thing I noticed, which made me think it's already supposed to work like that in #35, is that it does work like that if you don't add any onChange listener to the Input. )

A header cell with empty value is misaligned

react-spreadsheet-grid version: 1.1.1

Relevant code or config
One of columns is:

{
   id: 'deleteButton',
   title: '',
}

Problem description
A header cell for this column is misaligned:

screen shot 2017-11-29 at 18 59 54

Suggested solution
Add display: flex to styles of the header.

Customizing CSS styles not working as described

We tried to override the cell layout as described in the docs by naming the css file react_spreadsheet_grid_overrides.css.
Using it in an serverside react app we did not get our custom css working without using !important

  • react-spreadsheet-grid version: ^2.0.0
  • React version: ^16.12.0
  • Operating System: any

Relevant code or config

_app.js

  <link
            rel='stylesheet'
            type='text/css'
            href='/css/react_spreadsheet_grid_overrides.css'
          />

index.js

 const SheetExample2 = dynamic(
    () => import('../../components/SheetExample2'),
    {
      ssr: false
    }
  );

SheetExample2.jsx

import React, { useState, useRef } from 'react';
import { Grid as Table, Input, Select } from 'react-spreadsheet-grid';
import { IconButton, Button, Grid, makeStyles } from '@material-ui/core';
import DeleteForeverIcon from '@material-ui/icons/DeleteForever';
import AddCircleIcon from '@material-ui/icons/AddCircle';

const useStyles = makeStyles((theme) => ({
  gridAddIconButtonWrapper: { marginBottom: '5px' },
  gridDeleteButtonWrapper: { paddingTop: '40px' },
  addIcon: { color: '#008000' },
  deleteIcon: { color: '#FF0000' },
}));

const rowTemplate = { from: '', to: '', distance: '', fuel: '' };

const SheetExample2 = () => {
  const classes = useStyles();

  const rowIdIndex = useRef(1);
  const [rows, setRows] = useState([]);
  const [gridHeight, setGridHeight] = useState(100);

  const addNewRow = () => {
    setRows([...rows, { id: rowIdIndex.current, ...rowTemplate }]);
    setGridHeight((previousState) => previousState + 90);
    rowIdIndex.current++;
  };

  const onFieldChange = (rowId, field) => (value) => {
    const row = rows.find((row) => row.id === rowId);
    row[field] = value;
    setRows([].concat(rows));

    //calculation example for fuel, distance...
    if (row.from != null && row.to != null && row.from !== '' && row.to !== '') {
      row['distance'] = `${Math.floor(Math.random() * 100) + 100} km`;
      row['fuel'] = `${Math.floor(Math.random() * 100) + 50} L`;
    }
  };

  const deleteRow = (rowId) => {
    const remainedRows = rows.filter((row) => row.id !== rowId);
    setRows(remainedRows);
    setGridHeight((previousState) => previousState - 90);
  };

  const handleClick = (row, columnId) => {
    if (columnId === 'delete') {
      const remainedRows = rows.filter((r) => r.id !== row.id);
      setRows(remainedRows);
    }
  };

  return (
    <Grid container>
      <Grid item xs={12}>
        <IconButton variant='contained' onClick={addNewRow}>
          <AddCircleIcon fontSize='large' className={classes.addIcon} />
        </IconButton>
      </Grid>
      <Grid item xs={12}>
        <Table
          rowHeight={70}
          onCellClick={(row, columnId) => handleClick(row, columnId)}
          focusOnSingleClick={true}
          columns={[
            {
              id: 1,
              title: () => 'Start',
              value: (row, { focus }) => {
                return <Input value={row.from} onChange={onFieldChange(row.id, 'from')} focus={focus} />;
              },
            },
            {
              id: 2,
              title: () => 'End',
              value: (row, { focus }) => {
                return <Input value={row.to} onChange={onFieldChange(row.id, 'to')} focus={focus} />;
              },
            },
            {
              id: 3,
              title: () => 'Distance',
              value: (row, { focus }) => {
                return <Input value={row.distance} onChange={onFieldChange(row.id, 'distance')} focus={focus} />;
              },
            },
            },
            {
              id: 'delete',
              title: () => 'Action',
              value: () => {
                return (
                  <IconButton variant='contained' color='primary'>
                    <DeleteForeverIcon fontSize='large' className={classes.deleteIcon} />
                  </IconButton>
                );
              },
            },
          ]}
          rows={rows}
          getRowKey={(row) => {
            row.id;
          }}
        />
      </Grid>
    </Grid>
  );
};
export default SheetExample2;

react_spreadsheet_grid_overrides.css

...
.SpreadsheetGrid__headCell {
  display: inline-flex;
  position: relative;
  color: white;
  font-size: 12px;
  line-height: 14px;
  font-weight: 500;
  white-space: nowrap;
  border-bottom: none;
  padding: 10px 8px 8px 8px;
  text-align: left;
  background-color: #000000;
  align-items: center;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
  border-right: 1px solid rgba(0, 0, 0, 0.12);
}
...

package.json

{
  "name": "client",
  "version": "1.0.0",
  "description": "SheetViewExample",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon index.js",
    "build": "next build",
    "start": "next start"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@material-ui/core": "^4.7.1",
    "@material-ui/icons": "^4.5.1",
    "@material-ui/lab": "^4.0.0-alpha.34",
    "async": "^3.1.1",
    "axios": "^0.19.0",
    "base-64": "^0.1.0",
    "express": "^4.17.1",
    "is-number": "^7.0.0",
    "isomorphic-unfetch": "^3.0.0",
    "js-cookie": "^2.2.1",
    "jwt-decode": "^2.2.0",
    "konva": "^4.0.18",
    "lodash": "^4.17.15",
    "next": "^9.1.4",
    "next-cookies": "^1.1.3",
    "next-i18next": "^0.52.1",
    "nodemon": "^1.19.4",
    "perf_hooks": "0.0.1",
    "pigeon-maps": "^0.14.0",
    "pigeon-marker": "^0.3.4",
    "pigeon-overlay": "^0.2.3",
    "react": "^16.12.0",
    "react-countdown-now": "^2.1.2",
    "react-dom": "^16.12.0",
    "react-draggable": "^4.2.0",
    "react-konva": "^16.9.0-1",
    "react-spreadsheet-grid": "^2.0.0",
    "seedrandom": "^3.0.5",
    "socket.io-client": "^2.3.0",
    "use-image": "^1.0.5"
  },
  "repository": {
    "type": "git",
    "url": ""
  }
}

The changes in our css were not applied until we used !important after every css property.

Failed prop type: Invalid prop `items[0]`

  • react-spreadsheet-grid version: 1.4.3
  • React version: 16.8.6
  • Operating System: osx 10.14

Relevant code or config

const rowData = [
  {id: "1", date: "20-Feb-19", group: "Mechanical", advent: "Planned"},
  // and so on...
];

export function DowntimeTable() {
  const groups = ["Operational", "Mechanical", "Electrical", "Mining", "Uncontrolled"];
  const advents = ["Planned", "Unplanned"];
  return (
    <Grid
      columns={[
        {
          title: () => "Date",
          value: (row, {focus}) => {
            return <Input value={row.date} focus={focus} />;
          },
        },
        {
          title: () => "Group",
          value: (row, {focus}) => {
            return <Select value={row.group} isOpen={focus} items={groups} />;
          },
        },
        {
          title: () => "Advent",
          value: (row, {focus}) => {
            return <Select value={row.advent} isOpen={focus} items={advents} />;
          },
        },
      ]}
      rows={rowData}
      getRowKey={(row) => row.id}
    />
  );
}

What happened:
image

Demo - columns and column headers misaligned with scrollbar

See the screenshot below (from Chrome).

Browsers tested:
Chrome 62.0
Firefox 57.0

Side note: Internet Explorer does not work at all (tested IE 11.0). Scripts throw an error and display a blank page. Not sure if you intend to support Internet Explorer at all.

Let me know if you need anymore information.

ssapp1

Excel-like features

Awesome library! This is more of a feature request than an issue, let me know if you have other places for this that are more appropriate.

Are you planning on adding excel-like features to it, by which I mean things like:

  • Select multiple cells by holding shift
  • Go to the top / bottom / left / right by holding cmd (using mac)
  • On right mouse click, have options like delete or add row or column.

This kind of functionality is in Handsontable, as you might be aware of. First and foremost I'm wondering if you are planning to become more like this, or you're more focussed on a different kind of functionality.

Make columnWidthValues part of column array property?

Think it would be a bit neater to be able to do something like this:

class MyAwesomeGrid extends React.Component {
  render() {
    return (
      <Grid 
        columns={[
          {
            title: () => 'Name', 
            width: 100,
            value: (row, { focus }) => {
                return (
                    <Input  
                      value={row.name}
                      focus={focus}
                    />
                );
            }
           ...

is there a way to control column width?

  • react-spreadsheet-grid version:
  • React version:
  • Operating System:

Relevant code or config

What you did:

What happened:

Problem description:

Suggested solution:

Input: onChange instead of onBlur

With the current change in Input component, I think the documentation should also be updated.

Using onBlur to capture Input changes doesn't work now, it works if we use onChange props.

I can make a PR if you want.

Is there a way to make grid to responsive?

First thanks to open this wonderful library.
I want to use it my website admin page, and I often to access it with my mobile phone.
What I just want to is a horizontal scrollbar when small screen.

https://www.w3schools.com/howto/howto_css_table_responsive.asp

You can access above url and then test it with small screen, when screen got small,
it generate a horizontal scrollbar that can see contents easily.
Is there a way to do it?

I tried like

`<div style={{ overflowX: 'auto}}>
<Grid ... />

`

But it seems not working. :)

Make column widths correspond to contents

I have a rather wide table with many columns. I don't want them all squeezed inside the viewport. Instead I'd like column widths to fit column content and have a horizontal scrollbar to scroll to the columns that are offscreen.
Is that possible?

Uncaught RangeError: Maximum call stack size exceeded

  • react-spreadsheet-grid version: latest
  • React version: latest
  • Operating System: mac os chrome

Relevant code or config

What you did:
press keyboard ← when firstcell active
What happened:
image

no error
Problem description:

Suggested solution:

Can't add new rows

  • react-spreadsheet-grid version: 2.0.0
  • React version: 16.13.1
  • Operating System: win 10 x64

My code:
*`import React, { Fragment, useEffect, useState } from 'react';
import { Grid, Input, Select } from 'react-spreadsheet-grid'
import './App.css';

function App() {
  const positions = [{
   id: 1,
    name: 'Frontend developer'
  }, {
    id: 2,
    name: 'Backend developer'
  }];

  const [rows, setRows] = useState([{
    id: 1,
    name: '',
    positionId: 1
  }]);
  const onFieldChange = (rowId, field) => (value) => {
    // Find the row that is being changed
    const row = rows.find(({ id }) => id === rowId);

    // Change a value of a field
    row[field] = value;
    setRows([].concat(rows))
  }
  const addRow = () => {
    const id = [...rows][rows.length - 1].id + 1;
    const newRow = {
      id: id,
      name: '',
      positionId: 1
    };

    setRows(rows.concat(newRow))

  }

  useEffect(() => {
    console.log(rows)
  }, [rows])
  return (
    <Fragment>
      <Grid isScrollable={false}
        columns={[
          {
            title: () => 'Name',
            value: (row, { focus }) => {
              // You can use the built-in Input.
              return (
                <Input
                  value={row.name}
                  focus={focus}
                  onChange={onFieldChange(row.id, 'name')}
                />
              );
            }
          }, {
            id: 'position',
            title: () => {
              return <span>Position</span>
            },
            value: (row, { focus }) => {
              return (
                <Select
                  items={positions}
                  selectedId={row.positionId}
                  isOpen={focus}
                  onChange={onFieldChange(row.id, 'positionId')}
                />
              );
            }
          }
        ]}
        rows={rows}
        getRowKey={row => row.id}
      />
      <button onClick={addRow}>Add row</button>
    </Fragment>
  );
}

export default App;`*

What happened:

Created function that adds new row, but it's not working, console.log() shows that new data was added :/

Thats happens only if isScrollable set to false

screenshot

Display "there are no rows" even if there are

  • react-spreadsheet-grid version: 1.4.3
  • React version: 16.4.1
  • Operating System: Windows 7 64 bits

Reproducible example

https://codesandbox.io/s/9z87w6vk34

When grid is empty, click on BUG button : "there are no rows" is displayed even if there is 1 row

Then click on the scroll arrow : magic! Row appears

Intent

I have a Grid that gets updated when redux state is updated.

When the page is loaded, redux state is empty then the grid is updated with no rows a couple times then redux state is filled so the grid is updated with some data

Issue

The grid is not refreshed when updated with some data, so the message "there are no rows" stays

Analysis

I think this is what is happenning:

  • Grid is updated with no rows a couple times, SpreadsheetGridScrollWrapper.calculateScrollState is triggered and SpreadsheetGridScrollWrapper.state.last is set to 0
  • Grid is updated with some data, SpreadsheetGridScrollWrapper.calculateScrollState is triggered so that SpreadsheetGridScrollWrapper.state.last is updated...
  • ... but SpreadsheetGridScrollWrapper.calculateScrollState is throttled with requestAnimationFrame (scrollWrapper/index.js:31) so it is not executed before the grid render and...
  • ... when the grid renders SpreadsheetGridScrollWrapper.state.last is still equal to 0 so Grid takes the element from 0 to 0, that means nothing, that's why "there are no rows" is displayed even if this.props.rows contains some data

Fix

I really don't know 😞

The only workaround I found is to encaspulate the state update in requestAnimationFrame but I have the feeling that it can cause more bugs: https://codesandbox.io/s/9qy425m30o

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.