The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by
removing the max tokens filter.
├── .babelrc
├── .codeclimate.yml
├── .csslintrc
├── .gitignore
├── .npmignore
├── .prettierrc
├── .travis.yml
├── LICENSE
├── README.md
├── USAGE_TYPESCRIPT.md
├── docs
├── .gitignore
├── build
│ ├── asset-manifest.json
│ ├── favicon.ico
│ └── index.html
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── app.js
│ ├── examples
│ │ ├── BasicSheet.js
│ │ ├── ComponentSheet.js
│ │ ├── CustomRendererSheet.js
│ │ ├── MathSheet.js
│ │ ├── MathSheetFC.js
│ │ ├── OverrideEverythingSheet.js
│ │ ├── drag-drop.js
│ │ ├── index.js
│ │ └── override-everything.css
│ ├── index.css
│ ├── index.js
│ └── lib
└── yarn.lock
├── lib
├── Cell.js
├── CellShape.js
├── DataCell.js
├── DataEditor.js
├── DataSheet.js
├── Row.js
├── Sheet.js
├── ValueViewer.js
├── index.js
├── keys.js
├── react-datasheet.css
└── renderHelpers.js
├── package-lock.json
├── package.json
├── params.json
├── src
├── Cell.js
├── CellShape.js
├── DataCell.js
├── DataEditor.js
├── DataSheet.js
├── Row.js
├── Sheet.js
├── ValueViewer.js
├── index.js
├── keys.js
├── react-datasheet.css
└── renderHelpers.js
├── test
└── Datasheet.js
└── types
└── react-datasheet.d.ts
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2", "react"]
3 | }
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | csslint:
4 | enabled: true
5 | duplication:
6 | enabled: true
7 | config:
8 | languages:
9 | - javascript
10 | eslint:
11 | enabled: true
12 | fixme:
13 | enabled: true
14 | ratings:
15 | paths:
16 | - "src/**.css"
17 | - "src/**.js"
18 | exclude_paths:
19 | - test/
20 | - lib/
21 | - docs/
22 |
--------------------------------------------------------------------------------
/.csslintrc:
--------------------------------------------------------------------------------
1 | --exclude-exts=.min.css
2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *~
3 | *.iml
4 | .*.haste_cache.*
5 | .DS_Store
6 | .idea
7 | npm-debug.log
8 | node_modules
9 | .nyc_output
10 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *~
3 | *.iml
4 | .*.haste_cache.*
5 | .DS_Store
6 | .idea
7 | .babelrc
8 | .eslintrc
9 | npm-debug.log
10 | lib
11 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "arrowParens": "avoid",
5 | "printWidth": 80,
6 | "proseWrap": "always"
7 | }
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "stable"
4 | after_success: npm run coverage
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Nadim Islam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## react-datasheet is no longer under active development. New maintainers are wanted. Please contact me if you wish to maintain this repo.
2 |
3 | ---
4 |
5 |
6 | [](https://travis-ci.org/nadbm/react-datasheet)
7 | [](https://coveralls.io/github/nadbm/react-datasheet)
8 | [](https://codeclimate.com/github/nadbm/react-datasheet)
9 | [](https://badge.fury.io/js/react-datasheet)
10 |
11 | # React-Datasheet
12 |
13 | A simple react component to create a spreadsheet.
14 |
15 | Demo here: https://nadbm.github.io/react-datasheet/
16 |
17 | Examples are located in
18 | https://github.com/nadbm/react-datasheet/tree/master/docs/src/examples
19 |
20 | Current features:
21 |
22 | - Select cells, cut, copy and paste cells
23 | - Navigation using keyboard keys
24 | - Deletion using keyboard keys
25 | - Callbacks for onCellsChanged, valueRenderer(visible data)
26 | - dataRenderer(underlying data in the input, takes the value by default)
27 | - Supply your own editors and view controls with custom renderers
28 | - Extensive control over generated markup via custom renderers
29 |
30 | Using Typescript?
31 | [View Usage](https://github.com/nadbm/react-datasheet/tree/master/USAGE_TYPESCRIPT.md)
32 |
33 | ## Installation
34 |
35 | Install from npm:
36 |
37 | ```bash
38 | $ npm install react-datasheet --save
39 | ```
40 |
41 | Import in your project:
42 |
43 | ```javascript
44 | import ReactDataSheet from 'react-datasheet';
45 | // Be sure to include styles at some point, probably during your bootstrapping
46 | import 'react-datasheet/lib/react-datasheet.css';
47 | ```
48 |
49 | ## Usage
50 |
51 | React-Datasheet generates a table with the cells. Double-clicking or typing
52 | edits the value and if changed, initiates an `onCellsChanged` callback. Pasting
53 | tabular data or deleting a range of cells also calls `onCellsChanged`.
54 |
55 | The data provided should be an array of rows, and each row should include the
56 | cells.
57 |
58 | ### Basic Usage
59 |
60 | ```jsx
61 | class App extends React.Component {
62 | constructor(props) {
63 | super(props);
64 | this.state = {
65 | grid: [
66 | [{ value: 1 }, { value: 3 }],
67 | [{ value: 2 }, { value: 4 }],
68 | ],
69 | };
70 | }
71 | render() {
72 | return (
73 | <ReactDataSheet
74 | data={this.state.grid}
75 | valueRenderer={cell => cell.value}
76 | onCellsChanged={changes => {
77 | const grid = this.state.grid.map(row => [...row]);
78 | changes.forEach(({ cell, row, col, value }) => {
79 | grid[row][col] = { ...grid[row][col], value };
80 | });
81 | this.setState({ grid });
82 | }}
83 | />
84 | );
85 | }
86 | }
87 | ```
88 |
89 | ### Cells with underlying data
90 |
91 | There are two values that each cell shows. The first is via `valueRenderer` and
92 | the second is via `dataRenderer`. When a cell is in _edit mode_, it will show
93 | the value returned from `dataRenderer`. It needs to return a string as this
94 | value is set in an input field. Each of these callbacks are passed the cell
95 | value as well as the cell's coordinates in the spreadsheet. This allows you to
96 | apply formatting logic at rendering time, such as _all cells in the third column
97 | should be formatted as dates_.
98 |
99 | ```jsx
100 | const grid = [
101 | [{value: 5, expr: '1 + 4'}, {value: 6, expr: '6'}, {value: new Date('2008-04-10')}],
102 | [{value: 5, expr: '1 + 4'}, {value: 5, expr: '1 + 4'}, {value: new Date('2004-05-28')}]
103 | ]
104 | const onCellsChanged = (changes) => changes.forEach(({cell, row, col, value}) => console.log("New expression :" + value))
105 | <ReactDataSheet
106 | data={grid}
107 | valueRenderer={(cell, i, j) => j == 2 ? cell.value.toDateString() : cell.value}
108 | dataRenderer={(cell, i, j) => j == 2 ? cell.value.toISOString() : cell.expr}
109 | onCellsChanged={onCellsChanged}
110 | />
111 | ```
112 |
113 | ### Cells with underlying component
114 |
115 | ```jsx
116 | const grid = [
117 | [{
118 | value: 5,
119 | component: (
120 | <button onClick={() => console.log("clicked")}>
121 | Rendered
122 | </button>
123 | )
124 | }]
125 | ]
126 | <ReactDataSheet
127 | data={grid}
128 | valueRenderer={(cell) => cell.value}
129 | />
130 | ```
131 |
132 | This renders a single cell with the value 5. Once in edit mode, the button will
133 | appear.
134 |
135 | ### Cells with extra attributes
136 |
137 | ```jsx
138 | const grid = [
139 | [{value: 1, hint: 'Valid'}, {value: 3, hint: 'Not valid'}],
140 | [{value: 2}, {value: 4}]
141 | ]
142 | <ReactDataSheet
143 | data={grid}
144 | valueRenderer={(cell) => cell.value}
145 | attributesRenderer={(cell) => (cell.hint ? { 'data-hint': cell.hint } : {})}
146 | ...
147 | />
148 | ```
149 |
150 | This render 2 rows, each one with two cells, the cells in the first row will
151 | have an attribute data-hint and the other 2 will not.
152 |
153 | ### Custom renderers
154 |
155 | React-Datasheet allows you replace the renderers both for the overall structure
156 | (rows, cells, the sheet itself) as well as editors and viewers for individual
157 | cells. This allows you to radically refashion the sheet to suit your
158 | requirements.
159 |
160 | For example, this shows how to add separate headers and a checkbox at the start
161 | of each row to control row "selected" state. It also specifies a custom view
162 | renderer and a custom editor for the first column of each row:
163 |
164 | ```jsx
165 | const columns = getColumnsFromSomewhere()
166 | const isSelected = yourSelectionFunction
167 | const selectHandler = yourCallbackFunction
168 |
169 | <ReactDataSheet
170 | data={grid}
171 | valueRenderer={(cell) => cell.value}
172 | sheetRenderer={props => (
173 | <table className={props.className + ' my-awesome-extra-class'}>
174 | <thead>
175 | <tr>
176 | <th className='action-cell' />
177 | {columns.map(col => (<th>{col.name}</th>))}
178 | </tr>
179 | </thead>
180 | <tbody>
181 | {props.children}
182 | </tbody>
183 | </table>
184 | )}
185 | rowRenderer={props => (
186 | <tr>
187 | <td className='action-cell'>
188 | <input
189 | type='checkbox'
190 | checked={isSelected(props.row)}
191 | onChange={selectHandler}
192 | />
193 | </td>
194 | {props.children}
195 | </tr>
196 | )}
197 | valueViewer={MyViewComponent}
198 | dataEditor={props => (
199 | props.col === 0 ? <MyDatePicker {...props} /> : <DataEditor {...props}/>
200 | )}
201 | ...
202 | />
203 | ```
204 |
205 | _Note:_ For brevity, in this example the custom renderers are all defined as
206 | arrow functions inside of render, but using a
207 | [bound function](https://reactjs.org/docs/faq-functions.html) in the parent
208 | component or a separate custom component will let you avoid a lot of needless
209 | re-renders.
210 |
211 | ## Options
212 |
213 | | Option | Type | Description |
214 | | :-------------- | :----------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
215 | | data | Array | Array of rows and each row should contain the cell objects to display |
216 | | valueRenderer | func | Method to render the value of the cell `function(cell, i, j)`. This is visible by default |
217 | | dataRenderer | func | Method to render the underlying value of the cell `function(cell, i, j)`. This data is visible once in edit mode. |
218 | | overflow | 'wrap'\|'nowrap'\|'clip' | Grid default for how to render overflow text in cells |
219 | | onCellsChanged | func | onCellsChanged handler: `function(arrayOfChanges[, arrayOfAdditions]) {}`, where changes is an **array** of objects of the shape `{cell, row, col, value}`. See below for more details. |
220 | | onContextMenu | func | Context menu handler : `function(event, cell, i, j)` |
221 | | parsePaste | func | `function (string) {}` If set, the function will be called with the raw clipboard data. It should return an array of arrays of strings. This is useful for when the clipboard may have data with irregular field or line delimiters. If not set, rows will be split with line breaks and cells with tabs. |
222 | | isCellNavigable | func | `function (cell, row, col) {return true}` If set, the function is used to determine whether navigation to the indicated cell should be allowed or not. If not then using cursor or tab navigation will skip over not allowed cells until it finds the next allowed cell. |
223 | | handleCopy | func | `function ({ event, dataRenderer, valueRenderer, data, start, end, range })` If set, this function is called whenever the user copies cells. The return string of this function is stored on the clipboard. |
224 |
225 | ### Advanced options
226 |
227 | The following are optional functions or React Component that can completely
228 | override the native renderers of react datasheet. To know which props are passed
229 | down, see
230 | [custom renderers](https://github.com/nadbm/react-datasheet#custom-renderers-1)
231 |
232 | | Option | Type | Description |
233 | | :------------ | :----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
234 | | sheetRenderer | func | Optional function or React Component to render the main sheet element. The default renders a `table` element. |
235 | | rowRenderer | func | Optional function or React Component to render each row element. The default renders a `tr` element. |
236 | | cellRenderer | func | Optional function or React Component to render each cell element. The default renders a `td` element. |
237 | | valueViewer | func | Optional function or React Component to customize the way the value for each cell in the sheet is displayed. Affects every cell in the sheet. See [cell options](https://github.com/nadbm/react-datasheet#cell-options) to override individual cells. |
238 | | dataEditor | func | Optional function or React Component to render a custom editor. Affects every cell in the sheet. See [cell options](https://github.com/nadbm/react-datasheet#cell-options) to override individual cells. |
239 | | selected | object | Optional. Whether the selection is controlled or uncontrolled. Must be an object of this format: `{ start: { i: number, j; number }, end: { i: number, j: number } }`, or `null` for no selection. |
240 | | onSelect | func | Optional. `function ({ start, end }) {}` Triggered on every selection change. `start` and `end` have the same format as the `selected` prop. |
241 |
242 | ## `onCellsChanged(arrayOfChanges[, arrayOfAdditions])` handler
243 |
244 | React-DataSheet will call this callback whenever data in the grid changes:
245 |
246 | - When the user enters a new value in a cell
247 | - When the user hits the delete key with one or more selected cells
248 | - When the user pastes tabular data into the table
249 |
250 | The argument to the callback usually will be one **array** of objects with these
251 | properties:
252 |
253 | | Property | Type | Description |
254 | | :------- | :----: | :----------------------------------------------------------------------------------------------- |
255 | | cell | object | the original cell object you provided in the `data` property. This may be `null` (see below) |
256 | | row | number | row index of changed cell |
257 | | col | number | column index of changed cell |
258 | | value | any | The new cell value. This is usually a string, but a custom editor may provide any type of value. |
259 |
260 | If the change is the result of a user edit, the array will contain a single
261 | change object. If the user pastes data or deletes a range of cells, the array
262 | will contain an element for each affected cell.
263 |
264 | **Additions:** If the user pastes data that extends beyond the bounds of the
265 | grid (for example, pasting two-row-high data on the last line), there will be a
266 | second argument to the handler containing an array of objects that represent the
267 | out-of-bounds data. These object will have the same properties, except:
268 |
269 | - There is no `cell` property
270 | - either `row` or `col`, or both, will be outside the bounds of your original
271 | grid. They will correspond to the indices the new data would occupy if you
272 | expanded your grid to hold them.
273 |
274 | You can choose to ignore the additions, or you can expand your model to
275 | accommodate the new data.
276 |
277 | ### Deprecated handlers
278 |
279 | Previously React-DataSheet supported two change handlers. These are still
280 | supported for backwards compatibility, but will be removed at some point in the
281 | future.
282 |
283 | | Option | Type | Description |
284 | | :------- | :--: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
285 | | onChange | func | onChange handler: `function(cell, i, j, newValue) {}` |
286 | | onPaste | func | onPaste handler: `function(array) {}` If set, the function will be called with an array of rows. Each row has an array of objects containing the cell and raw pasted value. If the pasted value cannot be matched with a cell, the cell value will be undefined. |
287 |
288 | ## Cell Options
289 |
290 | The cell object is what gets passed back to the onChange callback. They can
291 | contain the following options as well
292 |
293 | | Option | Type | Default | Description |
294 | | :------------- | :------------------------ | :-------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
295 | | readOnly | Bool | false | Cell will never go in edit mode |
296 | | key | String | undefined | By default, each cell is given the key of col number and row number. This would override that key |
297 | | className | String | undefined | Additional class names for cells. |
298 | | component | ReactElement | undefined | Insert a react element or JSX to this field. This will render on edit mode |
299 | | forceComponent | bool | false | Renders what's in component at all times, even when not in edit mode |
300 | | disableEvents | bool | false | Makes cell unselectable and read only |
301 | | colSpan | number | 1 | The colSpan of the cell's td element |
302 | | rowSpan | number | 1 | The rowSpan of the cell's td element |
303 | | width | number or String | undefined | Sets the cell's td width using a style attribute. Number is interpreted as pixels, strings are used as-is. Note: This will only work if the table does not have a set width. |
304 | | overflow | 'wrap'\|'nowrap'\| 'clip' | undefined | How to render overflow text. Overrides grid-level `overflow` option. |
305 | | valueViewer | func | undefined | Optional function or React Component to customize the way the value for this cell is displayed. Overrides grid-level `valueViewer` option. |
306 | | dataEditor | func | undefined | Optional function or React Component to render a custom editor. Overrides grid-level `dataEditor` option. |
307 |
308 | ## Custom Renderers
309 |
310 | Each of the following custom renderers should be either a React Component or a
311 | function that takes a `props` argument and returns a react element (a.k.a
312 | stateless functional component). React-DataSheet will supply certain properties
313 | to each renderer.
314 |
315 | In some cases React-DataSheet will include event handlers as properties to your
316 | custom renderer. You must hook up these handlers to your component or aspects of
317 | React-DataSheet's built-in behavior will cease to work.
318 |
319 | Except for `valueViewer` and `dataEditor`, each custom renderer will receive
320 | react's regular `props.children`. Be sure to render `{props.children}` in your
321 | custom renderer.
322 |
323 | ### Sheet Renderer
324 |
325 | The `sheetRenderer` is responsible for laying out the sheet's main parent
326 | component. By default, React-DataSheet uses a `table` element. React-DataSheet
327 | will supply these properties:
328 |
329 | | Option | Type | Description |
330 | | :-------- | :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
331 | | data | Array | The same `data` array as from main `ReactDataSheet` component |
332 | | className | String | Classes to apply to your top-level element. You can add to these, but your should not overwrite or omit them unless you want to implement your own CSS also. |
333 | | children | Array or component | The regular react `props.children`. You must render `{props.children}` within your custom renderer or you won't see your rows and cells. |
334 |
335 | ### Row Renderer
336 |
337 | The `rowRenderer` lays out each row in the sheet. By default, React-DataSheet
338 | uses a `tr` element. React-DataSheet will supply these properties:
339 |
340 | | Option | Type | Description |
341 | | :------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------ |
342 | | row | number | The current row index |
343 | | selected | Bool | `true` in case the current row is selected |
344 | | cells | Array | The cells in the current row |
345 | | children | Array or component | The regular react `props.children`. You must render `{props.children}` within your custom renderer or you won't see your cells. |
346 |
347 | ### Cell Renderer
348 |
349 | The `cellRenderer` creates the container for each cell in the sheet. The default
350 | renders a `td` element. React-DataSheet will supply these properties:
351 |
352 | | Option | Type | Description |
353 | | :----------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
354 | | row | number | The current row index |
355 | | col | number | The current column index |
356 | | cell | Object | The cell's raw data structure |
357 | | className | String | Classes to apply to your cell element. You can add to these, but your should not overwrite or omit them unless you want to implement your own CSS also. |
358 | | style | Object | Generated styles that you should apply to your cell element. This may be null or undefined. |
359 | | selected | Bool | Is the cell currently selected |
360 | | editing | Bool | Is the cell currently being edited |
361 | | updated | Bool | Was the cell recently updated |
362 | | attributesRenderer | func | As for the main `ReactDataSheet` component |
363 | | onMouseDown | func | Event handler important for cell selection behavior |
364 | | onMouseOver | func | Event handler important for cell selection behavior |
365 | | onDoubleClick | func | Event handler important for editing |
366 | | onContextMenu | func | Event handler to launch default content-menu handling. You can safely ignore this handler if you want to provide your own content menu handling. |
367 | | children | Array or component | The regular react `props.children`. You must render `{props.children}` within your custom renderer or you won't your cell's data. |
368 |
369 | ### Value Viewer
370 |
371 | The `valueViewer` displays your cell's data with a custom component when in view
372 | mode. For example, you might show a "three star rating" component instead the
373 | number 3. You can specify a `valueViewer` for the entire sheet and/or for an
374 | individual cell.
375 |
376 | React-DataSheet will supply these properties:
377 |
378 | | Option | Type | Description |
379 | | :----- | :----- | :----------------------------------------- |
380 | | value | node | The result of the `valueRenderer` function |
381 | | row | number | The current row index |
382 | | col | number | The current column index |
383 | | cell | Object | The cell's raw data structure |
384 |
385 | ### Data Editor
386 |
387 | The `dataEditor` displays your cell's data when in edit mode. You can can use
388 | any component you want, as long as you hook up the event handlers that
389 | constitute the contract between React-DataSheet and your editor. You can specify
390 | a `dataEditor` for the entire sheet and/or for an individual cell.
391 |
392 | | Option | Type | Description |
393 | | :-------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
394 | | value | String or node | The result of the `dataRenderer` (or `valueRenderer` if none) |
395 | | row | number | The current row index |
396 | | col | number | The current column index |
397 | | cell | Object | The cell's raw data structure |
398 | | onChange | func | `function (string) {}` callback for when the user changes the value during editing (for example, each time they type a character into an `input`). `onChange` does not indicate the _final_ edited value. It works just like a [controlled component](https://reactjs.org/docs/forms.html#controlled-components) in a form. |
399 | | onKeyDown | func | `function (event) {}` An event handler that you can call to use default React-DataSheet keyboard handling to signal reverting an ongoing edit (Escape key) or completing an edit (Enter or Tab). For most editors based on an `input` element this will probably work. However, if this keyboard handling is unsuitable for your editor you can trigger these changes explicitly using the `onCommit` and `onRevert` callbacks. |
400 | | onCommit | func | `function (newValue, [event]) {}` A callback to indicate that editing is over, here is the final value. If you pass a `KeyboardEvent` as the second argument, React-DataSheet will perform default navigation for you (for example, going down to the next row if you hit the enter key). You actually don't need to use `onCommit` if the default keyboard handling is good enough for you. |
401 | | onRevert | func | `function () {}` A no-args callback that you can use to indicate that you want to cancel ongoing edits. As with `onCommit`, you don't need to worry about this if the default keyboard handling works for your editor. |
402 |
--------------------------------------------------------------------------------
/USAGE_TYPESCRIPT.md:
--------------------------------------------------------------------------------
1 | ### Usage with TypeScript
2 |
3 | The library comes with built-in type definitions, so there is no need to download anything separately from `@types`. Most of the defined types accept two generic parameters. The first (which is required) allows you to define the shape of the data in your `cell` objects. The second one allows you to define the type of the `value` property that is used by custom `dataEditor` components and `onCellsChanged` callbacks (this is not required, and it defaults to `string`) Basic usage looks like this:
4 |
5 |
6 | ```tsx
7 | import * as React from 'react';
8 | import ReactDataSheet from 'react-datasheet';
9 | import "react-datasheet/lib/react-datasheet.css";
10 |
11 | export interface GridElement extends ReactDataSheet.Cell<GridElement, number> {
12 | value: number | null;
13 | }
14 |
15 | class MyReactDataSheet extends ReactDataSheet<GridElement, number> { }
16 |
17 | interface AppState {
18 | grid: GridElement[][];
19 | }
20 |
21 | //You can also strongly type all the Components or SFCs that you pass into ReactDataSheet.
22 | let cellRenderer: ReactDataSheet.CellRenderer<GridElement, number> = (props) => {
23 | const backgroundStyle = props.cell.value && props.cell.value < 0 ? {color: 'red'} : undefined;
24 | return (
25 | <td style={backgroundStyle} onMouseDown={props.onMouseDown} onMouseOver={props.onMouseOver} onDoubleClick={props.onDoubleClick} className="cell">
26 | {props.children}
27 | </td>
28 | )
29 | }
30 |
31 | export class App extends React.Component<{}, AppState> {
32 | constructor (props: {}) {
33 | super(props)
34 | this.state = {
35 | grid: [
36 | [{value: 1}, {value: -3}],
37 | [{value: -2}, {value: 4}]
38 | ]
39 | }
40 | }
41 | render () {
42 | return (
43 | <MyReactDataSheet
44 | data={this.state.grid}
45 | valueRenderer={(cell) => cell.value}
46 | onCellsChanged={changes => {
47 | const grid = this.state.grid.map(row => [...row])
48 | changes.forEach(({cell, row, col, value}) => {
49 | grid[row][col] = {...grid[row][col], value}
50 | })
51 | this.setState({grid})
52 | }}
53 | cellRenderer={cellRenderer}
54 | />
55 | )
56 | }
57 | }
58 | ```
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log*
16 | yarn-debug.log*
17 | yarn-error.log*
18 |
19 |
--------------------------------------------------------------------------------
/docs/build/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "/react-datasheet/static/css/main.afdff407.chunk.css",
4 | "main.js": "/react-datasheet/static/js/main.10f2c6ee.chunk.js",
5 | "main.js.map": "/react-datasheet/static/js/main.10f2c6ee.chunk.js.map",
6 | "runtime~main.js": "/react-datasheet/static/js/runtime~main.e087b50f.js",
7 | "runtime~main.js.map": "/react-datasheet/static/js/runtime~main.e087b50f.js.map",
8 | "static/css/2.f916d21b.chunk.css": "/react-datasheet/static/css/2.f916d21b.chunk.css",
9 | "static/js/2.ed658b4d.chunk.js": "/react-datasheet/static/js/2.ed658b4d.chunk.js",
10 | "static/js/2.ed658b4d.chunk.js.map": "/react-datasheet/static/js/2.ed658b4d.chunk.js.map",
11 | "index.html": "/react-datasheet/index.html",
12 | "precache-manifest.3af6e8757c15cf56685ad91c52be8c77.js": "/react-datasheet/precache-manifest.3af6e8757c15cf56685ad91c52be8c77.js",
13 | "service-worker.js": "/react-datasheet/service-worker.js",
14 | "static/css/2.f916d21b.chunk.css.map": "/react-datasheet/static/css/2.f916d21b.chunk.css.map",
15 | "static/css/main.afdff407.chunk.css.map": "/react-datasheet/static/css/main.afdff407.chunk.css.map"
16 | }
17 | }
--------------------------------------------------------------------------------
/docs/build/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadbm/react-datasheet/13b5c35f28b4bab2547402b2c406986ef1913245/docs/build/favicon.ico
--------------------------------------------------------------------------------
/docs/build/index.html:
--------------------------------------------------------------------------------
1 | <!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="X-UA-Compatible" content="ie=edge"><link rel="shortcut icon" href="/react-datasheet/favicon.ico"><link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"><script async defer="defer" src="https://buttons.github.io/buttons.js"></script><title>React Datasheet Component</title><link href="/react-datasheet/static/css/2.f916d21b.chunk.css" rel="stylesheet"><link href="/react-datasheet/static/css/main.afdff407.chunk.css" rel="stylesheet"></head><body><div id="root"></div><script>!function(p){function e(e){for(var t,r,n=e[0],o=e[1],a=e[2],u=0,l=[];u<n.length;u++)r=n[u],Object.prototype.hasOwnProperty.call(f,r)&&f[r]&&l.push(f[r][0]),f[r]=0;for(t in o)Object.prototype.hasOwnProperty.call(o,t)&&(p[t]=o[t]);for(s&&s(e);l.length;)l.shift()();return i.push.apply(i,a||[]),c()}function c(){for(var e,t=0;t<i.length;t++){for(var r=i[t],n=!0,o=1;o<r.length;o++){var a=r[o];0!==f[a]&&(n=!1)}n&&(i.splice(t--,1),e=u(u.s=r[0]))}return e}var r={},f={1:0},i=[];function u(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return p[e].call(t.exports,t,t.exports,u),t.l=!0,t.exports}u.m=p,u.c=r,u.d=function(e,t,r){u.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},u.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},u.t=function(t,e){if(1&e&&(t=u(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(u.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)u.d(r,n,function(e){return t[e]}.bind(null,n));return r},u.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return u.d(t,"a",t),t},u.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},u.p="/react-datasheet/";var t=window["webpackJsonpreact-datasheet-example"]=window["webpackJsonpreact-datasheet-example"]||[],n=t.push.bind(t);t.push=e,t=t.slice();for(var o=0;o<t.length;o++)e(t[o]);var s=n;c()}([])</script><script src="/react-datasheet/static/js/2.ed658b4d.chunk.js"></script><script src="/react-datasheet/static/js/main.10f2c6ee.chunk.js"></script></body></html>
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-datasheet-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "http://nadbm.github.io/react-datasheet",
6 | "devDependencies": {
7 | "react-scripts": "^3.1.1"
8 | },
9 | "dependencies": {
10 | "gh-pages": "^2.1.1",
11 | "mathjs": "^6.2.1",
12 | "react": "^15.4.2",
13 | "react-dnd": "^2.5.4",
14 | "react-dnd-html5-backend": "^2.5.4",
15 | "react-dom": "^15.4.2",
16 | "react-select": "^1.0.0-rc.3"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test --env=jsdom",
22 | "eject": "react-scripts eject",
23 | "predeploy": "npm run build",
24 | "deploy": "gh-pages -d build"
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/docs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nadbm/react-datasheet/13b5c35f28b4bab2547402b2c406986ef1913245/docs/public/favicon.ico
--------------------------------------------------------------------------------
/docs/public/index.html:
--------------------------------------------------------------------------------
1 | <!doctype html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="utf-8">
5 | <meta name="viewport" content="width=device-width, initial-scale=1">
6 | <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 | <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
8 | <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
9 | <script async defer src="https://buttons.github.io/buttons.js"></script>
10 | <!--
11 | Notice the use of %PUBLIC_URL% in the tag above.
12 | It will be replaced with the URL of the `public` folder during the build.
13 | Only files inside the `public` folder can be referenced from the HTML.
14 |
15 | Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
16 | work correctly both with client-side routing and a non-root public URL.
17 | Learn how to configure a non-root public URL by running `npm run build`.
18 | -->
19 | <title>React Datasheet Component</title>
20 | </head>
21 | <body>
22 |
23 | <div id="root"></div>
24 | <!--
25 | This HTML file is a template.
26 | If you open it directly in the browser, you will see an empty page.
27 |
28 | You can add webfonts, meta tags, or analytics to this file.
29 | The build step will place the bundled scripts into the <body> tag.
30 |
31 | To begin the development, run `npm start`.
32 | To create a production bundle, use `npm run build`.
33 | -->
34 | </body>
35 | </html>
36 |
--------------------------------------------------------------------------------
/docs/src/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import 'react-select/dist/react-select.css'
3 | import './lib/react-datasheet.css'
4 | import {BasicSheet, MathSheet, ComponentSheet, CustomRendererSheet, OverrideEverythingSheet} from './examples/index';
5 |
6 | export default class App extends React.Component {
7 | render () {
8 | return (
9 | <div>
10 | <div className={'header'}>
11 | <h1>React datasheet</h1>
12 | <h4>Simple and highly customizable excel-like spreadsheet</h4>
13 | <pre>npm install react-datasheet --save</pre>
14 | <a className={'github-link'} href="https://github.com/nadbm/react-datasheet"><span className="hidden-xs"> View on GitHub </span><span className="octicon octicon-mark-github" aria-hidden="true"></span></a>
15 | </div>
16 | <div className={'container'} >
17 | <div style={{float: 'right', marginTop: '-20px'}}>
18 | <a
19 | className="github-button"
20 | href="https://github.com/nadbm/react-datasheet"
21 | data-style="mega" data-count-href="/nadbm/react-datasheet/stargazers"
22 | data-count-api="/repos/nadbm/react-datasheet#stargazers_count"
23 | data-count-aria-label="# stargazers on GitHub"
24 | aria-label="Star nadbm/react-datasheet on GitHub">
25 | Star
26 | </a>
27 |
28 | </div>
29 | <h3 style={{color: '#e63946'}}>Basic datasheet</h3>
30 | <small>
31 | This small component allows you to integrate an excel-like datasheet. By default,
32 | the spreadsheet handles <b>keyboard navigation</b> and <b>copy pasting</b> of cells.
33 | </small>
34 | <div className={'sheet-container'}>
35 | <BasicSheet />
36 | </div>
37 | <div className={'divider'} />
38 | <h3 style={{color: '#e63946'}}>Formula datasheet</h3>
39 | <small>
40 | This example computes expression underneath using mathjs.
41 | On a invalid expression the cell changes color to show the error.
42 | <b> Note that react-datasheet does not handle the validation nor the formula computation</b>
43 | </small>
44 | <div className={'sheet-container'}>
45 | <MathSheet />
46 | </div>
47 | <div className={'divider'} />
48 | <h3 style={{color: '#e63946'}}>Sheet with components</h3>
49 | <div className={'sheet-container'}>
50 | <ComponentSheet />
51 | </div>
52 | <div className={'divider'} />
53 | <h3 style={{color: '#e63946'}}>Sheet with custom renderers</h3>
54 | <small>
55 | Custom renderers allow you to add significant new capabilities
56 | to your sheets without requiring changes to react-datagrid itself.
57 | This example allows you to reorder both the columns and the rows
58 | using drag and drop. This is implemented by using custom components
59 | to render the main table (including a custom header) and each row.
60 | The drag handler for the rows is the gray cell at the beginning of each row.
61 | </small>
62 | <small>
63 | The "Rating" column also shows how to specify custom cell editing and viewing components.
64 | </small>
65 | <div className={'sheet-container'}>
66 | <CustomRendererSheet />
67 | </div>
68 | <div className={'divider'} />
69 | <h3 style={{color: '#e63946'}}>Sheet with custom structure</h3>
70 | <small>
71 | Ever wish you could <a href="https://github.com/nadbm/react-datasheet/issues/27">customize how data is displayed</a>,
72 | or <a href="https://github.com/nadbm/react-datasheet/pull/43">easily add custom attributes to your cells</a>,
73 | or <a href="https://github.com/nadbm/react-datasheet/issues/45">add new behaviors</a> that React-DataSheet
74 | doesn't currently support?
75 | This example demonstrates the great flexibility that custom renderers provide.
76 | You can completely change the sheet's structure:
77 | <ul>
78 | <li>Table - similar to the default rendering</li>
79 | <li>List - renders the data grid using an html unordered list</li>
80 | <li>Div - renders using divs</li>
81 | </ul>
82 | Although a bit contrived, it shows that you can deeply customize your sheet's markup while
83 | still retaining data sheet behavior. This example also adds controls for selecting rows. Note that the
84 | model and controls for row selection are separate from the grid itself.
85 | </small>
86 | <div className={'sheet-container'}>
87 | <OverrideEverythingSheet />
88 | </div>
89 | <div className={'divider'} />
90 | </div>
91 | <div className={'footer-container'}>
92 | <div className={'footer'} >
93 | Check out the GitHub project at <a href='https://github.com/nadbm/react-datasheet'>react-datasheet</a>
94 | </div>
95 | </div>
96 | </div>
97 | )
98 | }
99 | }
--------------------------------------------------------------------------------
/docs/src/examples/BasicSheet.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import React from 'react';
3 | import Datasheet from '../lib/DataSheet';
4 |
5 | export default class BasicSheet extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | grid: [
10 | [
11 | { readOnly: true, value: '' },
12 | { value: 'A', readOnly: true },
13 | { value: 'B', readOnly: true },
14 | { value: 'C', readOnly: true },
15 | { value: 'D', readOnly: true },
16 | ],
17 | [
18 | { readOnly: true, value: 1 },
19 | { value: 1 },
20 | { value: 3 },
21 | { value: 3 },
22 | { value: 3 },
23 | ],
24 | [
25 | { readOnly: true, value: 2 },
26 | { value: 2 },
27 | { value: 4 },
28 | { value: 4 },
29 | { value: 4 },
30 | ],
31 | [
32 | { readOnly: true, value: 3 },
33 | { value: 1 },
34 | { value: 3 },
35 | { value: 3 },
36 | { value: 3 },
37 | ],
38 | [
39 | { readOnly: true, value: 4 },
40 | { value: 2 },
41 | { value: 4 },
42 | { value: 4 },
43 | { value: 4 },
44 | ],
45 | ],
46 | };
47 | }
48 | valueRenderer = cell => cell.value;
49 | onCellsChanged = changes => {
50 | const grid = this.state.grid;
51 | changes.forEach(({ cell, row, col, value }) => {
52 | grid[row][col] = { ...grid[row][col], value };
53 | });
54 | this.setState({ grid });
55 | };
56 | onContextMenu = (e, cell, i, j) =>
57 | cell.readOnly ? e.preventDefault() : null;
58 |
59 | render() {
60 | return (
61 | <Datasheet
62 | data={this.state.grid}
63 | valueRenderer={this.valueRenderer}
64 | onContextMenu={this.onContextMenu}
65 | onCellsChanged={this.onCellsChanged}
66 | />
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/docs/src/examples/ComponentSheet.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Select from 'react-select'
3 | import _ from 'lodash'
4 | import Datasheet from '../lib/DataSheet'
5 |
6 | export default class ComponentSheet extends React.Component {
7 | constructor (props) {
8 | super(props)
9 | this.options = [
10 | { label: 'Bread', value: 2.35 },
11 | { label: 'Berries', value: 3.05 },
12 | { label: 'Milk', value: 3.99 },
13 | { label: 'Apples', value: 4.35 },
14 | { label: 'Chicken', value: 9.95 },
15 | { label: 'Yoghurt', value: 4.65 },
16 | { label: 'Onions', value: 3.45 },
17 | { label: 'Salad', value: 1.55 }
18 | ]
19 | this.state = {
20 | grocery: {},
21 | items: 3
22 | }
23 | }
24 |
25 | generateGrid () {
26 | const groceryValue = (id) => {
27 | if (this.state.grocery[id]) {
28 | const {label, value} = this.state.grocery[id]
29 | return `${label} (${value})`
30 | } else {
31 | return ''
32 | }
33 | }
34 | const component = (id) => {
35 | return (
36 | <Select
37 | autofocus
38 | openOnFocus
39 | value={this.state && this.state.grocery[id]}
40 | onChange={(opt) => this.setState({grocery: _.assign(this.state.grocery, {[id]: opt})})}
41 | options={this.options}
42 | />
43 | )
44 | }
45 | const total = _.reduce(_.values(this.state.grocery), (res, val, key) => {
46 | res += (val && val.value) || 0
47 | return res
48 | }, 0)
49 | let rows = [
50 | [{readOnly: true, colSpan: 2, value: 'Shopping List'}],
51 | [
52 | {readOnly: true, value: ''},
53 | {
54 | value: 'Grocery Item',
55 | component: (
56 | <div className={'add-grocery'}> Grocery List
57 | <div className={'add-button'} onClick={() => { console.log('add'); this.setState({items: this.state.items + 1}) }}> add item</div>
58 | </div>
59 | ),
60 | forceComponent: true
61 | }]
62 | ]
63 | rows = rows.concat(_.range(1, this.state.items + 1).map(id => [{readOnly: true, value: `Item ${id}`}, {value: groceryValue(id), component: component(id)}]))
64 |
65 | rows = rows.concat([[{readOnly: true, value: 'Total'}, {readOnly: true, value: `${total.toFixed(2)}
max tokens
The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by
removing the max tokens filter.