@masterkeymaterial/ui 0.0.1 → 0.0.2

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 (141) hide show
  1. package/README.md +9 -59
  2. package/ng-package.json +10 -0
  3. package/package.json +5 -14
  4. package/src/elements/ui-button/ui-button.css +229 -0
  5. package/src/elements/ui-button/ui-button.html +12 -0
  6. package/src/elements/ui-button/ui-button.ts +133 -0
  7. package/src/elements/ui-check-box/ui-check-box.css +66 -0
  8. package/src/elements/ui-check-box/ui-check-box.html +5 -0
  9. package/src/elements/ui-check-box/ui-check-box.ts +65 -0
  10. package/src/elements/ui-chip/ui-chip.css +24 -0
  11. package/src/elements/ui-chip/ui-chip.html +3 -0
  12. package/src/elements/ui-chip/ui-chip.ts +25 -0
  13. package/src/elements/ui-drop-zone/ui-drop-zone.css +91 -0
  14. package/src/elements/ui-drop-zone/ui-drop-zone.html +8 -0
  15. package/src/elements/ui-drop-zone/ui-drop-zone.ts +153 -0
  16. package/src/elements/ui-file-list/ui-file-list.css +43 -0
  17. package/src/elements/ui-file-list/ui-file-list.html +17 -0
  18. package/src/elements/ui-file-list/ui-file-list.ts +22 -0
  19. package/src/elements/ui-list-errors/ui-list-errors.css +30 -0
  20. package/src/elements/ui-list-errors/ui-list-errors.html +10 -0
  21. package/src/elements/ui-list-errors/ui-list-errors.ts +14 -0
  22. package/src/elements/ui-loading/ui-loading.css +13 -0
  23. package/src/elements/ui-loading/ui-loading.html +1 -0
  24. package/src/elements/ui-loading/ui-loading.ts +10 -0
  25. package/src/elements/ui-menu/ui-menu.css +69 -0
  26. package/src/elements/ui-menu/ui-menu.html +20 -0
  27. package/src/elements/ui-menu/ui-menu.ts +267 -0
  28. package/src/elements/ui-procurar/ui-procurar.css +48 -0
  29. package/src/elements/ui-procurar/ui-procurar.html +14 -0
  30. package/src/elements/ui-procurar/ui-procurar.ts +82 -0
  31. package/src/elements/ui-progress/ui-progress.css +0 -0
  32. package/src/elements/ui-progress/ui-progress.html +1 -0
  33. package/src/elements/ui-progress/ui-progress.ts +15 -0
  34. package/src/elements/ui-select/ui-select.css +211 -0
  35. package/src/elements/ui-select/ui-select.html +46 -0
  36. package/src/elements/ui-select/ui-select.ts +482 -0
  37. package/src/elements/ui-slide/ui-slide.css +75 -0
  38. package/src/elements/ui-slide/ui-slide.html +7 -0
  39. package/src/elements/ui-slide/ui-slide.ts +61 -0
  40. package/src/fields/Base/BaseFieldsForm/BaseFieldsForm.component.ts +113 -0
  41. package/src/fields/Base/BaseFieldsValues/BaseFieldsValues.ts +112 -0
  42. package/src/fields/Formulario/Formulario.ts +1056 -0
  43. package/src/fields/Formulario/form-action/form-action.css +98 -0
  44. package/src/fields/Formulario/form-action/form-action.html +75 -0
  45. package/src/fields/Formulario/form-action/form-action.ts +187 -0
  46. package/src/fields/Formulario/form-controls/form-controls.css +108 -0
  47. package/src/fields/Formulario/form-controls/form-controls.html +105 -0
  48. package/src/fields/Formulario/form-controls/form-controls.ts +122 -0
  49. package/src/fields/Formulario/form-fase/form-fase.css +84 -0
  50. package/src/fields/Formulario/form-fase/form-fase.html +24 -0
  51. package/src/fields/Formulario/form-fase/form-fase.ts +157 -0
  52. package/src/fields/Formulario/form-filter/form-filter.css +50 -0
  53. package/src/fields/Formulario/form-filter/form-filter.html +25 -0
  54. package/src/fields/Formulario/form-filter/form-filter.ts +53 -0
  55. package/src/fields/Formulario/form-no-action/form-no-action.css +32 -0
  56. package/src/fields/Formulario/form-no-action/form-no-action.html +12 -0
  57. package/src/fields/Formulario/form-no-action/form-no-action.ts +21 -0
  58. package/src/fields/Formulario/formated-values/formated-values.css +104 -0
  59. package/src/fields/Formulario/formated-values/formated-values.html +15 -0
  60. package/src/fields/Formulario/formated-values/formated-values.ts +186 -0
  61. package/src/fields/Formulario/single-values/single-values.css +88 -0
  62. package/src/fields/Formulario/single-values/single-values.html +11 -0
  63. package/src/fields/Formulario/single-values/single-values.ts +65 -0
  64. package/src/fields/autocomplete/autocomplete.css +94 -0
  65. package/src/fields/autocomplete/autocomplete.html +38 -0
  66. package/src/fields/autocomplete/autocomplete.ts +294 -0
  67. package/src/fields/button/button.css +7 -0
  68. package/src/fields/button/button.html +19 -0
  69. package/src/fields/button/button.ts +38 -0
  70. package/src/fields/checkbox/checkbox.css +27 -0
  71. package/src/fields/checkbox/checkbox.html +20 -0
  72. package/src/fields/checkbox/checkbox.ts +44 -0
  73. package/src/fields/color/CirculoColorido/circulocolorido.css +50 -0
  74. package/src/fields/color/CirculoColorido/circulocolorido.html +8 -0
  75. package/src/fields/color/CirculoColorido/circulocolorido.ts +24 -0
  76. package/src/fields/color/color.css +15 -0
  77. package/src/fields/color/color.html +24 -0
  78. package/src/fields/color/color.ts +47 -0
  79. package/src/fields/date/date.html +19 -0
  80. package/src/fields/date/date.ts +29 -0
  81. package/src/fields/datetime/datetime.html +19 -0
  82. package/src/fields/datetime/datetime.ts +29 -0
  83. package/src/fields/display/display.css +7 -0
  84. package/src/fields/display/display.html +20 -0
  85. package/src/fields/display/display.ts +43 -0
  86. package/src/fields/editor/editor.css +51 -0
  87. package/src/fields/editor/editor.html +37 -0
  88. package/src/fields/editor/editor.ts +218 -0
  89. package/src/fields/email/email.html +19 -0
  90. package/src/fields/email/email.ts +29 -0
  91. package/src/fields/fields.css +180 -0
  92. package/src/fields/generic/generic.html +3 -0
  93. package/src/fields/generic/generic.ts +91 -0
  94. package/src/fields/hidden/hidden.html +3 -0
  95. package/src/fields/hidden/hidden.ts +20 -0
  96. package/src/fields/icon/icon.css +19 -0
  97. package/src/fields/icon/icon.html +27 -0
  98. package/src/fields/icon/icon.ts +31 -0
  99. package/src/fields/multifactor/multifactor.css +21 -0
  100. package/src/fields/multifactor/multifactor.html +39 -0
  101. package/src/fields/multifactor/multifactor.ts +106 -0
  102. package/src/fields/multikv/multikv.css +43 -0
  103. package/src/fields/multikv/multikv.html +47 -0
  104. package/src/fields/multikv/multikv.ts +88 -0
  105. package/src/fields/multitext/multitext.css +36 -0
  106. package/src/fields/multitext/multitext.html +38 -0
  107. package/src/fields/multitext/multitext.ts +75 -0
  108. package/src/fields/number/number.html +20 -0
  109. package/src/fields/number/number.ts +35 -0
  110. package/src/fields/password/password.html +23 -0
  111. package/src/fields/password/password.ts +37 -0
  112. package/src/fields/search/search.css +0 -0
  113. package/src/fields/search/search.html +19 -0
  114. package/src/fields/search/search.ts +54 -0
  115. package/src/fields/select/select.css +15 -0
  116. package/src/fields/select/select.html +18 -0
  117. package/src/fields/select/select.ts +52 -0
  118. package/src/fields/slide/slide.css +27 -0
  119. package/src/fields/slide/slide.html +20 -0
  120. package/src/fields/slide/slide.ts +45 -0
  121. package/src/fields/text/text.html +19 -0
  122. package/src/fields/text/text.ts +30 -0
  123. package/src/fields/textarea/textarea.css +4 -0
  124. package/src/fields/textarea/textarea.html +20 -0
  125. package/src/fields/textarea/textarea.ts +31 -0
  126. package/src/fields/time/time.html +19 -0
  127. package/src/fields/time/time.ts +29 -0
  128. package/src/fields/upload/upload.css +24 -0
  129. package/src/fields/upload/upload.html +41 -0
  130. package/src/fields/upload/upload.ts +137 -0
  131. package/src/interfaces/interfaces.ts +61 -0
  132. package/src/public-api.ts +38 -0
  133. package/src/util/ClassOf.pipe.ts +11 -0
  134. package/src/util/JsonColorido.pipe.ts +11 -0
  135. package/src/util/util.ts +2151 -0
  136. package/tsconfig.lib.json +16 -0
  137. package/tsconfig.lib.prod.json +9 -0
  138. package/tsconfig.spec.json +13 -0
  139. package/fesm2022/masterkeymaterial-ui.mjs +0 -6457
  140. package/fesm2022/masterkeymaterial-ui.mjs.map +0 -1
  141. package/types/masterkeymaterial-ui.d.ts +0 -928
