Skip to content

132 Option to insert properties/values at the beginning #136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ The only *required* value is `data` (although you will need to provide a `setDat
| `jsonStringify` | `(data: JsonData) => string` | `(data) => JSON.stringify(data, null, 2)` | Similarly, you can override the default presentation of the JSON string when starting editing JSON. You can supply different formatting parameters to the native `JSON.stringify()`, or provide a third-party option, like the aforementioned JSON5. |
| `errorMessageTimeout` | `number` | `2500` | Time (in milliseconds) to display the error message in the UI. | |
| `keyboardControls` | `KeyboardControls` | As explained [above](#usage) | Override some or all of the keyboard controls. See [Keyboard customisation](#keyboard-customisation) for details. | |
| `insertAtTop` | `boolean\| "object \| "array"` | `false` | If `true`, inserts new values at the *top* rather than bottom. Can set the behaviour just for arrays or objects by setting to `"object"` or `"array"` respectively. | |

## Managing state

Expand Down Expand Up @@ -750,7 +751,9 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s

## Changelog

- **1.18.0**: Ability to [customise keyboard controls](#keyboard-customisation)
- **1.18.0**:
- Ability to [customise keyboard controls](#keyboard-customisation)
- Option to insert new values at the top
- **1.17.0**: `defaultValue` function takes the new `key` as second parameter
- **1.16.0**: Extend the "click" zone for collapsing nodes to the header bar and left margin (not just the collapse icon)
- **1.15.12**:
Expand Down
1 change: 1 addition & 0 deletions demo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ function App() {
// collapseModifier: 'Control',
// booleanConfirm: 'Enter',
// }}
// insertAtBeginning="object"
/>
</Box>
<VStack w="100%" align="flex-end" gap={4}>
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
"wrap-ansi": "7.0.0"
},
"dependencies": {
"object-property-assigner": "^1.3.1",
"object-property-extractor": "^1.0.12"
"object-property-assigner": "^1.3.5",
"object-property-extractor": "^1.0.13"
},
"devDependencies": {
"@rollup/plugin-terser": "^0.4.4",
Expand Down
8 changes: 6 additions & 2 deletions src/CollectionNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {
jsonStringify,
keyboardControls,
handleKeyboard,
insertAtTop,
} = props
const [stringifiedValue, setStringifiedValue] = useState(jsonStringify(data))

Expand Down Expand Up @@ -171,13 +172,16 @@ export const CollectionNode: React.FC<CollectionNodeProps> = (props) => {
animateCollapse(false)
const newValue = getDefaultNewValue(nodeData, key)
if (collectionType === 'array') {
onAdd(newValue, [...path, (data as unknown[]).length]).then((error) => {
const index = insertAtTop.array ? 0 : (data as unknown[]).length
const options = insertAtTop.array ? { insert: true } : {}
onAdd(newValue, [...path, index], options).then((error) => {
if (error) onError({ code: 'ADD_ERROR', message: error }, newValue as CollectionData)
})
} else if (key in data) {
onError({ code: 'KEY_EXISTS', message: translate('ERROR_KEY_EXISTS', nodeData) }, key)
} else {
onAdd(newValue, [...path, key]).then((error) => {
const options = insertAtTop.object ? { insertBefore: 0 } : {}
onAdd(newValue, [...path, key], options).then((error) => {
if (error) onError({ code: 'ADD_ERROR', message: error }, newValue as CollectionData)
})
}
Expand Down
26 changes: 16 additions & 10 deletions src/JsonEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import assign, { type Input } from 'object-property-assigner'
import assign, { type Options as AssignOptions, type Input } from 'object-property-assigner'
import extract from 'object-property-extractor'
import { CollectionNode } from './CollectionNode'
import {
Expand Down Expand Up @@ -72,6 +72,7 @@ const Editor: React.FC<JsonEditorProps> = ({
jsonStringify = (data: JsonData) => JSON.stringify(data, null, 2),
errorMessageTimeout = 2500,
keyboardControls = {},
insertAtTop = false,
}) => {
const { getStyles } = useTheme()
const collapseFilter = useCallback(getFilterFunction(collapse), [collapse])
Expand Down Expand Up @@ -166,12 +167,13 @@ const Editor: React.FC<JsonEditorProps> = ({
})
}

const onAdd: InternalUpdateFunction = async (value, path) => {
const onAdd: InternalUpdateFunction = async (value, path, options) => {
const { currentData, newData, currentValue, newValue } = updateDataObject(
data,
path,
value,
'add'
'add',
options
)

return await handleEdit(srcAdd, {
Expand Down Expand Up @@ -237,7 +239,7 @@ const Editor: React.FC<JsonEditorProps> = ({
[...targetPath, targetKey],
currentValue,
'add',
insertOptions as AssignOptions
insertOptions as UpdateOptions
)

return await handleEdit(srcEdit, {
Expand Down Expand Up @@ -304,6 +306,10 @@ const Editor: React.FC<JsonEditorProps> = ({
errorMessageTimeout,
handleKeyboard: handleKeyboardCallback,
keyboardControls: fullKeyboardControls,
insertAtTop: {
object: insertAtTop === true || insertAtTop === 'object',
array: insertAtTop === true || insertAtTop === 'array',
},
}

const mainContainerStyles = { ...getStyles('container', nodeData), minWidth, maxWidth }
Expand Down Expand Up @@ -335,19 +341,19 @@ export const JsonEditor: React.FC<JsonEditorProps> = (props) => {
)
}

interface AssignOptions {
interface UpdateOptions {
remove?: boolean
insert?: true
insertBefore?: string
insertAfter?: string
insert?: boolean
insertBefore?: string | number
insertAfter?: string | number
}

const updateDataObject = (
data: JsonData,
path: Array<string | number>,
newValue: unknown,
action: 'update' | 'delete' | 'add',
insertOptions: { insert?: true; insertBefore?: string; insertAfter?: string } = {}
insertOptions: AssignOptions = {}
) => {
if (path.length === 0) {
return {
Expand All @@ -358,7 +364,7 @@ const updateDataObject = (
}
}

const assignOptions: AssignOptions = {
const assignOptions: UpdateOptions = {
remove: action === 'delete',
...insertOptions,
}
Expand Down
6 changes: 5 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { type Options as AssignOptions } from 'object-property-assigner'
import { type LocalisedStrings, type TranslateFunction } from './localisation'

export type JsonData = CollectionData | ValueData
Expand Down Expand Up @@ -46,6 +47,7 @@ export interface JsonEditorProps {
jsonStringify?: (input: JsonData) => string
errorMessageTimeout?: number // ms
keyboardControls?: KeyboardControls
insertAtTop?: boolean | 'array' | 'object'
}

const ValueDataTypes = ['string', 'number', 'boolean', 'null'] as const
Expand Down Expand Up @@ -140,7 +142,8 @@ export type CompareFunction = (a: string, b: string) => number
// Internal update
export type InternalUpdateFunction = (
value: unknown,
path: CollectionKey[]
path: CollectionKey[],
options?: AssignOptions
) => Promise<string | void>

// For drag-n-drop
Expand Down Expand Up @@ -236,6 +239,7 @@ export interface CollectionNodeProps extends BaseNodeProps {
defaultValue: unknown
jsonParse: (input: string) => JsonData
jsonStringify: (data: JsonData) => string
insertAtTop: { object: boolean; array: boolean }
}

export type ValueData = string | number | boolean
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2433,12 +2433,12 @@ object-keys@^1.1.1:
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==

object-property-assigner@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/object-property-assigner/-/object-property-assigner-1.3.2.tgz#9630ab7cb39e8507c0a836771863b7eb3790b216"
integrity sha512-zhRYPERkZMJ2SATAFVIJLBTfWMd8r2dR4sgpAiObgEfL7YnsAhPPOQChH97pf+rfIwOWgtJsz1TDadOQQgjQzA==
object-property-assigner@^1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/object-property-assigner/-/object-property-assigner-1.3.5.tgz#f5037ff73b7b015a42e4059c3ff5c84017413ca2"
integrity sha512-DIzHzNSTnpoG8QPQCDNrHa6O3vLMhktK3Igirqpk523UYIVe8JNCKcn5C9WyLQxJc58EGsAIiiEu10gqPrud8w==

object-property-extractor@^1.0.12:
object-property-extractor@^1.0.13:
version "1.0.13"
resolved "https://registry.yarnpkg.com/object-property-extractor/-/object-property-extractor-1.0.13.tgz#fff188d6308ac5574eb2610221af906eb87b4f38"
integrity sha512-9kgEjTWDhTPuPn7nyof+5mLmCKBPKdU0c7IVpTbOvYKYSdXQ5skH4Pa/8MPbZXeyXBGrqS82JyWecsh6tMxiLw==
Expand Down