
Un componente React para editar o ver los datos de JSON/Objects

Importante
Cambios de ruptura:
theme . Los temas incorporados ahora deben importarse por separado y aprobarse, en lugar de simplemente nombrar el tema como una cadena. Esto es mejor para la sacudida de los árboles, por lo que los temas no utilizados no se agruparán con su construcción. Ver temas y estilossetData y no use onUpdate para actualizar sus datos externamente. Ver estado de gestión. npm i json-edit-react
o
yarn add json-edit-react
import { JsonEditor } from 'json-edit-react'
// In your React component:
return
< JsonEditor
data = { jsonData }
setData = { setJsonData } // optional
{ ... otherProps } /> (para el usuario final)
Es bastante explicativo (haga clic en el icono "Editar" para editar, etc.), pero hay algunas formas no tan obvias de interactuar con el editor:
Cmd/Ctrl/Shift-Enter para agregar una nueva línea ( Enter envía el valor)Enter para una nueva línea y Cmd/Ctrl/Shift-Enter para enviarEscape para cancelar la ediciónCmd/Ctrl copiará la ruta al nodo seleccionado en lugar de su valorjsonParse PROP. El único valor requerido son data (aunque deberá proporcionar un método setData para actualizar sus datos).
| apuntalar | tipo | por defecto | descripción |
|---|---|---|---|
data | object|array | Los datos a mostrar / editar | |
setData | object|array => void | Método para actualizar su objeto data . Consulte el estado de gestión a continuación para obtener notas adicionales. | |
rootName | string | "data" | Un nombre para mostrar en el editor como la raíz del objeto de datos. |
onUpdate | UpdateFunction | Una función para ejecutarse siempre que se actualice un valor (editar, eliminar o agregar) en el editor. Ver funciones de actualización. | |
onEdit | UpdateFunction | Una función para ejecutarse siempre que se edite un valor. | |
onDelete | UpdateFunction | Una función para ejecutarse siempre que se elimine un valor. | |
onAdd | UpdateFunction | Una función para ejecutar cada vez que se agrega una nueva propiedad. | |
onChange | OnChangeFunction | Una función para modificar/restringir la entrada del usuario a medida que escribe: consulte las funciones de cambio. | |
onError | OnErrorFunction | Una función para ejecutar cada vez que el componente informa un error: consulte OnErrorFunction. | |
showErrorMessages | boolean | true | Si el componente debe mostrar sus propios mensajes de error (probablemente solo quiera deshabilitar esto si proporcionó su propia función onError ) |
enableClipboard | boolean|CopyFunction | true | Si habilita o no el botón "Copiar al portapapeles" en la interfaz de usuario. Si se proporciona una función, se supone true y esta función se ejecutará cada vez que se copie un elemento. |
indent | number | 3 | Especifique la cantidad de sangría para cada nivel de anidación en los datos mostrados. |
collapse | boolean|number|FilterFunction | false | Define qué nodos del árbol JSON se mostrarán "abierto" en la interfaz de usuario con carga. Si es boolean , será todo o ninguno. Un number especifica una profundidad de anidación después de la cual se cerrarán los nodos. Para obtener más control fino, se puede proporcionar una función, consulte las funciones del filtro. |
collapseAnimationTime | number | 300 | Tiempo (en milisegundos) para la animación de transición al colapsar los nodos de recolección. |
restrictEdit | boolean|FilterFunction | false | Si true , no se permite la edición. Se puede proporcionar una función para obtener más especificidad; consulte las funciones del filtro |
restrictDelete | boolean|FilterFunction | false | Como con restrictEdit pero para la eliminación |
restrictAdd | boolean|FilterFunction | false | Como con restrictEdit pero por agregar nuevas propiedades |
restrictTypeSelection | boolean|DataType[]|TypeFilterFunction | true | Para restringir los tipos de datos que el usuario puede seleccionar. Puede ser una lista de tipos de datos (por ejemplo [ 'string', 'number', 'boolean', 'array', 'object', 'null' ] ) o un booleano. Se puede proporcionar una función: debe tomar la misma entrada que la FilterFunction anterior s, pero la salida debe ser boolean | DataType[] . |
restrictDrag | boolean|FilterFunction | true | Establecer en false para habilitar la funcionalidad de arrastrar y soltar. Ver Drag-N-Dop |
searchText | string | undefined | La visibilidad de los datos se filtrará coincidiendo con el valor, utilizando el método definido a continuación en searchFilter |
searchFilter | "key"|"value"|"all"|SearchFilterFunction | undefined | Defina cómo se debe coincidir searchText para filtrar los elementos visibles. Ver búsqueda/filtrado |
searchDebounceTime | number | 350 | El tiempo de desbloqueo cuando cambia searchText |
keySort | boolean|CompareFunction | false | Si es true , se ordenarán las teclas de objeto (usando JS .sort() predeterminado). También se puede proporcionar una función de comparación para definir el comportamiento de clasificación. |
showArrayIndices | boolean | true | Ya sea para mostrar o no el índice (como clave de propiedad) para elementos de matriz. |
showStringQuotes | boolean | true | Si mostrar o no valores de cadena en "Cotizaciones". |
showCollectionCount | boolean|"when-closed" | true | Si mostrar o no el número de elementos en cada colección (objeto o matriz). |
defaultValue | any|DefaultValueFilterFunction | null | Cuando se agrega una nueva propiedad, se inicializa con este valor. Se puede proporcionar una función con casi la misma entrada que la FilterFunction S, pero debe obtener un valor. Esto permite utilizar un valor predeterminado diferente según el estado de datos (por ejemplo, el valor predeterminado para el nivel superior es un objeto, pero una cadena en otro lugar). |
stringTruncate | number | 250 | Los valores de cadena más largos que esto, muchos caracteres se mostrarán truncados (con ... ). La cadena completa siempre será visible al editar. |
translations | Objeto LocalisedStrings | { } | Las cadenas de interfaz de usuario (como los mensajes de error) se pueden traducir pasando un objeto que contiene valores de cadena localizados (solo hay unos pocos). Ver localización |
theme | ThemeInput | default | Cualquiera de los temas incorporados (importados por separado), o un objeto que especifica algunas o todas las propiedades del tema. Ver temas. |
className | string | Nombre de una clase CSS para aplicar al componente. En la mayoría de los casos, especificar las propiedades theme será más sencillo. | |
id | string | Nombre para el atributo de id HTML en el contenedor de componentes principales. | |
icons | {[iconName]: JSX.Element, ... } | { } | Reemplace los iconos incorporados especificándolos aquí. Ver temas. |
minWidth | number|string (valor CSS) | 250 | Ancho mínimo para el contenedor del editor. |
maxWidth | number|string (valor CSS) | 600 | Ancho máximo para el contenedor del editor. |
rootFontSize | number|string (valor CSS) | 16px | El tamaño de la fuente "base" del que se derivan todas las demás cedidades (en em s). Al cambiar esto, escalará todo el componente. recipiente. |
customNodeDefinitions | CustomNodeDefinition[] | Puede proporcionar componentes personalizados para anular nodos específicos en el árbol de datos, de acuerdo con una función de condición. Consulte Vea nodos personalizados para obtener más detalles. (Se proporciona un componente personalizado simple para convertir las cadenas de URL en enlaces activos en el paquete principal, ver aquí) | |
customText | CustomTextDefinitions | Además de localizar las cadenas de texto del componente, también puede alterarlo dinámicamente , dependiendo de los datos. Vea el texto personalizado para obtener más detalles. | |
customButtons | CustomButtonDefinition[] | [] | Puede agregar sus propios botones al panel Editar botones si desea poder realizar una operación personalizada en los datos. Ver botones personalizados |
jsonParse | (input: string) => JsonData | JSON.parse | Al editar directamente un bloque de JSON, es posible que desee permitir una entrada "más suelta", por ejemplo, 'citas individuales', comas posteriores o nombres de campo sin cotizar. En este caso, puede proporcionar un método de análisis JSON de terceros. Recomiendo JSON5, que es lo que se usa en la demostración |
jsonStringify | (data: JsonData) => string | (data) => JSON.stringify(data, null, 2) | Del mismo modo, puede anular la presentación predeterminada de la cadena JSON al comenzar a editar JSON. Puede proporcionar diferentes parámetros de formato al nativo JSON.stringify() , o proporcionar una opción de terceros, como el JSON5 mencionado anteriormente. |
errorMessageTimeout | number | 2500 | Tiempo (en milisegundos) para mostrar el mensaje de error en la interfaz de usuario. |
keyboardControls | KeyboardControls | Como se explicó anteriormente | Anular algunos o todos los controles de teclado. Consulte la personalización del teclado para más detalles. |
insertAtTop | boolean| "object | "array" | false | Si true , inserta nuevos valores en la parte superior en lugar de la parte inferior. Puede establecer el comportamiento solo para matrices u objetos configurando en "object" o "array" respectivamente. |
Se recomienda que administre el estado data usted mismo fuera de este componente, simplemente pase en un método setData , que se llama internamente para actualizar sus data . Sin embargo, esto no es obligatorio: si no proporciona un método setData , los datos se administrarán internamente, lo que estaría bien si no está haciendo nada con los datos. La alternativa es utilizar las funciones de actualización para actualizar sus data externamente, pero esto no se recomienda, excepto en circunstancias especiales, ya que puede encontrar problemas para mantener sus datos sincronizados con el estado interno (que es lo que se muestra), así como los re-renderizadores innecesarios. Las funciones de actualización deben usarse idealmente solo para implementar los efectos secundarios, verificar los errores o mutar los datos antes de configurarlos con setData .
Se puede proporcionar una devolución de llamada que se ejecuta cada vez que se produzca una actualización de datos (editar, eliminar o agregar). Es posible que desee usar esto para actualizar algún estado externo, realizar una llamada API, modificar los datos antes de guardarlos o validar la estructura de datos contra un esquema JSON. Si desea la misma función para todas las actualizaciones, entonces solo el accesorio onUpdate es suficiente. Sin embargo, si necesita algo diferente para la edición, la eliminación y la adición, puede proporcionar funciones de actualización separadas a través de los accesorios onEdit , onDelete y onAdd .
La función recibirá el siguiente objeto como parámetro:
{
newData , // data state after update
currentData , // data state before update
newValue , // the new value of the property being updated
currentValue , // the current value of the property being updated
name , // name of the property being updated
path // full path to the property being updated, as an array of property keys
// (e.g. [ "user", "friends", 1, "name" ] ) (equivalent to "user.friends[1].name")
}La función no puede devolver nada (en cuyo caso los datos se actualizan normalmente), o un valor para representar el éxito/falla, el valor de error o los datos modificados. El valor de retorno puede ser uno de los siguientes y manejarse en consecuencia:
true / void / undefined : los datos continúan la actualización como lo normalfalse : considera que la actualización es un error, por lo que los datos no se actualizan (se vuelven al valor anterior), y se muestra un mensaje de error genérico en la interfaz de usuariostring : también se consideró un error, por lo que no hay actualización de datos, pero el mensaje de error de la interfaz de usuario será su cadena proporcionada[ "value", <value> ] : le dice al componente que use el <value> devuelto en lugar de los datos de entrada. Puede usar esto para modificar automáticamente la entrada del usuario, por ejemplo, clasificar una matriz o insertar un campo de marca de tiempo en un objeto.[ "error", <value> ] : igual que string , pero en el formato de tupla más largo. Similar a las funciones de actualización, la función onChange se ejecuta a medida que cambia la entrada del usuario. Puede usar esto para restringir o restringir la entrada del usuario, por ejemplo, limitar los números a valores positivos, o prevenir los descansos de línea en las cadenas. La función debe devolver un valor para actualizar el campo de entrada del usuario, por lo que si no se realizan cambios, simplemente devuélvalo sin modificar.
El objeto de entrada es similar a la entrada de la función de actualización, pero sin el campo newData (dado que esta operación ocurre antes de actualizar los datos).
// in <JsonEditor /> props
onChange = ( { newValue , name } ) => {
if ( name === "age" && newValue < 0 ) return 0 ;
if ( name === "age" && newValue > 100 ) return 100 ;
return newValue
} onChange = ( { newValue , name } ) => {
if ( name === 'name' && typeof newValue === "string" )
return newValue . replace ( / [^a-zA-Zs]|n|r / gm , '' ) ;
return newValue ;
} Normalmente, el componente mostrará mensajes de error simples cada vez que se detecte una condición de error (por ejemplo, la entrada JSON inválida, las teclas duplicadas o los errores personalizados devueltos por las funciones onUpdate )). Sin embargo, puede proporcionar su propia devolución de llamada onError para implementar su propia interfaz de usuario de error o ejecutar efectos secundarios adicionales. (En el caso anterior, probablemente también desee deshabilitar el accesorio showErrorMessages ). La entrada a la devolución de llamada es similar a las otras devoluciones de llamada:
{
currentData , // data state before update
currentValue , // the current value of the property being updated
errorValue , // the erroneous value that failed to update the property
name , // name of the property being updated
path , // full path to the property being updated, as an array of property keys
// (e.g. [ "user", "friends", 1, "name" ] ) (equivalent to "user.friends[1].name"),
error : {
code , // one of 'UPDATE_ERROR' | 'DELETE_ERROR' | 'ADD_ERROR' | 'INVALID_JSON' | 'KEY_EXISTS'
message // the (localised) error message that would be displayed
}
}(Se puede ver un ejemplo de un error personalizado UI en la demostración con el conjunto de datos "nodos personalizados", cuando ingresa la entrada JSON inválida, se muestra una notificación de "tostadas" en lugar del mensaje de error del componente normal).
Se ejecuta una devolución de llamada similar cada vez que se copia un elemento en el portapapeles (si se pasa al accesorio enableClipboard ), pero con un parámetro de entrada diferente:
key // name of the property being copied
path // path to the property
value // the value copied to the clipboard
type // Either "path" or "value" depending on whether "Cmd/Ctrl" was pressed
stringValue // A nicely stringified version of `value`
// (i.e. what the clipboard actually receives)Dado que hay muy pocos comentarios de los usuarios al hacer clic en "Copiar", una buena idea sería presentar algún tipo de notificación en esta devolución de llamada.
Además de los botones "Copiar", "Editar" y "Eliminar" que aparecen por cada valor, puede agregar sus propios botones si necesita permitir algunas operaciones personalizadas en los datos. Proporcione una variedad de definiciones de botones en el accesorio customButtons , en la siguiente estructura de definición:
{
Element : React . FC ,
onClick : ( nodeData : NodeData , e : React . MouseEvent ) => void
} Donde NodeData es la misma estructura de datos recibida por las "funciones de actualización" anteriores.
Puede controlar qué nodos de la estructura de datos se pueden editar, eliminar o agregar a, o tener su tipo de datos cambiado, pasando las funciones del filtro. Estos se solicitarán en cada propiedad en los datos y el atributo se aplicará dependiendo de si la función devuelve true o false (los medios true no se pueden editar).
La función recibe el siguiente objeto:
{
key , // name of the property
path , // path to the property (as an array of property keys)
level , // depth of the property (with 0 being the root)
index , // index of the node within its collection (based on display order)
value , // value of the property
size , // if a collection (object, array), the number of items (null for non-collections)
parentData , // parent object containing the current node
fullData // the full (overall) data object
collapsed // whether or not the current node is in a
// "collapsed" state (only for Collection nodes)
} También hay una función de filtro disponible para el accesorio collapse , por lo que puede hacer que sus datos aparezcan con colecciones profundamente anidadas abiertas, mientras colapsan todo lo demás, por ejemplo.
Para restringir los tipos de datos, la función de filtro (tipo) es ligeramente más sofisticada. La entrada es la misma, pero la salida puede ser un boolean (que restringiría los tipos disponibles para un nodo dado a todos o ninguno ), o una serie de tipos de datos a los que se restringir. Los valores disponibles son:
"string""number""boolean""null""object""array" No existe una función de restricción específica para editar nombres de clave de objetos, pero deben devolver true tanto para restrictEdit como para restrictDelete (y restrictAdd para las colecciones), ya que cambiar un nombre clave es equivalente a eliminar una propiedad y agregar una nueva.
También puede establecer un valor predeterminado dinámico pasando una función de filtro al Propalo de Value defaultValue : la entrada es la misma que la anterior, pero también toma el nuevo valor key como su segundo parámetro, por lo que el nuevo valor puede depender de la nueva clave agregada.
El uso de todos estos filtros de restricción juntos puede permitirle hacer cumplir un esquema de datos razonablemente sofisticado.
// in <JsonEditor /> props
restrictEdit = { ( { level } ) => level === 0 }id : restrictEdit = { ( { key } ) => key === "id" }
// You'd probably want to include this in `restrictDelete` as well restrictDelete = { ( { size } ) => size !== null } restrictAdd = { ( { key } ) => key !== "address" && key !== "users" }
// "Adding" is irrelevant for non-collection nodesstring solo se pueden cambiar a cadenas u objetos (para anidar)null no está permitido en ninguna parteboolean deben permanecer booleanos restrictTypeSelection = { ( { path , value } ) => {
if ( path . includes ( 'user' ) ) return [ 'string' , 'number' , 'boolean' ]
if ( typeof value === 'boolean' ) return false
if ( typeof value === 'string' ) return [ 'string' , 'object' ]
return [ 'string' , 'number' , 'boolean' , 'array' , 'object' ] // no "null"
} }Además de controlar dinámicamente el acceso a las diversas herramientas de edición como se describió anteriormente, es posible realizar la validación completa del esquema JSON creando una función de actualización que pasa los datos a una biblioteca de validación de esquemas de terceros (por ejemplo, AJV). Esto rechazará cualquier entrada inválida y mostrará un error en la interfaz de usuario (o mediante una función OnError personalizada). Puede ver un ejemplo de esto en la demostración con el conjunto de datos "JSON Schema Validation" (y el conjunto de datos "Nodos personalizados").
Una función de validación onUpdate de ejemplo (usando AJV) podría ser algo como esto:
import { JsonEditor } from 'json-edit-react'
import Ajv from 'ajv'
import schema from './my-json-schema.json'
const ajv = new Ajv ( )
const validate = ajv . compile ( schema )
/// Etc....
// In the React component:
return
< JsonEditor
data = { jsonData }
onUpdate = { ( { newData } ) => {
const valid = validate ( newData )
if ( ! valid ) {
console . log ( 'Errors' , validate . errors )
const errorMessage = validate . errors
?. map ( ( error ) => ` ${ error . instancePath } ${ error . instancePath ? ': ' : '' } ${ error . message } ` )
. join ( 'n' )
// Send detailed error message to an external UI element, such as a "Toast" notification
displayError ( {
title : 'Not compliant with JSON Schema' ,
description : errorMessage ,
status : 'error' ,
} )
// This string returned to and displayed in json-edit-react UI
return 'JSON Schema error'
}
} }
{ ... otherProps } />Nota
Esta es una nueva característica y debe considerarse "experimental". Proporcione comentarios o sugerencias para ayudar a mejorarlo.
La propiedad restrictDrag controla qué elementos (si los hay) se pueden arrastrar a nuevas posiciones. Por defecto, esto está desactivado , por lo que debe establecer restrictDrag = false para habilitar esta funcionalidad. Al igual que las restricciones de edición anteriores, esta propiedad también puede tomar una función de filtro para el control de grano fino. Sin embargo, hay un par de consideraciones adicionales:
jsonb (Binary JSON), el orden de las claves no tiene sentido, por lo que la próxima vez que se cargue el objeto, las teclas se enumerarán alfabéticamente.restrictDrag se aplica al elemento de origen (es decir, el nodo que se está arrastrando), no al destino.restrictDelete ), ya que arrastrar un nodo a un nuevo destino es esencialmente eliminarlo y agregarlo de nuevo en otro lugar. Los datos mostrados se pueden filtrar en función de la entrada de búsqueda de un usuario. La entrada del usuario debe capturarse de forma independiente (no proporcionamos una interfaz de usuario aquí) y pasaron con el Prop. searchText . Esta entrada se elimina internamente (el tiempo se puede establecer con el apoyo searchDebounceTime ), por lo que también no es necesario. Los valores con los que se prueba el searchText se especifica con el Prop. searchFilter . De forma predeterminada (no se define searchFilter ), coincidirá con los valores de los datos (con la coincidencia parcial insensible al caso, es decir, la entrada "ILB", coincidirá con el valor "bilbo").
Puede especificar lo que debe coincidir configurando searchFilter en "key" (coincidir con los nombres de propiedad), "value" (el predeterminado descrito anteriormente) o "all" (coincidir con las propiedades y valores). Esto debería ser suficiente para la mayoría de los casos de uso, pero puede especificar su propia SearchFilterFunction . La función de búsqueda es la misma firma que las funciones de filtro anteriores, pero toma un argumento adicional para el searchText , es decir
( { key , path , level , value , ... etc } : FilterFunctionInput , searchText : string ) => boolean Hay dos funciones auxiliares ( matchNode() y matchNodeKey() ) exportadas con el paquete que podrían facilitar la creación de su función de búsqueda (estas son las funciones utilizadas internamente para las coincidencias "key" y "value" descritas anteriormente). Puedes ver lo que hacen aquí.
Se puede ver una función de búsqueda personalizada de ejemplo en la demostración con el conjunto de datos "Lista de clientes": la función de búsqueda coincide con nombre y nombre de usuario, y hace que todo el objeto "cliente" sea visible cuando una de esas coincidencias, por lo que se puede usar para encontrar una persona en particular y editar sus detalles específicos:
( { path , fullData } , searchText ) => {
// Matches *any* node that shares a path (i.e. a descendent) with a matching name/username
if ( path ?. length >= 2 ) {
const index = path ?. [ 0 ]
return (
matchNode ( { value : fullData [ index ] . name } , searchText ) ||
matchNode ( { value : fullData [ index ] . username } , searchText )
)
} else return false
} Hay una pequeña selección de temas incorporados (como se ve en la aplicación de demostración). Para usar uno de estos, solo importárelo del paquete y pasarlo como el accesorio del tema:
import { JsonEditor , githubDarkTheme } from 'json-edit-react'
// ...other imports
const MyApp = ( ) => {
const [ data , setData ] = useState ( { one : 1 , two : 2 } )
return < JsonEditor
data = { data }
setData = { setData }
theme = { githubDarkTheme }
// other props...
/>
}Los siguientes temas están disponibles en el paquete (aunque de manera realista, existen más para mostrar las capacidades: estoy abierto a mejores temas incorporados, así que no dude en crear un problema con sugerencias):
githubDarkThemegithubLightThememonoDarkThememonoLightThemecandyWrapperThemepsychedelicThemeSin embargo, puede pasar su propio objeto temático, o parte del mismo. La estructura del tema es la siguiente (esta es la definición del tema "predeterminada"):
{
displayName : 'Default' ,
fragments : { edit : 'rgb(42, 161, 152)' } ,
styles : {
container : {
backgroundColor : '#f6f6f6' ,
fontFamily : 'monospace' ,
} ,
collection : { } ,
collectionInner : { } ,
collectionElement : { } ,
dropZone : { } ,
property : '#292929' ,
bracket : { color : 'rgb(0, 43, 54)' , fontWeight : 'bold' } ,
itemCount : { color : 'rgba(0, 0, 0, 0.3)' , fontStyle : 'italic' } ,
string : 'rgb(203, 75, 22)' ,
number : 'rgb(38, 139, 210)' ,
boolean : 'green' ,
null : { color : 'rgb(220, 50, 47)' , fontVariant : 'small-caps' , fontWeight : 'bold' } ,
input : [ '#292929' , { fontSize : '90%' } ] ,
inputHighlight : '#b3d8ff' ,
error : { fontSize : '0.8em' , color : 'red' , fontWeight : 'bold' } ,
iconCollection : 'rgb(0, 43, 54)' ,
iconEdit : 'edit' ,
iconDelete : 'rgb(203, 75, 22)' ,
iconAdd : 'edit' ,
iconCopy : 'rgb(38, 139, 210)' ,
iconOk : 'green' ,
iconCancel : 'rgb(203, 75, 22)' ,
} ,
} La propiedad styles es la principal en la que centrarse. Cada clave ( property , bracket , itemCount ) se refiere a una parte de la interfaz de usuario. El valor para cada clave es :
string , en cuyo caso se interpreta como el color (o color de fondo en el caso del container y inputHighlight )null ). Esto le permite cambiar dinámicamente el estilo de varios elementos según el contenido o la estructura.null . (En la matriz, los elementos posteriores tienen mayor precedencia)Para un ejemplo simple, si desea usar el tema "Githubdark", pero simplemente cambie un par de cosas pequeñas, especificaría algo como esto:
// in <JsonEditor /> props
theme = { [
githubDarkTheme ,
{
iconEdit : 'grey' ,
boolean : { color : 'red' , fontStyle : 'italic' , fontWeight : 'bold' , fontSize : '80%' } ,
} ,
] } Que cambiaría el icono de "editar" y los valores booleanos de esto: 
En esto: 
O puede crear su propio tema desde cero y sobrescribir todo el objeto del tema.
Entonces, para resumir, el accesorio theme puede tomar :
"candyWrapperTheme"fragments , styles , displayName , etc. o solo la parte de styles (en el nivel de la raíz)[ "<themeName>, {...overrides } ]Puede jugar con la edición en vivo de los temas en la aplicación de demostración seleccionando "Edite este tema!" Desde el selector de "datos de demostración" (aunque no podrá crear funciones en JSON).
Otra forma de diseñar el componente es apuntar directamente a las clases CSS. Cada elemento en el componente tiene un nombre de clase único, por lo que debería poder ubicarlos en el inspector de su navegador y anularlos en consecuencia. Todos los nombres de clases comienzan con el prefijo jer- , por ejemplo, jer-collection-header-row , jer-value-string .
La propiedad fragments anteriores es solo una conveniencia para permitir que los "fragmentos" de estilo repetido se definan una vez y se refieran al uso de un alias. Por ejemplo, si quería que todos sus íconos sean azules y ligeramente más grandes y espaciados, podría definir un fragmento así:
fragments: { iconAdjust : { color : "blue" , fontSize : "110%" , marginRight : "0.6em" } }Luego, en el objeto del tema, solo use:
{
... ,
iconEdit : "iconAdjust" ,
iconDelete : "iconAdjust" ,
iconAdd : "iconAdjust" ,
iconCopy : "iconAdjust" ,
}Luego, cuando desee ajustarlo más tarde, ¡solo necesita actualizarlo en un solo lugar!
Los fragmentos también se pueden mezclar con propiedades adicionales e incluso otros fragmentos, como así:
iconEdit: [ "iconAdjust" , "anotherFragment" , { marginLeft : "1em" } ] Internamente, todo el tamaño y el espaciado se realizan en em S, nunca px (aparte de rootFontSize , que establece el tamaño de "base"). Esto hace que la escala sea mucho más fácil: simplemente cambie el accesorio rootFontSize (o establezca fontSize en el contenedor principal mediante la orientación de la clase, o ajustando el tema) y vea la escala completa del componente en consecuencia.
Los iconos predeterminados se pueden reemplazar, pero debe proporcionarlos como elementos React/HTML. Simplemente defina cualquiera o todos ellos dentro del apoyo icons , con el siguiente aspecto:
icons = { {
add : < YourIcon />
edit : < YourIcon / >
delete : < YourIcon />
copy : < YourIcon / >
ok : < YourIcon / >
cancel : < YourIcon / >
chevron : < YourIcon / >
} }Los componentes del icono necesitarán tener sus propios estilos definidos, ya que los estilos temáticos no se agregarán a los elementos personalizados.
Localice su implementación pasando un objeto translations para reemplazar las cadenas predeterminadas. Las claves y los valores predeterminados (inglés) son los siguientes:
{
ITEM_SINGLE : '{{count}} item' ,
ITEMS_MULTIPLE : '{{count}} items' ,
KEY_NEW : 'Enter new key' ,
ERROR_KEY_EXISTS : 'Key already exists' ,
ERROR_INVALID_JSON : 'Invalid JSON' ,
ERROR_UPDATE : 'Update unsuccessful' ,
ERROR_DELETE : 'Delete unsuccessful' ,
ERROR_ADD : 'Adding node unsuccessful' ,
DEFAULT_STRING : 'New data!' ,
DEFAULT_NEW_KEY : 'key' ,
} Puede reemplazar ciertos nodos en el árbol de datos con sus propios componentes personalizados. Un ejemplo puede ser para una pantalla de imagen, o un editor de fechas personalizado, o simplemente para agregar algo de brillo visual. Consulte el conjunto de datos de "nodos personalizados" en la demostración interactiva para verlo en acción. (También hay un selector de fecha personalizado que aparece al editar cadenas ISO en los otros conjuntos de datos).
Los nodos personalizados se proporcionan en el accesorio customNodeDefinitions , como una matriz de objetos de la siguiente estructura:
{
condition , // a FilterFunction, as above
element , // React Component
customNodeProps , // object (optional)
hideKey , // boolean (optional)
defaultValue , // JSON value for a new instance of your component
showOnEdit // boolean, default false
showOnView // boolean, default true
showEditTools // boolean, default true
name // string (appears in Types selector)
showInTypesSelector , // boolean (optional), default false
// Only affects Collection nodes:
showCollectionWrapper // boolean (optional), default true
wrapperElement // React component (optional) to wrap *outside* the normal collection wrapper
wrapperProps // object (optional) -- props for the above wrapper component
} La condition es solo una función de filtro, con los mismos parámetros de entrada ( key , path , value , etc.), y element es un componente React. Cada nodo en la estructura de datos se ejecutará a través de cada función de condición, y cualquiera que coincida será reemplazado por su componente personalizado. Tenga en cuenta que si un nodo coincide con más de una condición de definición personalizada (de múltiples componentes), el primero se utilizará, así que colóquelos en la matriz en orden de prioridad.
El componente recibirá los mismos accesorios que un componente de nodo estándar (consulte la base de código), pero puede pasar accesorios adicionales a su componente si es necesario a través del objeto customNodeProps . Un ejemplo exhaustivo de un selector de fecha personalizado se usa en la demostración (junto con un par de otros presentes más básicos), que puede inspeccionar para ver cómo utilizar los accesorios estándar y un par de accesorios personalizados. Ver el código fuente aquí
Por defecto, su componente se presentará a la derecha de la clave de propiedad a la que pertenece, como cualquier otro valor. Sin embargo, puede ocultar la tecla en sí configurando hideKey: true , y el componente personalizado tomará toda la fila. (Consulte el conjunto de datos "Presentado por" en el conjunto de datos "Nodos personalizados" para un ejemplo).
Además, de forma predeterminada, su componente se tratará como un elemento de "pantalla", es decir, aparecerá en el visor JSON, pero al editar, volverá a la interfaz de edición estándar. Sin embargo, esto se puede cambiar con los accesorios de showOnEdit , showOnView y showEditTools . Por ejemplo, solo se puede requerir un selector de fecha al editar y dejarlo como para mostrar. El accesorio de showEditTools se refiere a los íconos de edición (copiar, agregar, editar, eliminar) que aparecen a la derecha de cada valor en el flotador. Si elige deshabilitarlos pero aún desea que su componente tenga un modo de "editar", deberá proporcionar su propio mecanismo de interfaz de usuario para alternar la edición.
Puede permitir a los usuarios crear nuevas instancias de sus nodos especiales seleccionándolos como un "tipo" en el selector de tipos al editar/agregar valores. Establecer showInTypesSelector: true para habilitar esto. Sin embargo, si esto está habilitado, también debe proporcionar un name (que es lo que el usuario verá en el selector) y un defaultValue , que son los datos que se insertan cuando el usuario selecciona este "tipo". (El defaultValue debe devolver true si se pasa a través de la función condition para que se muestre inmediatamente utilizando su componente personalizado).
Se proporciona un componente y definición personalizados simples para convertir las cadenas de URL en enlaces que se pueden hacer clic en el paquete principal para que pueda usar fuera de la caja. Simplemente importe y use así:
import { JsonEditor , LinkCustomNodeDefinition } from 'json-edit-react'
// ...Other stuff
return (
< JsonEditor
{ ... otherProps }
customNodeDefinitions = { [ LinkCustomNodeDefinition , ... otherCustomDefinitions ] }
/>
) En la mayoría de los casos, será preferible (y más simple) crear nodos personalizados para hacer coincidir los nodos de valor (es decir, no los array de recolección de objetos u object ), que es lo que muestran todos los ejemplos de demostración. Sin embargo, si desea apuntar a un nodo de recolección completo, hay un par de otras cosas que saber:
children , simplemente se convierte en responsabilidad de su componente de manejarlo.element regulares, que se mostrará dentro de los soportes de colección (es decir, aparece como el contenido de la colección)wrapperElement opcional, que se muestra fuera de la colección (los accesorios se pueden suministrar como se describe anteriormente con wrapperProps ). Nuevamente, el contenido interno (incluido su element personalizado) se puede mostrar con children React. En este ejemplo, el borde azul muestra el wrapperElement y el borde rojo muestra el element interno: 
showCollectionWrapper (verdadero true ), que, cuando se establece en false , oculta los elementos de recolección circundantes (es decir, el Chevron y los soportes de Hide/Show). En este caso, tendría que proporcionar su propio mecanismo de ocultación/show en su componente si lo desea. Es posible cambiar las diversas cadenas de texto que se muestran por el componente. Puede localizarlo, pero también puede especificar funciones para anular el texto que se muestra en función de ciertas condiciones. Por ejemplo, digamos que queremos que el texto del recuento de propiedades (por ejemplo, 6 items ) por defecto) proporcione un resumen de un cierto tipo de nodo, que puede verse bien cuando se derrumba. Por ejemplo (tomado de la demostración):

