gentera-rdnd 0.0.6 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/ng-package.json +7 -0
  2. package/package.json +16 -29
  3. package/src/lib/components/button/button.component.html +21 -0
  4. package/src/lib/components/button/button.component.scss +41 -0
  5. package/src/lib/components/button/button.component.ts +82 -0
  6. package/src/lib/components/input/input.component.html +27 -0
  7. package/src/lib/components/input/input.component.scss +86 -0
  8. package/src/lib/components/input/input.component.ts +105 -0
  9. package/src/lib/components/modal/modal.component.html +51 -0
  10. package/src/lib/components/modal/modal.component.scss +50 -0
  11. package/src/lib/components/modal/modal.component.ts +41 -0
  12. package/src/lib/components/screen-title/screen-title.component.html +3 -0
  13. package/src/lib/components/screen-title/screen-title.component.scss +16 -0
  14. package/src/lib/components/screen-title/screen-title.component.ts +16 -0
  15. package/src/lib/gentera-rdnd.component.ts +16 -0
  16. package/src/lib/gentera-rdnd.service.ts +9 -0
  17. package/src/lib/hooks/button.service.ts +31 -0
  18. package/src/lib/hooks/input.service.ts +75 -0
  19. package/src/lib/hooks/modal.service.ts +87 -0
  20. package/src/lib/styles/colors.scss +63 -0
  21. package/src/lib/styles/colors.ts +55 -0
  22. package/src/lib/styles/fonts.scss +93 -0
  23. package/src/lib/styles/sizes.scss +10 -0
  24. package/src/lib/styles/themes.ts +98 -0
  25. package/src/lib/styles/z_indexes.scss +3 -0
  26. package/{public-api.d.ts → src/public-api.ts} +16 -8
  27. package/tsconfig.lib.json +25 -0
  28. package/tsconfig.lib.prod.json +11 -0
  29. package/tsconfig.spec.json +15 -0
  30. package/esm2022/gentera-rdnd.mjs +0 -5
  31. package/esm2022/lib/components/button/button.component.mjs +0 -85
  32. package/esm2022/lib/components/input/input.component.mjs +0 -113
  33. package/esm2022/lib/components/modal/modal.component.mjs +0 -48
  34. package/esm2022/lib/components/screen-title/screen-title.component.mjs +0 -20
  35. package/esm2022/lib/hooks/button.service.mjs +0 -28
  36. package/esm2022/lib/hooks/input.service.mjs +0 -58
  37. package/esm2022/lib/hooks/modal.service.mjs +0 -83
  38. package/esm2022/lib/styles/colors.mjs +0 -47
  39. package/esm2022/lib/styles/themes.mjs +0 -97
  40. package/esm2022/public-api.mjs +0 -13
  41. package/fesm2022/gentera-rdnd.mjs +0 -559
  42. package/fesm2022/gentera-rdnd.mjs.map +0 -1
  43. package/index.d.ts +0 -5
  44. package/lib/components/button/button.component.d.ts +0 -121
  45. package/lib/components/input/input.component.d.ts +0 -35
  46. package/lib/components/modal/modal.component.d.ts +0 -110
  47. package/lib/components/screen-title/screen-title.component.d.ts +0 -7
  48. package/lib/hooks/button.service.d.ts +0 -14
  49. package/lib/hooks/input.service.d.ts +0 -19
  50. package/lib/hooks/modal.service.d.ts +0 -22
  51. package/lib/styles/colors.d.ts +0 -46
  52. package/lib/styles/themes.d.ts +0 -93
