kea-react
Version:
Componentes comunes de react
108 lines (96 loc) • 4.83 kB
text/typescript
import React = require('react');
import update = require('immutability-helper');
import interfaces = require("./interfaces");
/**
* Llama al metodo onModelChanged con el nuevo objeto del modelo con los datos cambiados,
* considerando que el modelo original es immutable
*/
export function handleModelPropertyChanged<TIn, TOut>(newValue: any, key: string, props: interfaces.ControlledValueProps<TIn, TOut>) {
console.warn("use handleFormChange ya que esta tipado");
if (props.onChange) {
var updateSpec = {};
updateSpec[key] = { $set: newValue };
var newModel : any = (update as any)(props.value!, updateSpec);
props.onChange(newModel);
}
}
/**Llama al método props.onChange incluyendo un cambio en una propiedad de value
* @param change Objeto parcial que indica las propiedades que cambiaron de value, junto con sus nuevos valores
* @param props Propiedades del componente
*/
export function handleChange<TIn, TOut>(change: Partial<TOut>, props: interfaces.ControlledValueProps<TIn, TOut>) {
console.warn("use handleFormChange ya que esta tipado");
const newModel = Object.assign({}, props.value! || {}, change);
if (props.onChange)
props.onChange(newModel as any as TOut);
}
function createChangeFunction<TIn, TOut>(propsThunk: () => { value?: TIn, onChange?: (value: TOut) => void | PromiseLike<void> }, key: string) : HandleChangeFunction<any> {
const changeFunc = ((value) => ({ [key as string]: value } as Partial<TOut>));
return async function (value: any) {
const props = propsThunk();
if (props.onChange) {
const change = changeFunc(value);
const newModel = Object.assign({}, props.value! || {}, change);
await props.onChange(newModel as any as TOut);
}
}
}
export interface HandleChangeFunction<T> {
(value: T): PromiseLike<void>
}
export interface HandleChangeNameFunction<T> {
<K extends keyof T>(key : K) : HandleChangeFunction<T[K]>;
}
/**
* Devuelve una curry-function que toma el props, el nombre de una propiedad de value, y el nuevo valor a asignar en esa propiedad.
* La segunda funcion siempre devuelve la misma instancia para el mismo nombre de propiedad
* En su clase cree la funcion de cambio:
* const handleChange = handleFormChange(() => this.props);
*
* En los componentes editores:
* <Text value={this.props.text} onChange={handleChange("Nombre")} />
*
* @param propsThunk Funcion que devuelve un objeto con el valor actual y la función de cambio
* @param key Nombre de la propiedad
* @param value Nuevo valor de la propiedad.
*
*/
export function handleFormChange<TIn, TOut>(propsThunk: () => { value?: TIn, onChange?: (value: TOut) => void | PromiseLike<void> }) : HandleChangeNameFunction<TOut> {
type cacheType = {
[P in keyof TOut]?: HandleChangeFunction<TOut[P]>;
};
const cache: cacheType = {};
return function <K extends keyof TOut>(key: K) {
return cache[key] || (cache[key] = createChangeFunction(propsThunk, key))
}
}
/**Devuelve una función que maneja el onChange de un control de una forma, donde la propiedad cambiada es una propiedad de props.value.
* Siempre devuelve la misma instancia de la función para un changeFunction equivalente.
* Esta es la manera recomendada de manejar el onChange en una forma ya que al devolver siempre la misma función para el mismo campo, evitamos redibujar el campo
*
* @param changeFunction Función que dado un nuevo valor devuelve un objecto parcial con la propiedad que se va a cambiar asignada al nuevo valor de esa propiedad. Esta función debe de ser pura
* @param propsThunk Función que devuelve el value y el onChange de la forma
* @param cache Objeto donde se va a almacenar el cache de funciones
*/
export function onChange<TIn, TOut>(changeFunction: (value: any) => Partial<TOut>, propsThunk: () => interfaces.ControlledValueProps<TIn, TOut>, cache: { [name: string]: any }) {
console.warn("use handleFormChange ya que esta tipado");
const keys = Object.keys(changeFunction("test"));
if (keys.length != 1) {
throw "La función del handleChange debe de ser pura y devolver un objeto con solo una propiedad";
}
const key = keys[0];
if (cache[key]) {
return cache[key];
} else {
const newFunc = newValue => {
const props = propsThunk();
const change = changeFunction(newValue);
const newModel = Object.assign({}, props.value! || {}, change);
if (props.onChange) {
props.onChange(newModel as any as TOut);
}
};
cache[key] = newFunc;
return newFunc;
}
}