diff --git a/.npmignore b/.npmignore index 466cf29..948a8fa 100644 --- a/.npmignore +++ b/.npmignore @@ -202,3 +202,4 @@ gulpfile.js .babelrc .eslintrc.json yarn.lock +circle.yml diff --git a/README.md b/README.md index 65b5790..e326937 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ npm install --save react-editable-json-tree ### Example Usage ```jsx // Import -import { JsonTree, deltaTypes } from 'react-editable-json-tree' +import { JsonTree, ADD_DELTA_TYPE, REMOVE_DELTA_TYPE, UPDATE_DELTA_TYPE } from 'react-editable-json-tree' // Data const data = { @@ -210,6 +210,21 @@ The library will add a `onClick`, `className` and `style` props on element. The library will add a `onClick`, `className` and `style` props on element. +### beforeRemoveAction +| Key | Description | Type | Required | Default | +|:------------------:|:------------------------------------------------------------:|:--------:|:---------:|:-----------------------------------------------------------:| +| beforeRemoveAction | Function called before each remove action (with minus menu) | Function | False | `(key, keyPath, deep) => new Promise(resolve => resolve())` | + +This function must return a `Promise`. In case of resolve of this one, the remove will be done. Otherwise, in reject, nothing will be done. + +Function parameters : + +| Key | Description | Type | Example | +|:-----------:|:-------------------------------:|:-------:|:---------------------------------------------------------------:| +| key | Key of current node/value | String | 'object' for data: { object: { string: 'test' } } | +| keyPath | key path | Array | ['object'] for data: { object: { string: 'test' } } | +| deep | Deep of current node | Number | 1 for data: { object: { string: 'test' } } on 'object' node | + ## Design The library provide CSS class on elements. All are prefixed by "rejt" to avoid conflict. To avoid being linked with a CSS file, the library will use the inline style. diff --git a/package.json b/package.json index f6c84e0..2fb4a59 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "serve": "gulp serve", - "release": "gulp release" + "release": "gulp release", + "start": "gulp serve" }, "keywords": [ "React", @@ -32,7 +33,7 @@ "eslint": "^3.10.2", "eslint-config-airbnb": "^13.0.0", "eslint-plugin-import": "^2.2.0", - "eslint-plugin-jsx-a11y": "^3.0.1", + "eslint-plugin-jsx-a11y": "^2.2.3", "eslint-plugin-react": "^6.7.1", "gulp": "^3.9.1", "gulp-babel": "^6.1.2", diff --git a/src/JsonTree.js b/src/JsonTree.js index e5e2ac8..75bc967 100644 --- a/src/JsonTree.js +++ b/src/JsonTree.js @@ -31,6 +31,7 @@ const propTypes = { textareaElement: PropTypes.element, minusMenuElement: PropTypes.element, plusMenuElement: PropTypes.element, + beforeRemoveAction: PropTypes.func, }; // Default props const defaultProps = { @@ -52,6 +53,7 @@ const defaultProps = { return value; } }, + beforeRemoveAction: (key, keyPath, deep) => new Promise(resolve => resolve()), }; /* ************************************* */ @@ -98,6 +100,7 @@ class JsonTree extends Component { textareaElement, minusMenuElement, plusMenuElement, + beforeRemoveAction, } = this.props; // Node type @@ -121,6 +124,7 @@ class JsonTree extends Component { textareaElement={textareaElement} minusMenuElement={minusMenuElement} plusMenuElement={plusMenuElement} + beforeRemoveAction={beforeRemoveAction} />); } else { node = 'Data must be an Array or Object'; diff --git a/src/components/JsonAddValue.js b/src/components/JsonAddValue.js index 213ee21..eedfc96 100644 --- a/src/components/JsonAddValue.js +++ b/src/components/JsonAddValue.js @@ -63,7 +63,7 @@ class JsonAddValue extends Component { const { handleAdd, onlyValue } = this.props; const { inputRefKey, inputRefValue } = this.state; const result = { - value: parse(inputRefValue.value), + newValue: parse(inputRefValue.value), }; // Check if we have the key if (!onlyValue) { diff --git a/src/components/JsonArray.js b/src/components/JsonArray.js index 3151ce8..e8b4a91 100644 --- a/src/components/JsonArray.js +++ b/src/components/JsonArray.js @@ -35,6 +35,7 @@ const propTypes = { textareaElement: PropTypes.element, minusMenuElement: PropTypes.element, plusMenuElement: PropTypes.element, + beforeRemoveAction: PropTypes.func, }; // Default props const defaultProps = { @@ -110,46 +111,51 @@ class JsonArray extends Component { handleRemoveItem(index) { return () => { + const { beforeRemoveAction } = this.props; const { data, keyPath, deep } = this.state; - const objType = getObjectType(data[index]); - let deltaUpdateResult = null; - if (objType === 'Object' || objType === 'Array') { - deltaUpdateResult = { - type: UPDATE_DELTA_TYPE, - keyPath, - deep, - key: index, - oldValue: data[index], - newValue: null, - }; - data[index] = null; - } else { - deltaUpdateResult = { - type: REMOVE_DELTA_TYPE, - keyPath, - deep, - key: index, - oldValue: data[index], - }; - data.splice(index, 1); - } - this.setState({ - data, + // Before Remove Action + beforeRemoveAction(index, keyPath, deep).then(() => { + const objType = getObjectType(data[index]); + let deltaUpdateResult = null; + if (objType === 'Object' || objType === 'Array') { + deltaUpdateResult = { + type: UPDATE_DELTA_TYPE, + keyPath, + deep, + key: index, + oldValue: data[index], + newValue: null, + }; + data[index] = null; + } else { + deltaUpdateResult = { + type: REMOVE_DELTA_TYPE, + keyPath, + deep, + key: index, + oldValue: data[index], + }; + data.splice(index, 1); + } + this.setState({ + data, + }); + // Spread new update + const { onUpdate, onDeltaUpdate } = this.props; + onUpdate(keyPath[keyPath.length - 1], data); + // Spread delta update + onDeltaUpdate(deltaUpdateResult); + }).catch(() => { }); - // Spread new update - const { onUpdate, onDeltaUpdate } = this.props; - onUpdate(keyPath[keyPath.length - 1], data); - // Spread delta update - onDeltaUpdate(deltaUpdateResult); }; } - handleAddValueAdd({ value }) { + handleAddValueAdd({ newValue }) { const { data, keyPath, deep } = this.state; // Update data const newData = [ ...data, - value, + newValue, ]; this.setState({ data: newData, @@ -165,7 +171,7 @@ class JsonArray extends Component { keyPath, deep, key: newData.length - 1, - newValue: value, + newValue, }); } @@ -242,6 +248,7 @@ class JsonArray extends Component { textareaElement, minusMenuElement, plusMenuElement, + beforeRemoveAction, } = this.props; const { minus, plus, delimiter, ul, addForm } = getStyle(name, data, keyPath, deep, dataType); @@ -277,6 +284,7 @@ class JsonArray extends Component { textareaElement={textareaElement} minusMenuElement={minusMenuElement} plusMenuElement={plusMenuElement} + beforeRemoveAction={beforeRemoveAction} />); const onlyValue = true; diff --git a/src/components/JsonNode.js b/src/components/JsonNode.js index 8538dd4..85d46d4 100644 --- a/src/components/JsonNode.js +++ b/src/components/JsonNode.js @@ -36,6 +36,7 @@ const propTypes = { textareaElement: PropTypes.element, minusMenuElement: PropTypes.element, plusMenuElement: PropTypes.element, + beforeRemoveAction: PropTypes.func, }; // Default props const defaultProps = { @@ -80,6 +81,7 @@ class JsonNode extends Component { textareaElement, minusMenuElement, plusMenuElement, + beforeRemoveAction, } = this.props; const readOnlyTrue = true; @@ -105,6 +107,7 @@ class JsonNode extends Component { textareaElement={textareaElement} minusMenuElement={minusMenuElement} plusMenuElement={plusMenuElement} + beforeRemoveAction={beforeRemoveAction} />); case 'Object': return (); case 'Array': return (); case 'String': return ( { - const objType = getObjectType(data[key]); - let deltaUpdateResult = null; - if (objType === 'Object' || objType === 'Array') { - deltaUpdateResult = { - type: UPDATE_DELTA_TYPE, - keyPath, - deep, - key, - oldValue: data[key], - newValue: null, - }; - data[key] = null; - } else { - deltaUpdateResult = { - type: REMOVE_DELTA_TYPE, - keyPath, - deep, - key, - oldValue: data[key], - }; - delete data[key]; - } - this.setState({ - data, + const { beforeRemoveAction } = this.props; + const { data, keyPath, deep } = this.state; + // Before Remove Action + beforeRemoveAction(key, keyPath, deep).then(() => { + const objType = getObjectType(data[key]); + let deltaUpdateResult = null; + if (objType === 'Object' || objType === 'Array') { + deltaUpdateResult = { + type: UPDATE_DELTA_TYPE, + keyPath, + deep, + key, + oldValue: data[key], + newValue: null, + }; + data[key] = null; + } else { + deltaUpdateResult = { + type: REMOVE_DELTA_TYPE, + keyPath, + deep, + key, + oldValue: data[key], + }; + delete data[key]; + } + this.setState({ + data, + }); + // Spread new update + const { onUpdate, onDeltaUpdate } = this.props; + onUpdate(keyPath[keyPath.length - 1], data); + // Spread delta update + onDeltaUpdate(deltaUpdateResult); + }).catch(() => { }); - // Spread new update - const { onUpdate, onDeltaUpdate } = this.props; - onUpdate(keyPath[keyPath.length - 1], data); - // Spread delta update - onDeltaUpdate(deltaUpdateResult); }; } @@ -239,6 +245,7 @@ class JsonObject extends Component { textareaElement, minusMenuElement, plusMenuElement, + beforeRemoveAction, } = this.props; const { minus, plus, addForm, ul, delimiter } = getStyle(name, data, keyPath, deep, dataType); @@ -275,6 +282,7 @@ class JsonObject extends Component { textareaElement={textareaElement} minusMenuElement={minusMenuElement} plusMenuElement={plusMenuElement} + beforeRemoveAction={beforeRemoveAction} />); const startObject = '{';