
Um componente React para editar ou visualizar dados JSON/Object

Importante
Breaking mudanças:
theme . Os temas embutidos agora devem ser importados separadamente e passados, em vez de apenas nomear o tema como uma string. Isso é melhor para troca de árvores, para que os temas não utilizados não sejam incluídos na sua construção. Veja temas e estilossetData e não use onUpdate para atualizar seus dados externamente. Consulte o estado de gerenciamento. 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 } /> (para usuário final)
É bastante auto-explicativo (clique no ícone "editar" para editar etc.), mas existem algumas maneiras não tão obviamente de interagir com o editor:
Cmd/Ctrl/Shift-Enter para adicionar uma nova linha ( Enter envia o valor)Enter para nova linha e Cmd/Ctrl/Shift-Enter para envioEscape para cancelar a ediçãoCmd/Ctrl copiará o caminho para o nó selecionado, em vez de seu valorjsonParse Prop. O único valor necessário são data (embora você precise fornecer um método setData para atualizar seus dados).
| prop | tipo | padrão | descrição |
|---|---|---|---|
data | object|array | Os dados a serem exibidos / editados | |
setData | object|array => void | Método para atualizar seu objeto data . Consulte o estado de gerenciamento abaixo para obter notas adicionais. | |
rootName | string | "data" | Um nome a ser exibido no editor como a raiz do objeto de dados. |
onUpdate | UpdateFunction | Uma função a ser executada sempre que um valor for atualizado (editar, excluir ou adicionar) no editor. Veja as funções de atualização. | |
onEdit | UpdateFunction | Uma função a ser executada sempre que um valor for editado . | |
onDelete | UpdateFunction | Uma função a ser executada sempre que um valor for excluído . | |
onAdd | UpdateFunction | Uma função a ser executada sempre que uma nova propriedade for adicionada . | |
onChange | OnChangeFunction | Uma função para modificar/restringir a entrada do usuário conforme eles digitam - consulte as funções de OnChange. | |
onError | OnErrorFunction | Uma função a ser executada sempre que o componente relata um erro - consulte o ONErrorFunction. | |
showErrorMessages | boolean | true | Se o componente deve ou não exibir suas próprias mensagens de erro (você provavelmente gostaria apenas de desativar isso se fornecer sua própria função onError ) |
enableClipboard | boolean|CopyFunction | true | Se deve ou não ativar o botão "cópia para a área de transferência" na interface do usuário. Se uma função for fornecida, é assumido true e essa função será executada sempre que um item for copiado. |
indent | number | 3 | Especifique a quantidade de indentação para cada nível de ninho nos dados exibidos. |
collapse | boolean|number|FilterFunction | false | Define quais nós da árvore json serão exibidos "abertos" na interface do usuário na carga. Se boolean , será tudo ou nenhum. Um number especifica uma profundidade de nidificação após os quais os nós serão fechados. Para um controle mais fino, uma função pode ser fornecida - consulte as funções do filtro. |
collapseAnimationTime | number | 300 | Tempo (em milissegundos) para a animação de transição ao recolher os nós de coleção. |
restrictEdit | boolean|FilterFunction | false | Se for true , nenhuma edição é permitida. Uma função pode ser fornecida para mais especificidade - consulte Funções de filtro |
restrictDelete | boolean|FilterFunction | false | Como restrictEdit , mas para exclusão |
restrictAdd | boolean|FilterFunction | false | Como no restrictEdit , mas para adicionar novas propriedades |
restrictTypeSelection | boolean|DataType[]|TypeFilterFunction | true | Para restringir os tipos de dados, o usuário pode selecionar. Pode ser uma lista de tipos de dados (por exemplo [ 'string', 'number', 'boolean', 'array', 'object', 'null' ] ) ou um booleano. Uma função pode ser fornecida - deve ter a mesma entrada que as funções FilterFunction acima, mas a saída deve ser boolean | DataType[] . |
restrictDrag | boolean|FilterFunction | true | Defina como false para ativar a funcionalidade de arrastar e soltar. Veja Drag-N-Drop |
searchText | string | undefined | A visibilidade dos dados será filtrada combinando com o valor, usando o método definido abaixo no searchFilter |
searchFilter | "key"|"value"|"all"|SearchFilterFunction | undefined | Defina como searchText deve ser correspondido para filtrar os itens visíveis. Consulte Pesquisa/filtragem |
searchDebounceTime | number | 350 | Tempo de debounce quando searchText muda |
keySort | boolean|CompareFunction | false | Se true , as chaves do objeto serão encomendadas (usando JS .sort() ). Uma função de comparação também pode ser fornecida para definir o comportamento de classificação. |
showArrayIndices | boolean | true | Se deve ou não exibir o índice (como chave de propriedade) para elementos de matriz. |
showStringQuotes | boolean | true | Se deve ou não exibir valores de string em "Quotes". |
showCollectionCount | boolean|"when-closed" | true | Se deve ou não exibir o número de itens em cada coleção (objeto ou matriz). |
defaultValue | any|DefaultValueFilterFunction | null | Quando uma nova propriedade é adicionada, ela é inicializada com esse valor. Uma função pode ser fornecida com a mesma entrada que a FilterFunction s, mas deve gerar um valor. Isso permite que um valor padrão diferente seja usado, dependendo do estado de dados (por exemplo, o padrão para o nível superior é um objeto, mas uma string em outro lugar.) |
stringTruncate | number | 250 | Valores da string mais longos do que esses muitos caracteres serão exibidos truncados (com ... ). A sequência completa sempre será visível ao editar. |
translations | Objeto de LocalisedStrings | { } | Strings de interface do usuário (como mensagens de erro) podem ser traduzidas passando um objeto contendo valores de string localizados (existem apenas alguns). Veja Localização |
theme | ThemeInput | default | Um dos temas internos (importados separadamente) ou um objeto que especifica algumas ou todas as propriedades do tema. Veja temas. |
className | string | Nome de uma classe CSS para aplicar ao componente. Na maioria dos casos, a especificação de propriedades theme será mais direta. | |
id | string | Nome do atributo HTML id no contêiner principal do componente. | |
icons | {[iconName]: JSX.Element, ... } | { } | Substitua os ícones embutidos, especificando-os aqui. Veja temas. |
minWidth | number|string (valor CSS) | 250 | Largura mínima para o contêiner do editor. |
maxWidth | number|string (valor CSS) | 600 | Largura máxima para o contêiner do editor. |
rootFontSize | number|string (valor CSS) | 16px | O tamanho da fonte "base" do qual todos os outros sizings são derivados (em em S). Ao alterar isso, você escalará o componente inteiro. recipiente. |
customNodeDefinitions | CustomNodeDefinition[] | Você pode fornecer componentes personalizados para substituir nós específicos na árvore de dados, de acordo com uma função de condição. Consulte Veja nós personalizados para obter mais detalhes. (Um componente personalizado simples para transformar strings de URL em links ativos é fornecido no pacote principal - veja aqui) | |
customText | CustomTextDefinitions | Além de localizar as seqüências de texto do componente, você também pode alterá -lo dinamicamente , dependendo dos dados. Consulte o texto personalizado para obter mais detalhes. | |
customButtons | CustomButtonDefinition[] | [] | Você pode adicionar seus próprios botões ao painel de botões de edição se quiser poder executar uma operação personalizada nos dados. Veja botões personalizados |
jsonParse | (input: string) => JsonData | JSON.parse | Ao editar diretamente um bloco de JSON, você pode permitir alguma entrada "mais frouxa" - por exemplo, 'citações únicas', vírgulas à direita ou nomes de campo não citados. Nesse caso, você pode fornecer um método de análise JSON de terceiros. Eu recomendo JSON5, que é o que é usado na demonstração |
jsonStringify | (data: JsonData) => string | (data) => JSON.stringify(data, null, 2) | Da mesma forma, você pode substituir a apresentação padrão da string json ao iniciar a edição do JSON. Você pode fornecer parâmetros de formatação diferentes para o nativo JSON.stringify() ou fornecer uma opção de terceiros, como o JSON5 mencionado acima. |
errorMessageTimeout | number | 2500 | Tempo (em milissegundos) para exibir a mensagem de erro na interface do usuário. |
keyboardControls | KeyboardControls | Como explicado acima | Substitua alguns ou todos os controles do teclado. Consulte a personalização do teclado para obter detalhes. |
insertAtTop | boolean| "object | "array" | false | Se true , insira novos valores na parte superior e não em baixo. Pode definir o comportamento apenas para matrizes ou objetos definindo para "object" ou "array" respectivamente. |
Recomenda -se que você gerencie o estado data fora deste componente - basta passar em um método setData , que é chamado internamente para atualizar seus data . No entanto, isso não é obrigatório - se você não fornecer um método setData , os dados serão gerenciados internamente, o que seria bom se você não estiver fazendo nada com os dados. A alternativa é usar as funções de atualização para atualizar seus data externamente, mas isso não é recomendado, exceto em circunstâncias especiais, pois você pode ter problemas para manter seus dados em sincronia com o estado interno (que é o que é exibido), além de renderizações desnecessárias. As funções de atualização devem ser idealmente usadas apenas para implementar efeitos colaterais, verificar erros ou mudar os dados antes de defini -los com setData .
Um retorno de chamada a ser executado sempre que ocorre uma atualização de dados (editar, excluir ou adicionar) pode ser fornecida. Você pode usar isso para atualizar algum estado externo, fazer uma chamada de API, modificar os dados antes de salvá -los ou validar a estrutura de dados em relação a um esquema JSON. Se você deseja a mesma função para todas as atualizações, apenas o suporte onUpdate é suficiente. No entanto, se você precisar de algo diferente para edição, exclusão e adição, poderá fornecer funções de atualização separadas por meio dos adereços onEdit , onDelete e onAdd .
A função receberá o seguinte objeto como um 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")
}A função não pode retornar nada (nesse caso, os dados são atualizados normalmente) ou um valor para representar sucesso/falha, valor de erro ou dados modificados. O valor de retorno pode ser um dos seguintes e tratados de acordo:
true / void / undefined : Data continua atualizando normalmentefalse : considera a atualização um erro, portanto os dados não são atualizados (reverte para o valor anterior) e uma mensagem de erro genérico é exibida na interface do usuáriostring : também considerado um erro, portanto, nenhuma atualização de dados, mas a mensagem de erro da interface do usuário será sua sequência fornecida[ "value", <value> ] : diz ao componente para usar o <value> retornado em vez dos dados de entrada. Você pode usá -lo para modificar automaticamente a entrada do usuário - por exemplo, classificar uma matriz ou inserir um campo de carimbo de data / hora em um objeto.[ "error", <value> ] : o mesmo que string , mas no formato de tupla mais longo. Semelhante às funções de atualização, a função onChange é executada como as alterações de entrada do usuário. Você pode usá -lo para restringir ou restringir a entrada do usuário - por exemplo, números limitando a valores positivos ou prevenção de quebras de linha em strings. A função deve retornar um valor para atualizar o campo de entrada do usuário; portanto, se nenhuma alteração for feita, basta devolvê -lo não modificado.
O objeto de entrada é semelhante à entrada da função de atualização, mas sem campo de newData (pois esta operação ocorre antes que os dados sejam atualizados).
// 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, o componente exibirá mensagens de erro simples sempre que uma condição de erro for detectada (por exemplo, entrada inválida JSON, chaves duplicadas ou erros personalizados retornados pelas funções onUpdate )). No entanto, você pode fornecer seu próprio retorno de chamada onError para implementar sua própria interface do usuário de erro ou executar efeitos colaterais adicionais. (No primeiro caso, você provavelmente também gostaria de desativar o suporte showErrorMessages .) A entrada para o retorno de chamada é semelhante aos outros retornos de chamada:
{
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
}
}(Um exemplo de uma interface do usuário de erro personalizado pode ser visto na demonstração com o conjunto de dados "nós personalizados" - quando você insere a entrada inválida do JSON, uma notificação de "brinde" é exibida em vez da mensagem de erro normal do componente.)
Um retorno de chamada semelhante é executado sempre que um item é copiado para a área de transferência (se passada para o suporte enableClipboard ), mas com um 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)Como há muito pouco feedback do usuário ao clicar em "Copiar", uma boa idéia seria apresentar algum tipo de notificação nesse retorno de chamada.
Além dos botões "Copiar", "Editar" e "Excluir" que aparecem por cada valor, você pode adicionar seus próprios botões se precisar permitir algumas operações personalizadas nos dados. Forneça uma matriz de definições de botões no suporte customButtons , na seguinte estrutura de definição:
{
Element : React . FC ,
onClick : ( nodeData : NodeData , e : React . MouseEvent ) => void
} Onde NodeData é a mesma estrutura de dados recebida pelas "funções de atualização" anteriores.
Você pode controlar quais nós da estrutura de dados podem ser editados, excluídos ou adicionados a ou para que seu tipo de dados seja alterado, passando as funções do filtro. Eles serão chamados em cada propriedade nos dados e o atributo será aplicado, dependendo de a função retornar true ou false (os meios true não podem ser editados).
A função recebe o seguinte 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)
} Uma função de filtro também está disponível para o suporte collapse , para que você possa aparecer com seus dados com coleções profundamente aninhadas abertas, enquanto colapsou todo o resto, por exemplo.
Para restringir os tipos de dados, a função de filtro (tipo) é um pouco mais sofisticada. A entrada é a mesma, mas a saída pode ser um boolean (o que restringiria os tipos disponíveis para um determinado nó a todos ou nenhum ) ou uma variedade de tipos de dados a serem restritos. Os valores disponíveis são:
"string""number""boolean""null""object""array" Não existe uma função de restrição específica para editar nomes de chave do objeto, mas eles devem retornar true para restrictEdit e restrictDelete (e restrictAdd as coleções), pois alterar um nome de chave é equivalente a excluir uma propriedade e adicionar uma nova.
Você também pode definir um valor padrão dinâmico, passando uma função de filtro para o suporte defaultValue - a entrada é a mesma que o acima, mas também assume o novo valor key como seu segundo parâmetro, para que o novo valor possa depender da nova chave adicionada.
O uso de todos esses filtros de restrição juntos pode permitir que você aplique um esquema de dados razoavelmente sofisticado.
// in <JsonEditor /> props
restrictEdit = { ( { level } ) => level === 0 }id ser editado: 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 só podem ser alterados para strings ou objetos (para nidificação)null não é permitido em nenhum lugarboolean devem 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"
} }Além de controlar dinamicamente o acesso às várias ferramentas de edição, conforme descrito acima, é possível fazer a validação completa do esquema JSON criando uma função de atualização que passa os dados para uma biblioteca de validação de esquema de terceiros (por exemplo, AJV). Isso rejeitará qualquer entrada inválida e exibirá um erro na interface do usuário (ou por meio de uma função personalizada do ONERROR). Você pode ver um exemplo disso na demonstração com o conjunto de dados "JSON Schema Validation" (e o conjunto de dados "nós personalizados").
Um exemplo de função de validação onUpdate (usando AJV) pode ser algo assim:
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 } />Observação
Este é um novo recurso e deve ser considerado "experimental". Forneça feedback ou sugestões para ajudar a melhorá -lo.
A propriedade restrictDrag controla quais itens (se houver) podem ser arrastados para novas posições. Por padrão, isso está desligado , então você deve definir restrictDrag = false para ativar essa funcionalidade. Como as restrições de edição acima, essa propriedade também pode adotar uma função de filtro para controle de granulação fina. Existem algumas considerações adicionais:
jsonb (JSON binário), a ordem das chaves não tem sentido; portanto, na próxima vez que o objeto for carregado, as chaves serão listadas em ordem alfabética.restrictDrag se aplica ao elemento de origem (ou seja, o nó que está sendo arrastado), não o destino.restrictDelete Prop), pois arrastar um nó para um novo destino é essencialmente excluindo-o e adicionando-o de volta em outro lugar. Os dados exibidos podem ser filtrados com base na entrada de pesquisa de um usuário. A entrada do usuário deve ser capturada de forma independente (não fornecemos uma interface do usuário aqui) e passamos com o suporte searchText . Essa entrada é debouncida internamente (o tempo pode ser definido com o searchDebounceTime Prop), portanto, também não há necessidade disso. Os valores contra os quais o searchText são testados são especificados com o searchFilter Prop. Por padrão (nenhum searchFilter definido), ele corresponderá aos valores dos dados (com a correspondência parcial insensível ao caso-ou seja, entrada "ILB", corresponderá ao valor "Bilbo").
Você pode especificar o que deve ser correspondido definindo searchFilter como "key" (nomes de propriedades correspondentes), "value" (o padrão descrito acima) ou "all" (corresponda a propriedades e valores). Isso deve ser suficiente para a maioria dos casos de uso, mas você pode especificar sua própria SearchFilterFunction . A função de pesquisa é a mesma assinatura que as funções de filtragem acima, mas leva um argumento adicional para o searchText , ou seja,
( { key , path , level , value , ... etc } : FilterFunctionInput , searchText : string ) => boolean Existem duas funções auxiliares ( matchNode() e matchNodeKey() ) exportadas com o pacote que pode facilitar a criação de sua função de pesquisa (essas são as funções usadas internamente para as correspondências "key" e "value" descritas acima). Você pode ver o que eles fazem aqui.
Um exemplo de função de pesquisa personalizada pode ser vista na demonstração com o conjunto de dados da "Lista de clientes" - a função de pesquisa corresponde ao nome e pelo nome de usuário e torna o objeto "cliente" inteiro visível quando uma dessas correspondências, para que possa ser usada para encontrar uma pessoa em particular e editar seus detalhes 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
} Há uma pequena seleção de temas internos (como visto no aplicativo de demonstração). Para usar um deles, basta importar -o do pacote e passá -lo como o suporte do 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...
/>
}Os seguintes temas estão disponíveis no pacote (embora realisticamente, eles existem mais para mostrar os recursos-estou aberto a melhores temas internos, então fique à vontade para criar um problema com sugestões):
githubDarkThemegithubLightThememonoDarkThememonoLightThemecandyWrapperThemepsychedelicThemeNo entanto, você pode passar em seu próprio objeto de tema, ou parte dele. A estrutura do tema é a seguinte (esta é a definição de tema "padrão"):
{
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)' ,
} ,
} A propriedade styles é a principal a se concentrar. Cada chave ( property , bracket , itemCount ) refere -se a uma parte da interface do usuário. O valor para cada chave é :
string , nesse caso, é interpretada como a cor (ou cor de fundo no caso de container e inputHighlight )null ). Isso permite que você altere dinamicamente o estilo de vários elementos com base no conteúdo ou na estrutura.null . (Na matriz, os itens posteriores têm maior precedência)Para um exemplo simples, se você quiser usar o tema "GithubDark", mas basta mudar algumas coisas pequenas, especificaria algo assim:
// in <JsonEditor /> props
theme = { [
githubDarkTheme ,
{
iconEdit : 'grey' ,
boolean : { color : 'red' , fontStyle : 'italic' , fontWeight : 'bold' , fontSize : '80%' } ,
} ,
] } O que mudaria o ícone "editar" e os valores booleanos disso: 
nisso: 
Ou você pode criar seu próprio tema do zero e substituir todo o objeto tema.
Então, para resumir, o suporte theme pode levar :
"candyWrapperTheme"fragments , styles , displayName etc. ou apenas a parte styles (no nível da raiz)[ "<themeName>, {...overrides } ]Você pode jogar com a edição ao vivo dos temas no aplicativo de demonstração, selecionando "Editar este tema!" Do seletor "Demo Data" (embora você não consiga criar funções no JSON).
Outra maneira de estilizar o componente é direcionar diretamente as classes CSS. Todo elemento do componente possui um nome de classe exclusivo, para que você possa localizá -los no inspetor do navegador e substituí -los de acordo. Todos os nomes de classe começam com o prefixo jer- , por exemplo, jer-collection-header-row , jer-value-string .
A propriedade fragments acima é apenas uma conveniência para permitir que "fragmentos" de estilo repetido sejam definidos uma vez e referidos usando um pseudônimo. Por exemplo, se você quisesse que todos os seus ícones fossem azuis e um pouco maiores e espaçados, pode definir um fragmento assim:
fragments: { iconAdjust : { color : "blue" , fontSize : "110%" , marginRight : "0.6em" } }Então, no objeto tema, basta usar:
{
... ,
iconEdit : "iconAdjust" ,
iconDelete : "iconAdjust" ,
iconAdd : "iconAdjust" ,
iconCopy : "iconAdjust" ,
}Então, quando você quiser ajustá -lo mais tarde, você só precisa atualizá -lo em um só lugar!
Os fragmentos também podem ser misturados com propriedades adicionais e até outros fragmentos, assim:
iconEdit: [ "iconAdjust" , "anotherFragment" , { marginLeft : "1em" } ] Internamente, todo o dimensionamento e espaçamento são feitos em em S, nunca px (além do rootFontSize , que define o tamanho "base"). Isso facilita muito a escala - basta alterar o suporte rootFontSize (ou definir fontSize no contêiner principal através da segmentação da classe ou ajustando o tema) e observe todo o componente escalar de acordo.
Os ícones padrão podem ser substituídos, mas você precisa fornecê -los como elementos React/HTML. Basta definir qualquer um ou todos eles no suporte icons , com chave da seguinte forma:
icons = { {
add : < YourIcon />
edit : < YourIcon / >
delete : < YourIcon />
copy : < YourIcon / >
ok : < YourIcon / >
cancel : < YourIcon / >
chevron : < YourIcon / >
} }Os componentes do ícone precisarão ter seus próprios estilos definidos, pois os estilos de temas não serão adicionados aos elementos personalizados.
Localize sua implementação, aprovando um objeto translations para substituir as seqüências de caracteres padrão. Os valores das chaves e padrão (inglês) são os seguintes:
{
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' ,
} Você pode substituir determinados nós na árvore de dados por seus próprios componentes personalizados. Um exemplo pode ser para uma exibição de imagem ou um editor de data personalizado, ou apenas para adicionar um pouco de bling visual. Consulte o conjunto de dados "nós personalizados" na demonstração interativa para vê -lo em ação. (Há também um seletor de data personalizado que aparece ao editar strings ISO nos outros conjuntos de dados.)
Os nós personalizados são fornecidos no Prop customNodeDefinitions , como uma variedade de objetos da estrutura seguinte:
{
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
} A condition é apenas uma função de filtro, com os mesmos parâmetros de entrada ( key , path , value etc.), e element é um componente de reação. Cada nó na estrutura de dados será executado por cada função de condição e qualquer correspondência será substituída pelo seu componente personalizado. Observe que, se um nó corresponder a mais de uma condição de definição personalizada (de vários componentes), o primeiro será usado, portanto, coloque -os na matriz em ordem prioritária.
O componente receberá todos os mesmos adereços que um componente de nó padrão (consulte CodeBase), mas você pode passar adereços adicionais ao seu componente, se necessário, pelo objeto customNodeProps . Um exemplo completo de um selecionador de data personalizado é usado na demonstração (junto com alguns outros de apresentação mais básicos), que você pode inspecionar para ver como utilizar os adereços padrão e alguns adereços personalizados. Veja o código -fonte aqui
Por padrão, seu componente será apresentado à direita da chave da propriedade à qual pertence, como qualquer outro valor. No entanto, você pode ocultar a chave definindo hideKey: true , e o componente personalizado levará a linha inteira. (Consulte a caixa "Apresentada por" no conjunto de dados "nós personalizados" para um exemplo.)
Além disso, por padrão, seu componente será tratado como um elemento "exibição", ou seja, ele aparecerá no visualizador JSON, mas, ao editar, ele será revertido para a interface de edição padrão. Isso pode ser alterado, no entanto, com os adereços showOnEdit , showOnView e showEditTools . Por exemplo, um seletor de data só pode ser necessário ao editar e deixar como como é exibido. O Prop showEditTools Prop refere -se aos ícones de edição (Copiar, Adicionar, Editar, Excluir) que aparecem à direita de cada valor no Hover. Se você optar por desativá -los, mas ainda deseja que seu componente tenha um modo de "edição", precisará fornecer seu próprio mecanismo da interface do usuário para alternar a edição.
Você pode permitir que os usuários criem novas instâncias de seus nós especiais, selecionando -os como um "tipo" no seletor de tipos ao editar/adicionar valores. Defina showInTypesSelector: true para ativar isso. No entanto, se isso estiver ativado, você também precisará fornecer um name (que é o que o usuário verá no seletor) e um defaultValue , que é os dados que são inseridos quando o usuário selecionar esse "tipo". (O defaultValue deve retornar true se passado pela função condition para que ela seja exibida imediatamente usando seu componente personalizado.)
Um simples componente e definição personalizados para transformar strings de URL em links clicáveis é fornecido com o pacote principal para você usar fora da caixa. Apenas importe e use assim:
import { JsonEditor , LinkCustomNodeDefinition } from 'json-edit-react'
// ...Other stuff
return (
< JsonEditor
{ ... otherProps }
customNodeDefinitions = { [ LinkCustomNodeDefinition , ... otherCustomDefinitions ] }
/>
) Na maioria dos casos, será preferível (e mais simples) criar nós personalizados para corresponder aos nós de valor (ou seja, não array ou nós de coleta de object ), que é o que todos os exemplos de demonstração mostram. No entanto, se você deseja atingir um nó de coleção inteiro, há algumas outras coisas a saber:
children , apenas se torna a responsabilidade do seu componente.element regular, que será exibido dentro dos suportes de coleção (ou seja, aparece como o conteúdo da coleção)wrapperElement opcional, exibido fora da coleção (os adereços podem ser fornecidos conforme descrito acima com wrapperProps ). Novamente, o conteúdo interno (incluindo o seu element personalizado) pode ser exibido usando children React. Neste exemplo, a borda azul mostra o wrapperElement e a borda vermelha mostra o element interno: 
showCollectionWrapper (padrão true ), que, quando definido como false , esconde os elementos de coleção circundantes (a saber, o Hide/Show Chevron e os suportes). Nesse caso, você teria que fornecer seu próprio mecanismo de esconderijo/show em seu componente, caso deseje. É possível alterar as várias seqüências de texto exibidas pelo componente. Você pode localizá -lo, mas também pode especificar funções para substituir o texto exibido com base em determinadas condições. Por exemplo, digamos que queremos o texto da contagem de propriedades (por exemplo, 6 items por padrão) para fornecer um resumo de um certo tipo de nó, que pode parecer bom quando desmoronado. Por exemplo (retirado da demonstração):

A propriedade customText pega um objeto, com qualquer uma das teclas locais como teclas, com uma função que retorna uma string (ou null , o que faz com que ela se encaixe na sequência localizada ou padrão). A entrada para essas funções é a mesma das funções de filtro; portanto, neste exemplo, seria definido assim:
// 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 ,
} Os controles de teclado padrão são descritos acima, mas é possível personalizar/substituir esses. Basta passar em um suporte keyboardControls com as ações que você deseja substituir definidas. O objeto de configuração padrão é:
{
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' ,
}Se (por exemplo), você deseja alterar a ação geral de "confirmação" para "cmd-entr" (no Mac) ou "ctrl-entra", você apenas passaria:
keyboardControls = {
confirm : {
key : "Enter" ,
modifier : [ "Meta" , "Control" ]
}
}Considerações :
stringConfirm , numberConfirm e booleanConfirm se eles diferirem do seu valor confirm .clipboardModifier ). Embora a funcionalidade de desfazer/refazer provavelmente seja desejável na maioria dos casos, isso não é incorporado ao componente, por dois motivos principais:
Algumas funções, componentes e tipos auxiliares que podem ser úteis em suas próprias implementações (da criação de funções de filtro ou atualização ou componentes personalizados) são exportados do pacote:
themes : um objeto que contém todas as definições de temas embutidasLinkCustomComponent : O componente usado para renderizar hiperlinksLinkCustomNodeDefinition : Definição de nós personalizados para hiperlinksIconAdd , IconEdit , IconDelete , IconCopy , IconOk , IconCancel , IconChevron : todos os componentes do ícone embutidosmatchNode , matchNodeKey : Ajudantes para definir funções de pesquisa personalizadastruncate : função para truncar uma string a um comprimento especificado. Veja aquiextract : função para extrair um valor de objeto profundamente aninhado de um caminho de string. Veja aquiassign : função para definir um valor profundo do objeto a partir de um caminho de string. Veja aquiThemeName : String Literal de nomes de temas internosTheme : um objeto de tema completoThemeInput : tipo de entrada para o suporte themeJsonEditorProps : todos os adereços de entrada para o componente do editor JSONJsonData : Objeto data principal - qualquer estrutura JSON válidaUpdateFunction , OnChangeFunction , OnErrorFunction FilterFunction , CopyFunction , SearchFilterFunction , CompareFunction , TypeFilterFunction , LocalisedString , CustomNodeDefinition , CustomTextDefinitions , CustomTextFunction ,TranslateFunction : função que pega uma chave de localização e retorna uma string traduzidaIconReplacements : tipo de entrada para o suporte iconsCollectionNodeProps : todos os adereços passados internamente para os nós de "coleção" (ou seja, objetos/matrizes)ValueNodeProps : todos os adereços passados internamente para os nós "Value" (ou seja, não objetos/matrizes)CustomNodeProps : todos os adereços passados internamente para nós personalizados; Basicamente, o mesmo que CollectionNodeProps com um campo Extra customNodeProps para passar adereços exclusivos para o seu componente`DataType : "string" | "number" | "boolean" | "null" | "object" | "array"KeyboardControls : estrutura para o suporte de personalização do teclado Abra um problema: https://github.com/carlosnz/json-edit-react/issues
Os principais recursos que eu gostaria de apresentar são:
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