@stackhouseos/box-core
v4.8.0
Published
Json generator layout
Downloads
34
Readme
Box
Libreria per la creazione di form e layout avanzati, è integrabile su qualsiasi progetto react/redux.
Table of Contents
- Installation
- Getting Started
- Configs
- Field schema
- Field component
- Id
- Methods
- Rules and validation
- Prefix
- Container
- Reducer
Peer Dependencies
| Peer Dependency | Version | |-----------------|----------| | react | ^16.11.0 | | react-redux | ^7.1.3 | | redux | ^4.0.4 |
Installation
npm install @stackhouseos/box-core
Getting Started
• Basic
import Box from '@stackhouseos/box-core';
const model = [{
type: 'input',
placeholder: 'Name',
id: 'name'
}]
<Box prefix="nomereducer" fields={model} />
import Box from '@stackhouseos/box-core';
const CustomInput = ({onChange, value, placeholder}) => {
return (
<input
value={value}
onChange={(evt) => onChange(evt.target.value)} placeholder={placeholder}
/>
)
}
Box.extendControls({CustomInput});
const model = [
{
type: 'CustomInput',
placeholder: 'Name',
id: 'name'
}
]
<Box prefix="nomereducer" fields={model} />
Attenzione per poter usare Box ricordati di estendere il tuo reducer con quello di Box
Esempio Reducer
Configs
Box
| Prop Name | Type | Is Required | Default Value | Description |
|--------------|----------------|-------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| fields | array|object
| yes | | Schema del modello da visualizzare |
| prefix | string
| yes | | Path (dotStyle) è il nome del reducer in cui salvare e leggere i dati, es. tickets.detail |
| destroyValue | bool
| optional | false | Regola di default per tutti i field del modello, se true svuota il dato se il componente viene distrutto, utile quando ci sono le regole, si evita di lasciare dati sporchi nel form |
Field schema
| Prop Name | Type | Is Required | Default Value | Description |
|-----------------|----------------------------------|-------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| type | string|component
| optional | div
| Componente da visualizzare |
| id | string|reselect
| optional | | redux path selector per leggere o salvare i dati |
| (*_)fromId | string|reselect
| optional | | permette di leggere i dati da un selettore diverso da id, in quetso caso id viene utilizzato solo per salvare, utile quando si usano le select, che devono salvare su id ma prendere i dati da un'altro selettore, name_fromId |
| fields | array|object
| optional | | Recursive fields |
| _fields | array|object
| optional | | Recursive fields |
| onChange | string|func({value, dispatch})
| optional, id
required | | Viene scatenata ad ogni aggiornamento dell'id corrispondente, se viene usata una stringa deve corrispondere ad una azione di redux |
| onLoad | string|func({value, dispatch})
| optional,id
required | | Viene scatenata ad mount del compomente, se viene usata una stringa deve corrispondere ad una azione di redux |
| prefix | string
| optional | | Path (dotStyle) aggiunge un prefisso a tutti gli id successivi |
| container | string|object
| optional | | Wrappa il componente dentro un'altro componente |
| rules | array|object
| optional | | vedi lib [json-rules] |
| ruleModeDisable | bool
| optional | | Aggiunge la props disable nel componente, con false non si esegue il render del componente in base alle rules |
| validate | array|object
| optional | | vedi lib [json-rules] |
| required | bool
| optional | | campo obbligatorio, solo se presente id |
| pattern | string|regex
| optional | | es. "^[1-9][0-9]$" |
| errorMessages | string|object
| optional | | es. Il campo è obbligatorio, oppure {required:'Richiesto', min: 'Lunghezza minima 5'}
|
| destroyValue | bool
| optional | false | se true svuota il dato se il componente viene distrutto, utile quando ci sono le regole, si evita di lasciare dati sporchi nel form |
| action | string|func
| optional | | Se stringa scatena un dispatch sul nome dell'azione, se funzione passa il dispatch per poter invocare azioni custom |
Field Component
I tuoi componenti custom riceveranno in automatico le seguenti props, oltre al tutte le proprietà che userai nel tuo schema
| Prop Name | Type | Description |
|-----------|----------|-------------------------------------------------------------------------|
| onChange | func
| Metodo per aggiornare i dati nell'id indicato |
| value | any
| Valore recuperato dal selettore |
| id | string
| Id field, obbligatorio se si vogliono leggere o salvare i dati su redux |
| field | object
| Schema del field corrente |
| onAction | func
| Da utilizzare per invocare il dispatch |
| disabled | bool
| in base alla rules |
| error | string
| in base a validation |
| onBlur | func
| Necessario per attivare la validazione degli input |
| renderFields | func
| Utile per renderizzare nuovi componenti nello stesso contesto di validazione |
Id
Il campo id viene utilizzato per recuperare i dati da redux o context, allo stesso modo viene utilizzato per salvare i dati su redux
const model = [
{
type: 'CustomInput',
placeholder: 'Name',
id: 'name',
},
{
type: 'CustomInput',
placeholder: 'tipologia',
id: 'dettagli.tipologia',
}
]
<Box prefix="nomereducer" fields={model} />
i dati potranno essere recuperati usando come id direttamente name, Box salverà i dati su redux nel reducer nomereducer.name
e nomereducer.dettagli.tipologia
Può essere utile anche recuperare i dati da altri reducer che non sono al livello di nomereducer
, tramite l'utilizzo del carattere ^ come prefisso dell'id, es:
• Redux state
const initialState = {
attivita: {items: [1,2,3]},
ticket: {name: 'Andrea', dettagli: {tipologia: 'dev'}}
}
import Box, { BoxContextProvider } from '@stackhouseos/box-core';
const model = [
{
type: 'Lista',
id: '^attivita.items', // print [1,2,3]
},
{
type: 'Testo',
id: 'ticket.dettagli.tipologia', // print 'dev'
},
{
type: 'Testo',
id: '^role', // print 'user'
}
]
<BoxContextProvider value={{ role: 'user' }}>
<Box prefix="ticket" fields={model} />
</BoxContextProvider>
Questa convenzione sarà utilizzata anche per la gestione delle rules e validazioni
const model = [
{
type: 'Testo',
placeholder: 'Name',
id: 'name',
rules: {
'^role': {eq: 'user'} // appare solo se il ruolo utente è uguale a 'user'
},
validation: {
'name': { min: 10 } // verrà validato solo se rules è valido
}
}
]
Methods
• Add components
Box.extendControls({ ...components });
• Set components
Box.setControls({ ...onlyThiscomponents });
• Extends data with Context, per aggiungere dati che non sono su redux
import Box, { BoxContextProvider } from '@stackhouseos/box-core';
const model = [
{
type: 'Testo',
id: '^role', // print 'user'
}
]
<BoxContextProvider value={{ role: 'user' }}>
<Box prefix="ticket" fields={model} />
</BoxContextProvider>
Rules and validation
| Key | Type | Description |
|-----------|--------|--------------------------------------------------------------------------|
| ^hasError | bool
| E' presente un errore nel form, vengono analizzati solo i field visibili |
| ^isValid | bool
| Il form è valido, vengono analizzati solo i field visibili |
| ^fieldId | string
| Valore della chiave |
Utile quando si vuole disabilitare il tasto salva se nel form sono presenti errori
• example
{
type: 'button',
title: 'SALVA',
ruleModeDisable: true,
rules: { '^hasError': { eq: false } }
}
• Field con regole
Tutti i field passati nel modello possono esser gestiti tramite rules, basterà appendere al nome _rules
{
type: 'button',
title_default: 'Salva', // titolo se non si trova nessuna corrispondenza con le regole
title_rules: {
'Aggiungi': {
'id' : {ex: false}, // il titolo sarà "Aggiungi" se id non esiste
},
'Salva': {
'id' : {ex: true}, // il titolo sarà "Salva" se id esiste, questa regola può essere omessa usando il title_default
}
},
}
• Root reducer
^
utilizare l'accento circonflesso, per recuperare i dati dalla root di reducer, questo ignora un qualasi prefix indicato
Prefissi
E' possibile aggiungere un prefisso a livello di componente
<Box prefix="nomereducer" />
oppure dentro un qualsiasi fields. Aggiungendo un prefisso al padre sarà aggiunto in automatico a tutti i fields figli.
const modello = [
{
id: 'name', // selector nomereducer.name
type: 'input'
},
{
type: 'grid',
prefix: 'dati',
fields:[
{
id: 'name' // selector nomereducer.dati.name
},
{
id: 'lastname' // selector nomereducer.dati.lastname
}
]
}
]
<Box prefix="nomereducer" fields={modello} />
Container
Capiterà molto spesso di dover mettere attorno ai tuoi fields un componente di layout, questa operazione si potrà fare in 2 modi:
• Modalità normale
const model = [{
type: 'Paper',
fields:[{type: 'text', text: 'ciao'}]
}]
// esempio da compilato
<Paper>
<Text>Ciao</Text>
</Paper>
• Modalità container base
const model = [{
container: 'Paper',
type: 'text',
text: 'ciao'
}]
// esempio da compilato
<Paper>
<Text>Ciao</Text>
</Paper>
• Modalità container con props
const model = [{
container: {type: 'Paper', color: 'red'},
type: 'text',
text: 'ciao'
}]
// esempio da compilato
<Paper color="red">
<Text>Ciao</Text>
</Paper>
Visualizzare tutti gli errori
Passare al context il campo showErrors: true, per visualizzare tutti gli errori
<BoxContextProvider value={{ showErrors: true }}>
<Box prefix="ticket" fields={model} />
</BoxContextProvider>
Redux reducer
Se vuoi usare Box su un progetto esistente, ti basterà estendere il tuo reducer con l'azione di default
• Reducer example
import { boxReducer } from '@stackhouseos/box-core';
const ticketReducer = (state = initialState, action) =>
produce(state, () => {
switch (action.type) {
case DEFAULT_ACTION:
break;
case TUE_AZIONI:
break;
default:
// necessario per fare comunicare il tuo redux con Box
return boxReducer('folder', state, action);
}
});
• Reducer example Redux Toolkit
const slice = createSlice({
name: 'categories',
initialState,
reducers: {
// ... actions
},
extraReducers: {
// necessario per fare comunicare il tuo redux con Box
'@box/categories/update': (state, action) => _set(state, action.payload.id, action.payload.value),
},
});