@up_si_vale/sivale-componentes-angular 1.0.0 → 1.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 (94) hide show
  1. package/esm2022/lib/atoms/button/button.component.mjs +55 -0
  2. package/esm2022/lib/atoms/checkbox/checkbox.component.mjs +174 -0
  3. package/esm2022/lib/atoms/date-picker/date-picker.component.mjs +835 -0
  4. package/esm2022/lib/atoms/input/input.component.mjs +218 -0
  5. package/esm2022/lib/atoms/loader/loader.component.mjs +81 -0
  6. package/esm2022/lib/atoms/radio/radio.component.mjs +142 -0
  7. package/esm2022/lib/atoms/textarea/textarea.component.mjs +126 -0
  8. package/esm2022/lib/directives/asset-source.directive.mjs +68 -0
  9. package/esm2022/lib/directives/icon-source.directive.mjs +65 -0
  10. package/esm2022/lib/directives/no-leading-space.directive.mjs +24 -0
  11. package/esm2022/lib/directives/only-letters.directive.mjs +25 -0
  12. package/esm2022/lib/directives/only-number.directive.mjs +21 -0
  13. package/esm2022/lib/directives/rfc.directive.mjs +67 -0
  14. package/esm2022/lib/directives/tooltip.directive.mjs +199 -0
  15. package/esm2022/lib/models/snackbar.models.mjs +2 -0
  16. package/esm2022/lib/molecules/alert/alert.component.mjs +79 -0
  17. package/esm2022/lib/molecules/copy-input/copy-input.component.mjs +46 -0
  18. package/esm2022/lib/molecules/multiselect/multiselect.component.mjs +466 -0
  19. package/esm2022/lib/molecules/option/option.component.mjs +55 -0
  20. package/esm2022/lib/molecules/phone-input/phone-input.component.mjs +64 -0
  21. package/esm2022/lib/molecules/select/select.component.mjs +498 -0
  22. package/esm2022/lib/molecules/snackbar/snackbar.component.mjs +581 -0
  23. package/esm2022/lib/organisms/sidebar/sidebar-icon.component.mjs +91 -0
  24. package/esm2022/lib/organisms/sidebar/sidebar.component.mjs +115 -0
  25. package/esm2022/lib/services/snackbar.service.mjs +96 -0
  26. package/esm2022/lib/tokens/asset-base-url.token.mjs +10 -0
  27. package/esm2022/public-api.mjs +37 -0
  28. package/esm2022/up_si_vale-sivale-componentes-angular.mjs +5 -0
  29. package/fesm2022/up_si_vale-sivale-componentes-angular.mjs +4116 -0
  30. package/fesm2022/up_si_vale-sivale-componentes-angular.mjs.map +1 -0
  31. package/index.d.ts +5 -0
  32. package/lib/atoms/button/button.component.d.ts +20 -0
  33. package/lib/atoms/checkbox/checkbox.component.d.ts +31 -0
  34. package/lib/atoms/date-picker/date-picker.component.d.ts +134 -0
  35. package/lib/atoms/input/input.component.d.ts +35 -0
  36. package/lib/atoms/loader/loader.component.d.ts +10 -0
  37. package/lib/atoms/radio/radio.component.d.ts +25 -0
  38. package/lib/atoms/textarea/textarea.component.d.ts +27 -0
  39. package/lib/directives/asset-source.directive.d.ts +19 -0
  40. package/lib/directives/icon-source.directive.d.ts +18 -0
  41. package/lib/directives/no-leading-space.directive.d.ts +6 -0
  42. package/lib/directives/only-letters.directive.d.ts +7 -0
  43. package/lib/directives/only-number.directive.d.ts +6 -0
  44. package/lib/directives/rfc.directive.d.ts +12 -0
  45. package/lib/directives/tooltip.directive.d.ts +27 -0
  46. package/{src/lib/models/snackbar.models.ts → lib/models/snackbar.models.d.ts} +8 -10
  47. package/lib/molecules/alert/alert.component.d.ts +29 -0
  48. package/lib/molecules/copy-input/copy-input.component.d.ts +14 -0
  49. package/lib/molecules/multiselect/multiselect.component.d.ts +74 -0
  50. package/lib/molecules/option/option.component.d.ts +19 -0
  51. package/lib/molecules/phone-input/phone-input.component.d.ts +12 -0
  52. package/lib/molecules/select/select.component.d.ts +88 -0
  53. package/lib/molecules/snackbar/snackbar.component.d.ts +17 -0
  54. package/lib/organisms/sidebar/sidebar-icon.component.d.ts +8 -0
  55. package/lib/organisms/sidebar/sidebar.component.d.ts +47 -0
  56. package/lib/services/snackbar.service.d.ts +40 -0
  57. package/{src/lib/tokens/asset-base-url.token.ts → lib/tokens/asset-base-url.token.d.ts} +1 -5
  58. package/package.json +39 -28
  59. package/{src/public-api.ts → public-api.d.ts} +3 -15
  60. package/ng-package.json +0 -9
  61. package/src/lib/atoms/button/button.component.html +0 -21
  62. package/src/lib/atoms/button/button.component.scss +0 -242
  63. package/src/lib/atoms/button/button.component.ts +0 -43
  64. package/src/lib/atoms/checkbox/checkbox.component.scss +0 -131
  65. package/src/lib/atoms/checkbox/checkbox.component.ts +0 -130
  66. package/src/lib/atoms/date-picker/date-picker.component.html +0 -295
  67. package/src/lib/atoms/date-picker/date-picker.component.scss +0 -1002
  68. package/src/lib/atoms/date-picker/date-picker.component.ts +0 -942
  69. package/src/lib/atoms/input/input.component.ts +0 -239
  70. package/src/lib/atoms/loader/loader.component.scss +0 -144
  71. package/src/lib/atoms/loader/loader.component.ts +0 -44
  72. package/src/lib/atoms/radio/radio.component.scss +0 -115
  73. package/src/lib/atoms/radio/radio.component.ts +0 -103
  74. package/src/lib/atoms/textarea/textarea.component.ts +0 -155
  75. package/src/lib/directives/asset-source.directive.ts +0 -64
  76. package/src/lib/directives/icon-source.directive.ts +0 -74
  77. package/src/lib/directives/no-leading-space.directive.ts +0 -18
  78. package/src/lib/directives/only-letters.directive.ts +0 -21
  79. package/src/lib/directives/only-number.directive.ts +0 -15
  80. package/src/lib/directives/rfc.directive.ts +0 -60
  81. package/src/lib/directives/tooltip.directive.ts +0 -211
  82. package/src/lib/molecules/copy-input/copy-input.component.html +0 -29
  83. package/src/lib/molecules/copy-input/copy-input.component.scss +0 -101
  84. package/src/lib/molecules/copy-input/copy-input.component.ts +0 -41
  85. package/src/lib/molecules/multiselect/multiselect.component.scss +0 -298
  86. package/src/lib/molecules/multiselect/multiselect.component.ts +0 -487
  87. package/src/lib/molecules/option/option.component.ts +0 -45
  88. package/src/lib/molecules/phone-input/phone-input.component.scss +0 -78
  89. package/src/lib/molecules/phone-input/phone-input.component.ts +0 -43
  90. package/src/lib/molecules/select/select.component.ts +0 -482
  91. package/src/lib/molecules/snackbar/snackbar.component.scss +0 -201
  92. package/src/lib/molecules/snackbar/snackbar.component.ts +0 -321
  93. package/src/lib/services/snackbar.service.ts +0 -103
  94. package/tsconfig.json +0 -31