@@ -0,0 +1,19 @@
1
+ <div class="fieldContainer" [class.isTouched]="campo()?.touched" [class.showTouched]="form().showTouched()"
2
+ [class.isInvalid]="campo()?.invalid" [class.isDisabled]="campo()?.disabled" [class.isReadonly]="campo()?.readonly"
3
+ [class.isNeed]="campo()?.need" [class.isPending]="campo()?.pending" [class.isEmpty]="campo()?.empty">
4
+ <div class="fieldLabel" (click)="onClickLabel()" [class.hideLabel]="campo()?.hideLabel">
5
+ @if(campo()?.icone){ <div class="fieldIcon"><i [class]="campo()?.icone"></i></div> }
6
+ {{ campo()?.titulo }}
7
+ </div>
8
+ <div class="fieldControl doCampo">
9
+ <div class="fieldEffect">
10
+ <div class="fieldField FieldDate">
11
+ <input type="datetime-local" [value]="value()" (input)="onInput($event.target.value)" (change)="onChangeEmit()"
12
+ [name]="campo()?.prop" [disabled]="campo()?.disabled" [placeholder]="campo()?.placeholder ?? ''"
13
+ [attr.maxLength]="campo()?.maxl" [attr.minLength]="campo()?.minl" [class]="campo()?.classe"
14
+ [style]="campo()?.style" [class.outlined]="true" [class.input]="true" />
15
+ </div>
16
+ </div>
17
+ </div>
18
+ <ui-list-errors [errors]="campo()?.errors" [dica]="campo()?.dica" [show]="campo()?.touched"></ui-list-errors>
19
+ </div>
@@ -0,0 +1,29 @@
1
+ import { Component, effect } from '@angular/core';
2
+ import { LibUtil } from '../../util/util';
3
+ import { BaseFieldsForm } from '../Base/BaseFieldsForm/BaseFieldsForm.component';
4
+ import { UiListErrors } from "../../elements/ui-list-errors/ui-list-errors";
5
+
6
+ @Component({
7
+ selector: 'fields-datetime',
8
+ templateUrl: './datetime.html',
9
+ styleUrls: ['../fields.css'],
10
+ imports: [UiListErrors],
11
+ })
12
+ export class FieldsDatetime extends BaseFieldsForm {
13
+
14
+ constructor() {
15
+ super();
16
+ effect(() => {
17
+ const val = this.value();
18
+ let empty = val === null || val === undefined || val === '';
19
+ this.updateCampo({ empty });
20
+ });
21
+ }
22
+
23
+ onInput(newValue: string) {
24
+ if (this.campo()?.mask) newValue = LibUtil.mascarar(newValue, this.campo()?.mask) ?? '';
25
+ this.updateValue(newValue);
26
+ this.campo()?.onInput?.(this.form());
27
+ }
28
+
29
+ }
@@ -0,0 +1,7 @@
1
+ .fieldField.FieldDisplay {
2
+ border: 0px;
3
+ min-height: auto;
4
+ padding: 0 5px;
5
+ background: transparent;
6
+ outline: 0px solid transparent;
7
+ }
@@ -0,0 +1,20 @@
1
+ <div class="fieldContainer" [class.isTouched]="campo()?.touched" [class.showTouched]="form().showTouched()"
2
+ [class.isInvalid]="campo()?.invalid" [class.isDisabled]="campo()?.disabled" [class.isReadonly]="campo()?.readonly"
3
+ [class.isNeed]="campo()?.need" [class.isEmpty]="campo()?.empty" (click)="onClickEmit()">
4
+ <div class="fieldLabel" (click)="onClickLabel()" [class.hideLabel]="campo()?.hideLabel">
5
+ @if(campo()?.icone){ <div class="fieldIcon"><i [class]="campo()?.icone"></i></div> }
6
+ {{ campo()?.titulo }}
7
+ </div>
8
+ <div class="fieldControl doCampo">
9
+ <div class="fieldEffect">
10
+ <div class="fieldField FieldDisplay">
11
+ @if(campo()?.classe == 'displayJson') {
12
+ <pre class="p-2" [innerHTML]="value() | jsonColorido"></pre>
13
+ }@else {
14
+ <div [class]="campo()?.classe" [style]="campo()?.style" [innerHTML]="displayValue()"></div>
15
+ }
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <ui-list-errors [errors]="campo()?.errors" [dica]="campo()?.dica" [show]="campo()?.touched"></ui-list-errors>
20
+ </div>
@@ -0,0 +1,43 @@
1
+ import { Component, computed, effect, inject, OnInit } from '@angular/core';
2
+ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
3
+ import { LibUtil } from '../../util/util';
4
+ import { BaseFieldsForm } from '../Base/BaseFieldsForm/BaseFieldsForm.component';
5
+ import { UiListErrors } from "../../elements/ui-list-errors/ui-list-errors";
6
+ import { JsonColoridoPipe } from '../../util/JsonColorido.pipe';
7
+
8
+ @Component({
9
+ selector: 'fields-display',
10
+ templateUrl: './display.html',
11
+ styleUrls: ['../fields.css', './display.css'],
12
+ imports: [UiListErrors, JsonColoridoPipe],
13
+ })
14
+ export class FieldsDisplay extends BaseFieldsForm {
15
+
16
+ sanitizer = inject(DomSanitizer);
17
+
18
+ // Importante:
19
+ // - Este campo não é editável, então não tem onChange ou onInput.
20
+ // - Este campo não deve entrar no estado Pendente. A exibição foi removida e o fundo foi deixado transparente.
21
+
22
+ readonly displayValue = computed<SafeHtml>(() => {
23
+ let value = this.value();
24
+ if (this.campo()?.mask) value = LibUtil.mascarar(value, this.campo()?.mask) ?? '';
25
+ if (LibUtil.classof(value) === 'boolean') {
26
+ value = value ? 'Sim' : 'Não';
27
+ }
28
+ if (value == null) {
29
+ value = '';
30
+ }
31
+ return this.sanitizer.bypassSecurityTrustHtml(value.toString());
32
+ });
33
+
34
+ constructor() {
35
+ super();
36
+ effect(() => {
37
+ const val = this.value();
38
+ let empty = val === null || val === undefined || val === '';
39
+ this.updateCampo({ empty });
40
+ });
41
+ }
42
+
43
+ }
@@ -0,0 +1,51 @@
1
+ .fieldField.fieldEditor {
2
+ display: flex;
3
+ flex-direction: column;
4
+ border: 0px;
5
+ padding: 2px;
6
+ }
7
+
8
+ .fieldField.fieldEditor .corpo {
9
+ min-height: 100px;
10
+ overflow: auto;
11
+ padding: 8px;
12
+ width: 100%;
13
+ line-height: 20px;
14
+ border-radius: var(--MasterRadius);
15
+ border: 1px solid var(--outlineColor);
16
+ }
17
+
18
+ .fieldField.fieldEditor .corpo:focus-visible {
19
+ outline: 2px solid var(--campoCor);
20
+ }
21
+
22
+ .fieldField.fieldEditor .toolbar {
23
+ display: flex;
24
+ gap: 5px;
25
+ padding: 4px 4px;
26
+ }
27
+
28
+ .fieldField.fieldEditor .toolbar .icone {
29
+ outline: 1px outset color-mix(in srgb, var(--sys-outline) 20%, transparent 80%);
30
+ height: 30px;
31
+ width: 30px;
32
+ display: flex;
33
+ justify-content: center;
34
+ align-items: center;
35
+
36
+ border-radius: 50%;
37
+ overflow: hidden;
38
+ }
39
+
40
+ .toolbar .ativo {
41
+ outline: 1px outset var(--sys-high);
42
+ box-shadow:
43
+ 0 0 1px var(--sys-high),
44
+ inset 0 0 5px var(--sys-high);
45
+ transform: scale(0.9);
46
+
47
+ }
48
+
49
+ .toolbar .espaco {
50
+ margin-left: 10px;
51
+ }
@@ -0,0 +1,37 @@
1
+ <div class="fieldContainer" [class.isTouched]="campo()?.touched" [class.showTouched]="form().showTouched()"
2
+ [class.isInvalid]="campo()?.invalid" [class.isDisabled]="campo()?.disabled" [class.isReadonly]="campo()?.readonly"
3
+ [class.isNeed]="campo()?.need" [class.isPending]="campo()?.pending" [class.isEmpty]="campo()?.empty">
4
+ <div class="fieldLabel" (click)="onClickLabel()" [class.hideLabel]="campo()?.hideLabel">
5
+ @if(campo()?.icone){ <div class="fieldIcon"><i [class]="campo()?.icone"></i></div> }
6
+ {{ campo()?.titulo }}
7
+ </div>
8
+ <div class="fieldControl doCampo">
9
+ <div class="fieldEffect">
10
+ <div class="fieldField fieldEditor">
11
+ @if(campo()?.showToolbar !== false) {
12
+ <div class="toolbar">
13
+ <ui-button tipo="icon" tema="primary" class="icone" [class.ativo]="isNegrito" [disabled]="campo()?.disabled"
14
+ (click)="onNegrito()" [icone]="iconeNegrito"></ui-button>
15
+ <ui-button tipo="icon" tema="primary" class="icone" [class.ativo]="isItalico" [disabled]="campo()?.disabled"
16
+ (click)="onItalico()" [icone]="iconeItalico"></ui-button>
17
+ <ui-button tipo="icon" tema="primary" class="icone" [class.ativo]="isSublinhado"
18
+ [disabled]="campo()?.disabled" (click)="onSublinhado()" [icone]="iconeUnderline"></ui-button>
19
+
20
+ <ui-button tipo="icon" tema="primary" class="icone espaco" [class.ativo]="currentJustify === 'left'"
21
+ [disabled]="campo()?.disabled" (click)="onJustify('left')" [icone]="iconeJustifyLeft"></ui-button>
22
+ <ui-button tipo="icon" tema="primary" class="icone" [class.ativo]="currentJustify === 'center'"
23
+ [disabled]="campo()?.disabled" (click)="onJustify('center')" [icone]="iconeJustifyCenter"></ui-button>
24
+ <ui-button tipo="icon" tema="primary" class="icone" [class.ativo]="currentJustify === 'right'"
25
+ [disabled]="campo()?.disabled" (click)="onJustify('right')" [icone]="iconeJustifyRight"></ui-button>
26
+ <ui-button tipo="icon" tema="primary" class="icone" [disabled]="campo()?.disabled" (click)="onClearFormat()"
27
+ [icone]="iconeClearFormat"></ui-button>
28
+ </div>
29
+ }
30
+ <div #editavel [class.corpo]="true" [contentEditable]="!campo()?.disabled && !campo()?.readonly"
31
+ [class]="campo()?.classe" [style]="campo()?.style" (input)="onInput($event)" [innerHTML]="safeValue()"
32
+ (blur)="onChange()" (drop)="onDragEvent($event)" (keydown)="onKeyDown($event)"></div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ <ui-list-errors [errors]="campo()?.errors" [dica]="campo()?.dica" [show]="campo()?.touched"></ui-list-errors>
37
+ </div>
@@ -0,0 +1,218 @@
1
+ import { Component, computed, effect, ElementRef, inject, OnInit, viewChild } from '@angular/core';
2
+ import { BaseFieldsForm } from '../Base/BaseFieldsForm/BaseFieldsForm.component';
3
+ import { UiButton } from "../../elements/ui-button/ui-button";
4
+ import { LibUtil, LOG } from '../../util/util';
5
+ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
6
+ import { UiListErrors } from "../../elements/ui-list-errors/ui-list-errors";
7
+
8
+ @Component({
9
+ selector: 'fields-editor',
10
+ templateUrl: './editor.html',
11
+ styleUrls: ['../fields.css', './editor.css'],
12
+ imports: [UiButton, UiListErrors],
13
+ })
14
+ export class FieldsEditor extends BaseFieldsForm implements OnInit {
15
+
16
+ sanitizer = inject(DomSanitizer);
17
+ editavel = viewChild('editavel', { read: ElementRef });
18
+
19
+ iconeJustifyLeft = 'fa fa-align-left';//'bi bi-justify-left';
20
+ iconeJustifyCenter = 'fa fa-align-center';//'bi bi-text-center';
21
+ iconeJustifyRight = 'fa fa-align-right';//'bi bi-justify-right';
22
+ iconeJustify = 'fa fa-align-justify';//'bi bi-justify';
23
+ iconeNegrito = 'fa fa-bold';//'bi bi-type-bold';
24
+ iconeItalico = 'fa fa-italic';//'bi bi-type-italic';
25
+ iconeUnderline = 'fa fa-underline';//'bi bi-type-underline';
26
+ iconeClearFormat = 'fa fa-eraser';//'bi bi-eraser';
27
+
28
+ isNegrito: boolean = false;
29
+ isItalico: boolean = false;
30
+ isSublinhado: boolean = false;
31
+ currentJustify: 'left' | 'center' | 'right' | null = null;
32
+
33
+ safeValue = computed<SafeHtml>(() => {
34
+ let value = this.value();
35
+ if (value == null) {
36
+ value = '';
37
+ }
38
+ return this.sanitizer.bypassSecurityTrustHtml(value.toString());
39
+ });
40
+
41
+ constructor() {
42
+ super();
43
+ effect(() => {
44
+ const val = this.value();
45
+ let empty = val === null || val === undefined || val === '';
46
+ this.updateCampo({ empty });
47
+ });
48
+ }
49
+ override ngOnInit() {
50
+ super.ngOnInit();
51
+ this.inicializarEstados();
52
+ }
53
+
54
+ onInput(ev?: Event, cursorPosition?: { start: number; end: number, plus: number } | null) {
55
+ if (this.campo()?.disabled) return;
56
+ let eEditavel = this.editavel()?.nativeElement as HTMLDivElement;
57
+ if (!eEditavel) return;
58
+ let texto = eEditavel.innerHTML;
59
+ if (!texto) return;
60
+
61
+ // Salva a posição do cursor apenas quando o usuário está digitando
62
+ if (cursorPosition === undefined) {
63
+ cursorPosition = ev ? LibUtil.saveCursorPosition(eEditavel) : null;
64
+ }
65
+
66
+ // Converte <br> em [br]s para preservar quebras de linha
67
+ texto = texto.replace(/<br>/g, '[br]');
68
+
69
+ // Ao ocorrer mudança aqui, deve-se retirar todas as tags de hipertexto e depois aplicar apenas as que estão ativas.
70
+ texto = LibUtil.removeHtmlTags(texto);
71
+
72
+ // Restaura as quebras de linha
73
+ texto = texto.replace(/\[br\]/g, '<br>');
74
+ if (texto === "<br>") {
75
+ texto = "";
76
+ }
77
+
78
+ if (this.isNegrito) {
79
+ texto = `<b>${texto}</b>`;
80
+ }
81
+ if (this.isItalico) {
82
+ texto = `<i>${texto}</i>`;
83
+ }
84
+ if (this.isSublinhado) {
85
+ texto = `<u>${texto}</u>`;
86
+ }
87
+ if (this.currentJustify) {
88
+ texto = `<div style="text-align: ${this.currentJustify};">${texto}</div>`;
89
+ }
90
+ eEditavel.innerHTML = texto;
91
+
92
+ if (cursorPosition) {
93
+ LibUtil.restoreCursorPosition(eEditavel, cursorPosition);
94
+ }
95
+
96
+ this.campo()?.onInput?.(this.form());
97
+ }
98
+
99
+ onChange() {
100
+ if (this.campo()?.disabled) return;
101
+ let eEditavel = this.editavel()?.nativeElement as HTMLDivElement;
102
+ if (!eEditavel) return;
103
+
104
+ let texto = eEditavel.innerHTML;
105
+ this.updateValue(texto);
106
+
107
+ this.onChangeEmit();
108
+ }
109
+
110
+ onDragEvent(dragEvent: DragEvent) {
111
+ if (this.campo()?.disabled) return;
112
+ const dataTransfer = dragEvent.dataTransfer;
113
+ if (!dataTransfer) return;
114
+
115
+ // Drag and Drop não é suportado.
116
+ dragEvent.preventDefault();
117
+ dragEvent.stopPropagation();
118
+ const text = dataTransfer.getData('text/plain');
119
+ LOG(1, "Drag and Drop Text: ", text, dragEvent);
120
+ }
121
+
122
+ onNegrito() {
123
+ if (this.campo()?.disabled) return;
124
+ this.isNegrito = !this.isNegrito;
125
+ this.onInput();
126
+ this.onChange();
127
+ }
128
+ onItalico() {
129
+ if (this.campo()?.disabled) return;
130
+ this.isItalico = !this.isItalico;
131
+ this.onInput();
132
+ this.onChange();
133
+ }
134
+ onSublinhado() {
135
+ if (this.campo()?.disabled) return;
136
+ this.isSublinhado = !this.isSublinhado;
137
+ this.onInput();
138
+ this.onChange();
139
+ }
140
+ onJustify(direction: 'left' | 'center' | 'right') {
141
+ if (this.campo()?.disabled) return;
142
+ if (this.currentJustify === direction) {
143
+ this.currentJustify = null;
144
+ this.onInput();
145
+ this.onChange();
146
+ return;
147
+ }
148
+ this.currentJustify = direction;
149
+ this.onInput();
150
+ this.onChange();
151
+ }
152
+
153
+
154
+ onClearFormat() {
155
+ if (this.campo()?.disabled) return;
156
+ let eEditavel = this.editavel()?.nativeElement as HTMLDivElement;
157
+ if (!eEditavel) return;
158
+ let texto = eEditavel.innerHTML;
159
+ if (!texto) return;
160
+
161
+ this.currentJustify = null;
162
+ this.isNegrito = false;
163
+ this.isItalico = false;
164
+ this.isSublinhado = false;
165
+
166
+ texto = LibUtil.removeHtmlTags(texto);
167
+ eEditavel.innerHTML = texto;
168
+ this.onChange();
169
+ }
170
+
171
+ onKeyDown(event: KeyboardEvent) {
172
+ if (this.campo()?.disabled) return;
173
+ if (event.key === 'Enter') {
174
+ event.preventDefault();
175
+
176
+ const eEditavel = this.editavel()?.nativeElement as HTMLDivElement;
177
+ if (!eEditavel) return;
178
+
179
+ // Salva a posição do cursor
180
+ const cursorPosition = LibUtil.saveCursorPosition(eEditavel, 1);
181
+
182
+ // Insere uma quebra de linha (<br>) na posição do cursor
183
+ const selection = window.getSelection();
184
+ if (selection && selection.rangeCount > 0) {
185
+ const range = selection.getRangeAt(0);
186
+ range.deleteContents();
187
+
188
+ const br = document.createElement('br');
189
+ range.insertNode(br);
190
+
191
+ // Move o cursor para depois do <br>
192
+ range.setStartAfter(br);
193
+ range.setEndAfter(br);
194
+ selection.removeAllRanges();
195
+ selection.addRange(range);
196
+ }
197
+
198
+ this.onInput(undefined, cursorPosition);
199
+ }
200
+ }
201
+
202
+ inicializarEstados() {
203
+ let valor = this.value();
204
+ if (typeof valor !== 'string' || !valor) return;
205
+ valor = valor.toLowerCase();
206
+
207
+ this.isNegrito = valor.includes('<b>') && valor.includes('</b>');
208
+ this.isItalico = valor.includes('<i>') && valor.includes('</i>');
209
+ this.isSublinhado = valor.includes('<u>') && valor.includes('</u>');
210
+ if (valor.includes('text-align: left')) {
211
+ this.currentJustify = 'left';
212
+ } else if (valor.includes('text-align: center')) {
213
+ this.currentJustify = 'center';
214
+ } else if (valor.includes('text-align: right')) {
215
+ this.currentJustify = 'right';
216
+ }
217
+ }
218
+ }
@@ -0,0 +1,19 @@
1
+ <div class="fieldContainer" [class.isTouched]="campo()?.touched" [class.showTouched]="form().showTouched()"
2
+ [class.isInvalid]="campo()?.invalid" [class.isDisabled]="campo()?.disabled" [class.isReadonly]="campo()?.readonly"
3
+ [class.isNeed]="campo()?.need" [class.isPending]="campo()?.pending" [class.isEmpty]="campo()?.empty">
4
+ <div class="fieldLabel" (click)="onClickLabel()" [class.hideLabel]="campo()?.hideLabel">
5
+ @if(campo()?.icone){ <div class="fieldIcon"><i [class]="campo()?.icone"></i></div> }
6
+ {{ campo()?.titulo }}
7
+ </div>
8
+ <div class="fieldControl doCampo">
9
+ <div class="fieldEffect">
10
+ <div class="fieldField FieldEmail">
11
+ <input type="email" [value]="value()" (input)="onInput($event.target.value)" (change)="onChangeEmit()"
12
+ [name]="campo()?.prop" [disabled]="campo()?.disabled" [placeholder]="campo()?.placeholder ?? ''"
13
+ [attr.maxLength]="campo()?.maxl" [attr.minLength]="campo()?.minl" [class]="campo()?.classe"
14
+ [style]="campo()?.style" [class.outlined]="true" [class.input]="true" />
15
+ </div>
16
+ </div>
17
+ </div>
18
+ <ui-list-errors [errors]="campo()?.errors" [dica]="campo()?.dica" [show]="campo()?.touched"></ui-list-errors>
19
+ </div>
@@ -0,0 +1,29 @@
1
+ import { Component, effect } from '@angular/core';
2
+ import { LibUtil } from '../../util/util';
3
+ import { BaseFieldsForm } from '../Base/BaseFieldsForm/BaseFieldsForm.component';
4
+ import { UiListErrors } from "../../elements/ui-list-errors/ui-list-errors";
5
+
6
+ @Component({
7
+ selector: 'fields-email',
8
+ templateUrl: './email.html',
9
+ styleUrls: ['../fields.css'],
10
+ imports: [UiListErrors],
11
+ })
12
+ export class FieldsEmail extends BaseFieldsForm {
13
+
14
+ constructor() {
15
+ super();
16
+ effect(() => {
17
+ const val = this.value();
18
+ let empty = val === null || val === undefined || val === '';
19
+ this.updateCampo({ empty });
20
+ });
21
+ }
22
+
23
+ onInput(newValue: string) {
24
+ if (this.campo()?.mask) newValue = LibUtil.mascarar(newValue, this.campo()?.mask) ?? '';
25
+ this.updateValue(newValue);
26
+ this.campo()?.onInput?.(this.form());
27
+ }
28
+
29
+ }
@@ -0,0 +1,180 @@
1
+ :host {
2
+ display: block;
3
+ --campoCor: var(--sys-primary);
4
+ --outlineColor: var(--sys-outline)
5
+ }
6
+
7
+ .fieldContainer {
8
+ position: relative;
9
+ margin: 2px;
10
+ display: flex;
11
+ flex-direction: column;
12
+ height: 100%;
13
+ gap: 1px;
14
+ }
15
+
16
+ .fieldField {
17
+ display: flex;
18
+ position: relative;
19
+ border: 1px solid var(--outlineColor);
20
+ border-radius: var(--MasterRadius);
21
+ height: 100%;
22
+ min-height: 37px;
23
+ outline: 2px solid var(--sys-card);
24
+ background: var(--sys-card);
25
+ }
26
+
27
+
28
+ .fieldInput,
29
+ .fieldField .input {
30
+ padding: 0 10px;
31
+ border: none;
32
+ border-radius: var(--MasterRadius);
33
+ font-family: inherit;
34
+ font: inherit;
35
+ letter-spacing: inherit;
36
+ text-decoration: inherit;
37
+ text-transform: inherit;
38
+ color: var(--sys-on-card);
39
+ caret-color: var(--sys-primary);
40
+ outline: none;
41
+ flex-grow: 1;
42
+ }
43
+
44
+ .fieldInput {
45
+ outline: 1px solid var(--outlineColor);
46
+ }
47
+
48
+ .fieldLabel {
49
+ display: flex;
50
+ align-items: center;
51
+ gap: 0.5rem;
52
+ line-height: 20px;
53
+ font-size: 14px;
54
+ font-weight: 600;
55
+ padding-left: 5px;
56
+ }
57
+
58
+ .fieldLabel.hideLabel {
59
+ display: none;
60
+ }
61
+
62
+ .fieldField:has(.outlined:focus) {
63
+ outline: 2px solid var(--campoCor);
64
+ }
65
+
66
+ .fieldContainer.isTouched.showTouched {
67
+ outline: 2px dotted green;
68
+ border-radius: 5px;
69
+ outline-offset: 0px;
70
+ animation: borderOutline 1s linear infinite;
71
+ }
72
+
73
+ @keyframes borderOutline {
74
+ 0% {
75
+ outline-color: green;
76
+ }
77
+
78
+ 50% {
79
+ outline-color: transparent;
80
+ }
81
+
82
+ 100% {
83
+ outline-color: green;
84
+ }
85
+ }
86
+
87
+ /* VALIDADOR FIELDS */
88
+ .isTouched.isInvalid .fieldInput,
89
+ .isTouched.isInvalid .fieldField {
90
+ outline: 2px solid var(--sys-error);
91
+ }
92
+
93
+ .fieldControl {
94
+ display: flex;
95
+ position: relative;
96
+ gap: 0.5rem;
97
+ height: fit-content;
98
+ }
99
+
100
+ .fieldTopRight {
101
+ position: absolute;
102
+ top: 0;
103
+ right: 0;
104
+ font-size: 14px;
105
+ }
106
+
107
+ .fieldContainer.isDisabled {
108
+ filter: grayscale(100%);
109
+ cursor: not-allowed;
110
+ --outlineColor: color-mix(in srgb, var(--sys-outline) 50%, transparent 50%);
111
+ }
112
+
113
+ .fieldContainer.isDisabled .fieldControl {
114
+ pointer-events: none;
115
+ }
116
+
117
+ .fieldContainer.isDisabled .fieldLabel {
118
+ opacity: 0.6;
119
+ }
120
+
121
+ .isNeed .fieldControl::after {
122
+ content: '*';
123
+ position: absolute;
124
+ right: -1px;
125
+ top: -1px;
126
+ font-size: 14px;
127
+ color: color-mix(in srgb, var(--sys-outline) 80%, var(--sys-error) 20%);
128
+ }
129
+
130
+ .fieldIcon {
131
+ display: flex;
132
+ align-items: center;
133
+ font-size: 16px;
134
+ }
135
+
136
+ .fieldEffect {
137
+ position: relative;
138
+ width: 100%;
139
+ border-radius: var(--MasterRadius);
140
+ padding: 3px;
141
+ height: fit-content;
142
+ }
143
+
144
+ .isPending .fieldEffect::before {
145
+ content: '';
146
+ position: absolute;
147
+ top: 0;
148
+ left: 0;
149
+ width: 100%;
150
+ height: 100%;
151
+ border-radius: inherit;
152
+ background: repeating-conic-gradient(from var(--anglePendingEffect),
153
+ var(--sys-error) 0%,
154
+ var(--sys-error) 5%,
155
+ transparent 5%,
156
+ transparent 15%,
157
+ var(--sys-error) 25%,
158
+ var(--sys-info) 30%,
159
+ transparent 30%,
160
+ transparent 40%,
161
+ var(--sys-error) 50%);
162
+ animation: rotacionar 4s linear infinite;
163
+ }
164
+
165
+
166
+ @property --anglePendingEffect {
167
+ syntax: '<angle>';
168
+ inherits: false;
169
+ initial-value: 0deg;
170
+ }
171
+
172
+ @keyframes rotacionar {
173
+ 0% {
174
+ --anglePendingEffect: 0deg;
175
+ }
176
+
177
+ 100% {
178
+ --anglePendingEffect: 360deg;
179
+ }
180
+ }
@@ -0,0 +1,3 @@
1
+ @if (getComponentForType(campo() ? campo()?.tipo : undefined); as component) {
2
+ <ng-container [ngComponentOutlet]="component" [ngComponentOutletInputs]="{ form: this.form(), name: name() }" />
3
+ }