gascox-component-library
v0.0.6-p
Published
Design system for Gasco
Downloads
20
Readme
GASCO COMPONENTS LIBRARY README
Esta creado con StencilJs https://stenciljs.com/
Para clonar el repo y echar a andar todo:
- Clonar el repo con git clone
- cd a la carpeta donde se clono el repo, en mi caso gascox-component-library
- la primera vez necesitaras instalar los node_modules con:
npm install
- para correr el app:
npm run start
Para crear un nuevo componente
- Tienes que estar con la consola apuntando a la carpeta donde esta el proyecto:
npm run generate
completas el nombre del componente y le dasyes
- Vas a la carpeta
src/components
y ya esta tu componente listo para trabajarlo
Para publicar cambios en la libreria:
- (solo 1 vez) En la consola dentro del proyecto
npm login
, ingresar password, id, email - Ir al package.json y cambiar el "version" a la siguiente version
- En la consola dentro del proyecto
npm run build
- En la consola dentro del proyecto
npm publish
Carpetas de src
- assets: es donde iran las imagenes, videos, etc. necesarios para los componentes
- components: donde estan los componentes creados
- globals: para dejar archivos globales de scss como variables, mixins etc...
- utils: lo trae por default el stencil
Para agregarlo a un Proyecto Angular
En la consola dentro del proyecto:
npm i --save gascox-component-library
o si quieres actualizar la versionnpm i --save [email protected]
donde despues del @ sera la version, o le dasnpm uninstall gascox-component-library
y luegonpm i --save gascox-component-library
En el AppModule.ts (y en el modulo mas cercano donde se espamea algun componente) agregar
schemas: [CUSTOM_ELEMENTS_SCHEMA],
desde@angular/core
, esto es para permitir elementos custom dentro de angualrEn el Main.ts agregar:
import { defineCustomElements } from 'gascox-component-library/loader';
y lineas ,as abajodefineCustomElements(window);
ya solo queda llamar en el componente de angular el selector del componente de la libreria de gasco ejm:
<gasco-button></gasco-button>
, recuerden el paso 2 en su modulo mas cercano
Forma de enviarle las props
las Variables que son booleanas puedes no enviarle valor ya que tienen valor por default, ejm en el caso de disabled ppuedes enviar
disabled='true'
o puedes solo enviarledisabled
, tambien puedes enviarledisabled={{myVar}}
o[disabled]="myVar"
de esta forma bindeas una variable desde el .tslas variables array o tipo Json (objetos)
[steps]="myArray"
donde [steps] es la variable dentro del componente y myArray un array en el .ts donde se esta implementando el componente de la libreriavariables desde el .ts para que sean diamicos o cambien segun lo necesitemos:
[steps]="myVarFromTs"
donde steps es el var dentro del componente de la libreria y myVarFromTs es la variable en el .ts donde se implemente el componente de la libreriala variables de tipo string puedes enviarlas con
prop='Hola mundo'
oprop={myVar}
o[prop]='myVar'
o si no te resulta conprop={{myVar}}
donde my var es la variable en el .ts donde se esta implementando em componente
Forma de utilizar Funciones del componente (stencil) desde angular
Si tu componente de Stencil (para este caso <modalGasco/>
) tiene un @Method o un metodo como close o open, puedes llamarlo desde el angular de la siguiente forma:
- en tu .Html
<modalGasco #miCustomModal/>
- en tu .ts
@ViewChild('miCustomModal') modal!: ElementRef;
- en tu .ts donde colocaste el @ViewChild
this.modal.nativeElement.openModal();
Forma de enviarle una Funcion al componente (stencil) desde angular para que se ejecute
Si tu componente de Stencil (para este caso <modalGasco/>
) tiene una @Prop de tipo Function, le puedes enviar de esta forma tu funcion a ejecutar desde angular de la siguiente forma:
- en tu .Html
<modalGasco [propStencilComponent]='myFunctuonAngular.bind(this)'/>
el.bind(this)
es necestario que se lo agreges despues del nombre d tu fincion sin las () de la funcion - en tu .ts
myFunctuonAngular(){console.log('hola mundo')
- en tu componente stencil ya puedes ocupar esa funcion
---------------------BUTTON GASCO------------------------------------------------
Selector:
<gasco-button></gasco-button>
Recibe varios properties (props)
<gasco-button
type="primary"
text="Texto muestra"
left="add"
disabled={{myDisabledVar}}
outline
right="mail"
></gasco-button>
type: es el tipo de boton, se le puede enviar 'primary' para azul o 'secondary' para rojo. Si no se le envia nada por default sera primary
text: Es el value que tendra el button, si no se le envia nada por defaul sera 'Aceptar'. Si solo es texto se alineara al centro, si tiene un icono a la izquierda se alinieada con flex-start o al comienzo
left= es un parametro opcional, este sera para spamear un icono a la izquierda. Por ahora solo se puede pasar el valor de 'add' para spamear un icono de una cruz con redondo azul
disabled= es un parametro opcional, si se pasa como true se spamea el style para el button disabled y elimina los eventos del mouse sobre el, myDisabledVar es una variable en el .ts
outline= es un parametro opcional, es para cambiar el tipo de button a outline, o sin relleno en el medio
right= permite spamear un icono a la derecha, al momento de este readme solo se permite el mail
IMPORTANTE: en el repo
fe_pagoEnLinea-sinLogin
en el archivostyles.scss
que esta a la par del main.ts se encuentra una clase.containerButtons
la cual la agregas en el div que contendra los buttons y de forma automatica spamea los styles colocando los botones a los costados y en mobile spameandolos en toda la pantalla, se recomienda agregarlos en elstyles.scss
de tu proyecto y desde el componente donde estas trabajando darle un@import
a esos stylos de esa forma tendras styles globales para todo tu proyecto
---------------------INPUT GASCO------------------------------------------------
Selector:
<gasco-input></gasco-input>
Recibe varios properties (props)
<gasco-input
placeholder="Soy una etiqueta"
value="Soy el texto del input"
required={{myVariable}}
validator="number"
min-length="9"
max-length="9"
counter
searchicon
error="Mensaje de error"
haserror={{true}}
appAccessor
formControlName="myInput"
></gasco-input>
placeholder: es el texto que tendra la etiqueta, si el input no tiene value la etiqueta se espamea dentro del input, si tiene el input value la etiqueta se espamea ensima del input
value: es el texto que contiene el input
required: para convertir este input en requerido, el usuario tiene que completarlo. Si el usuario da click en el y se sale, el borde y el place holder se cambia a rojo y se spamea un default message error de 'Este campo es requerido', si no le envias nada asume que es true
validator: es para aplicarle al input que acepte solo: letras, numeros u otro validador. los parametos aceptados son se encuentan en ValidatorTypes y al momento de hacer este readme pueden ser: [ number letters rut]. Si no se le pasa uno o no coincide con esos no le aplica ningun validador
min-length: minimo de caracteres para que el input sea valido, si el usuario no completa los caracteres se le mostrara un mensaje d error de que necesita completar este campo
max-length: maximo de caracteres para que el input sea valido, si el usuario no completa los caracteres se le mostrara un mensaje d error de que necesita completar este campo. Si le agregas este valor, el input no dejara ingresar un mayor numero de caracteres, es decir, si agregas max-length en 5 el input no permite agregar mas de 5 caracteres
counter: para spamear del lado derecho-abajo un contador que muestra el total de caracteres ingresados y el total necesario, si no le envias nada asume que es true
error: mensaje de error que quiere que se pinte en el input, marca al input como invalid hasta q el usuario modifique el value
searchicon: para poder spamear un icono de lupa a la izquierda del input, si no le envias nada asume que es true
haserror: para forzar al input a error, osea que se muestre en rojo el borde
appAccessor: es una directiva que se tiene que crear en Angular para que lo tome los formularios reactivos (buscar seccion "DIRECTIVA FORMULARIO REACTIVO")
formControlName: es el controlname para insertarlo en el formulario reactivo de la forma tradicional, pero se necesita la directiva del paso 11
TIP: el width del input lo puedes dar con la propiedad de css de width o con flex-basic tanto en px, vw, %, rem. Ya que se comporta como una etiqueta HTML
---------------------STEPPER GASCO------------------------------------------------
Selector:
<gasco-stepper></gasco-stepper>
Nota: Este componente sirve para 3,4 y 5 pasos, la cantidad de caracteres del titulo pueden ir de 1 a 13 (lo recomendable segun maquetacion), la cantidad del subtitulo puede ser de 1 a 19 (lo recomendable segun maquetacion), Este componente es responsive por ende segun la cantidad de pasos y la medida de pantalla (diferentes mediaQuery) pasara de tener circulo,titulo,subtitulo y linea a solo tener circulo y linea
Recibe dos Prop:
<gasco-stepper
[steps]="steps"
[active]="stepActive"
></gasco-stepper>
steps: es el array de pasos, este se declara en el .ts y se llama en el html donde este el steper
active: es el paso activo o paso actual como quieras llamarlo. Se puede pasar del paso 1 al 5, del 5 al 1 de una vez indicandole el valor del paso que quieres colocar activo, el steper si estas en el paso 1 y le indicas al paso 5 coloca al paso 5 como activo y los otros como done, si estas en el 5 y le indicas 1 coloca al 1 como activo y los otros como disabled, si estas en el paso 1 y le indicas 2 coloca al 1 como disabled y al 2 como activo
mySteps es un array de elementos tipo string
{
number: '1', //Este es el numero dentro del circulo
title: 'Cliente', //este es el texto del titulo
subTitle: 'Búsqueda de cliente', //este es el texto del subtitulo
}
Este es un Objeto para 5 pasos el cual debes declarar en tu .ts donde se este implementando el steper, por default colocara como activo el primer elemento del array
mySteps = [
{
number: '1',
title: 'Cliente',
subTitle: 'Búsqueda de cliente',
},
{
number: '2',
title: 'Cuentas',
subTitle: 'Cuentas por pagar',
},
{
number: '3',
title: 'Medio de pago',
subTitle: 'Información de pago',
},
{
number: '4',
title: 'Comprobante',
subTitle: 'Finalizar pago',
},
{
number: '5',
title: 'Medio de pago',
subTitle: 'Informacion de pago',
},
];
---------------------MODAL GASCO------------------------------------------------
Selector:
En el .html
<gasco-modal #myModal></gasco-modal>
En el .ts hacer un @ViewChild('myModal') modal!: ElementRef;
Recibe properties (props)
- closeBackgroud: (es Opcional) esta propiedad permite que el modal se cierre dando click fuera de el, por defecto es true (ya que es opcional), por ende se cierra al darle click fuera. Si no quieres eso tendras que pasarle esta propertie en false
<gasco-modal [closeBackgroud]='false'></gasco-modal>
- Abrir y Cerrar: despues de ocupar el @viewChild
myModal.nativeElement.open()
myModal.nativeElement.close()
MODAL CUSTOM (
info
error
success
) Funcion para setear los parametros a los modalesinfo
error
success
. Recomiendo crear una constante o enum con estos parametros
tipo de modal a spamear ('info' 'error' 'success'): Recuerca crear el enum o const con los tipos de modal que le puedes pasar, por q si no le pasas exactamente cualquier de estos valores, no se va a ver nada
const type:string = 'success';
titleModal: es un parametro opcional, es un texto que si lo envias se coloca a la altura donde esta la x de cerrar el modal con una linea debajo del texto
const modalTitle:string = 'Soy el titulo';
array de botones: Puedes parametrizar cada boton ya que es un gascoButton y acepta todas sus props, ademas acepta una funcion que se ejecuta cuando le dan click. Si le envias 1 solo button se centra, si le envias 2 (es lo maximo maquetado) se colocan en los bordes
const buttons = [ { text: 'Regresar', type="secondary" outline onClickFunction: this.myCustomFunction.bind(this) { text: 'Aceptar', type="primary" outline onClickFunction: this.myNewCustomFunctionWithParams.bind(this) ];
Body del modal: titleBodyModal: es el texto en color debajo del icono text1: es un parrafo sin palabras a color, es opcional, si no lo envias no se spamea y no modifca styles text2: Es un parrafo donde su ultima parte o el
strongText
termina en color elejidocolor
. Es opcional, si no se envia no se spamea ni modifica styles color: puede sergreen
red
blue
yellow
const body = { titleBodyModal: 'Titulo Body', text1: 'Soy un parrafo de tipo uno sin palabra strong', text2: { normalText: 'Soy un parrafo de tipo 2 ', strongText: 'y yo la palabra strong', color: 'red', }, };
Forma en como pasarle estos parametos al modal y abrirlo desde el angular
myModal.nativeElement.setValuesModalCustom( type, buttons, body,modalTitle ); myModal.nativeElement.openModal();
---------------------TOAST GASCO------------------------------------------------
Selector
En el .html
<gasco-toast></gasco-toast>
Recibe tres Prop:
<gasco-toast [display]="true" [type]="primary" [text]="Texto de prueba"></gasco-toast>
display: true | false : indica si el toast debe o no mostrarse, en caso de colocar false, este se remueve del dom.
type: "primary" | "warning" : indica el tipo de toast y con ello las clases css especificas para cada uno, hasta el momento soporta primary para tipo informativo azul y warning tipo alerta amarillo.
text: string : permite agregar una cadena de texto al toast.
---------------------Loading------------------------------------------------
Selector:
<gasco-loading></gasco-loading>
- Agregas en .html
<gasco-loading #loadingGasco></gasco-loading>
- en el .ts
@ViewChild('loadingGasco') gsLoading!: ElementRef;
- En el mismo .ts en la llamada http
this.gsLoading.nativeElement.open();
para cerrarlo (puedes cerrarlo en el siguiente componente o step si lo necesitas)
this.gsLoading.nativeElement.close();
Nota: es responsive, solo espamealo y el mismo se adapta
---------------------DIRECTIVA FORMULARIO REACTIVO------------------------------------------------
Esta directiva t permite obtener el value de los inputs mediante los formularios reactivos.
Creas una directiva e insertas este codigo (recuerda registrarla en el module del app o el mas cercano)
import {
Directive,
forwardRef,
HostBinding,
HostListener,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Directive({
selector: '[appAccessor]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormDirective),
multi: true,
},
],
})
export class FormDirective implements ControlValueAccessor {
@HostBinding('value') hostValue: any;
lastValue: any;
private onChange = (value: any) => {};
private onTouched = () => {};
writeValue(value: any) {
this.hostValue = this.lastValue = value == null ? '' : value;
}
registerOnChange(fn: (value: any) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}
@HostListener('valueChanged', ['$event.detail'])
_handleInputEvent(value: any) {
if (JSON.stringify(value) !== JSON.stringify(this.lastValue)) {
this.lastValue = value;
this.onChange(value);
this.onTouched();
}
}
}
Este es el archivo de test para subir el coverage
import { FormDirective } from './form-directive.directive';
describe('FormDirectiveDirective', () => {
let directive: FormDirective;
beforeEach(() => {
directive = new FormDirective();
});
it('should create an instance', () => {
expect(directive).toBeTruthy();
});
it('Test onChange', () => {
const toBe = 'algo';
spyOn<any>(directive, 'onChange').and.callThrough();
directive['onChange']('algo');
expect(directive['onChange']).toHaveBeenCalledWith('algo');
});
it('Test onTouched', () => {
spyOn<any>(directive, 'onTouched').and.callThrough();
directive['onTouched']();
expect(directive['onTouched']).toHaveBeenCalled();
});
it('Test writeValue sin parametro', () => {
directive.lastValue = 'ultimo';
directive.writeValue(null);
expect(directive.lastValue).toEqual('');
});
it('Test writeValue con parametro', () => {
const newParam = 'algo nuevo';
directive.lastValue = 'ultimo';
directive.writeValue(newParam);
expect(directive.lastValue).toEqual(newParam);
});
it('registerOnChange test', () => {
spyOn<any>(directive, 'registerOnChange').and.callThrough();
directive['onChange'] = () => console.log(`Hola Mundo`);
const newFunction = () => {};
directive.registerOnChange(newFunction);
expect(directive.registerOnChange).toHaveBeenCalled();
expect(directive['onChange']).toEqual(newFunction);
});
it('registerOnTouched test', () => {
spyOn<any>(directive, 'registerOnTouched').and.callThrough();
directive['onTouched'] = () => console.log(`Hola Mundo`);
const newFunction = () => {};
directive.registerOnTouched(newFunction);
expect(directive.registerOnTouched).toHaveBeenCalled();
expect(directive['onTouched']).toEqual(newFunction);
});
it('_handleInputEvent Bad request ', () => {
spyOn<any>(directive, 'onChange').and.callThrough();
spyOn<any>(directive, 'onTouched').and.callThrough();
const valor = 'fake';
const newValor = 'new';
directive.lastValue = valor;
directive._handleInputEvent(valor);
expect(directive.lastValue).not.toEqual(newValor);
expect(directive['onChange']).not.toHaveBeenCalled();
expect(directive['onTouched']).not.toHaveBeenCalled();
});
it('_handleInputEvent OK', () => {
spyOn<any>(directive, 'onChange').and.callThrough();
spyOn<any>(directive, 'onTouched').and.callThrough();
const valor = 'fake';
const newValor = 'new';
directive.lastValue = valor;
directive._handleInputEvent(newValor);
expect(directive.lastValue).toEqual(newValor);
expect(directive['onChange']).toHaveBeenCalled();
expect(directive['onTouched']).toHaveBeenCalled();
});
});