@@ -1,155 +0,0 @@
1
- import { Component, Input, forwardRef, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { ControlValueAccessor, NG_VALUE_ACCESSOR, ReactiveFormsModule, FormsModule } from '@angular/forms';
4
-
5
- @Component({
6
- selector: 'app-textarea',
7
- standalone: true,
8
- imports: [CommonModule, ReactiveFormsModule, FormsModule],
9
- changeDetection: ChangeDetectionStrategy.OnPush,
10
- template: `
11
- <div class="textarea-wrapper">
12
- <label *ngIf="label" [for]="id" class="textarea-label">{{ label }}</label>
13
- <div class="textarea-container" [class.error]="hasError">
14
- <textarea
15
- [id]="id"
16
- [placeholder]="placeholder"
17
- [rows]="rows"
18
- [disabled]="disabled"
19
- [readonly]="readonly"
20
- [attr.maxlength]="maxLength"
21
- class="textarea-field"
22
- [class.error]="hasError"
23
- [value]="value"
24
- (blur)="onBlur()"
25
- (input)="onInputChange($event)"
26
- ></textarea>
27
- </div>
28
- <div *ngIf="hasError && errorMessage" class="field-error">
29
- {{ errorMessage }}
30
- </div>
31
- </div>
32
- `,
33
- styles: [`
34
- .textarea-wrapper {
35
- width: 100%;
36
- display: flex;
37
- flex-direction: column;
38
- gap: 6px;
39
- }
40
-
41
- .textarea-label {
42
- font-family: 'Quicksand', sans-serif;
43
- font-weight: 500;
44
- font-size: 14px;
45
- line-height: 20px;
46
- color: #414651;
47
- }
48
-
49
- .textarea-container {
50
- width: 100%;
51
-
52
- &.error .textarea-field {
53
- border-color: #F04438;
54
- }
55
- }
56
-
57
- .textarea-field {
58
- width: 100%;
59
- padding: 10px 14px;
60
- background: #FFFFFF;
61
- border: 1px solid #D5D7DA;
62
- border-radius: 8px;
63
- font-family: 'Quicksand', sans-serif;
64
- font-weight: 400;
65
- font-size: 16px;
66
- line-height: 24px;
67
- color: #2E353A;
68
- resize: vertical;
69
- min-height: 100px;
70
- transition: all 0.2s ease;
71
- box-sizing: border-box;
72
-
73
- &::placeholder {
74
- color: #A4A7AE;
75
- }
76
-
77
- &:focus {
78
- outline: none;
79
- border-color: #F59100;
80
- box-shadow: 0 0 0 4px rgba(245, 145, 0, 0.1);
81
- }
82
-
83
- &:disabled {
84
- background: #F9FAFB;
85
- cursor: not-allowed;
86
- }
87
-
88
- &.error {
89
- border-color: #F04438;
90
-
91
- &:focus {
92
- box-shadow: 0 0 0 4px rgba(240, 68, 56, 0.1);
93
- }
94
- }
95
- }
96
-
97
- .field-error {
98
- color: #F04438;
99
- font-size: 0.875rem;
100
- font-family: 'Quicksand', sans-serif;
101
- }
102
- `],
103
- providers: [
104
- {
105
- provide: NG_VALUE_ACCESSOR,
106
- useExisting: forwardRef(() => TextareaComponent),
107
- multi: true
108
- }
109
- ]
110
- })
111
- export class TextareaComponent implements ControlValueAccessor {
112
- @Input() label = '';
113
- @Input() id = '';
114
- @Input() placeholder = '';
115
- @Input() rows = 4;
116
- @Input() maxLength?: number;
117
- @Input() hasError = false;
118
- @Input() errorMessage = '';
119
- @Input() disabled = false;
120
- @Input() readonly = false;
121
-
122
- value = '';
123
- onChange: any = () => {};
124
- onTouched: any = () => {};
125
-
126
- constructor(private cdr: ChangeDetectorRef) {}
127
-
128
- writeValue(value: any): void {
129
- this.value = value || '';
130
- this.cdr.markForCheck();
131
- }
132
-
133
- registerOnChange(fn: any): void {
134
- this.onChange = fn;
135
- }
136
-
137
- registerOnTouched(fn: any): void {
138
- this.onTouched = fn;
139
- }
140
-
141
- setDisabledState(isDisabled: boolean): void {
142
- this.disabled = isDisabled;
143
- this.cdr.markForCheck();
144
- }
145
-
146
- onInputChange(event: Event): void {
147
- const target = event.target as HTMLTextAreaElement;
148
- this.value = target.value;
149
- this.onChange(this.value);
150
- }
151
-
152
- onBlur(): void {
153
- this.onTouched();
154
- }
155
- }
@@ -1,64 +0,0 @@
1
- import { Directive, Input, ElementRef, OnInit, OnChanges, AfterViewInit, Inject, Optional } from '@angular/core';
2
- import { ASSET_BASE_URL } from '../tokens/asset-base-url.token';
3
-
4
- export type AssetSource = 'mf' | 'main';
5
-
6
- @Directive({
7
- selector: '[assetSource]',
8
- standalone: true
9
- })
10
- export class AssetSourceDirective implements OnInit, OnChanges, AfterViewInit {
11
- @Input() assetSource: AssetSource = 'mf';
12
- @Input() assetPath?: string;
13
-
14
- private originalSrc: string | null = null;
15
-
16
- constructor(
17
- private el: ElementRef<HTMLImageElement>,
18
- @Optional() @Inject(ASSET_BASE_URL) private assetBaseUrl: string | null
19
- ) {}
20
-
21
- ngOnInit() {
22
- this.captureOriginalSrc();
23
- }
24
-
25
- ngAfterViewInit() {
26
- this.updateSrc();
27
- }
28
-
29
- ngOnChanges() {
30
- this.updateSrc();
31
- }
32
-
33
- private captureOriginalSrc() {
34
- if (this.el.nativeElement.tagName === 'IMG') {
35
- this.originalSrc = this.el.nativeElement.getAttribute('src');
36
- }
37
- }
38
-
39
- private updateSrc() {
40
- const assetPath = this.assetPath || this.originalSrc;
41
-
42
- if (!assetPath) {
43
- return;
44
- }
45
-
46
- const baseUrl = this.getBaseUrl();
47
- const fullPath = `${baseUrl}/${assetPath}`;
48
-
49
- if (this.el.nativeElement.tagName === 'IMG') {
50
- this.el.nativeElement.src = fullPath;
51
- }
52
- }
53
-
54
- private getBaseUrl(): string {
55
- switch (this.assetSource) {
56
- case 'mf':
57
- return this.assetBaseUrl ?? '';
58
- case 'main':
59
- return '/assets';
60
- default:
61
- return this.assetBaseUrl ?? '';
62
- }
63
- }
64
- }
@@ -1,74 +0,0 @@
1
- import { Directive, Input, ElementRef, OnInit, OnChanges, AfterViewInit, Inject, Optional } from '@angular/core';
2
- import { ASSET_BASE_URL } from '../tokens/asset-base-url.token';
3
-
4
- export type IconName =
5
- 'user'
6
- | 'mail'
7
- | 'build'
8
- | 'map-pin'
9
- | 'money'
10
- | 'card'
11
- | 'nav-arrow-up'
12
- | 'nav-arrow-down'
13
- | 'car'
14
- | 'trash'
15
- | 'hand-card'
16
- | 'help-outlined'
17
- | 'edit'
18
- | 'shopping-cart';
19
-
20
- @Directive({
21
- selector: 'i[iconName]',
22
- standalone: true
23
- })
24
- export class IconSourceDirective implements OnInit, OnChanges, AfterViewInit {
25
- @Input() iconName!: IconName;
26
- @Input() assetSource: 'mf' | 'main' = 'mf';
27
-
28
- constructor(
29
- private el: ElementRef<HTMLElement>,
30
- @Optional() @Inject(ASSET_BASE_URL) private assetBaseUrl: string | null
31
- ) {
32
- }
33
-
34
- ngOnInit() {
35
- this.addIconClass();
36
- }
37
-
38
- ngAfterViewInit() {
39
- this.setIconUrl();
40
- }
41
-
42
- ngOnChanges() {
43
- this.setIconUrl();
44
- }
45
-
46
- private addIconClass() {
47
- if (this.iconName) {
48
- this.el.nativeElement.classList.add(`icon-${this.iconName}`);
49
- }
50
- }
51
-
52
- private setIconUrl() {
53
- if (!this.iconName) {
54
- return;
55
- }
56
-
57
- const baseUrl = this.getBaseUrl();
58
- const iconUrl = `${baseUrl}/icons/${this.iconName}.svg`;
59
-
60
- this.el.nativeElement.style.maskImage = `url('${iconUrl}')`;
61
- this.el.nativeElement.style.webkitMaskImage = `url('${iconUrl}')`;
62
- }
63
-
64
- private getBaseUrl(): string {
65
- switch (this.assetSource) {
66
- case 'mf':
67
- return this.assetBaseUrl ?? '';
68
- case 'main':
69
- return '/assets';
70
- default:
71
- return this.assetBaseUrl ?? '';
72
- }
73
- }
74
- }
@@ -1,18 +0,0 @@
1
- import { Directive, HostListener } from '@angular/core';
2
-
3
- @Directive({
4
- selector: '[noLeadingSpace]',
5
- standalone: true
6
- })
7
- export class NoLeadingSpaceDirective {
8
-
9
- @HostListener('input', ['$event'])
10
- onInput(event: any) {
11
- const value = event.target.value;
12
-
13
- // Elimina espacios al inicio
14
- if (value.startsWith(' ')) {
15
- event.target.value = value.trimStart();
16
- }
17
- }
18
- }
@@ -1,21 +0,0 @@
1
- import { Directive, HostListener } from '@angular/core';
2
-
3
- @Directive({
4
- selector: '[onlyLetters]',
5
- standalone: true
6
- })
7
-
8
- export class OnlyLettersDirective {
9
-
10
- private regex = /^[A-Za-zÁÉÍÓÚÜÑáéíóúüñ' -]*$/;
11
-
12
- @HostListener('input', ['$event'])
13
- onInput(event: any) {
14
- const value: string = event.target.value;
15
-
16
- event.target.value = value
17
- .split('')
18
- .filter(char => this.regex.test(char))
19
- .join('');
20
- }
21
- }
@@ -1,15 +0,0 @@
1
- import { Directive, HostListener } from '@angular/core';
2
-
3
- @Directive({
4
- selector: '[onlyNumber]',
5
- standalone: true
6
- })
7
-
8
- export class OnlyNumberDirective {
9
- @HostListener('input', ['$event'])
10
- onInput(event: any) {
11
- const value = event.target.value;
12
- event.target.value = value.replace(/\D/g, '');
13
- }
14
-
15
- }
@@ -1,60 +0,0 @@
1
- import { Directive, HostListener, Input, Optional, Self } from '@angular/core';
2
- import { NgControl } from '@angular/forms';
3
-
4
- @Directive({
5
- selector: '[rfcValidator]',
6
- standalone: true
7
- })
8
- export class RfcDirective {
9
-
10
- @Input() tipoContribuyente: string | null = null;
11
-
12
- constructor(@Optional() @Self() private ngControl: NgControl | null) {
13
- }
14
-
15
- // Función para obtener el límite según el tipo de contribuyente
16
- private getMaxLength(): number {
17
- if (this.tipoContribuyente === 'fisica') return 13;
18
- if (this.tipoContribuyente === 'moral') return 12;
19
- return 13; // Default por si no llega el valor
20
- }
21
-
22
- @HostListener('input', ['$event'])
23
- onInput(event: Event) {
24
- const input = event.target as HTMLInputElement;
25
- let value = input.value;
26
-
27
- // Solo letras y números
28
- value = value.replace(/[^a-zA-Z0-9]/g, '');
29
-
30
- // Mayúsculas
31
- value = value.toUpperCase();
32
-
33
- // Aplicar límite dinámico
34
- const max = this.getMaxLength();
35
- if (value.length > max) {
36
- value = value.substring(0, max);
37
- }
38
-
39
- this.ngControl?.control?.setValue(value, { emitEvent: false });
40
- }
41
-
42
- @HostListener('paste', ['$event'])
43
- onPaste(event: ClipboardEvent) {
44
- const pasted = event.clipboardData?.getData('text') || '';
45
- const max = this.getMaxLength();
46
-
47
- // Bloquear pegado con caracteres inválidos
48
- if (/[^a-zA-Z0-9]/.test(pasted)) {
49
- event.preventDefault();
50
- return;
51
- }
52
-
53
- // Bloquear pegado si excede el máximo
54
- if (pasted.length > max) {
55
- event.preventDefault();
56
- }
57
- }
58
- }
59
-
60
-
@@ -1,211 +0,0 @@
1
- import {
2
- Directive,
3
- Input,
4
- ElementRef,
5
- HostListener,
6
- Renderer2,
7
- OnDestroy,
8
- HostBinding
9
- } from '@angular/core';
10
-
11
- type TooltipPosition = 'top' | 'bottom' | 'left' | 'right' | 'auto';
12
-
13
- @Directive({
14
- selector: '[appTooltip]',
15
- standalone: true
16
- })
17
- export class TooltipDirective implements OnDestroy {
18
- @Input('appTooltip') tooltipText = '';
19
- @Input() tooltipPosition: TooltipPosition = 'auto';
20
- @Input() tooltipDelay = 300;
21
- @Input() tooltipMaxWidth = 280;
22
- @Input() tooltipClass = '';
23
-
24
- @HostBinding('style.cursor') cursor = 'help';
25
-
26
- private tooltipElement: HTMLElement | null = null;
27
- private showTimeout?: number;
28
- private hideTimeout?: number;
29
-
30
- constructor(
31
- private el: ElementRef,
32
- private renderer: Renderer2
33
- ) {}
34
-
35
- @HostListener('mouseenter')
36
- onMouseEnter(): void {
37
- if (this.hideTimeout) {
38
- clearTimeout(this.hideTimeout);
39
- this.hideTimeout = undefined;
40
- }
41
-
42
- this.showTimeout = window.setTimeout(() => {
43
- this.showTooltip();
44
- }, this.tooltipDelay);
45
- }
46
-
47
- @HostListener('mouseleave')
48
- onMouseLeave(): void {
49
- if (this.showTimeout) {
50
- clearTimeout(this.showTimeout);
51
- this.showTimeout = undefined;
52
- }
53
-
54
- this.hideTimeout = window.setTimeout(() => {
55
- this.hideTooltip();
56
- }, 100);
57
- }
58
-
59
- @HostListener('click')
60
- onClick(): void {
61
- // Allow click events to propagate
62
- }
63
-
64
- private showTooltip(): void {
65
- if (!this.tooltipText || this.tooltipElement) {
66
- return;
67
- }
68
-
69
- // Create tooltip element
70
- this.tooltipElement = this.renderer.createElement('div');
71
- this.renderer.addClass(this.tooltipElement, 'app-tooltip');
72
-
73
- if (this.tooltipClass) {
74
- this.renderer.addClass(this.tooltipElement, this.tooltipClass);
75
- }
76
-
77
- // Create tooltip content
78
- const tooltipContent = this.renderer.createElement('div');
79
- this.renderer.addClass(tooltipContent, 'app-tooltip-content');
80
- this.renderer.setStyle(tooltipContent, 'max-width', `${this.tooltipMaxWidth}px`);
81
-
82
- const textNode = this.renderer.createText(this.tooltipText);
83
- this.renderer.appendChild(tooltipContent, textNode);
84
- this.renderer.appendChild(this.tooltipElement, tooltipContent);
85
-
86
- // Create arrow element
87
- const arrow = this.renderer.createElement('div');
88
- this.renderer.addClass(arrow, 'app-tooltip-arrow');
89
- this.renderer.appendChild(this.tooltipElement, arrow);
90
-
91
- // Add to body
92
- this.renderer.appendChild(document.body, this.tooltipElement);
93
-
94
- // Position tooltip
95
- this.positionTooltip();
96
-
97
- // Trigger animation
98
- requestAnimationFrame(() => {
99
- if (this.tooltipElement) {
100
- this.renderer.addClass(this.tooltipElement, 'app-tooltip-show');
101
- }
102
- });
103
- }
104
-
105
- private hideTooltip(): void {
106
- if (!this.tooltipElement) {
107
- return;
108
- }
109
-
110
- this.renderer.removeClass(this.tooltipElement, 'app-tooltip-show');
111
-
112
- setTimeout(() => {
113
- if (this.tooltipElement) {
114
- this.renderer.removeChild(document.body, this.tooltipElement);
115
- this.tooltipElement = null;
116
- }
117
- }, 200);
118
- }
119
-
120
- private positionTooltip(): void {
121
- if (!this.tooltipElement) {
122
- return;
123
- }
124
-
125
- const hostRect = this.el.nativeElement.getBoundingClientRect();
126
- const tooltipRect = this.tooltipElement.getBoundingClientRect();
127
- const scrollX = window.scrollX || window.pageXOffset;
128
- const scrollY = window.scrollY || window.pageYOffset;
129
- const gap = 16; // Space between element and tooltip
130
-
131
- // Calculate available space in each direction
132
- const spaceTop = hostRect.top;
133
- const spaceBottom = window.innerHeight - hostRect.bottom;
134
- const spaceLeft = hostRect.left;
135
- const spaceRight = window.innerWidth - hostRect.right;
136
-
137
- let position = this.tooltipPosition;
138
- let top = 0;
139
- let left = 0;
140
-
141
- // Auto-detect best position
142
- if (position === 'auto') {
143
- if (spaceTop >= tooltipRect.height + gap) {
144
- position = 'top';
145
- } else if (spaceBottom >= tooltipRect.height + gap) {
146
- position = 'bottom';
147
- } else if (spaceRight >= tooltipRect.width + gap) {
148
- position = 'right';
149
- } else if (spaceLeft >= tooltipRect.width + gap) {
150
- position = 'left';
151
- } else {
152
- // Default to top if no space is sufficient
153
- position = 'top';
154
- }
155
- }
156
-
157
- // Calculate position based on detected/specified position
158
- switch (position) {
159
- case 'top':
160
- top = hostRect.top + scrollY - tooltipRect.height - gap;
161
- left = hostRect.left + scrollX + (hostRect.width / 2) - (tooltipRect.width / 2);
162
- break;
163
-
164
- case 'bottom':
165
- top = hostRect.bottom + scrollY + gap;
166
- left = hostRect.left + scrollX + (hostRect.width / 2) - (tooltipRect.width / 2);
167
- break;
168
-
169
- case 'left':
170
- top = hostRect.top + scrollY + (hostRect.height / 2) - (tooltipRect.height / 2);
171
- left = hostRect.left + scrollX - tooltipRect.width - gap;
172
- break;
173
-
174
- case 'right':
175
- top = hostRect.top + scrollY + (hostRect.height / 2) - (tooltipRect.height / 2);
176
- left = hostRect.right + scrollX + gap;
177
- break;
178
- }
179
-
180
- // Adjust horizontal position to keep tooltip within viewport
181
- if (position === 'top' || position === 'bottom') {
182
- const minLeft = scrollX + 10;
183
- const maxLeft = scrollX + window.innerWidth - tooltipRect.width - 10;
184
- left = Math.max(minLeft, Math.min(left, maxLeft));
185
- }
186
-
187
- // Adjust vertical position to keep tooltip within viewport
188
- if (position === 'left' || position === 'right') {
189
- const minTop = scrollY + 10;
190
- const maxTop = scrollY + window.innerHeight - tooltipRect.height - 10;
191
- top = Math.max(minTop, Math.min(top, maxTop));
192
- }
193
-
194
- // Apply position
195
- this.renderer.setStyle(this.tooltipElement, 'top', `${top}px`);
196
- this.renderer.setStyle(this.tooltipElement, 'left', `${left}px`);
197
-
198
- // Add position class for arrow styling
199
- this.renderer.addClass(this.tooltipElement, `app-tooltip-${position}`);
200
- }
201
-
202
- ngOnDestroy(): void {
203
- if (this.showTimeout) {
204
- clearTimeout(this.showTimeout);
205
- }
206
- if (this.hideTimeout) {
207
- clearTimeout(this.hideTimeout);
208
- }
209
- this.hideTooltip();
210
- }
211
- }
@@ -1,29 +0,0 @@
1
- <div class="copy-input-wrapper">
2
-
3
- <!-- Tooltip -->
4
- <div
5
- class="copy-tooltip"
6
- *ngIf="isCopied"
7
- >
8
- Copiado
9
- </div>
10
-
11
- <!-- Componente -->
12
- <div
13
- class="copy-input"
14
- (click)="copyToClipboard()"
15
- tabindex="0"
16
- role="button"
17
- [attr.aria-label]="ariaLabel"
18
- (keydown.enter)="copyToClipboard()"
19
- >
20
- <i
21
- class="copy-input__icon"
22
- [ngClass]="isCopied ? copiedIcon : icon">
23
- </i>
24
-
25
- <span class="copy-input__text">
26
- {{ value }}
27
- </span>
28
- </div>
29
- </div>