Skip to content

Commit

Permalink
Add Block realisation, add validation, add HTTPTransport
Browse files Browse the repository at this point in the history
  • Loading branch information
VladToby committed Jul 26, 2024
1 parent c36ba65 commit ac1b43b
Show file tree
Hide file tree
Showing 54 changed files with 3,080 additions and 195 deletions.
12 changes: 12 additions & 0 deletions .stylelintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"plugins": ["stylelint-less"],
"rules": {
"at-rule-no-unknown": null,
"color-no-invalid-hex": true,
"less/color-no-invalid-hex": true
},
"ignoreFiles": [
"dist/*",
"node_modules/*"
]
}
12 changes: 12 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default [
{
files: ["src/**/*.ts"],
rules: {
"max-len": [2, 100],
"max-params": [2, 3],
"no-console": "off",
"eol-last": ['error', 'always'],
},
ignores: ["dist", "node_modules"],
}
];
2,193 changes: 2,176 additions & 17 deletions package-lock.json

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@
"type": "module",
"scripts": {
"dev": "vite --port 3000",
"prebuild": "tsc --noEmit",
"build": "npm run prebuild && vite build",
"build": "vite build",
"preview": "vite preview",
"start": "vite build && vite preview --port 3000"
"start": "vite build && vite preview --port 3000",
"eslint": "npx eslint"
},
"devDependencies": {
"vite": "^5.3.1",
"less": "^4.2.0"
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.16.1",
"@typescript-eslint/parser": "^7.16.1",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.1",
"less": "^4.2.0",
"stylelint-less": "^3.0.1",
"typescript": "^5.5.3",
"vite": "^5.3.1"
},
"dependencies": {
"@stylistic/eslint-plugin": "^2.3.0",
"handlebars": "^4.7.8",
"uuid": "^10.0.0",
"vite-plugin-handlebars": "^2.0.0"
},
"engines": {
Expand Down
16 changes: 16 additions & 0 deletions src/components/button/button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import './button.less';
import Block, {Props} from '../../core/Block';
import ButtonTmpl from './button.hbs?raw';

export class Button extends Block {
constructor(props: Props) {
super({...props});
this.props.events = {
click: this.props.onClick || (() => {}),
};
}

render(): string {
return ButtonTmpl;
}
}
2 changes: 0 additions & 2 deletions src/components/button/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/error/error.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div class="error container">
<h1 class="error title">{{errorTitle}}</h1>
<span class="error text">{{errorText}}
{{> Button class="error back-button" label="Chat" page="chatPage" }}
{{{ Button class="error back-button" label="Chat" page="ChatPage" }}}
</span>
</div>
13 changes: 13 additions & 0 deletions src/components/error/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import './error.less';
import Block, {Props} from "../../core/Block";
import ErrorTmpl from './error.hbs?raw';

export class Error extends Block {
constructor(props: Props) {
super(props);
}

render(): string {
return ErrorTmpl;
}
}
2 changes: 0 additions & 2 deletions src/components/error/index.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/components/index.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/components/input/index.ts

This file was deleted.

14 changes: 12 additions & 2 deletions src/components/input/input.hbs
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
<label for="{{ name }}">{{ label }}</label>
<input type="{{ type }}" name="{{ name }}" class="input {{ class }}" placeholder="{{ placeholder }}" value="{{ value }}" />
<div class="input-wrapper {{#if hasError}}has-error{{/if}}">
<label for="{{ name }}">{{ label }}</label>
<input
type="{{ type }}"
name="{{ name }}"
class="input {{ class }}"
placeholder="{{ placeholder }}"
value="{{ value }}"
{{#if autocomplete}}autocomplete="{{ autocomplete }}"{{/if}}
/>
<div class="error-message">{{ error }}</div>
</div>
31 changes: 26 additions & 5 deletions src/components/input/input.less
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,32 @@
font-size: @font-size;
}

.input {
.input();
.input-wrapper {
margin-bottom: 3rem;

&:hover, &:active, &:focus-visible {
border: 1px solid @main__button-background-color !important;
outline: none;
label {
margin-bottom: 0.25rem;
}

.input {
.input();

&:hover, &:active, &:focus-visible {
border: 1px solid @main__button-background-color !important;
outline: none;
}
}

.error-message {
position: absolute;
font-size: 0.75rem;
color: #ff0000; // Цвет текста ошибки
margin-top: 0.25rem; // Небольшой отступ от инпута
}

&.has-error {
.input {
.input(@border: 1px solid #ff0000) !important;
}
}
}
68 changes: 68 additions & 0 deletions src/components/input/input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Block, { Props } from '../../core/Block';
import template from './input.hbs?raw';
import { validateField } from '../../utils/validation';

export class Input extends Block {
constructor(props: Props) {
super({
...props,
value: props.value || '',
error: '',
hasError: false,
events: {
blur: (e: FocusEvent) => {
this.validate();
if (typeof this.props.onBlur === 'function') {
this.props.onBlur(e);
}
},
input: (e: Event) => {
const input = e.target as HTMLInputElement;
this.props.value = input.value;
}
}
});
}

public setValue(value: string): void {
this.setProps({ value });
}

public getValue(): unknown {
return this.props.value;
}

public validate(): boolean {
const errorMessage: string | null = validateField(<string>this.props.name, <string>this.props.value);
const hasError: boolean = !!errorMessage;
this.setProps({
error: errorMessage,
hasError: hasError
});
console.log(!!errorMessage);
return !errorMessage;
}

render(): string {
return template;
}

protected componentDidUpdate(oldProps: any, newProps: any): boolean {
if (this._element) {
if (newProps.hasError !== oldProps.hasError) {
this._element.classList.toggle('has-error', newProps.hasError);
}

const errorElement = this._element.querySelector('.error-message');
if (errorElement) {
errorElement.textContent = newProps.error || '';
}

const inputElement = this._element.querySelector('input') as HTMLInputElement;
if (inputElement && inputElement.value !== newProps.value) {
inputElement.value = newProps.value;
}
}
return false;
}
}
53 changes: 53 additions & 0 deletions src/core/BaseForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Block, { Props } from './Block';
import { Input } from '../components/input/input';

export class BaseForm extends Block {
constructor(props: Props) {
super({
...props,
events: {
submit: (event: Event) => {
event.preventDefault();
this.onSubmit();
},
},
});
}

protected onSubmit() {
const formData: Record<string, string> = {};
let isValid: boolean = true;

Object.values(this.children).forEach((child: Block | Element) => {
if (child instanceof Input) {
const { name } = child.props;
formData[name] = child.getValue();
if (!child.validate()) {
isValid = false;
}
}
});

if (isValid) {
this.onValid(formData);
} else {
this.onInvalid();
}
}

protected onValid(formData: Record<string, string>) {
// This method should be overridden in child classes
}

protected onInvalid() {
// This method can be overridden in child classes if needed
}

protected navigate(page: string) {
const event = new CustomEvent('navigate', {
bubbles: true,
detail: { page }
});
document.dispatchEvent(event);
}
}
Loading

0 comments on commit ac1b43b

Please sign in to comment.