verben-ng-ui 0.0.1
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.
- package/README.md +24 -0
- package/ng-package.json +10 -0
- package/package.json +34 -0
- package/src/lib/Verbena-input/error.service.ts +23 -0
- package/src/lib/Verbena-input/verbena-input.component.css +59 -0
- package/src/lib/Verbena-input/verbena-input.component.html +64 -0
- package/src/lib/Verbena-input/verbena-input.component.spec.ts +25 -0
- package/src/lib/Verbena-input/verbena-input.component.ts +162 -0
- package/src/lib/Verbena-input/verbena-input.module.ts +12 -0
- package/src/lib/components/TemplateDirective.directive.ts +10 -0
- package/src/lib/components/card/card.component.css +20 -0
- package/src/lib/components/card/card.component.html +23 -0
- package/src/lib/components/card/card.component.spec.ts +23 -0
- package/src/lib/components/card/card.component.ts +33 -0
- package/src/lib/components/card/card.module.ts +10 -0
- package/src/lib/components/card-data-view/card-data-view-footer/card-data-view-footer.component.css +3 -0
- package/src/lib/components/card-data-view/card-data-view-footer/card-data-view-footer.component.html +1 -0
- package/src/lib/components/card-data-view/card-data-view-footer/card-data-view-footer.component.spec.ts +23 -0
- package/src/lib/components/card-data-view/card-data-view-footer/card-data-view-footer.component.ts +10 -0
- package/src/lib/components/card-data-view/card-data-view-header/card-data-view-header.component.css +7 -0
- package/src/lib/components/card-data-view/card-data-view-header/card-data-view-header.component.html +1 -0
- package/src/lib/components/card-data-view/card-data-view-header/card-data-view-header.component.spec.ts +23 -0
- package/src/lib/components/card-data-view/card-data-view-header/card-data-view-header.component.ts +10 -0
- package/src/lib/components/card-data-view/card-data-view.component.css +39 -0
- package/src/lib/components/card-data-view/card-data-view.component.html +29 -0
- package/src/lib/components/card-data-view/card-data-view.component.spec.ts +23 -0
- package/src/lib/components/card-data-view/card-data-view.component.ts +66 -0
- package/src/lib/components/card-data-view/card-data-view.module.ts +20 -0
- package/src/lib/components/card-data-view/card-data.ts +7 -0
- package/src/lib/components/card-data-view/left-card-data/left-card-data.component.css +15 -0
- package/src/lib/components/card-data-view/left-card-data/left-card-data.component.html +4 -0
- package/src/lib/components/card-data-view/left-card-data/left-card-data.component.spec.ts +23 -0
- package/src/lib/components/card-data-view/left-card-data/left-card-data.component.ts +19 -0
- package/src/lib/components/card-data-view/left-card-data-view/left-card-data-view.component.css +0 -0
- package/src/lib/components/card-data-view/left-card-data-view/left-card-data-view.component.html +4 -0
- package/src/lib/components/card-data-view/left-card-data-view/left-card-data-view.component.spec.ts +23 -0
- package/src/lib/components/card-data-view/left-card-data-view/left-card-data-view.component.ts +12 -0
- package/src/lib/components/card-data-view/right-card-data-view/right-card-data-view.component.css +3 -0
- package/src/lib/components/card-data-view/right-card-data-view/right-card-data-view.component.html +1 -0
- package/src/lib/components/card-data-view/right-card-data-view/right-card-data-view.component.spec.ts +23 -0
- package/src/lib/components/card-data-view/right-card-data-view/right-card-data-view.component.ts +10 -0
- package/src/lib/components/chip/ChipChangeEvent.ts +4 -0
- package/src/lib/components/chip/chip.component.css +94 -0
- package/src/lib/components/chip/chip.component.html +49 -0
- package/src/lib/components/chip/chip.component.spec.ts +23 -0
- package/src/lib/components/chip/chip.component.ts +209 -0
- package/src/lib/components/chip/chip.module.ts +24 -0
- package/src/lib/components/chip/documentation.md +26 -0
- package/src/lib/components/data-export/data-export.component.css +0 -0
- package/src/lib/components/data-export/data-export.component.html +90 -0
- package/src/lib/components/data-export/data-export.component.spec.ts +23 -0
- package/src/lib/components/data-export/data-export.component.ts +158 -0
- package/src/lib/components/data-export/data-export.module.ts +13 -0
- package/src/lib/components/data-export/data-export.service.spec.ts +16 -0
- package/src/lib/components/data-export/data-export.service.ts +152 -0
- package/src/lib/components/data-export/data-export.types.ts +21 -0
- package/src/lib/components/data-table/column.directive.spec.ts +8 -0
- package/src/lib/components/data-table/column.directive.ts +19 -0
- package/src/lib/components/data-table/data-table.component.css +0 -0
- package/src/lib/components/data-table/data-table.component.html +55 -0
- package/src/lib/components/data-table/data-table.component.spec.ts +21 -0
- package/src/lib/components/data-table/data-table.component.ts +336 -0
- package/src/lib/components/data-table/data-table.module.ts +11 -0
- package/src/lib/components/data-table/data-table.types.ts +13 -0
- package/src/lib/components/data-table/style.types.ts +55 -0
- package/src/lib/components/data-view/data-view-click-outside.directive.ts +44 -0
- package/src/lib/components/data-view/data-view.component.css +74 -0
- package/src/lib/components/data-view/data-view.component.html +161 -0
- package/src/lib/components/data-view/data-view.component.spec.ts +23 -0
- package/src/lib/components/data-view/data-view.component.ts +136 -0
- package/src/lib/components/data-view/data-view.module.ts +16 -0
- package/src/lib/components/date-picker/date-picker.component.css +65 -0
- package/src/lib/components/date-picker/date-picker.component.html +60 -0
- package/src/lib/components/date-picker/date-picker.component.specs.ts +23 -0
- package/src/lib/components/date-picker/date-picker.component.ts +143 -0
- package/src/lib/components/date-picker/date-picker.module.ts +12 -0
- package/src/lib/components/drop-down/DropdownChangeEvent.ts +4 -0
- package/src/lib/components/drop-down/DropdownLoadEvent.ts +19 -0
- package/src/lib/components/drop-down/DropdownMenuItem.ts +42 -0
- package/src/lib/components/drop-down/documentation.md +69 -0
- package/src/lib/components/drop-down/drop-down-item/drop-down-item.component.css +123 -0
- package/src/lib/components/drop-down/drop-down-item/drop-down-item.component.html +133 -0
- package/src/lib/components/drop-down/drop-down-item/drop-down-item.component.spec.ts +23 -0
- package/src/lib/components/drop-down/drop-down-item/drop-down-item.component.ts +88 -0
- package/src/lib/components/drop-down/drop-down.component.css +317 -0
- package/src/lib/components/drop-down/drop-down.component.html +177 -0
- package/src/lib/components/drop-down/drop-down.component.spec.ts +23 -0
- package/src/lib/components/drop-down/drop-down.component.ts +757 -0
- package/src/lib/components/drop-down/drop-down.module.ts +24 -0
- package/src/lib/components/image/image.component.css +12 -0
- package/src/lib/components/image/image.component.html +18 -0
- package/src/lib/components/image/image.component.spec.ts +23 -0
- package/src/lib/components/image/image.component.ts +45 -0
- package/src/lib/components/image/image.module.ts +11 -0
- package/src/lib/components/notification/notification.component.css +3 -0
- package/src/lib/components/notification/notification.component.html +19 -0
- package/src/lib/components/notification/notification.component.spec.ts +23 -0
- package/src/lib/components/notification/notification.component.ts +77 -0
- package/src/lib/components/notification/notification.module.ts +14 -0
- package/src/lib/components/shared.module.ts +9 -0
- package/src/lib/components/sort-table/sort-table.component.css +67 -0
- package/src/lib/components/sort-table/sort-table.component.html +164 -0
- package/src/lib/components/sort-table/sort-table.component.spec.ts +23 -0
- package/src/lib/components/sort-table/sort-table.component.ts +204 -0
- package/src/lib/components/sort-table/sort-table.module.ts +11 -0
- package/src/lib/components/svg/svg.component.css +0 -0
- package/src/lib/components/svg/svg.component.html +1 -0
- package/src/lib/components/svg/svg.component.spec.ts +23 -0
- package/src/lib/components/svg/svg.component.ts +64 -0
- package/src/lib/components/svg/svg.module.ts +10 -0
- package/src/lib/components/table-filter/table-filter.component.css +93 -0
- package/src/lib/components/table-filter/table-filter.component.html +293 -0
- package/src/lib/components/table-filter/table-filter.component.spec.ts +23 -0
- package/src/lib/components/table-filter/table-filter.component.ts +221 -0
- package/src/lib/components/table-filter/table-filter.module.ts +25 -0
- package/src/lib/components/tooltip/tooltip.component.css +8 -0
- package/src/lib/components/tooltip/tooltip.component.html +13 -0
- package/src/lib/components/tooltip/tooltip.component.spec.ts +23 -0
- package/src/lib/components/tooltip/tooltip.component.ts +84 -0
- package/src/lib/components/tooltip/tooltip.module.ts +11 -0
- package/src/lib/components/verben-mail/verben-mail.component.config.ts +11 -0
- package/src/lib/components/verben-mail/verben-mail.component.css +71 -0
- package/src/lib/components/verben-mail/verben-mail.component.html +139 -0
- package/src/lib/components/verben-mail/verben-mail.component.ts +151 -0
- package/src/lib/components/verben-mail/verben-mail.module.ts +18 -0
- package/src/lib/components/visible-column/visible-column.component.css +83 -0
- package/src/lib/components/visible-column/visible-column.component.html +77 -0
- package/src/lib/components/visible-column/visible-column.component.spec.ts +23 -0
- package/src/lib/components/visible-column/visible-column.component.ts +106 -0
- package/src/lib/components/visible-column/visible-column.module.ts +11 -0
- package/src/lib/config.ts +37 -0
- package/src/lib/control-options/control-options.directive.ts +129 -0
- package/src/lib/control-options/control-options.module.ts +10 -0
- package/src/lib/convert-to-integer/convert-to-integer.directive.ts +28 -0
- package/src/lib/convert-to-integer/convert-to-integer.module.ts +10 -0
- package/src/lib/convert-to-integer/public-api.ts +1 -0
- package/src/lib/convert-to-number/convert-to-number.directive.ts +22 -0
- package/src/lib/convert-to-number/convert-to-number.module.ts +8 -0
- package/src/lib/convert-to-number/public-api.ts +1 -0
- package/src/lib/email-validator/email-validator.directive.ts +24 -0
- package/src/lib/email-validator/email-validator.module.ts +14 -0
- package/src/lib/models/column-filter.ts +5 -0
- package/src/lib/models/data-filter.ts +8 -0
- package/src/lib/models/mail-model.ts +8 -0
- package/src/lib/models/sort-filter.ts +0 -0
- package/src/lib/models/table-filter.ts +34 -0
- package/src/lib/number-range/number-range.directive.ts +35 -0
- package/src/lib/number-range/number-range.module.ts +11 -0
- package/src/lib/phone-number/phone-number.directive.ts +22 -0
- package/src/lib/phone-number/phone-number.module.ts +10 -0
- package/src/lib/phone-number/public-api.ts +1 -0
- package/src/lib/required-input/required-input.directive.ts +18 -0
- package/src/lib/required-input/required-input.module.ts +8 -0
- package/src/lib/theme-switcher/theme-switcher.directive.spec.ts +8 -0
- package/src/lib/theme-switcher/theme-switcher.directive.ts +70 -0
- package/src/lib/theme-switcher/theme-switcher.module.ts +8 -0
- package/src/lib/validate/error-message.service.ts +104 -0
- package/src/lib/validate/validate.directive.ts +110 -0
- package/src/lib/validate/validate.module.ts +17 -0
- package/src/lib/validate-input/validate-input.directive.ts +8 -0
- package/src/lib/validate-input/validate-input.module.ts +8 -0
- package/src/lib/verben-ng-ui.component.spec.ts +23 -0
- package/src/lib/verben-ng-ui.component.ts +16 -0
- package/src/lib/verben-ng-ui.service.spec.ts +16 -0
- package/src/lib/verben-ng-ui.service.ts +9 -0
- package/src/lib/verbena-badge/verbena-badge.component.css +16 -0
- package/src/lib/verbena-badge/verbena-badge.component.html +13 -0
- package/src/lib/verbena-badge/verbena-badge.component.spec.ts +25 -0
- package/src/lib/verbena-badge/verbena-badge.component.ts +18 -0
- package/src/lib/verbena-badge/verbena-badge.module.ts +10 -0
- package/src/lib/verbena-button/verbena-button.component.css +20 -0
- package/src/lib/verbena-button/verbena-button.component.html +25 -0
- package/src/lib/verbena-button/verbena-button.component.spec.ts +25 -0
- package/src/lib/verbena-button/verbena-button.component.ts +92 -0
- package/src/lib/verbena-button/verbena-button.module.ts +11 -0
- package/src/lib/verbena-switch/verbena-switch.component.css +45 -0
- package/src/lib/verbena-switch/verbena-switch.component.html +8 -0
- package/src/lib/verbena-switch/verbena-switch.component.spec.ts +25 -0
- package/src/lib/verbena-switch/verbena-switch.component.ts +31 -0
- package/src/lib/verbena-switch/verbena-switch.module.ts +10 -0
- package/src/lib/verbena-textarea/verbena-textarea.component.css +0 -0
- package/src/lib/verbena-textarea/verbena-textarea.component.html +19 -0
- package/src/lib/verbena-textarea/verbena-textarea.component.spec.ts +33 -0
- package/src/lib/verbena-textarea/verbena-textarea.component.ts +44 -0
- package/src/lib/verbena-textarea/verbena-textarea.module.ts +11 -0
- package/src/public-api.ts +122 -0
- package/src/styles.css +103 -0
- package/tsconfig.lib.json +15 -0
- package/tsconfig.lib.prod.json +11 -0
- package/tsconfig.spec.json +15 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './convert-to-integer.module';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Directive, ElementRef, HostListener, Renderer2, Output, EventEmitter } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[appConvertToNumber]'
|
|
5
|
+
})
|
|
6
|
+
export class ConvertToNumberDirective {
|
|
7
|
+
|
|
8
|
+
@Output() numberValue = new EventEmitter<number | null>();
|
|
9
|
+
|
|
10
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
|
11
|
+
|
|
12
|
+
@HostListener('input', ['$event.target.value']) onInput(value: string) {
|
|
13
|
+
const num = Number(value);
|
|
14
|
+
if (!isNaN(num)) {
|
|
15
|
+
this.numberValue.emit(num);
|
|
16
|
+
this.renderer.setProperty(this.el.nativeElement, 'value', num);
|
|
17
|
+
} else {
|
|
18
|
+
this.numberValue.emit(null);
|
|
19
|
+
}
|
|
20
|
+
console.log(`this is ${num}`)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './convert-to-number.module';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[validateEmail]'
|
|
5
|
+
})
|
|
6
|
+
export class EmailValidatorDirective {
|
|
7
|
+
|
|
8
|
+
private emailRegex: RegExp = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
9
|
+
|
|
10
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
|
11
|
+
|
|
12
|
+
@HostListener('input', ['$event.target.value']) onInput(value: string) {
|
|
13
|
+
if (!this.emailRegex.test(value)) {
|
|
14
|
+
this.renderer.setStyle(this.el.nativeElement, 'border', '2px solid red');
|
|
15
|
+
} else {
|
|
16
|
+
this.renderer.setStyle(this.el.nativeElement, 'border', 'none');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// import { MaxNumberModule } from 'verbena-ui-peace22/max-number';
|
|
22
|
+
// import { MinNumberModule } from 'verbena-ui-peace22/min-number';
|
|
23
|
+
// import { RequiredInputModule } from 'verbena-ui-peace22/required-input';
|
|
24
|
+
// import { EmailValidatorModule } from 'verbena-ui-peace22/email-validator';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { EmailValidatorDirective } from './email-validator.directive';
|
|
3
|
+
|
|
4
|
+
@NgModule({
|
|
5
|
+
declarations: [EmailValidatorDirective],
|
|
6
|
+
exports: [EmailValidatorDirective]
|
|
7
|
+
})
|
|
8
|
+
export class EmailValidatorModule {}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// import { MaxNumberModule } from 'verbena-ui-peace22/max-number';
|
|
12
|
+
// import { MinNumberModule } from 'verbena-ui-peace22/min-number';
|
|
13
|
+
// import { RequiredInputModule } from 'verbena-ui-peace22/required-input';
|
|
14
|
+
// import { EmailValidatorModule } from 'verbena-ui-peace22/email-validator';
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export enum DataFilterType {
|
|
2
|
+
String = 'String',
|
|
3
|
+
Integer = 'Integer',
|
|
4
|
+
Decimal = 'Decimal',
|
|
5
|
+
Credit= 'Credit',
|
|
6
|
+
Date = 'Date',
|
|
7
|
+
Bool = "Bool",
|
|
8
|
+
Number="Number"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface IDataFilter {
|
|
12
|
+
name:string,
|
|
13
|
+
type: DataFilterType;
|
|
14
|
+
value?:any;
|
|
15
|
+
checked: boolean;
|
|
16
|
+
condition?:string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export enum ConditionalOptions {
|
|
20
|
+
LessThan = 'Less than',
|
|
21
|
+
GreaterThan = 'Greater than',
|
|
22
|
+
Equal = 'Equal',
|
|
23
|
+
NotEqual = 'Not equal',
|
|
24
|
+
On = 'On',
|
|
25
|
+
Before = 'Before',
|
|
26
|
+
After = 'After',
|
|
27
|
+
Yes = 'Yes',
|
|
28
|
+
No = 'No'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ITypeOption {
|
|
32
|
+
type: DataFilterType;
|
|
33
|
+
options: string[];
|
|
34
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[appNumberRange]'
|
|
5
|
+
})
|
|
6
|
+
export class NumberRangeDirective {
|
|
7
|
+
@Input() maxNumber!: number;
|
|
8
|
+
@Input() minNumber!: number;
|
|
9
|
+
|
|
10
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
|
11
|
+
|
|
12
|
+
@HostListener('input', ['$event.target.value']) onInput(value: string) {
|
|
13
|
+
const numberValue = parseFloat(value);
|
|
14
|
+
let borderStyle = 'none';
|
|
15
|
+
|
|
16
|
+
if (isNaN(numberValue)) {
|
|
17
|
+
borderStyle = 'none';
|
|
18
|
+
} else if (this.maxNumber !== undefined && numberValue > this.maxNumber) {
|
|
19
|
+
borderStyle = '1px solid red';
|
|
20
|
+
} else if (this.minNumber !== undefined && numberValue < this.minNumber) {
|
|
21
|
+
borderStyle = '1px solid red';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.renderer.setStyle(this.el.nativeElement, 'border', borderStyle);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// <input type="number" appNumberRange [maxNumber]="10">
|
|
31
|
+
// <input type="number" appNumberRange [minNumber]="5">
|
|
32
|
+
// <input type="number" appNumberRange [maxNumber]="10" [minNumber]="5">
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { NumberRangeDirective } from './number-range.directive';
|
|
4
|
+
|
|
5
|
+
@NgModule({
|
|
6
|
+
declarations: [NumberRangeDirective],
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
exports: [NumberRangeDirective]
|
|
9
|
+
})
|
|
10
|
+
export class NumberRangeModule {}
|
|
11
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[appPhoneNumber]'
|
|
5
|
+
})
|
|
6
|
+
export class PhoneNumberDirective {
|
|
7
|
+
|
|
8
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
|
9
|
+
|
|
10
|
+
@HostListener('input', ['$event'])
|
|
11
|
+
onInputChange(event: Event): void {
|
|
12
|
+
let inputValue = (event.target as HTMLInputElement).value;
|
|
13
|
+
const numericValue = this.formatToNumeric(inputValue);
|
|
14
|
+
this.renderer.setProperty(this.el.nativeElement, 'value', numericValue);
|
|
15
|
+
console.log(`Formatted phone number: ${numericValue}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private formatToNumeric(value: string): string {
|
|
19
|
+
// Remove all non-numeric characters except leading zeros
|
|
20
|
+
return value.replace(/[^0-9]/g, '');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { PhoneNumberDirective } from './phone-number.directive';
|
|
4
|
+
|
|
5
|
+
@NgModule({
|
|
6
|
+
declarations: [PhoneNumberDirective],
|
|
7
|
+
imports: [CommonModule],
|
|
8
|
+
exports: [PhoneNumberDirective]
|
|
9
|
+
})
|
|
10
|
+
export class PhoneNumberModule {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './phone-number.module';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[requiredInput]'
|
|
5
|
+
})
|
|
6
|
+
export class RequiredInputDirective {
|
|
7
|
+
|
|
8
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
|
9
|
+
|
|
10
|
+
@HostListener('input') onInput() {
|
|
11
|
+
const value = this.el.nativeElement.value.trim();
|
|
12
|
+
if (value === '') {
|
|
13
|
+
this.renderer.setStyle(this.el.nativeElement, 'border', '2px solid red');
|
|
14
|
+
} else {
|
|
15
|
+
this.renderer.setStyle(this.el.nativeElement, 'border', 'none');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Directive, ElementRef, Input, Renderer2, HostListener } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Directive({
|
|
4
|
+
selector: '[appThemeSwitcher]'
|
|
5
|
+
})
|
|
6
|
+
export class ThemeSwitcherDirective {
|
|
7
|
+
@Input() switchColor: string = 'black'; // Custom color for dark mode
|
|
8
|
+
@Input() switchClass: string = ''; // Additional classes provided by the user
|
|
9
|
+
|
|
10
|
+
private isDarkMode: boolean = false;
|
|
11
|
+
private originalColor: string = ''; // Store the original color of the element
|
|
12
|
+
|
|
13
|
+
constructor(private el: ElementRef, private renderer: Renderer2) {
|
|
14
|
+
this.loadTheme();
|
|
15
|
+
this.storeOriginalColor(); // Store the computed color of the element
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@HostListener('click') onClick() {
|
|
19
|
+
this.toggleTheme();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private toggleTheme(): void {
|
|
23
|
+
const themeClass = 'dark';
|
|
24
|
+
|
|
25
|
+
if (this.isDarkMode) {
|
|
26
|
+
// Switch to light mode for the whole page
|
|
27
|
+
this.renderer.removeClass(document.documentElement, themeClass);
|
|
28
|
+
this.applyElementStyles(this.originalColor); // Reset the element's original color
|
|
29
|
+
localStorage.setItem('theme', 'light');
|
|
30
|
+
} else {
|
|
31
|
+
// Switch to dark mode for the whole page
|
|
32
|
+
this.renderer.addClass(document.documentElement, themeClass);
|
|
33
|
+
this.applyElementStyles(this.switchColor); // Apply dark mode color for the element
|
|
34
|
+
localStorage.setItem('theme', 'dark');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.isDarkMode = !this.isDarkMode; // Toggle the mode state
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private applyElementStyles(color: string): void {
|
|
41
|
+
// Apply inline color to the element
|
|
42
|
+
this.el.nativeElement.style.color = color;
|
|
43
|
+
|
|
44
|
+
// Apply user-provided custom class if available
|
|
45
|
+
if (this.switchClass) {
|
|
46
|
+
this.renderer.addClass(this.el.nativeElement, this.switchClass);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private storeOriginalColor(): void {
|
|
51
|
+
// Get the computed style of the element to find its original color
|
|
52
|
+
const computedStyle = window.getComputedStyle(this.el.nativeElement);
|
|
53
|
+
this.originalColor = computedStyle.color;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private loadTheme(): void {
|
|
57
|
+
const savedTheme = localStorage.getItem('theme');
|
|
58
|
+
|
|
59
|
+
if (savedTheme === 'dark') {
|
|
60
|
+
// If dark mode was previously set, apply it to the page and element
|
|
61
|
+
this.renderer.addClass(document.documentElement, 'dark');
|
|
62
|
+
this.isDarkMode = true;
|
|
63
|
+
this.applyElementStyles(this.switchColor);
|
|
64
|
+
} else {
|
|
65
|
+
// Apply the original color if the light theme is active
|
|
66
|
+
this.isDarkMode = false;
|
|
67
|
+
this.applyElementStyles(this.originalColor);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
@Injectable({
|
|
4
|
+
providedIn: 'root'
|
|
5
|
+
})
|
|
6
|
+
export class ErrorMessageService {
|
|
7
|
+
public createErrorMessage(
|
|
8
|
+
inputElement: HTMLInputElement,
|
|
9
|
+
message: string,
|
|
10
|
+
position: 'above' | 'below',
|
|
11
|
+
color: string,
|
|
12
|
+
showErrorIcon: boolean,
|
|
13
|
+
tooltipPosition: 'top' | 'bottom' | 'left' | 'right'
|
|
14
|
+
) {
|
|
15
|
+
this.removeErrorMessage(inputElement);
|
|
16
|
+
|
|
17
|
+
// Error message element
|
|
18
|
+
if (message) {
|
|
19
|
+
const errorElement = document.createElement('span');
|
|
20
|
+
errorElement.textContent = message;
|
|
21
|
+
errorElement.style.color = color;
|
|
22
|
+
errorElement.style.fontSize = '12px';
|
|
23
|
+
errorElement.classList.add('error-message');
|
|
24
|
+
|
|
25
|
+
if (position === 'above') {
|
|
26
|
+
inputElement.parentNode?.insertBefore(errorElement, inputElement);
|
|
27
|
+
} else {
|
|
28
|
+
inputElement.parentNode?.insertBefore(errorElement, inputElement.nextSibling);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Tooltip behavior for the error icon
|
|
33
|
+
if (showErrorIcon) {
|
|
34
|
+
const errorDot = document.createElement('div');
|
|
35
|
+
errorDot.style.width = '8px';
|
|
36
|
+
errorDot.style.height = '8px';
|
|
37
|
+
errorDot.style.backgroundColor = 'red';
|
|
38
|
+
errorDot.style.borderRadius = '50%';
|
|
39
|
+
errorDot.style.position = 'absolute';
|
|
40
|
+
errorDot.style.top = '50%';
|
|
41
|
+
errorDot.style.right = '10px';
|
|
42
|
+
errorDot.style.transform = 'translateY(-50%)';
|
|
43
|
+
errorDot.style.cursor = 'pointer';
|
|
44
|
+
errorDot.classList.add('error-dot');
|
|
45
|
+
|
|
46
|
+
// Tooltip element
|
|
47
|
+
const tooltip = document.createElement('span');
|
|
48
|
+
tooltip.textContent = message;
|
|
49
|
+
tooltip.style.position = 'absolute';
|
|
50
|
+
tooltip.style.padding = '5px';
|
|
51
|
+
tooltip.style.backgroundColor = 'red';
|
|
52
|
+
tooltip.style.color = 'white';
|
|
53
|
+
tooltip.style.borderRadius = '4px';
|
|
54
|
+
tooltip.style.fontSize = '10px';
|
|
55
|
+
tooltip.style.whiteSpace = 'nowrap';
|
|
56
|
+
tooltip.style.visibility = 'hidden'; // Hidden until hover/click
|
|
57
|
+
tooltip.classList.add('error-tooltip');
|
|
58
|
+
|
|
59
|
+
this.setTooltipPosition(tooltip, errorDot, tooltipPosition);
|
|
60
|
+
|
|
61
|
+
// Show tooltip on hover/click
|
|
62
|
+
errorDot.addEventListener('mouseenter', () => (tooltip.style.visibility = 'visible'));
|
|
63
|
+
errorDot.addEventListener('mouseleave', () => (tooltip.style.visibility = 'hidden'));
|
|
64
|
+
errorDot.addEventListener('click', () => (tooltip.style.visibility = 'visible'));
|
|
65
|
+
|
|
66
|
+
inputElement.parentNode?.appendChild(errorDot);
|
|
67
|
+
inputElement.parentNode?.appendChild(tooltip);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private setTooltipPosition(tooltip: HTMLElement, errorDot: HTMLElement, position: 'top' | 'bottom' | 'left' | 'right') {
|
|
72
|
+
switch (position) {
|
|
73
|
+
case 'top':
|
|
74
|
+
tooltip.style.bottom = '20px';
|
|
75
|
+
tooltip.style.left = '50%';
|
|
76
|
+
tooltip.style.transform = 'translateX(-50%)';
|
|
77
|
+
break;
|
|
78
|
+
case 'bottom':
|
|
79
|
+
tooltip.style.top = '20px';
|
|
80
|
+
tooltip.style.left = '50%';
|
|
81
|
+
tooltip.style.transform = 'translateX(-50%)';
|
|
82
|
+
break;
|
|
83
|
+
case 'left':
|
|
84
|
+
tooltip.style.right = '20px';
|
|
85
|
+
tooltip.style.top = '50%';
|
|
86
|
+
tooltip.style.transform = 'translateY(-50%)';
|
|
87
|
+
break;
|
|
88
|
+
case 'right':
|
|
89
|
+
tooltip.style.left = '20px';
|
|
90
|
+
tooltip.style.top = '50%';
|
|
91
|
+
tooltip.style.transform = 'translateY(-50%)';
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public removeErrorMessage(inputElement: HTMLInputElement) {
|
|
97
|
+
const errorElements = inputElement.parentNode?.querySelectorAll('.error-message, .error-dot, .error-tooltip');
|
|
98
|
+
if (errorElements) {
|
|
99
|
+
errorElements.forEach((errorElement) => {
|
|
100
|
+
errorElement.remove();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Directive, ElementRef, Input, HostListener, Renderer2 } from '@angular/core';
|
|
2
|
+
import { ErrorMessageService } from './error-message.service';
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: '[appValidate]'
|
|
6
|
+
})
|
|
7
|
+
export class ValidateDirective {
|
|
8
|
+
@Input('appValidate') validationType: 'text' | 'number' | 'decimal' | 'integer' | 'email' = 'text';
|
|
9
|
+
@Input() required: boolean = false;
|
|
10
|
+
@Input() showBorder: boolean = true; // The controlling factor for the error icon
|
|
11
|
+
@Input() showErrorMessage: boolean = true;
|
|
12
|
+
|
|
13
|
+
@Input() errorBorderColor: string = 'red'; // Border color for errors
|
|
14
|
+
@Input() errorMessageColor: string = 'red'; // Color for error message
|
|
15
|
+
@Input() errorIconTooltipPosition: 'top' | 'bottom' | 'left' | 'right' = 'top'; // Tooltip position for error dot
|
|
16
|
+
@Input() showErrorIcon: boolean = true;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
private el: ElementRef,
|
|
20
|
+
private errorMessageService: ErrorMessageService,
|
|
21
|
+
private renderer: Renderer2
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
@HostListener('input', ['$event.target']) onInput(inputElement: any) {
|
|
25
|
+
const value = inputElement.value.trim();
|
|
26
|
+
|
|
27
|
+
switch (this.validationType) {
|
|
28
|
+
case 'text':
|
|
29
|
+
this.validateText(inputElement, value);
|
|
30
|
+
break;
|
|
31
|
+
case 'number':
|
|
32
|
+
this.validateNumber(inputElement, value);
|
|
33
|
+
break;
|
|
34
|
+
case 'decimal':
|
|
35
|
+
this.validateDecimal(inputElement, value);
|
|
36
|
+
break;
|
|
37
|
+
case 'integer':
|
|
38
|
+
this.validateInteger(inputElement, value);
|
|
39
|
+
break;
|
|
40
|
+
case 'email':
|
|
41
|
+
this.validateEmail(inputElement, value);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private validateText(input: any, value: string) {
|
|
47
|
+
if (this.required && value === '') {
|
|
48
|
+
this.showError(input, 'Text is required');
|
|
49
|
+
} else {
|
|
50
|
+
this.clearError(input);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private validateNumber(input: any, value: string) {
|
|
55
|
+
if (isNaN(+value)) {
|
|
56
|
+
this.blockInvalidInput(input, 'Please enter a valid number');
|
|
57
|
+
} else {
|
|
58
|
+
this.clearError(input);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private validateDecimal(input: any, value: string) {
|
|
63
|
+
const regex = /^\d*\.?\d*$/;
|
|
64
|
+
if (!regex.test(value)) {
|
|
65
|
+
this.showError(input, 'Please enter a valid decimal number');
|
|
66
|
+
} else {
|
|
67
|
+
this.clearError(input);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private validateInteger(input: any, value: string) {
|
|
72
|
+
const regex = /^\d+$/;
|
|
73
|
+
if (!regex.test(value)) {
|
|
74
|
+
this.blockInvalidInput(input, 'Please enter a valid integer');
|
|
75
|
+
} else {
|
|
76
|
+
this.clearError(input);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private validateEmail(input: any, value: string) {
|
|
81
|
+
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
82
|
+
if (!regex.test(value)) {
|
|
83
|
+
this.blockInvalidInput(input, 'Please enter a valid email address');
|
|
84
|
+
} else {
|
|
85
|
+
this.clearError(input);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private blockInvalidInput(input: any, message: string) {
|
|
90
|
+
input.value = '';
|
|
91
|
+
this.showError(input, message);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private showError(input: any, message: string) {
|
|
95
|
+
if (this.showBorder) {
|
|
96
|
+
this.renderer.setStyle(input, 'borderColor', this.errorBorderColor);
|
|
97
|
+
this.renderer.addClass(input, 'error-with-dot'); // Add error class
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private clearError(input: any) {
|
|
104
|
+
if (this.showBorder) {
|
|
105
|
+
this.renderer.removeStyle(input, 'borderColor');
|
|
106
|
+
this.renderer.removeClass(input, 'error-with-dot'); // Remove error class
|
|
107
|
+
}
|
|
108
|
+
this.errorMessageService.removeErrorMessage(input);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { ValidateDirective } from './validate.directive';
|
|
3
|
+
import { ErrorMessageService } from './error-message.service';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@NgModule({
|
|
7
|
+
declarations: [
|
|
8
|
+
ValidateDirective
|
|
9
|
+
],
|
|
10
|
+
providers: [
|
|
11
|
+
ErrorMessageService
|
|
12
|
+
],
|
|
13
|
+
exports: [
|
|
14
|
+
ValidateDirective
|
|
15
|
+
]
|
|
16
|
+
})
|
|
17
|
+
export class ValidationModule { }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { VerbenNgUiComponent } from './verben-ng-ui.component';
|
|
4
|
+
|
|
5
|
+
describe('VerbenNgUiComponent', () => {
|
|
6
|
+
let component: VerbenNgUiComponent;
|
|
7
|
+
let fixture: ComponentFixture<VerbenNgUiComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [VerbenNgUiComponent]
|
|
12
|
+
})
|
|
13
|
+
.compileComponents();
|
|
14
|
+
|
|
15
|
+
fixture = TestBed.createComponent(VerbenNgUiComponent);
|
|
16
|
+
component = fixture.componentInstance;
|
|
17
|
+
fixture.detectChanges();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should create', () => {
|
|
21
|
+
expect(component).toBeTruthy();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { VerbenNgUiService } from './verben-ng-ui.service';
|
|
4
|
+
|
|
5
|
+
describe('VerbenNgUiService', () => {
|
|
6
|
+
let service: VerbenNgUiService;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
TestBed.configureTestingModule({});
|
|
10
|
+
service = TestBed.inject(VerbenNgUiService);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should be created', () => {
|
|
14
|
+
expect(service).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|