diff --git a/package.json b/package.json index 8980f88..17b1676 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@github/catalyst": "^1.1.3", - "lit-html": "^1.4.1", + "core/utils": "^1.4.1", "validator": "^13.6.0" }, "devDependencies": { diff --git a/src/common/core/BaseElement/BaseElement.ts b/src/common/core/BaseElement/BaseElement.ts index ecce741..eb738d3 100644 --- a/src/common/core/BaseElement/BaseElement.ts +++ b/src/common/core/BaseElement/BaseElement.ts @@ -1,4 +1,4 @@ -import { html, render, TemplateResult } from 'lit-html'; +import { html, render, TemplateResult } from 'core/utils'; import { AppLoaderElement, AppMainElement, AppModalElement, AppRootElement } from 'components/'; import { AppService, RouterService } from 'core/services'; import { AuthStore } from 'core/store'; @@ -71,7 +71,7 @@ class BaseElement extends HTMLElement { }); }; - render = (): TemplateResult | Temp => { + render = (): TemplateResult => { return html``; }; diff --git a/src/common/core/Validator/Validator.ts b/src/common/core/Validator/Validator.ts new file mode 100644 index 0000000..45e5acd --- /dev/null +++ b/src/common/core/Validator/Validator.ts @@ -0,0 +1,86 @@ +import { AppFormElement } from 'components/'; +import { validatorErrors } from 'core/constants'; +import { firstUpper, validator } from 'core/utils'; + +class Validator { + public _error: string; + public _valid: boolean; + constructor(public input: any, public form: AppFormElement, public rules: string) {} + + get value() { + return this.input?._value; + } + + get name() { + return this.input?.name; + } + + get error() { + return this._error; + } + + set error(error) { + this._error = error; + } + + get valid() { + return this._valid; + } + + set valid(error) { + this._valid = error; + } + + validate = () => { + const rules = this.rules?.split('|').filter((a) => a); + const value = this.value; + const validArr = rules + .slice() + .reverse() + .map((rule) => { + let args = []; + if (rule.includes('[') && rule.includes(']')) { + const begSep = rule.lastIndexOf('['); + const endSep = rule.lastIndexOf(']'); + + args = rule + .slice(begSep + 1, endSep) + .split(',') + .map((arg: string) => { + if (this.form && arg?.includes?.('field')) { + const begBr = arg.lastIndexOf('('); + const endBr = arg.lastIndexOf(')'); + const field = arg.slice(begBr + 1, endBr); + + return this.form?.values[field]; + } + }); + rule = rule.slice(0, begSep); + } + let validRule = validator?.[rule]; + let ruleArray = validRule ? Array.isArray(validRule) : false; + let valid = true; + + if (validRule) { + if (ruleArray) { + valid = validRule?.[0]?.(value, ...args); + } else { + valid = validRule?.(value, ...args); + } + } + if (!valid) { + const error = validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString())); + this.error = ruleArray ? validRule?.[1]?.replaceAll('{- name}', firstUpper(this.name?.toString())) : error; + } + return valid; + }); + const _return = validArr?.includes(false); + if (_return) { + this.error = null; + } + this.valid = !_return; + return !_return; + }; +} + +export default Validator; diff --git a/src/common/index.ts b/src/common/index.ts index f769514..d3e4e76 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,4 +1,6 @@ export { default as BaseElement } from './core/BaseElement/BaseElement'; +export { default as Validator } from './core/Validator/Validator'; + export * from './layouts'; export * from './components'; export * from './pages'; diff --git a/src/common/pages/BasePageElement/BasePageElement.ts b/src/common/pages/BasePageElement/BasePageElement.ts index 8655bf3..f998dc5 100644 --- a/src/common/pages/BasePageElement/BasePageElement.ts +++ b/src/common/pages/BasePageElement/BasePageElement.ts @@ -1,5 +1,5 @@ import { attr } from '@github/catalyst'; -import { html, render } from 'lit-html'; +import { html, render } from 'core/utils'; import { BaseElement } from 'common/'; import { isTrue } from 'core/utils'; diff --git a/src/components/app-dropdown/AppDropdownElement.ts b/src/components/app-dropdown/AppDropdownElement.ts index ea1f397..4165923 100644 --- a/src/components/app-dropdown/AppDropdownElement.ts +++ b/src/components/app-dropdown/AppDropdownElement.ts @@ -1,10 +1,10 @@ import { attr, controller, target } from '@github/catalyst'; -import { findMethod, firstUpper } from 'core/utils'; -import { html } from 'lit-html'; +import { closest, findMethod, firstUpper } from 'core/utils'; +import { html } from 'core/utils'; import randomId from 'core/utils/random-id'; -import validator from 'validator'; import { validatorErrors } from 'core/constants'; -import { BaseComponentElement } from 'common/'; +import { BaseComponentElement, Validator } from 'common/'; +import { AppFormElement } from 'components/app-form/AppFormElement'; @controller class AppDropdownElement extends BaseComponentElement { @@ -13,12 +13,12 @@ class AppDropdownElement extends BaseComponentElement { @attr rules: string; @target main: HTMLElement; @target inp: HTMLElement; + @target dropdowncontainer: HTMLElement; @attr displaykey: string = 'name'; @attr valuekey: string = 'id'; @attr fetch: string; - fetchFunc: any; + @closest appForm: AppFormElement; - error: boolean; errorMessage: string; searchPhrase: string; @@ -32,10 +32,56 @@ class AppDropdownElement extends BaseComponentElement { totalItems: number; page: number = 1; rpp: number = 30; + validator: Validator; constructor() { super(); } + + updateCallback = () => { + this.dropdowncontainer?.scrollIntoView(); + }; + + public elementConnected = (): void => { + this.validator = new Validator(this, this.appForm, this.rules); + this.randId = `${name}${randomId()}`; + this.update(); + + const options = { + rpp: this.rpp, + page: this.page, + }; + this.getItems(options); + }; + + attributeChangedCallback(): void { + this.update(); + } + + setError = (error) => { + this.validator.error = error; + }; + + get error(): string { + return this.validator?.error; + } + + get isValid(): boolean { + return this.validator?.valid; + } + + get required(): boolean { + return this.rules.includes('required'); + } + + get _value() { + return this.value; + } + + validate = (): boolean => { + return this.validator.validate(); + }; + getItems = async (options?: any): Promise => { if (typeof this.fetchFunc !== 'function') return; try { @@ -68,8 +114,6 @@ class AppDropdownElement extends BaseComponentElement { return value == item[valuekey]; }); - console.log(item, value, valuekey); - return item; } @@ -83,61 +127,16 @@ class AppDropdownElement extends BaseComponentElement { return values; } - public elementConnected = (): void => { - this.randId = `${name}${randomId()}`; - this.fetchFunc = findMethod(this.fetch, this.appMain); - this.update(); + get fetchFunc() { + return findMethod(this.fetch, this.appMain); + } - const options = { - rpp: this.rpp, - page: this.page, - }; - this.getItems(options); + setOpen = (isOpen) => { + this.isOpen = isOpen; }; - attributeChangedCallback(): void { - this.update(); - } - - get valid(): boolean { - return !!this.error; - } - - get required(): boolean { - return this.rules.includes('required'); - } - - validate(): boolean { - let _return = true; - const rules = this.rules?.split('|').filter((a) => a); - const value = (this.inp as HTMLSelectElement)?.value; - rules - .slice() - .reverse() - .forEach((rule) => { - let valid = true; - if (rule == 'required') { - if (value === '') valid = false; - } else { - if (validator.hasOwnProperty(rule)) { - valid = validator?.[rule]?.(value); - } - } - if (!valid) { - const error = validatorErrors[rule]?.replaceAll('{- name}', firstUpper(this.name?.toString())); - _return = false; - this.error = error; - } - }); - if (_return) { - this.error = null; - } - this.update(); - return _return; - } - openDropdown = () => { - this.isOpen = true; + this.setOpen(true); }; stopPropagation = (e) => { @@ -146,24 +145,24 @@ class AppDropdownElement extends BaseComponentElement { toggleDropdown = () => { const isOpen = this.isOpen; - this.isOpen = !isOpen; + this.setOpen(!isOpen); }; itemSelected = (e) => { const value = (e.target as HTMLSpanElement).getAttribute('data-value'); - this.value = value; - this.isOpen = false; + this.setOpen(false); + this.setValue(value); + this.appForm?.inputChange(e); }; - get _value() { - return this.value; - } + setValue = (value) => { + this.value = value; + this.update(); + }; render = () => { const { label, error, errorMessage, isOpen, searchPhrase, items, selectedItem, displaykey, valuekey } = this; - console.log(isOpen); - const renderItem = (item) => { return html`