Skip to content
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,7 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s

- **1.24.0**:
- Option to access (and render) the original node (and its key) within a [Custom Node](#custom-nodes) ([#180](https://github.com/CarlosNZ/json-edit-react/issues/180))
- Cancelling edit after changing type correctly reverts to previous value ([#122](https://github.com/CarlosNZ/json-edit-react/issues/122))
- **1.23.1**: Fix bug where you could collapse a node by clicking inside a "new key" input field [#175](https://github.com/CarlosNZ/json-edit-react/issues/175)
- **1.23.0**:
- Add `viewOnly` prop as a shorthand for restricting all editing [#168](https://github.com/CarlosNZ/json-edit-react/issues/168)
Expand Down
11 changes: 10 additions & 1 deletion src/CollectionNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {
currentlyEditingElement,
setCurrentlyEditingElement,
areChildrenBeingEdited,
previousValue,
setPreviousValue,
} = useTreeState()
const {
mainContainerRef,
Expand Down Expand Up @@ -99,7 +101,7 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {

useEffect(() => {
setStringifiedValue(jsonStringify(data))
if (isEditing) setCurrentlyEditingElement(null)
// if (isEditing) setCurrentlyEditingElement(null)
}, [data])

useEffect(() => {
Expand Down Expand Up @@ -189,6 +191,7 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {
try {
const value = jsonParse(stringifiedValue)
setCurrentlyEditingElement(null)
setPreviousValue(null)
setError(null)
if (JSON.stringify(value) === JSON.stringify(data)) return
onEdit(value, path).then((error) => {
Expand Down Expand Up @@ -236,8 +239,13 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {

const handleCancel = () => {
setCurrentlyEditingElement(null)
if (previousValue !== null) {
onEdit(previousValue, path)
return
}
setError(null)
setStringifiedValue(jsonStringify(data))
setPreviousValue(null)
}

const showLabel = showArrayIndices || !isArray
Expand Down Expand Up @@ -366,6 +374,7 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {
canEdit
? () => {
hasBeenOpened.current = true
setPreviousValue(null)
setCurrentlyEditingElement(path)
}
: undefined
Expand Down
15 changes: 14 additions & 1 deletion src/ValueNodeWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export const ValueNodeWrapper: React.FC<ValueNodeProps> = (props) => {
setPreviouslyEditedElement,
tabDirection,
setTabDirection,
previousValue,
setPreviousValue,
} = useTreeState()
const [value, setValue] = useState<typeof data | CollectionData>(
// Bad things happen when you put a function into useState
Expand Down Expand Up @@ -178,6 +180,7 @@ export const ValueNodeWrapper: React.FC<ValueNodeProps> = (props) => {

const handleEdit = () => {
setCurrentlyEditingElement(null)
setPreviousValue(null)
let newValue: JsonData
switch (dataType) {
case 'object':
Expand All @@ -202,7 +205,12 @@ export const ValueNodeWrapper: React.FC<ValueNodeProps> = (props) => {

const handleCancel = () => {
setCurrentlyEditingElement(null)
if (previousValue !== null) {
onEdit(previousValue, path)
return
}
setValue(data)
setPreviousValue(null)
}

const handleDelete = () => {
Expand Down Expand Up @@ -322,7 +330,12 @@ export const ValueNodeWrapper: React.FC<ValueNodeProps> = (props) => {
showEditButtons && (
<EditButtons
startEdit={
canEdit ? () => setCurrentlyEditingElement(path, handleCancel) : undefined
canEdit
? () => {
setPreviousValue(value)
setCurrentlyEditingElement(path, handleCancel)
}
: undefined
}
handleDelete={canDelete ? handleDelete : undefined}
enableClipboard={enableClipboard}
Expand Down
13 changes: 12 additions & 1 deletion src/contexts/TreeStateProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import React, { createContext, useContext, useRef, useState } from 'react'
import { type TabDirection, type CollectionKey } from '../types'
import { type TabDirection, type CollectionKey, type JsonData } from '../types'
import { toPathString } from '../helpers'

interface CollapseAllState {
Expand Down Expand Up @@ -37,6 +37,8 @@ interface TreeStateContext {
setDragSource: (newState: DragSource) => void
tabDirection: TabDirection
setTabDirection: (dir: TabDirection) => void
previousValue: JsonData | null
setPreviousValue: (value: JsonData | null) => void
}
const initialContext: TreeStateContext = {
collapseState: null,
Expand All @@ -51,13 +53,20 @@ const initialContext: TreeStateContext = {
setDragSource: () => {},
tabDirection: 'next',
setTabDirection: () => {},
previousValue: null,
setPreviousValue: () => {},
}

const TreeStateProviderContext = createContext(initialContext)

export const TreeStateProvider = ({ children }: { children: React.ReactNode }) => {
const [collapseState, setCollapseState] = useState<CollapseAllState | null>(null)
const [currentlyEditingElement, setCurrentlyEditingElement] = useState<string | null>(null)

// This value holds the "previous" value when user changes type. Because
// changing data type causes a proper data update, cancelling afterwards
// doesn't revert to the previous type. This value allows us to do that.
const [previousValue, setPreviousValue] = useState<JsonData | null>(null)
const [dragSource, setDragSource] = useState<DragSource>({
path: null,
pathString: null,
Expand Down Expand Up @@ -130,6 +139,8 @@ export const TreeStateProvider = ({ children }: { children: React.ReactNode }) =
setTabDirection: (dir: TabDirection) => {
tabDirection.current = dir
},
previousValue,
setPreviousValue,
// Drag-n-drop
dragSource,
setDragSource,
Expand Down