La propiedad customText toma un objeto, con cualquiera de las claves localizables como claves, con una función que devuelve una cadena (o null , que hace que se retire a la cadena localizada o predeterminada). La entrada a estas funciones es la misma que para las funciones del filtro, por lo que en este ejemplo, se definiría así:
// The function definition
const itemCountReplacement = ( { key , value , size } ) => {
// This returns "Steve Rogers (Marvel)" for the node summary
if ( value instanceof Object && 'name' in value )
return ` ${ value . name } ( ${ ( value ) ?. publisher ?? '' } )`
// This returns "X names" for the alias lists
if ( key === 'aliases' && Array . isArray ( value ) )
return ` ${ size } ${ size === 1 ? 'name' : 'names' } `
// Everything else as normal
return null
}
// And in component props...
. . . otherProps ,
customText = {
ITEM_SINGLE : itemCountReplacement ,
ITEMS_MULTIPLE : itemCountReplacement ,
} Los controles de teclado predeterminados se describen anteriormente, pero es posible personalizar/anularlos. Simplemente pase en un accesorio keyboardControls con las acciones que desea anular definidas. El objeto de configuración predeterminado es:
{
confirm : 'Enter' , // default for all Value nodes, and key entry
cancel : 'Escape' ,
objectConfirm : { key : 'Enter' , modifier : [ 'Meta' , 'Shift' , 'Control' ] } ,
objectLineBreak : 'Enter' ,
stringConfirm : 'Enter' ,
stringLineBreak : { key : 'Enter' , modifier : 'Shift' } ,
numberConfirm : 'Enter' ,
numberUp : 'ArrowUp' ,
numberDown : 'ArrowDown' ,
booleanConfirm : 'Enter' ,
clipboardModifier : [ 'Meta' , 'Control' ] ,
collapseModifier : 'Alt' ,
}Si (por ejemplo), solo desea cambiar la acción general de "confirmación" a "cmd-enter" (en Mac), o "ctrl-enter", solo pasaría:
keyboardControls = {
confirm : {
key : "Enter" ,
modifier : [ "Meta" , "Control" ]
}
}Consideraciones :
stringConfirm , numberConfirm y booleanConfirm si deben diferir de su valor confirm .clipboardModifier predeterminado). Aunque la funcionalidad de deshacer/rehacer probablemente sea deseable en la mayoría de los casos, esto no está integrado en el componente, por dos razones principales:
Se exportan algunas funciones, componentes y tipos que pueden ser útiles en sus propias implementaciones (desde la creación de funciones de filtro o actualización, o componentes personalizados) desde el paquete:
themes : un objeto que contiene todas las definiciones de temas incorporadosLinkCustomComponent : el componente utilizado para renderizar hipervínculosLinkCustomNodeDefinition : definición de nodo personalizado para hipervínculosIconAdd , IconEdit , IconDelete , IconCopy , IconOk , IconCancel , IconChevron : todos los componentes de icono incorporadosmatchNode , matchNodeKey : ayudantes para definir funciones de búsqueda personalizadastruncate : función para truncar una cadena a una longitud especificada. Ver aquíextract : función para extraer un valor de objeto profundamente anidado de una ruta de cadena. Ver aquíassign : función para establecer un valor de objeto profundo de una ruta de cadena. Ver aquíThemeName : Lista literal de cadenas de nombres de temas incorporadosTheme : un objeto de tema completoThemeInput : Tipo de entrada para el accesorio themeJsonEditorProps : Todos los accesorios de entrada para el componente del editor JSONJsonData : objeto data principales: cualquier estructura JSON válidaUpdateFunction , OnChangeFunction , OnErrorFunction FilterFunction , CopyFunction , SearchFilterFunction , CompareFunction , TypeFilterFunction , LocalisedString , CustomNodeDefinition , CustomTextDefinitions , CustomTextFunction ,TranslateFunction : función que toma una clave de localización y devuelve una cadena traducidaIconReplacements : tipo de entrada para el accesorio iconsCollectionNodeProps : todos los accesorios pasaron internamente a nodos de "colección" (es decir, objetos/matrices)ValueNodeProps : todos los accesorios pasaron internamente a nodos de "valor" (es decir, no objetos/matrices)CustomNodeProps : todos los accesorios pasaron internamente a nodos personalizados; Básicamente, lo mismo que CollectionNodeProps con un campo adicional customNodeProps para pasar accesorios exclusivos de su componente 'DataType : "string" | "number" | "boolean" | "null" | "object" | "array"KeyboardControls : estructura para el accesorio de personalización del teclado Abra un problema: https://github.com/carlosnz/json-edit-react/issues
Las características principales que me gustaría presentar son:
This component is heavily inspired by react-json-view, a great package that I've used in my own projects. However, it seems to have been abandoned now, and requires a few critical fixes, so I decided to create my own from scratch and extend the functionality while I was at it.
defaultValue function takes the new key as second parameteroverflow: clip setting based on animating statetrue to represent successsetData prop to discourage reliance on internal data state managementuseEffect hooksnull #90onError callback available for custom error handlingrootFontSize prop to set the "base" size for the componentonChange prop to allow validation/restriction of user input as they typedata if user hasn't actually changed a value (prevents Undo from being unnecessarily triggered)wrapperElement propid propindex in Filter (and other) function inputdefaultValue prop