diff --git a/README.md b/README.md index cc562dbe..2f728460 100644 --- a/README.md +++ b/README.md @@ -662,7 +662,9 @@ Custom nodes are provided in the `customNodeDefinitions` prop, as an array of ob showOnView // boolean, default true showEditTools // boolean, default true name // string (appears in Types selector) - showInTypesSelector, // boolean (optional), default false + showInTypesSelector // boolean (optional), default false + passOriginalNode // boolean (optional), default false -- if `true` makes the original node + // for rendering within Custom Node // Only affects Collection nodes: showCollectionWrapper // boolean (optional), default true @@ -673,7 +675,7 @@ Custom nodes are provided in the `customNodeDefinitions` prop, as an array of ob The `condition` is just a [Filter function](#filter-functions), with the same input parameters (`key`, `path`, `value`, etc.), 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. -The component will receive *all* the same props as a standard node component plus some additional ones — see [BaseNodeProps](https://github.com/CarlosNZ/json-edit-react/blob/b085f6391dabf574809f1040b11401c13344923d/src/types.ts#L219-L265) (common to all nodes) and [CustomNodeProps](https://github.com/CarlosNZ/json-edit-react/blob/b085f6391dabf574809f1040b11401c13344923d/src/types.ts#L275-L287) type definitions. Specifically, if you want to update the data structure from your custom node, you'll need to call the `setValue` method on your node's data value. +The component will receive *all* the same props as a standard node component plus some additional ones — see [BaseNodeProps](https://github.com/CarlosNZ/json-edit-react/blob/b085f6391dabf574809f1040b11401c13344923d/src/types.ts#L219-L265) (common to all nodes) and [CustomNodeProps](https://github.com/CarlosNZ/json-edit-react/blob/b085f6391dabf574809f1040b11401c13344923d/src/types.ts#L275-L287) type definitions. Specifically, if you want to update the data structure from your custom node, you'll need to call the `setValue` method on your node's data value. And if you enable `passOriginalNode` above, you'll also have access to `originalNode` and `originalNodeKey` in order to render the standard content (i.e. what would have been rendered if it wasn't intercepted by this Custom Node) -- this can be helpful if you want your Custom Node to just be the default content with a little extra decoration. (*Note:* you may need a little custom CSS to render these original node components identically to the default display.) You can pass additional props specific to your component, if required, through the `customNodeProps` object. A thorough example of a custom **Date Picker** is used in the demo (along with a couple of other more basic presentational ones), which you can inspect to see how to utilise the standard props and a couple of custom props. View the source code [here](https://github.com/CarlosNZ/json-edit-react/blob/main/demo/src/customComponents/DateTimePicker.tsx). @@ -850,6 +852,8 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s ## Changelog +- **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)) - **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) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 18356b40..c15302b8 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -415,6 +415,29 @@ function App() { className="block-shadow" stringTruncate={90} customNodeDefinitions={dataDefinition?.customNodeDefinitions} + // customNodeDefinitions={[ + // { + // condition: ({ key }) => key === 'string', + // element: ({ nodeData, value, originalNode, originalNodeKey }) => ( + //
+ // {originalNodeKey} + // {/* {nodeData.key} */} + // ICON:{' '} + // {originalNode} + //
+ // ), + // hideKey: true, + // passOriginalNode: true, + // showOnEdit: true, + // }, + // ]} customText={dataDefinition?.customTextDefinitions} // icons={{ chevron: }} // customButtons={[ diff --git a/src/CustomNode.ts b/src/CustomNode.ts index 5665bc17..b266b630 100644 --- a/src/CustomNode.ts +++ b/src/CustomNode.ts @@ -13,6 +13,7 @@ export interface CustomNodeData { showOnView?: boolean showEditTools?: boolean showCollectionWrapper?: boolean + passOriginalNode?: boolean } // Fetches matching custom nodes (based on condition filter) from custom node diff --git a/src/KeyDisplay.tsx b/src/KeyDisplay.tsx index d0cbdb38..45c2fc51 100644 --- a/src/KeyDisplay.tsx +++ b/src/KeyDisplay.tsx @@ -54,8 +54,9 @@ export const KeyDisplay: React.FC = ({ {/* display "" using pseudo class CSS */} ) : ( - `${name}:` + `${name}` )} + : ) diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index fed80671..4abbd0f1 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -112,6 +112,7 @@ export const ValueNodeWrapper: React.FC = (props) => { showEditTools = true, showOnEdit, showOnView, + passOriginalNode, } = customNodeData // Include custom node options in dataType list @@ -256,6 +257,20 @@ export const ValueNodeWrapper: React.FC = (props) => { }, } + const keyDisplayProps = { + canEditKey, + isEditingKey, + pathString, + path, + name: name as string, + handleKeyboard, + handleEditKey, + handleCancel, + styles: getStyles('property', nodeData), + getNextOrPrevious: (type: 'next' | 'prev') => + getNextOrPrevious(nodeData.fullData, path, type, sort), + } + const ValueComponent = showCustomNode ? ( = (props) => { isEditing={isEditing} setIsEditing={() => setCurrentlyEditingElement(path)} getStyles={getStyles} + originalNode={passOriginalNode ? getInputComponent(data, inputProps) : undefined} + originalNodeKey={passOriginalNode ? : undefined} /> ) : ( // Need to re-fetch data type to make sure it's one of the "core" ones @@ -277,20 +294,6 @@ export const ValueNodeWrapper: React.FC = (props) => { getInputComponent(data, inputProps) ) - const keyDisplayProps = { - canEditKey, - isEditingKey, - pathString, - path, - name: name as string, - handleKeyboard, - handleEditKey, - handleCancel, - styles: getStyles('property', nodeData), - getNextOrPrevious: (type: 'next' | 'prev') => - getNextOrPrevious(nodeData.fullData, path, type, sort), - } - return (
"" */ .jer-empty-string::after { - content: ':'; + content: ''; font-style: italic; font-size: 90%; } diff --git a/src/types.ts b/src/types.ts index 76bd08fd..cfacedc9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -285,6 +285,8 @@ export interface CustomNodeProps> extends BaseNodePr setIsEditing: React.Dispatch> getStyles: (element: ThemeableElement, nodeData: NodeData) => React.CSSProperties children?: JSX.Element | JSX.Element[] | null + originalNode?: JSX.Element + originalNodeKey?: JSX.Element } export interface CustomNodeDefinition, U = Record> { @@ -298,6 +300,7 @@ export interface CustomNodeDefinition, U = Record