@@ -0,0 +1,7 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/gentera-rdnd",
4
+ "lib": {
5
+ "entryFile": "src/public-api.ts"
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,29 +1,16 @@
1
- {
2
- "name": "gentera-rdnd",
3
- "version": "0.0.6",
4
- "peerDependencies": {
5
- "@angular/common": "^18.2.0",
6
- "@angular/core": "^18.2.0",
7
- "@fortawesome/angular-fontawesome": "^0.15.0",
8
- "@fortawesome/free-brands-svg-icons": "^6.5.2",
9
- "@fortawesome/free-regular-svg-icons": "^6.5.2",
10
- "@fortawesome/free-solid-svg-icons": "^6.5.2"
11
- },
12
- "dependencies": {
13
- "tslib": "^2.3.0"
14
- },
15
- "sideEffects": false,
16
- "module": "fesm2022/gentera-rdnd.mjs",
17
- "typings": "index.d.ts",
18
- "exports": {
19
- "./package.json": {
20
- "default": "./package.json"
21
- },
22
- ".": {
23
- "types": "./index.d.ts",
24
- "esm2022": "./esm2022/gentera-rdnd.mjs",
25
- "esm": "./esm2022/gentera-rdnd.mjs",
26
- "default": "./fesm2022/gentera-rdnd.mjs"
27
- }
28
- }
29
- }
1
+ {
2
+ "name": "gentera-rdnd",
3
+ "version": "0.0.9",
4
+ "peerDependencies": {
5
+ "@angular/common": "^18.2.0",
6
+ "@angular/core": "^18.2.0",
7
+ "@fortawesome/angular-fontawesome": "^0.15.0",
8
+ "@fortawesome/free-brands-svg-icons": "^6.5.2",
9
+ "@fortawesome/free-regular-svg-icons": "^6.5.2",
10
+ "@fortawesome/free-solid-svg-icons": "^6.5.2"
11
+ },
12
+ "dependencies": {
13
+ "tslib": "^2.3.0"
14
+ },
15
+ "sideEffects": false
16
+ }
@@ -0,0 +1,21 @@
1
+ <button
2
+ [ngClass]="{
3
+ 'full': size === 'full',
4
+ 'contained': size === 'contained',
5
+ 'bordered': borders,
6
+ 'disabled': disabled
7
+ }"
8
+ [style.background]="disabled ? themes.disabled.default : theme.default"
9
+ [style.color]="theme.fontColor"
10
+ [style.border]="borders ? '1px solid ' + theme.border : 'none'"
11
+ [style.cursor]="disabled ? 'not-allowed' : 'pointer'"
12
+ [attr.type]="type"
13
+ [disabled]="disabled"
14
+
15
+ (mouseleave)="onMouseLeave()"
16
+ (click)="handleClick($event)"
17
+ (mouseenter)="onMouseEnter()"
18
+ >
19
+ <fa-icon *ngIf="icon" [icon]="icon" class="icon"></fa-icon>
20
+ {{ text }}
21
+ </button>
@@ -0,0 +1,41 @@
1
+ button {
2
+ height: 40px;
3
+ display: flex;
4
+ align-items: center;
5
+ justify-content: center;
6
+ gap: 4px;
7
+ padding: 10px;
8
+ font-size: 14px;
9
+ transition: all 0.3s ease;
10
+
11
+ &.full {
12
+ width: 100%;
13
+ }
14
+
15
+ &.contained {
16
+ width: fit-content;
17
+ }
18
+
19
+ &.bordered {
20
+ border-radius: 5px;
21
+ }
22
+
23
+ &.disabled {
24
+ pointer-events: none;
25
+ background-color: #ddd;
26
+ border-color: transparent !important;
27
+ color: #9E9E9E !important;
28
+ }
29
+
30
+ .icon {
31
+ transition: all 0.3s ease;
32
+ }
33
+
34
+ &:hover {
35
+ opacity: 0.8;
36
+ }
37
+ &:active {
38
+ transform: scale(0.99);
39
+ }
40
+
41
+ }
@@ -0,0 +1,82 @@
1
+ import { Component, Input, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
2
+ import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
3
+ import {Observable, Subscription} from 'rxjs';
4
+ import {FaIconComponent} from "@fortawesome/angular-fontawesome";
5
+ import {NgClass, NgIf} from "@angular/common";
6
+ // @ts-ignore
7
+ import {themes} from "../../styles/themes";
8
+ import {ButtonService, ButtonServiceType} from "../../hooks/button.service";
9
+ // @ts-ignore
10
+
11
+
12
+
13
+ @Component({
14
+ selector: 'rdnd-button',
15
+ templateUrl: './button.component.html',
16
+ standalone: true,
17
+ imports: [
18
+ FaIconComponent,
19
+ NgIf,
20
+ NgClass
21
+ ],
22
+ styleUrls: ['./button.component.scss']
23
+ })
24
+ export class RdndButton implements OnInit, OnDestroy {
25
+ @Input() id!: string;
26
+ @Input() icon?: IconDefinition;
27
+ @Input() text: string = 'Enviar';
28
+ @Input() theme: any = themes.magenta;
29
+ @Input() size: 'contained' | 'full' = 'full';
30
+ @Input() type: 'button' | 'submit' | 'reset' = 'submit';
31
+ @Input() borders: boolean = true;
32
+ @Input() disabled: boolean = false;
33
+
34
+ @Output() callback: EventEmitter<void> = new EventEmitter<void>();
35
+
36
+ protected readonly themes = themes;
37
+ private subscription!: Subscription;
38
+ hoverBackgroundColor: string = this.theme.default;
39
+
40
+ buttonControl!: ButtonServiceType ;
41
+
42
+ constructor(private buttonService: ButtonService) {
43
+ }
44
+
45
+ ngOnInit(): void {
46
+ this.buttonControl = this.buttonService.useButton(this.id);
47
+
48
+ this.subscription = new Subscription( () =>
49
+ this.buttonControl.disabled$.subscribe((isDisabled: boolean) => {
50
+ this.disabled = isDisabled;
51
+ })
52
+ )
53
+
54
+ }
55
+
56
+ ngOnDestroy(): void {
57
+ if(this.subscription){
58
+ this.subscription.unsubscribe();
59
+ }
60
+ }
61
+
62
+ handleClick(event: MouseEvent): void {
63
+ event.stopPropagation();
64
+ if (!this.disabled && this.type !== 'submit') {
65
+ this.callback.emit();
66
+ }
67
+ }
68
+
69
+ onMouseEnter() {
70
+ if (!this.disabled) {
71
+ this.hoverBackgroundColor = this.theme.hover;
72
+ }
73
+ }
74
+
75
+ onMouseLeave() {
76
+ if (!this.disabled) {
77
+ this.hoverBackgroundColor = this.theme.default;
78
+ }
79
+ }
80
+
81
+ protected readonly event = event;
82
+ }
@@ -0,0 +1,27 @@
1
+ <div [ngClass]="{ 'disabled': disabled }" class="input-container">
2
+ <!-- Ícono de error que aparece por encima del campo si hay error -->
3
+ <span *ngIf="hasError()" class="error-icon" (click)="toggleErrorDisplay()">&#9432;</span>
4
+
5
+ <!-- Botón de mostrar/ocultar contraseña centrado verticalmente -->
6
+ <button *ngIf="type === 'password'" type="button" (click)="handleTogglePassword()" class="toggle-button">
7
+ <fa-icon [icon]="faEyeSlash" class="icon" [class.active]="showPassword"></fa-icon>
8
+ </button>
9
+
10
+ <!-- Input que cambia de borde si tiene error -->
11
+ <input
12
+ [type]="type === 'password' && showPassword ? 'text' : type"
13
+ [formControl]="control"
14
+ [placeholder]="placeholder"
15
+ [disabled]="disabled"
16
+ (keydown)="handleKeyDown($event)"
17
+ (paste)="handlePaste($event)"
18
+ (focus)="handleFocus($event)"
19
+ (blur)="handleBlur($event)"
20
+ [ngClass]="{ 'error-border': hasError() }"
21
+ />
22
+
23
+ <!-- Mensaje de error que aparece solo cuando se clickea en el ícono de error -->
24
+ <div *ngIf="control.invalid && control.dirty && showError" class="error-message">
25
+ {{ getErrorMessage() }}
26
+ </div>
27
+ </div>
@@ -0,0 +1,86 @@
1
+ .input-container {
2
+ width: 100%;
3
+ min-width: 100%;
4
+ box-sizing: border-box;
5
+ position: relative;
6
+ display: block;
7
+ }
8
+
9
+ input {
10
+ position: relative;
11
+ width: 100%;
12
+ min-width: 100%;
13
+ padding: 7px 35px 7px 8px;
14
+ border-radius: 3px;
15
+ font-family: 'Poppins', sans-serif;
16
+ height: 40px;
17
+ font-size: 16px;
18
+ border: 1px solid #ccc;
19
+ outline: none;
20
+ box-sizing: border-box;
21
+ transition: all 0.3s ease;
22
+ background-color: white !important;
23
+ appearance: none;
24
+ -moz-appearance: textfield;
25
+ -webkit-appearance: textfield;
26
+
27
+ &:-webkit-autofill {
28
+ background-color: white !important;
29
+ }
30
+
31
+ &.error-border {
32
+ border-color: red;
33
+ }
34
+ }
35
+
36
+ input:focus {
37
+ border: 1px solid blue;
38
+ }
39
+
40
+ .error-icon {
41
+ position: absolute;
42
+ right: 8px;
43
+ top: 1px;
44
+ bottom: 1px;
45
+ font-size: 24px;
46
+ color: red;
47
+ cursor: pointer;
48
+ display: flex;
49
+ flex-direction: column;
50
+ justify-content: center;
51
+ align-items: center;
52
+ z-index: 3;
53
+ background-color: white;
54
+ }
55
+
56
+ .error-message {
57
+ position: absolute;
58
+ bottom: 0;
59
+ left: 0;
60
+ //background-color: #ffdddd;
61
+ color: red;
62
+ padding: 0 0 0 8px;
63
+ border-radius: 4px;
64
+ font-size: 12px;
65
+ font-family: sans-serif;
66
+ white-space: nowrap;
67
+ }
68
+
69
+ .toggle-button {
70
+ position: absolute;
71
+ right: 8px;
72
+ top: 50%;
73
+ transform: translateY(-50%);
74
+ background: transparent;
75
+ border: none;
76
+ cursor: pointer;
77
+ z-index: 2;
78
+ }
79
+
80
+ .icon {
81
+ transition: opacity 0.3s ease;
82
+ }
83
+
84
+ .icon.active {
85
+ opacity: 0.5;
86
+ }
@@ -0,0 +1,105 @@
1
+ import {Component, Input, Output, EventEmitter, OnInit} from '@angular/core';
2
+ import {FormControl, ReactiveFormsModule, ValidationErrors, ValidatorFn, Validators} from '@angular/forms';
3
+ import {faEyeSlash} from '@fortawesome/free-solid-svg-icons';
4
+ import {NgClass, NgIf} from '@angular/common';
5
+ import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
6
+ import {InputService} from "../../hooks/input.service";
7
+
8
+
9
+ @Component({
10
+ selector: 'rdnd-input',
11
+ templateUrl: './input.component.html',
12
+ standalone: true,
13
+ imports: [
14
+ NgIf,
15
+ NgClass,
16
+ FontAwesomeModule,
17
+ ReactiveFormsModule
18
+ ],
19
+ styleUrls: ['./input.component.scss']
20
+ })
21
+ export class RdndInput implements OnInit {
22
+ @Input() id!: string;
23
+ @Input() name!: string;
24
+ @Input() type: 'text' | 'password' | 'number' = 'text';
25
+ @Input() placeholder: string = '';
26
+ @Input() value: string = '';
27
+ @Input() validators: ValidatorFn[] = [];
28
+ @Input() disabled: boolean = false;
29
+
30
+ @Output() valueChange = new EventEmitter<string>();
31
+ @Output() onKeyDown = new EventEmitter<KeyboardEvent>();
32
+ @Output() onPaste = new EventEmitter<ClipboardEvent>();
33
+ @Output() onFocus = new EventEmitter<FocusEvent>();
34
+ @Output() onBlur = new EventEmitter<FocusEvent>();
35
+
36
+ control!: FormControl;
37
+ faEyeSlash = faEyeSlash;
38
+ showPassword: boolean = false;
39
+ showError: boolean = false;
40
+
41
+ constructor(private inputService: InputService) {
42
+ }
43
+
44
+ ngOnInit() {
45
+ this.control = new FormControl(this.value, this.validators);
46
+
47
+ this.valueChange.emit(this.value);
48
+ this.inputService.updateInputState(this.control, this.id);
49
+
50
+ this.control.valueChanges.subscribe((value) => {
51
+ this.valueChange.emit(value);
52
+ this.inputService.updateInputState(this.control, this.id);
53
+ });
54
+
55
+ }
56
+
57
+ getErrorMessage(): string | null {
58
+ if (this.control && this.control.errors) {
59
+ const errorKeys = Object.keys(this.control.errors);
60
+ if (errorKeys.length > 0) {
61
+ const firstErrorKey = errorKeys[0];
62
+ return (this.control.errors as ValidationErrors)[firstErrorKey];
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+
68
+ toggleErrorDisplay() {
69
+ this.showError = !this.showError;
70
+ }
71
+
72
+ hasError(): boolean {
73
+ return this.control.invalid && (this.control.dirty || this.control.touched);
74
+ }
75
+
76
+ handleTogglePassword(): void {
77
+ this.showPassword = !this.showPassword;
78
+ }
79
+
80
+ handleKeyDown(event: KeyboardEvent): void {
81
+ const allowRegex = /^[a-zA-Z!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]*$/
82
+
83
+ if (
84
+ this.type === 'number' && !(
85
+ ['Backspace', 'Shift', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)
86
+ ) && !(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
87
+ ) {
88
+ event.key.match(allowRegex) ? event.preventDefault() : this.onKeyDown.emit(event);
89
+ } else {
90
+ this.onKeyDown.emit(event);
91
+ }
92
+ }
93
+
94
+ handlePaste(event: ClipboardEvent): void {
95
+ this.onPaste.emit(event);
96
+ }
97
+
98
+ handleFocus(event: FocusEvent): void {
99
+ this.onFocus.emit(event);
100
+ }
101
+
102
+ handleBlur(event: FocusEvent): void {
103
+ this.onBlur.emit(event);
104
+ }
105
+ }
@@ -0,0 +1,51 @@
1
+ <div class="modal-wrapper">
2
+
3
+ <div class="container" (click)="$event.stopPropagation()">
4
+
5
+ <div class="content">
6
+
7
+ @if (icon) {
8
+ <fa-icon [icon]="icon" class="icon" [style.color]="theme.default"
9
+ />
10
+ }
11
+
12
+ <span class="subtitle align-center">{{ title }}</span>
13
+
14
+ <div class="text align-center" [innerHTML]="content">
15
+ </div>
16
+
17
+
18
+ @if (type !== 'question') {
19
+ <rdnd-button
20
+ [id]="'btn-modal'"
21
+ [type]="'button'"
22
+ (callback)="closeModal(true)"
23
+ [text]="'Aceptar'"
24
+ [theme]="theme"
25
+ [size]="'full'"
26
+ />
27
+ } @else {
28
+ <rdnd-button
29
+ [id]="'btn-modal-accept'"
30
+ [type]="'button'"
31
+ (callback)="closeModal(true)"
32
+ [text]="confirmText"
33
+ [theme]="theme"
34
+ [size]="'full'"
35
+ />
36
+ <rdnd-button
37
+ [id]="'btn-modal-cancel'"
38
+ [type]="'button'"
39
+ (callback)="closeModal(false)"
40
+ [text]="cancelText"
41
+ [theme]="themes.bordered"
42
+ [size]="'full'"
43
+ />
44
+ }
45
+
46
+ </div>
47
+
48
+
49
+ </div>
50
+ </div>
51
+
@@ -0,0 +1,50 @@
1
+ @import "../../styles/z_indexes";
2
+ @import "../../styles/sizes";
3
+ @import "../../styles/fonts";
4
+ @import "../../styles/colors";
5
+
6
+ .modal-wrapper {
7
+ position: fixed;
8
+ top: 0;
9
+ bottom: 0;
10
+ left: 0;
11
+ right: 0;
12
+ z-index: $z-index-modal;
13
+ background-color: rgba(0, 0, 0, 0.7);
14
+ backdrop-filter: blur(5px);
15
+ display: flex;
16
+ justify-content: center;
17
+ align-items: center;
18
+ padding: 16px;
19
+ }
20
+
21
+ .modal-wrapper .container {
22
+ width: 100%;
23
+ max-width: $screen-max-width-small;
24
+ background-color: white;
25
+ padding: 32px 16px;
26
+ border-radius: 4px;
27
+ position: relative;
28
+ }
29
+
30
+ .modal-wrapper .container .content {
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: 8px;
34
+ width: 100%;
35
+ max-width: 380px;
36
+ margin: auto;
37
+
38
+ .icon {
39
+ margin: auto;
40
+ font-size: 40px;
41
+ line-height: normal;
42
+ }
43
+
44
+ p {
45
+ margin: 14px 0;
46
+ }
47
+
48
+
49
+
50
+ }
@@ -0,0 +1,41 @@
1
+ import {Component, EventEmitter, Input, Output} from '@angular/core';
2
+ import {CommonModule} from '@angular/common';
3
+ import {IconDefinition} from '@fortawesome/free-solid-svg-icons';
4
+ import {themes} from "../../styles/themes";
5
+ import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
6
+ import {RdndButton} from "../button/button.component";
7
+ import {RdndScreenTitle} from "../screen-title/screen-title.component";
8
+
9
+ @Component({
10
+ selector: 'rdnd-modal',
11
+ standalone: true,
12
+ imports: [
13
+ CommonModule,
14
+ FontAwesomeModule,
15
+ RdndButton,
16
+ RdndScreenTitle,
17
+ ],
18
+ templateUrl: './modal.component.html',
19
+ styleUrl: './modal.component.scss'
20
+ })
21
+ export class RdndModal {
22
+ @Input() title: string = '';
23
+ @Input() type: 'success' | 'error' | 'question' | 'warning' | 'info' = 'success';
24
+ @Input() theme: any = themes.magenta;
25
+ @Input() confirmText: string = '';
26
+ @Input() cancelText: string = '';
27
+ @Output() close = new EventEmitter<boolean>();
28
+
29
+ protected readonly themes = themes;
30
+
31
+ icon?: IconDefinition;
32
+ content: string = '';
33
+
34
+ closeModal(result: boolean) {
35
+ this.close.emit(result);
36
+ }
37
+
38
+ constructor() {
39
+ }
40
+
41
+ }
@@ -0,0 +1,3 @@
1
+ <h1 [class]=" 'align-' + align ">
2
+ {{ title }}
3
+ </h1>
@@ -0,0 +1,16 @@
1
+ h1 {
2
+ font-size: 24px;
3
+ font-family: 'Poppins', sans-serif;
4
+ color: #910677;
5
+ font-weight: normal;
6
+ width: 100%;
7
+
8
+ &.align-LEFT {
9
+ text-align: left;
10
+ }
11
+
12
+ &.align-CENTER {
13
+ text-align: center;
14
+ }
15
+
16
+ }
@@ -0,0 +1,16 @@
1
+ import {Component, Input} from '@angular/core';
2
+ import {NgClass} from "@angular/common";
3
+
4
+ @Component({
5
+ selector: 'rdnd-screen-title',
6
+ standalone: true,
7
+ imports: [
8
+ NgClass
9
+ ],
10
+ templateUrl: './screen-title.component.html',
11
+ styleUrl: './screen-title.component.scss'
12
+ })
13
+ export class RdndScreenTitle {
14
+ @Input() title!: string;
15
+ @Input() align: 'LEFT' | 'CENTER' = 'CENTER';
16
+ }
@@ -0,0 +1,16 @@
1
+ import { Component } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'lib-gentera-rdnd',
5
+ standalone: true,
6
+ imports: [],
7
+ template: `
8
+ <p>
9
+ gentera-rdnd works!
10
+ </p>
11
+ `,
12
+ styles: ``
13
+ })
14
+ export class GenteraRdndComponent {
15
+
16
+ }
@@ -0,0 +1,9 @@
1
+ import { Injectable } from '@angular/core';
2
+
3
+ @Injectable({
4
+ providedIn: 'root'
5
+ })
6
+ export class GenteraRdndService {
7
+
8
+ constructor() { }
9
+ }
@@ -0,0 +1,31 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject, Observable } from 'rxjs';
3
+
4
+ export interface ButtonServiceType {
5
+ enable: () => void;
6
+ disable: () => void;
7
+ disabled$: Observable<boolean>
8
+ }
9
+
10
+ @Injectable({
11
+ providedIn: 'root',
12
+ })
13
+ export class ButtonService {
14
+ private buttonsState: { [id: string]: BehaviorSubject<boolean> } = {};
15
+
16
+ private ensureButtonExists(id: string): void {
17
+ if (!this.buttonsState[id]) {
18
+ this.buttonsState[id] = new BehaviorSubject<boolean>(false);
19
+ }
20
+ }
21
+
22
+ useButton(id: string): ButtonServiceType {
23
+ this.ensureButtonExists(id);
24
+
25
+ return {
26
+ disabled$: this.buttonsState[id].asObservable(),
27
+ enable: () => this.buttonsState[id].next(false),
28
+ disable: () => this.buttonsState[id].next(true),
29
+ };
30
+ }
31
+ }