
Un composant réact pour modifier ou afficher les données JSON / objet

Important
Changements de rupture:
theme . Les thèmes intégrés doivent désormais être importés séparément et transmis, plutôt que de simplement nommer le thème en tant que chaîne. C'est mieux pour les thèmes des arbres, donc les thèmes inutilisés ne seront pas regroupés avec votre construction. Voir les thèmes et les stylessetData et de ne pas utiliser onUpdate pour mettre à jour vos données en externe. Voir la gestion de l'état. npm i json-edit-react
ou
yarn add json-edit-react
import { JsonEditor } from 'json-edit-react'
// In your React component:
return
< JsonEditor
data = { jsonData }
setData = { setJsonData } // optional
{ ... otherProps } /> (pour l'utilisateur final)
C'est assez explicite (cliquez sur l'icône "Modifier" pour modifier, etc.), mais il existe quelques façons pas si évidentes d'interagir avec l'éditeur:
Cmd/Ctrl/Shift-Enter pour ajouter une nouvelle ligne ( Enter soumet la valeur)Enter pour une nouvelle ligne, et Cmd/Ctrl/Shift-Enter pour soumettreEscape pour annuler l'éditionCmd/Ctrl copiera le chemin du nœud sélectionné plutôt que sa valeurjsonParse Prop. La seule valeur requise est data (bien que vous deviez fournir une méthode setData pour mettre à jour vos données).
| soutenir | taper | défaut | description |
|---|---|---|---|
data | object|array | Les données à afficher / éditées | |
setData | object|array => void | Méthode pour mettre à jour votre objet data . Voir la gestion de l'état ci-dessous pour des notes supplémentaires. | |
rootName | string | "data" | Un nom à afficher dans l'éditeur comme racine de l'objet de données. |
onUpdate | UpdateFunction | Une fonction à exécuter chaque fois qu'une valeur est mise à jour (modifier, supprimer ou ajouter) dans l'éditeur. Voir les fonctions de mise à jour. | |
onEdit | UpdateFunction | Une fonction à exécuter chaque fois qu'une valeur est modifiée . | |
onDelete | UpdateFunction | Une fonction à exécuter chaque fois qu'une valeur est supprimée . | |
onAdd | UpdateFunction | Une fonction à exécuter chaque fois qu'une nouvelle propriété est ajoutée . | |
onChange | OnChangeFunction | Une fonction pour modifier / contraindre l'entrée de l'utilisateur au fur et à mesure qu'ils tapent - voir les fonctions OnChange. | |
onError | OnErrorFunction | Une fonction à exécuter chaque fois que le composant rapporte une erreur - voir onErrorFunction. | |
showErrorMessages | boolean | true | Que le composant soit ou non afficher ses propres messages d'erreur (vous ne souhaitez probablement désactiver cela que si vous avez fourni votre propre fonction onError ) |
enableClipboard | boolean|CopyFunction | true | Que ce soit pour activer ou non le bouton "Copier dans le presse-papiers" dans l'interface utilisateur. Si une fonction est fournie, true est supposé et cette fonction sera exécutée chaque fois qu'un élément est copié. |
indent | number | 3 | Spécifiez la quantité d'indentation pour chaque niveau de nidification dans les données affichées. |
collapse | boolean|number|FilterFunction | false | Définit les nœuds de l'arborescence JSON s'afficheront "ouverts" dans l'interface utilisateur sur charge. Si boolean , ce sera tout ou pas. Un number spécifie une profondeur de nidification, après quoi les nœuds seront fermés. Pour un contrôle plus fin, une fonction peut être fournie - voir les fonctions du filtre. |
collapseAnimationTime | number | 300 | Temps (en millisecondes) pour l'animation de transition lors de l'effondrement des nœuds de collecte. |
restrictEdit | boolean|FilterFunction | false | Si true , aucun montage n'est autorisé. Une fonction peut être fournie pour plus de spécificité - voir les fonctions du filtre |
restrictDelete | boolean|FilterFunction | false | Comme pour restrictEdit mais pour la suppression |
restrictAdd | boolean|FilterFunction | false | Comme avec restrictEdit mais pour ajouter de nouvelles propriétés |
restrictTypeSelection | boolean|DataType[]|TypeFilterFunction | true | Pour restreindre les types de données que l'utilisateur peut sélectionner. Peut être une liste des types de données (par exemple [ 'string', 'number', 'boolean', 'array', 'object', 'null' ] ) ou un booléen. Une fonction peut être fournie - elle doit prendre la même entrée que la fonction FilterFunction ci-dessus, mais la sortie doit être boolean | DataType[] . |
restrictDrag | boolean|FilterFunction | true | Définissez sur false pour activer les fonctionnalités de glisser-déposer. Voir drag-n-drop |
searchText | string | undefined | La visibilité des données sera filtrée en correspondant à la valeur, en utilisant la méthode définie ci-dessous dans searchFilter |
searchFilter | "key"|"value"|"all"|SearchFilterFunction | undefined | Définissez comment searchText doit être apparié pour filtrer les éléments visibles. Voir la recherche / filtrage |
searchDebounceTime | number | 350 | Déboucher le temps lorsque searchText change |
keySort | boolean|CompareFunction | false | Si true , les touches d'objet seront commandées (en utilisant JS .sort() ) par défaut. Une fonction de comparaison peut également être fournie pour définir le comportement de tri. |
showArrayIndices | boolean | true | S'il faut afficher ou non l'index (en tant que clé de propriété) pour les éléments du tableau. |
showStringQuotes | boolean | true | S'il faut afficher ou non les valeurs de chaîne dans "Citations". |
showCollectionCount | boolean|"when-closed" | true | S'il faut afficher ou non le nombre d'éléments dans chaque collection (objet ou tableau). |
defaultValue | any|DefaultValueFilterFunction | null | Lorsqu'une nouvelle propriété est ajoutée, elle est initialisée avec cette valeur. Une fonction peut être fournie avec presque la même entrée que la FilterFunction S, mais doit produire une valeur. Cela permet d'utiliser une valeur par défaut différente en fonction de l'état de données (par exemple, la valeur par défaut pour le niveau supérieur est un objet, mais une chaîne ailleurs.) |
stringTruncate | number | 250 | Des valeurs de chaîne plus longues que ces nombreux caractères seront affichées tronquées (avec ... ). La chaîne complète sera toujours visible lors de l'édition. |
translations | Objet LocalisedStrings | { } | Les chaînes d'interface utilisateur (telles que les messages d'erreur) peuvent être traduites en passant un objet contenant des valeurs de chaîne localisées (il n'y en a que quelques-unes). Voir la localisation |
theme | ThemeInput | default | Soit l'un des thèmes intégrés (importés séparément), soit un objet spécifiant certaines ou toutes les propriétés du thème. Voir les thèmes. |
className | string | Nom d'une classe CSS à s'appliquer au composant. Dans la plupart des cas, la spécification des propriétés theme sera plus simple. | |
id | string | Nom de l'attribut id HTML sur le conteneur de composant principal. | |
icons | {[iconName]: JSX.Element, ... } | { } | Remplacez les icônes intégrées en les spécifiant ici. Voir les thèmes. |
minWidth | number|string (valeur CSS) | 250 | Largeur minimale pour le conteneur de l'éditeur. |
maxWidth | number|string (valeur CSS) | 600 | Largeur maximale pour le conteneur de l'éditeur. |
rootFontSize | number|string (valeur CSS) | 16px | La taille de la police "de base" à partir de laquelle toutes les autres tailles sont dérivées (en em ). En modifiant cela, vous allez mettre à l'échelle l'ensemble du composant. récipient. |
customNodeDefinitions | CustomNodeDefinition[] | Vous pouvez fournir des composants personnalisés pour remplacer les nœuds spécifiques dans l'arborescence de données, selon une fonction de condition. Voir Voir les nœuds personnalisés pour plus de détails. (Un composant personnalisé simple pour transformer les chaînes d'URL en liens actifs est fourni dans le package principal - voir ici) | |
customText | CustomTextDefinitions | En plus de localiser les chaînes de texte des composants, vous pouvez également les modifier dynamiquement , selon les données. Voir le texte personnalisé pour plus de détails. | |
customButtons | CustomButtonDefinition[] | [] | Vous pouvez ajouter vos propres boutons au panneau de boutons Modifier si vous souhaitez pouvoir effectuer une opération personnalisée sur les données. Voir les boutons personnalisés |
jsonParse | (input: string) => JsonData | JSON.parse | Lorsque vous modifiez directement un bloc de JSON, vous souhaiterez peut-être autoriser une entrée "plus lâche" - par exemple "citations simples", des virgules de fin ou des noms de champ non. Dans ce cas, vous pouvez fournir une méthode d'analyse JSON tierce. Je recommande JSON5, qui est ce qui est utilisé dans la démo |
jsonStringify | (data: JsonData) => string | (data) => JSON.stringify(data, null, 2) | De même, vous pouvez remplacer la présentation par défaut de la chaîne JSON lors du début de l'édition de JSON. Vous pouvez fournir différents paramètres de formatage au natif JSON.stringify() , ou fournir une option tierce, comme le JSON5 susmentionné. |
errorMessageTimeout | number | 2500 | Temps (en millisecondes) pour afficher le message d'erreur dans l'interface utilisateur. |
keyboardControls | KeyboardControls | Comme expliqué ci-dessus | Remplacez certains ou tous les commandes du clavier. Voir Personnalisation du clavier pour plus de détails. |
insertAtTop | boolean| "object | "array" | false | Si true , insère de nouvelles valeurs en haut plutôt qu'en bas. Peut définir le comportement uniquement pour les tableaux ou les objets en définissant respectivement "object" ou "array" . |
Il est recommandé de gérer vous-même l'état data en dehors de ce composant - il suffit de passer une méthode setData , qui est appelée en interne pour mettre à jour vos data . Cependant, ce n'est pas obligatoire - si vous ne fournissez pas de méthode setData , les données seront gérées en interne, ce qui serait bien si vous ne faites rien avec les données. L'alternative consiste à utiliser les fonctions de mise à jour pour mettre à jour vos data à l'extérieur, mais cela n'est pas recommandé, sauf dans des circonstances particulières, car vous pouvez rencontrer des problèmes en gardant vos données en synchronisation avec l'état interne (ce qui est affiché), ainsi que des redevateurs inutiles. Les fonctions de mise à jour doivent être idéalement utilisées uniquement pour implémenter les effets secondaires, vérifier les erreurs ou muter les données avant de les définir avec setData .
Un rappel à exécuter chaque fois qu'une mise à jour de données (modifier, supprimer ou ajouter) se produit. Vous souhaiterez peut-être l'utiliser pour mettre à jour un état externe, passer un appel API, modifier les données avant de les enregistrer ou valider la structure de données par rapport à un schéma JSON. Si vous voulez la même fonction pour toutes les mises à jour, alors le proportion onUpdate est suffisant. Cependant, si vous avez besoin de quelque chose de différent pour l'édition, la suppression et l'ajout, vous pouvez fournir des fonctions de mise à jour distinctes via les accessoires onEdit , onDelete et onAdd .
La fonction recevra l'objet suivant en tant que paramètre:
{
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 fonction ne peut rien retourner (auquel cas les données sont mises à jour normalement), ou une valeur pour représenter le succès / l'échec, la valeur d'erreur ou les données modifiées. La valeur de retour peut être l'une des opérations suivantes et gérée en conséquence:
true / void / undefined : les données continuent la mise à jour comme d'habitudefalse : considère la mise à jour comme une erreur, donc les données ne sont pas mises à jour (revient à la valeur précédente), et un message d'erreur générique s'affiche dans l'interface utilisateurstring : également considéré comme une erreur, donc pas de mise à jour des données, mais le message d'erreur de l'interface utilisateur sera votre chaîne fournie[ "value", <value> ] : dit au composant d'utiliser le <value> renvoyé au lieu des données d'entrée. Vous pouvez l'utiliser pour modifier automatiquement l'entrée de l'utilisateur - par exemple, le tri d'un tableau ou l'insertion d'un champ d'horodatage dans un objet.[ "error", <value> ] : Identique à string , mais au format Tuple plus long. Semblable aux fonctions de mise à jour, la fonction onChange est exécutée à mesure que l'entrée utilisateur change. Vous pouvez l'utiliser pour restreindre ou limiter l'entrée de l'utilisateur - par exemple, limiter les nombres aux valeurs positives, ou empêcher les ruptures de ligne dans les chaînes. La fonction doit renvoyer une valeur afin de mettre à jour le champ de saisie de l'utilisateur, donc si aucune modification n'est apportée, renvoyez-la non modifiée.
L'objet d'entrée est similaire à l'entrée de fonction de mise à jour, mais sans champ newData (car cette opération se produit avant la mise à jour des données).
// 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 ;
} Normalement, le composant affichera des messages d'erreur simples chaque fois qu'une condition d'erreur est détectée (par exemple, l'entrée JSON non valide, les touches en double ou les erreurs personnalisées renvoyées par les fonctions onUpdate )). Cependant, vous pouvez fournir votre propre rappel onError afin d'implémenter votre propre interface utilisateur d'erreur ou d'exécuter des effets secondaires supplémentaires. (Dans le premier cas, vous voudriez probablement désactiver le conduit showErrorMessages aussi.) L'entrée du rappel est similaire aux autres rappels:
{
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
}
}(Un exemple d'une interface utilisateur d'erreur personnalisée peut être vu dans la démo avec l'ensemble de données "Nœuds personnalisés" - lorsque vous entrez une entrée JSON non valide, une notification "Toast" s'affiche au lieu du message d'erreur du composant normal.)
Un rappel similaire est exécuté chaque fois qu'un élément est copié dans le presse-papiers (s'il est transmis à l' enableClipboard Prop), mais avec un paramètre d'entrée différent:
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)Puisqu'il y a très peu de commentaires des utilisateurs lors de la cliquetis "Copier", une bonne idée serait de présenter une sorte de notification dans ce rappel.
En plus des boutons "copier", "modifier" et "supprimer" qui apparaissent par chaque valeur, vous pouvez ajouter vos propres boutons si vous devez autoriser certaines opérations personnalisées sur les données. Fournissez un tableau de définitions de bouton dans l'hélice customButtons , dans la structure de définition suivante:
{
Element : React . FC ,
onClick : ( nodeData : NodeData , e : React . MouseEvent ) => void
} Où NodeData est la même structure de données reçue par les "fonctions de mise à jour" précédentes.
Vous pouvez contrôler les nœuds de la structure de données peuvent être modifiés, supprimés ou ajoutés, ou faire modifier leur type de données, en passant des fonctions de filtre. Ceux-ci seront appelés sur chaque propriété dans les données et l'attribut sera appliqué selon que la fonction renvoie true ou false (les moyens true ne peuvent pas être modifiés).
La fonction reçoit l'objet suivant:
{
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)
} Une fonction de filtre est également disponible pour l'hélice collapse , de sorte que vos données apparaissent avec des collections profondément imbriquées ouvertes, tout en effondrant tout le reste, par exemple.
Pour restreindre les types de données, la fonction (type) du filtre est légèrement plus sophistiquée. L'entrée est la même, mais la sortie peut être soit un boolean (qui restreindrait les types disponibles pour un nœud donné à tout ou à aucun ), soit un tableau de types de données à limiter. Les valeurs disponibles sont:
"string""number""boolean""null""object""array" Il n'y a pas de fonction de restriction spécifique pour l'édition de noms de clés d'objets, mais ils doivent retourner true pour la restrictEdit et restrictDelete (et restrictAdd les collections), car le changement de nom de clé est équivalent à supprimer une propriété et à en ajouter un nouveau.
Vous pouvez également définir une valeur par défaut dynamique en passant une fonction de filtre au Prop defaultValue - l'entrée est la même que celle ci-dessus, mais prend également la nouvelle valeur key comme deuxième paramètre, de sorte que la nouvelle valeur peut dépendre de la nouvelle clé ajoutée.
L'utilisation de tous ces filtres de restriction peut vous permettre d'appliquer un schéma de données raisonnablement sophistiqué.
// in <JsonEditor /> props
restrictEdit = { ( { level } ) => level === 0 }id être édité: 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 ne peuvent être changées que en chaînes ou objets (pour la nidification)null n'est autorisé nulle partboolean doivent rester booléennes 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"
} }En plus de contrôler dynamiquement l'accès aux différents outils d'édition comme décrit ci-dessus, il est possible de faire la validation complète du schéma JSON en créant une fonction de mise à jour qui transmet les données à une bibliothèque de validation de schéma du 3e schéma (par exemple AJV). Cela rejettera ensuite toute entrée non valide et affichera une erreur dans l'interface utilisateur (ou via une fonction ONERROR personnalisée). Vous pouvez en voir un exemple dans la démo avec l'ensemble de données "JSON Schema Validation" (et l'ensemble de données "Nœuds personnalisés").
Un exemple de fonction de validation onUpdate (en utilisant AJV) pourrait être quelque chose comme ceci:
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 } />Note
Il s'agit d'une nouvelle fonctionnalité et doit être considéré comme "expérimental". Veuillez fournir des commentaires ou des suggestions pour aider à l'améliorer.
La propriété restrictDrag contrôle quels éléments (le cas échéant) peuvent être traînés dans de nouvelles positions. Par défaut, cela est désactivé , vous devez donc définir restrictDrag = false pour activer cette fonctionnalité. Comme les restrictions d'édition ci-dessus, cette propriété peut également prendre une fonction de filtre pour un contrôle à grain fin. Il y a cependant quelques considérations supplémentaires:
jsonb (JSON binaire), l'ordre des clés est dénué de sens, donc la prochaine fois que l'objet sera chargé, les clés seront répertoriées par ordre alphabétique.restrictDrag s'applique à l'élément source (c'est-à-dire que le nœud est glissé), pas à la destination.restrictDelete ), car faire glisser un nœud vers une nouvelle destination est essentiellement simplement le supprimer et le ajouter ailleurs. Les données affichées peuvent être filtrées en fonction des entrées de recherche d'un utilisateur. L'entrée de l'utilisateur doit être capturée indépendamment (nous ne fournissons pas d'interface utilisateur ici) et transmises avec l'hélice searchText . Cette entrée est débonvenée en interne (le temps peut être défini avec le Prop de searchDebounceTime ), donc pas besoin de cela également. Les valeurs contre lesquelles le searchText sont testées sont spécifiées avec la propulsion de recherche searchFilter . Par défaut (aucune searchFilter définie), elle correspondra aux valeurs de données (avec une correspondance partielle insensible à la cas - c'est-à-dire l'entrée "Ilb", la valeur "Bilbo").
Vous pouvez spécifier ce qui devrait être égalé en définissant searchFilter sur "key" (correspondant des noms de propriétés), "value" (la par défaut décrite ci-dessus) ou "all" (correspondent à la fois à des propriétés et des valeurs). Cela devrait être suffisant pour la majorité des cas d'utilisation, mais vous pouvez spécifier votre propre SearchFilterFunction . La fonction de recherche est la même signature que les filtres ci-dessus mais prend un argument supplémentaire pour le searchText
( { key , path , level , value , ... etc } : FilterFunctionInput , searchText : string ) => boolean Il existe deux fonctions d'assistance ( matchNode() et matchNodeKey() ) exportées avec le package qui pourrait faciliter la création de votre fonction de recherche (ce sont les fonctions utilisées en interne pour la "key" et "value" correspond aux correspondances ci-dessus). Vous pouvez voir ce qu'ils font ici.
Un exemple de fonction de recherche personnalisée peut être vu dans la démo avec l'ensemble de données "liste client" - la fonction de recherche correspond par nom et nom d'utilisateur, et rend l'objet "client" entier visible lorsque l'une de ces correspondances, il peut donc être utilisée pour trouver une personne en particulier et modifier ses détails spécifiques:
( { 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
} Il existe une petite sélection de thèmes intégrés (comme on le voit dans l'application de démonstration). Afin d'utiliser l'un d'eux, il suffit de l'importer du package et de le passer comme l'hélice du thème:
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...
/>
}Les thèmes suivants sont disponibles dans le package (bien que de manière réaliste, celles-ci existent davantage pour présenter les capacités - je suis ouvert à de meilleurs thèmes intégrés, alors n'hésitez pas à créer un problème avec des suggestions):
githubDarkThemegithubLightThememonoDarkThememonoLightThemecandyWrapperThemepsychedelicThemeCependant, vous pouvez transmettre votre propre objet de thème ou une partie de celui-ci. La structure du thème est la suivante (il s'agit de la définition du thème "par défaut"):
{
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 propriété styles est la principale sur laquelle se concentrer. Chaque clé ( property , bracket , itemCount ) fait référence à une partie de l'interface utilisateur. La valeur pour chaque clé est soit :
string , auquel cas il est interprété comme la couleur (ou la couleur d'arrière-plan dans le cas de container et inputHighlight )null ). Cela vous permet de modifier dynamiquement le style de divers éléments en fonction du contenu ou de la structure.null . (Dans le tableau, les derniers éléments ont une priorité plus élevée)Pour un exemple simple, si vous souhaitez utiliser le thème "Githubdark", mais changez simplement quelques petites choses, vous spécifieriez quelque chose comme ceci:
// in <JsonEditor /> props
theme = { [
githubDarkTheme ,
{
iconEdit : 'grey' ,
boolean : { color : 'red' , fontStyle : 'italic' , fontWeight : 'bold' , fontSize : '80%' } ,
} ,
] } Ce qui changerait l'icône "Modifier" et les valeurs booléennes de ceci: 
dans ceci: 
Ou vous pouvez créer votre propre thème à partir de zéro et écraser l'ensemble de l'objet de thème.
Ainsi, pour résumer, l'hélice theme peut prendre soit :
"candyWrapperTheme"fragments , styles , displayName , etc., ou simplement la partie styles (au niveau racine)[ "<themeName>, {...overrides } ]Vous pouvez jouer avec l'édition en direct des thèmes dans l'application de démonstration en sélectionnant "Modifier ce thème!" à partir du sélecteur "Dono Data" (bien que vous ne puissiez pas créer des fonctions dans JSON).
Une autre façon de styliser le composant consiste à cibler directement les classes CSS. Chaque élément du composant a un nom de classe unique, vous devriez donc être en mesure de les localiser dans votre inspecteur de navigateur et de les remplacer en conséquence. Tous les noms de classe commencent par le préfixe jer- , par exemple jer-collection-header-row , jer-value-string .
La propriété fragments ci-dessus n'est qu'une commodité pour permettre la définition de "fragments" de style répété une fois et fait référence à l'utilisation d'un alias. Par exemple, si vous vouliez que toutes vos icônes soient bleues et légèrement plus grandes et espacées, vous pouvez définir un fragment comme tel:
fragments: { iconAdjust : { color : "blue" , fontSize : "110%" , marginRight : "0.6em" } }Ensuite, dans l'objet thème, utilisez simplement:
{
... ,
iconEdit : "iconAdjust" ,
iconDelete : "iconAdjust" ,
iconAdd : "iconAdjust" ,
iconCopy : "iconAdjust" ,
}Ensuite, lorsque vous voulez le modifier plus tard, il vous suffit de le mettre à jour en un seul endroit!
Les fragments peuvent également être mélangés avec des propriétés supplémentaires, et même d'autres fragments, comme ainsi:
iconEdit: [ "iconAdjust" , "anotherFragment" , { marginLeft : "1em" } ] En interne, tout le dimensionnement et l'espacement sont effectués dans em S, jamais px (à part le rootFontSize , qui définit la taille de "base"). Cela rend la mise à l'échelle beaucoup plus facile - modifiez simplement l'hélice rootFontSize (ou définissez fontSize sur le conteneur principal via le ciblage de la classe, ou en peaufinant le thème), et regardez l' ensemble de l'échelle des composants en conséquence.
Les icônes par défaut peuvent être remplacées, mais vous devez les fournir en tant qu'éléments React / HTML. Définissez simplement tout ou partie de l'hélice des icons , clés comme suit:
icons = { {
add : < YourIcon />
edit : < YourIcon / >
delete : < YourIcon />
copy : < YourIcon / >
ok : < YourIcon / >
cancel : < YourIcon / >
chevron : < YourIcon / >
} }Les composants de l'icône devront avoir leurs propres styles définis, car les styles de thème ne seront pas ajoutés aux éléments personnalisés.
Localisez votre implémentation en transmettant un objet translations pour remplacer les chaînes par défaut. Les clés et les valeurs par défaut (anglais) sont les suivantes:
{
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' ,
} Vous pouvez remplacer certains nœuds de l'arborescence de données par vos propres composants personnalisés. Un exemple peut être pour un affichage d'image, ou un éditeur de date personnalisé, ou simplement pour ajouter un bling visuel. Voir l'ensemble de données "nœuds personnalisés" dans la démo interactive pour les voir en action. (Il existe également un sélecteur de date personnalisé qui apparaît lors de la modification des chaînes ISO dans les autres ensembles de données.)
Les nœuds personnalisés sont fournis dans le propulse de customNodeDefinitions , comme un tableau d'objets de structure suivante:
{
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 n'est qu'une fonction filtrante, avec les mêmes paramètres d'entrée ( key , path , value , etc.), et element est un composant React. Chaque nœud de la structure de données sera exécuté via chaque fonction de condition, et toute correspondance sera remplacée par votre composant personnalisé. Notez que si un nœud correspond à plusieurs conditions de définition personnalisées (à partir de plusieurs composants), le premier sera utilisé, alors placez-les dans le tableau dans l'ordre prioritaire.
Le composant recevra tous les mêmes accessoires qu'un composant de nœud standard (voir CodeBase), mais vous pouvez transmettre des accessoires supplémentaires à votre composant si nécessaire via l'objet customNodeProps . Un exemple approfondi de sélecteur de date personnalisé est utilisé dans la démo (ainsi que quelques autres présentations plus basiques), que vous pouvez inspecter pour voir comment utiliser les accessoires standard et quelques accessoires personnalisés. Consultez le code source ici
Par défaut, votre composant sera présenté à droite de la clé de propriété à laquelle il appartient, comme toute autre valeur. Cependant, vous pouvez masquer la clé elle-même en définissant hideKey: true , et le composant personnalisé prendra toute la ligne. (Voir la boîte "présentée par" dans l'ensemble de données "Nœuds personnalisés" pour un exemple.)
De plus, par défaut, votre composant sera traité comme un élément "Affichage", c'est-à-dire qu'il apparaîtra dans la visionneuse JSON, mais lors de l'édition, il reviendra à l'interface d'édition standard. Cela peut être modifié, cependant, avec les accessoires showOnEdit , showOnView et showEditTools . Par exemple, un sélecteur de dattes ne peut être requis que lors du montage et laissé tel quel pour l'affichage. L'accessoire showEditTools fait référence aux icônes d'édition (copier, ajouter, modifier, supprimer) qui apparaissent à droite de chaque valeur sur le plan de survol. Si vous choisissez de les désactiver mais que vous voulez toujours que votre composant ait un mode "Modifier", vous devrez fournir votre propre mécanisme d'interface utilisateur pour basculer l'édition.
Vous pouvez permettre aux utilisateurs de créer de nouvelles instances de vos nœuds spéciaux en les sélectionnant comme un "type" dans le sélecteur de types lors de l'édition / ajout de valeurs. Définissez showInTypesSelector: true pour l'activer. Cependant, si cela est activé, vous devez également fournir un name (ce que l'utilisateur verra dans le sélecteur) et une defaultValue qui est les données insérées lorsque l'utilisateur sélectionne ce "type". (La defaultValue doit retourner true si elle est transmise par le biais de la fonction condition afin qu'elle soit immédiatement affichée à l'aide de votre composant personnalisé.)
Un composant et une définition personnalisés simples pour transformer les chaînes d'URL en liens clickables sont fournis avec le package principal à utiliser hors de la boîte. Il suffit d'importer et d'utiliser comme ça:
import { JsonEditor , LinkCustomNodeDefinition } from 'json-edit-react'
// ...Other stuff
return (
< JsonEditor
{ ... otherProps }
customNodeDefinitions = { [ LinkCustomNodeDefinition , ... otherCustomDefinitions ] }
/>
) Dans la plupart des cas, il sera préférable (et plus simple) de créer des nœuds personnalisés pour correspondre aux nœuds de valeur (c'est-à-dire non des nœuds array ou de collecte object ), ce que tous les exemples de démonstration montrent. Cependant, si vous souhaitez cibler un nœud de collection entier, il y a quelques autres choses à savoir:
children , il devient simplement la responsabilité de votre composant de le gérer.element ordinaire, qui sera affichée à l'intérieur des supports de collection (c'est-à-dire qu'il apparaît comme le contenu de la collection)wrapperElement en option, qui est affiché à l'extérieur de la collection (les accessoires peuvent être fournis comme décrit ci-dessus avec wrapperProps ). Encore une fois, le contenu intérieur (y compris votre element personnalisé) peut être affiché à l'aide children React. Dans cet exemple, la bordure bleue montre le wrapperElement et la bordure rouge montre l' element intérieur: 
showCollectionWrapper (par défaut true ), qui, lorsqu'il est défini sur false , cache les éléments de collection environnants (à savoir le Chevron Hide / Show et les supports). Dans ce cas, vous devrez fournir votre propre mécanisme de peau / affichage dans votre composant si vous le souhaitez. Il est possible de modifier les différentes chaînes de texte affichées par le composant. Vous pouvez le localiser, mais vous pouvez également spécifier des fonctions pour remplacer le texte affiché en fonction de certaines conditions. Par exemple, disons que nous voulons que le texte du nombre de propriétés (par exemple 6 items par défaut) donne un résumé d'un certain type de nœud, qui peut être beau lorsqu'il est effondré. Par exemple (tiré de la démo):

La propriété customText prend un objet, avec l'une des touches localisables sous forme de touches, avec une fonction qui renvoie une chaîne (ou null , ce qui le fait se calmer à la chaîne localisée ou par défaut). L'entrée de ces fonctions est la même que pour les fonctions de filtre, donc dans cet exemple, il serait défini comme le tel:
// 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 ,
} Les commandes de clavier par défaut sont décrites ci-dessus, mais il est possible de les personnaliser / les remplacer. Passez simplement un accessoire keyboardControls avec les actions que vous souhaitez remplacer. L'objet de configuration par défaut est:
{
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 (par exemple), vous souhaitez simplement modifier l'action générale "Confirmation" en "CMD-enter" (sur Mac), ou "Ctrl-enter", vous feriez simplement passer:
keyboardControls = {
confirm : {
key : "Enter" ,
modifier : [ "Meta" , "Control" ]
}
}Considérations :
stringConfirm , numberConfirm et booleanConfirm si elles devraient différer de votre valeur confirm .clipboardModifier par défaut). Même si la fonctionnalité d'annulation / de rétro-rétroc est probablement souhaitable dans la plupart des cas, cela n'est pas intégré au composant, pour deux raisons principales:
Quelques fonctions, composants et types d'assistance qui pourraient être utiles dans vos propres implémentations (à partir de la création de fonctions de filtre ou de mise à jour, ou composants personnalisés) sont exportées à partir du package:
themes : un objet contenant toutes les définitions de thème intégréesLinkCustomComponent : le composant utilisé pour rendre les hyperliensLinkCustomNodeDefinition : Définition du nœud personnalisé pour les hyperliensIconAdd , IconEdit , IconDelete , IconCopy , IconOk , IconCancel , IconChevron : tous les composants icônes intégrésmatchNode , matchNodeKey : Aiders pour définir les fonctions de recherche personnaliséestruncate : fonction pour tronquer une chaîne à une longueur spécifiée. Voir iciextract : fonction pour extraire une valeur d'objet profondément imbriquée à partir d'un chemin de chaîne. Voir iciassign : fonction pour définir une valeur d'objet profonde à partir d'un chemin de chaîne. Voir iciThemeName : String Litteral Liste des noms de thème intégrésTheme : un objet à thème completThemeInput : Type d'entrée pour l'hélice themeJsonEditorProps : tous les accessoires d'entrée pour le composant de l'éditeur JSONJsonData : Objet data principal - Toute structure JSON valideUpdateFunction , OnChangeFunction , OnErrorFunction FilterFunction , CopyFunction , SearchFilterFunction , CompareFunction , TypeFilterFunction , LocalisedString , CustomNodeDefinition , CustomTextDefinitions , CustomTextFunction ,TranslateFunction : fonction qui prend une clé de localisation et renvoie une chaîne traduiteIconReplacements : Type d'entrée pour les iconsCollectionNodeProps : Tous les accessoires passaient en interne aux nœuds "Collection" (IE objets / tableaux)ValueNodeProps : tous les accessoires passaient en interne aux nœuds "valeur" (c'est-à-dire pas d'objets / tableaux)CustomNodeProps : tous les accessoires passaient en interne aux nœuds personnalisés; Fondamentalement, le même que CollectionNodeProps avec un champ supplémentaire customNodeProps pour passer des accessoires uniques à votre composant`DataType : "string" | "number" | "boolean" | "null" | "object" | "array"KeyboardControls : Structure de la personnalisation du clavier Veuillez ouvrir un problème: https://github.com/carlosnz/json-edit-react/issues
Les principales fonctionnalités que j'aimerais présenter sont:
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