json-edit-react 0.9.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@ Features include:
9
9
  - edit individual values, or whole objects as JSON text
10
10
  - fine-grained control over which elements can be edited, deleted, or added to
11
11
  - customisable UI, through simple, pre-defined [themes](#themes), or specific CSS overrides
12
- - self-contained — constructed with HTML/CSS, so no dependance on external UI libraries
12
+ - self-contained — rendered with plain HTML/CSS, so no dependance on external UI libraries
13
13
 
14
14
  **[Explore the Demo](https://carlosnz.github.io/json-edit-react/)**
15
15
 
@@ -28,6 +28,7 @@ Features include:
28
28
  - [A note about sizing and scaling](#a-note-about-sizing-and-scaling)
29
29
  - [Icons](#icons)
30
30
  - [Localisation](#localisation)
31
+ - [Custom nodes](#custom-nodes)
31
32
  - [Undo functionality](#undo-functionality)
32
33
  - [Issues, bugs, suggestions?](#issues-bugs-suggestions)
33
34
  - [Roadmap](#roadmap)
@@ -59,7 +60,7 @@ import { JsonEditor } from 'json-edit-react'
59
60
 
60
61
  It's pretty self explanatory (click the "edit" icon to edit, etc.), but there are a few not-so-obvious ways of interacting with the editor:
61
62
 
62
- - Double-click a value to edit it
63
+ - Double-click a value (or a key) to edit it
63
64
  - When editing a string, use `Cmd/Ctrl/Shift-Enter` to add a new line (`Enter` submits the value)
64
65
  - It's the opposite when editing a full object/array node (which you do by clicking "edit" on an object or array value) — `Enter` for new line, and `Cmd/Ctrl/Shift-Enter` for submit
65
66
  - `Escape` to cancel editing
@@ -69,30 +70,33 @@ It's pretty self explanatory (click the "edit" icon to edit, etc.), but there ar
69
70
 
70
71
  The only *required* value is `data`.
71
72
 
72
- | prop | type | default | description |
73
- | ------------------ | -------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
74
- | `data` | `object\|array` | | The data to be displayed / edited |
75
- | `rootName` | `string` | `"data"` | A name to display in the editor as the root of the data object. |
76
- | `onUpdate` | `UpdateFunction` | | A function to run whenever a value is **updated** (edit, delete *or* add) in the editor. See [Update functions](#update-functions). |
77
- | `onUpdate` | `UpdateFunction` | | A function to run whenever a value is **edited**. |
78
- | `onDelete` | `UpdateFunction` | | A function to run whenever a value is **deleted**. |
79
- | `onAdd` | `UpdateFunction` | | A function to run whenever a new property is **added**. |
80
- | `enableClipboard` | `boolean\|CopyFunction` | `true` | Whether or not to enable the "Copy to clipboard" button in the UI. If a function is provided, `true` is assumed and this function will be run whenever an item is copied. |
81
- | `indent` | `number` | `4` | Specify the amount of indentation for each level of nesting in the displayed data. |
82
- | `collapse` | `boolean\|number\|FilterFunction` | `false` | Defines which nodes of the JSON tree will be displayed "opened" in the UI on load. If `boolean`, it'll be either all or none. A `number` specifies a nesting depth after which nodes will be closed. For more fine control a function can be provided — see [Filter functions](#filter-functions). |
83
- | `restrictEdit` | `boolean\|FilterFunction` | `false` | If `false`, no editing is permitted. A function can be provided for more specificity — see [Filter functions](#filter-functions) |
84
- | `restrictDelete` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for deletion |
85
- | `restrictAdd` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for adding new properties |
86
- | `keySort` | `boolean\|CompareFunction` | `false` | If `true`, object keys will be ordered (using default JS `.sort()`). A [compare function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) can also be provided to define sorting behaviour. |
87
- | `showArrayIndices` | `boolean` | `true` | Whether or not to display the index (as a property key) for array elements. |
88
- | `defaultValue` | `any` | `null` | When a new property is added, it is initialised with this value. |
89
- | `stringTruncate` | `number` | `250` | String values longer than this many characters will be displayed truncated (with `...`). The full string will always be visible when editing. |
90
- | `translations` | `LocalisedStrings` object | `{ }` | UI strings (such as error messages) can be translated by passing an object containing localised string values (there are only a few). See [Localisation](#localisation) |
91
- | `theme` | `string\|ThemeObject\|[string, ThemeObject]` | `"default"` | Either the name of one of the built-in themes, or an object specifying some or all theme properties. See [Themes](#themes). |
92
- | `className` | `string` | | Name of a CSS class to apply to the component. In most cases, specifying `theme` properties will be more straightforward. |
93
- | `icons` | `{[iconName]: JSX.Element, ... }` | `{ }` | Replace the built-in icons by specifying them here. See [Themes](#themes). | |
94
- | `minWidth` | `number\|string` (CSS value) | `250` | Minimum width for the editor container. |
95
- | `maxWidth` | `number\|string` (CSS value) | `600` | Maximum width for the editor container. |
73
+ | prop | type | default | description |
74
+ | ----------------------- | -------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
75
+ | `data` | `object\|array` | | The data to be displayed / edited |
76
+ | `rootName` | `string` | `"data"` | A name to display in the editor as the root of the data object. |
77
+ | `onUpdate` | `UpdateFunction` | | A function to run whenever a value is **updated** (edit, delete *or* add) in the editor. See [Update functions](#update-functions). |
78
+ | `onUpdate` | `UpdateFunction` | | A function to run whenever a value is **edited**. |
79
+ | `onDelete` | `UpdateFunction` | | A function to run whenever a value is **deleted**. |
80
+ | `onAdd` | `UpdateFunction` | | A function to run whenever a new property is **added**. |
81
+ | `enableClipboard` | `boolean\|CopyFunction` | `true` | Whether or not to enable the "Copy to clipboard" button in the UI. If a function is provided, `true` is assumed and this function will be run whenever an item is copied. |
82
+ | `indent` | `number` | `4` | Specify the amount of indentation for each level of nesting in the displayed data. |
83
+ | `collapse` | `boolean\|number\|FilterFunction` | `false` | Defines which nodes of the JSON tree will be displayed "opened" in the UI on load. If `boolean`, it'll be either all or none. A `number` specifies a nesting depth after which nodes will be closed. For more fine control a function can be provided — see [Filter functions](#filter-functions). |
84
+ | `restrictEdit` | `boolean\|FilterFunction` | `false` | If `false`, no editing is permitted. A function can be provided for more specificity — see [Filter functions](#filter-functions) |
85
+ | `restrictDelete` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for deletion |
86
+ | `restrictAdd` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for adding new properties |
87
+ | `restrictTypeSelection` | `boolean\|DataType[]\|TypeFilterFunction` | `false` | For restricting the data types the user can select. This varies slightly from the above restrictions in that the value (or output of the `TypeFilterFunction`) can be a list of data types *or* a `boolean`. |
88
+ | `keySort` | `boolean\|CompareFunction` | `false` | If `true`, object keys will be ordered (using default JS `.sort()`). A [compare function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) can also be provided to define sorting behaviour. |
89
+ | `showArrayIndices` | `boolean` | `true` | Whether or not to display the index (as a property key) for array elements. |
90
+ | `showCollectionCount` | `boolean\|"when-closed"` | `true` | Whether or not to display the number of items in each collection (object or array). |
91
+ | `defaultValue` | `any` | `null` | When a new property is added, it is initialised with this value. |
92
+ | `stringTruncate` | `number` | `250` | String values longer than this many characters will be displayed truncated (with `...`). The full string will always be visible when editing. |
93
+ | `translations` | `LocalisedStrings` object | `{ }` | UI strings (such as error messages) can be translated by passing an object containing localised string values (there are only a few). See [Localisation](#localisation) |
94
+ | `theme` | `string\|ThemeObject\|[string, ThemeObject]` | `"default"` | Either the name of one of the built-in themes, or an object specifying some or all theme properties. See [Themes](#themes). |
95
+ | `className` | `string` | | Name of a CSS class to apply to the component. In most cases, specifying `theme` properties will be more straightforward. |
96
+ | `icons` | `{[iconName]: JSX.Element, ... }` | `{ }` | Replace the built-in icons by specifying them here. See [Themes](#themes). | |
97
+ | `minWidth` | `number\|string` (CSS value) | `250` | Minimum width for the editor container. |
98
+ | `maxWidth` | `number\|string` (CSS value) | `600` | Maximum width for the editor container. |
99
+ | `customNodeDefinitions` | `CustomNodeDefinition[]` | | You can provide customised components to override specific nodes in the data tree, according to a condition function. See see [Custom nodes](#custom-nodes) for more detail. |
96
100
 
97
101
  ## Update functions
98
102
 
@@ -119,17 +123,19 @@ The function needn't return anything, but if it returns `false`, it will be cons
119
123
  A similar callback is executed whenever an item is copied to the clipboard (if passed to the `enableClipboard` prop), but with a different input parameter:
120
124
 
121
125
  ```js
122
- key: // name of the property being copied
123
- path: // path to the property
124
- value: // the value copied to the clipboard (Note: this value will be serialised to a string)
125
- type: // Either "path" or "value" depending on whether "Cmd/Ctrl" was pressed
126
+ key // name of the property being copied
127
+ path // path to the property
128
+ value // the value copied to the clipboard
129
+ type // Either "path" or "value" depending on whether "Cmd/Ctrl" was pressed
130
+ stringValue // A nicely stringified version of `value`
131
+ // (i.e. what the clipboard actually receives)
126
132
  ```
127
133
 
128
134
  Since there is very little user feedback when clicking "Copy", a good idea would be to present some kind of notification in this callback.
129
135
 
130
136
  ## Filter functions
131
137
 
132
- You can control which nodes of the data structure can be edited, deleted, or added to by passing Filter functions. These will be called on each property in the data and the attribute will be enforced depending on whether the function returns `true` or `false` (`true` means *cannot* be edited).
138
+ You can control which nodes of the data structure can be edited, deleted, or added to, or have their data type changed, by passing Filter functions. These will be called on each property in the data and the attribute will be enforced depending on whether the function returns `true` or `false` (`true` means *cannot* be edited).
133
139
 
134
140
  The function receives the following object:
135
141
  ```js
@@ -144,6 +150,18 @@ The function receives the following object:
144
150
 
145
151
  A Filter function is available for the `collapse` prop as well, so you can have your data appear with deeply-nested collections opened up, while collapsing everything else, for example.
146
152
 
153
+ For restricting data types, the (Type) filter function is slightly more sophisticated. The input is the same, but the output can be either a `boolean` (which would restrict the available types for a given node to either *all* or *none*), or an array of data types to be restricted to. The available values are:
154
+ - `"string"`
155
+ - `"number"`
156
+ - `"boolean"`
157
+ - `"null"`
158
+ - `"object"`
159
+ - `"array"`
160
+
161
+ There is no specific restriction function for editing object key names, but they must return `true` for *both* `restrictEdit` and `restrictDelete` (and `restrictAdd` for collections), since changing a key name is equivalent to deleting a property and adding a new one.
162
+
163
+ Using all these restriction filters together can allow you to enforce a reasonably sophisticated data schema.
164
+
147
165
  ### Examples
148
166
 
149
167
  - A good case would be ensure your root node is not directly editable:
@@ -172,6 +190,20 @@ restrictAdd = { ({ key }) => key !== "address" && key !== "users" }
172
190
  // "Adding" is irrelevant for non-collection nodes
173
191
  ```
174
192
 
193
+ - Multiple type restrictions:
194
+ - `string` values can only be changed to strings or objects (for nesting)
195
+ - `null` is not allowed anywhere
196
+ - `boolean` values must remain boolean
197
+ - data nested below the "user" field can be any simple property (i.e. not objects or arrays), and doesn't have to follow the above rules (except no "null")
198
+ ```js
199
+ restrictTypeSelection = { ({ path, value }) => {
200
+ if (path.includes('user')) return ['string', 'number', 'boolean']
201
+ if (typeof value === 'boolean') return false
202
+ if (typeof value === 'string') return ['string', 'object']
203
+ return ['string', 'number', 'boolean', 'array', 'object'] // no "null"
204
+ } }
205
+ ```
206
+
175
207
  ## Themes
176
208
 
177
209
  There is a small selection of built-in themes (as seen in the [Demo app](https://carlosnz.github.io/json-edit-react/)). In order to use one of these, just pass the name into the `theme` prop (although realistically, these exist more to showcase the capabilities — I'm open to better built-in themes, so feel free to [create an issue](https://github.com/CarlosNZ/json-edit-react/issues) with suggestions). The available themes are:
@@ -311,6 +343,32 @@ Localise your implementation by passing in a `translations` object to replace th
311
343
 
312
344
  ```
313
345
 
346
+ ## Custom nodes
347
+
348
+ You can replace certain nodes in the data tree with your own custom components. An example might be for an image display, or a custom date editor, or just to add some visual bling. See the "Custom Nodes" data set in the [interactive demo](https://carlosnz.github.io/json-edit-react/) to see it in action.
349
+
350
+ Custom nodes are provided in the `customNodeDefinitions` prop, as an array of objects of following structure:
351
+
352
+ ```js
353
+ {
354
+ condition, // a FilterFunction, as above
355
+ element, // React Component
356
+ props, // object (optional)
357
+ hideKey, // boolean (optional)
358
+ showInTypesSelector, // boolean (optional)
359
+ defaultValue, // JSON value for a new instance of your component
360
+ name // string
361
+ }
362
+ ```
363
+
364
+ The `condition` is just a [Filter function](#filter-functions), with the same input parameters (`key`, `path`, `level`, `value`, `size`), and `element` is a React component. Every node in the data structure will be run through each condition function, and any that match will be replaced by your custom component. Note that if a node matches more than one custom definition conditions (from multiple components), the *first* one will be used, so place them in the array in priority order.
365
+
366
+ The component will receive *all* the same props as a standard node component (see codebase), but you can pass additional props to your component if required through the `props` object.
367
+
368
+ By default, your component will be presented to the right of the property key it belongs to, like any other value. However, you can hide the key itself by setting `hideKey: true`, and the custom component will take the whole row. (See the "Presented by" box in the "Custom Nodes" data set for an example.)
369
+
370
+ You can allow users to create new instances of your special nodes by selecting them as a "Type" in the types selector when editing/adding values. Set `showInTypesSelector: true` to enable this. However, if this is enabled you need to also provide a `name` (which is what the user will see in the selector) and a `defaultValue` which is the data that is inserted when the user selects this "type". (The `defaultValue` must return `true` if passed through the `condition` function in order for it to be immediately displayed using your custom component.)
371
+
314
372
  ## Undo functionality
315
373
 
316
374
  Even though Undo/Redo functionality is probably desirable in most cases, this is not built in to the component, for two main reasons:
@@ -335,6 +393,13 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s
335
393
 
336
394
  ## Changelog
337
395
 
396
+ - **1.0.0**:
397
+ - [Custom nodes](#custom-nodes)
398
+ - Allow editing of keys
399
+ - Option to define restrictions on data type selection
400
+ - Option to hide array/object item counts
401
+ - Improve keyboard interaction
402
+ - **0.9.6**: Performance improvement by not processing child elements if not visible
338
403
  - **0.9.4**:
339
404
  - Layout improvements
340
405
  - Better internal handling of functions in data