crdx-components 1.0.0

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 (128) hide show
  1. package/.github/workflows/publish.yml +38 -0
  2. package/bun.lock +491 -0
  3. package/crdx-components-1.0.0.tgz +0 -0
  4. package/crdx-components-tokenized-components-1.0.1.tgz +0 -0
  5. package/ng-package.json +12 -0
  6. package/npm +0 -0
  7. package/package.json +33 -0
  8. package/src/index.ts +45 -0
  9. package/src/lib/components/breadcrumb/breadcrumb.component.css +206 -0
  10. package/src/lib/components/breadcrumb/breadcrumb.component.html +15 -0
  11. package/src/lib/components/breadcrumb/breadcrumb.component.ts +47 -0
  12. package/src/lib/components/button/button.css +371 -0
  13. package/src/lib/components/button/button.html +187 -0
  14. package/src/lib/components/button/button.ts +103 -0
  15. package/src/lib/components/card/card.css +285 -0
  16. package/src/lib/components/card/card.html +69 -0
  17. package/src/lib/components/card/card.ts +93 -0
  18. package/src/lib/components/checkbox/checkbox-showcase.component.css +42 -0
  19. package/src/lib/components/checkbox/checkbox-showcase.component.html +36 -0
  20. package/src/lib/components/checkbox/checkbox-showcase.component.ts +13 -0
  21. package/src/lib/components/checkbox/checkbox.css +10 -0
  22. package/src/lib/components/checkbox/checkbox.html +13 -0
  23. package/src/lib/components/checkbox/checkbox.ts +64 -0
  24. package/src/lib/components/circular-progress-stepper/circular-progress-stepper.css +89 -0
  25. package/src/lib/components/circular-progress-stepper/circular-progress-stepper.html +23 -0
  26. package/src/lib/components/circular-progress-stepper/circular-progress-stepper.ts +40 -0
  27. package/src/lib/components/dialogs/alert-modal/alert-modal.css +118 -0
  28. package/src/lib/components/dialogs/alert-modal/alert-modal.html +29 -0
  29. package/src/lib/components/dialogs/alert-modal/alert-modal.ts +28 -0
  30. package/src/lib/components/dialogs/confirm-modal/confirm-modal.css +219 -0
  31. package/src/lib/components/dialogs/confirm-modal/confirm-modal.html +60 -0
  32. package/src/lib/components/dialogs/confirm-modal/confirm-modal.store.ts +139 -0
  33. package/src/lib/components/dialogs/confirm-modal/confirm-modal.ts +63 -0
  34. package/src/lib/components/dialogs/container-custom/container-custom.css +11 -0
  35. package/src/lib/components/dialogs/container-custom/container-custom.html +3 -0
  36. package/src/lib/components/dialogs/container-custom/container-custom.ts +37 -0
  37. package/src/lib/components/dialogs/container-custom/custom-modal.state.ts +57 -0
  38. package/src/lib/components/dialogs/error-modal/error-modal.css +53 -0
  39. package/src/lib/components/dialogs/error-modal/error-modal.html +17 -0
  40. package/src/lib/components/dialogs/error-modal/error-modal.ts +20 -0
  41. package/src/lib/components/dialogs/side-modal/side-modal.css +80 -0
  42. package/src/lib/components/dialogs/side-modal/side-modal.html +30 -0
  43. package/src/lib/components/dialogs/side-modal/side-modal.state.ts +78 -0
  44. package/src/lib/components/dialogs/side-modal/side-modal.ts +50 -0
  45. package/src/lib/components/divider/divider.css +24 -0
  46. package/src/lib/components/divider/divider.html +7 -0
  47. package/src/lib/components/divider/divider.ts +13 -0
  48. package/src/lib/components/footer-actions/footer/footer-flow.store.ts +30 -0
  49. package/src/lib/components/footer-actions/footer/footer.html +14 -0
  50. package/src/lib/components/footer-actions/footer/footer.ts +50 -0
  51. package/src/lib/components/footer-actions/modal-footer-actions/modal-footer-actions.css +44 -0
  52. package/src/lib/components/footer-actions/modal-footer-actions/modal-footer-actions.html +7 -0
  53. package/src/lib/components/footer-actions/modal-footer-actions/modal-footer-actions.ts +12 -0
  54. package/src/lib/components/footer-actions/page-footer-actions/page-footer-actions.css +31 -0
  55. package/src/lib/components/footer-actions/page-footer-actions/page-footer-actions.html +7 -0
  56. package/src/lib/components/footer-actions/page-footer-actions/page-footer-actions.ts +12 -0
  57. package/src/lib/components/form-field/select-field.css +178 -0
  58. package/src/lib/components/form-field/select-field.html +94 -0
  59. package/src/lib/components/form-field/select-field.ts +324 -0
  60. package/src/lib/components/form-field/text-field.css +41 -0
  61. package/src/lib/components/form-field/text-field.html +38 -0
  62. package/src/lib/components/form-field/text-field.ts +102 -0
  63. package/src/lib/components/header/header.css +142 -0
  64. package/src/lib/components/header/header.html +36 -0
  65. package/src/lib/components/header/header.ts +101 -0
  66. package/src/lib/components/icon-button/icon-button.css +445 -0
  67. package/src/lib/components/icon-button/icon-button.html +15 -0
  68. package/src/lib/components/icon-button/icon-button.ts +49 -0
  69. package/src/lib/components/list-item/list-item.css +122 -0
  70. package/src/lib/components/list-item/list-item.html +79 -0
  71. package/src/lib/components/list-item/list-item.ts +104 -0
  72. package/src/lib/components/menu/menu.css +39 -0
  73. package/src/lib/components/menu/menu.html +57 -0
  74. package/src/lib/components/menu/menu.ts +159 -0
  75. package/src/lib/components/shared-table/shared-table-cell-template.directive.ts +25 -0
  76. package/src/lib/components/shared-table/shared-table.component.css +223 -0
  77. package/src/lib/components/shared-table/shared-table.component.html +96 -0
  78. package/src/lib/components/shared-table/shared-table.component.ts +172 -0
  79. package/src/lib/components/sidebar/sidebar.css +234 -0
  80. package/src/lib/components/sidebar/sidebar.html +67 -0
  81. package/src/lib/components/sidebar/sidebar.ts +92 -0
  82. package/src/lib/components/slide-toggle/slide-toggle.css +0 -0
  83. package/src/lib/components/slide-toggle/slide-toggle.html +3 -0
  84. package/src/lib/components/slide-toggle/slide-toggle.ts +18 -0
  85. package/src/lib/components/spinner/spinner.css +9 -0
  86. package/src/lib/components/spinner/spinner.html +9 -0
  87. package/src/lib/components/spinner/spinner.ts +17 -0
  88. package/src/lib/components/tooltip/tooltip.css +32 -0
  89. package/src/lib/components/tooltip/tooltip.html +3 -0
  90. package/src/lib/components/tooltip/tooltip.ts +31 -0
  91. package/src/lib/icons/configuration-countable.svg +8 -0
  92. package/src/lib/icons/edit-table.svg +3 -0
  93. package/src/lib/icons/edit.svg +3 -0
  94. package/src/lib/icons/error-circle.svg +8 -0
  95. package/src/lib/icons/hub.svg +3 -0
  96. package/src/lib/icons/icon-menu.svg +8 -0
  97. package/src/lib/icons/info-error.svg +8 -0
  98. package/src/lib/icons/keyboard_arrow_down.svg +1 -0
  99. package/src/lib/icons/logo.svg +0 -0
  100. package/src/lib/icons/logout.svg +0 -0
  101. package/src/lib/icons/notifications.svg +0 -0
  102. package/src/lib/icons/profile-user-menu.svg +0 -0
  103. package/src/lib/icons/profile.svg +0 -0
  104. package/src/lib/icons/register-icons.ts +101 -0
  105. package/src/lib/icons/visibility.svg +0 -0
  106. package/src/lib/lib-ui/lib-ui.html +1 -0
  107. package/src/lib/lib-ui/lib-ui.scss +0 -0
  108. package/src/lib/lib-ui/lib-ui.ts +9 -0
  109. package/src/lib/styles/generated/_app-tokens.scss +2757 -0
  110. package/src/lib/styles/generated/_md3-tokens.scss +179 -0
  111. package/src/lib/styles/generated/_tokens-avatars.scss +4 -0
  112. package/src/lib/styles/global-material-theme.scss +69 -0
  113. package/src/lib/styles/index.scss +16 -0
  114. package/src/lib/styles/layout.scss +29 -0
  115. package/src/lib/styles/overrides/_index.scss +11 -0
  116. package/src/lib/styles/overrides/_mat-button-overrides.scss +105 -0
  117. package/src/lib/styles/overrides/_mat-checkbox-overrides.scss +49 -0
  118. package/src/lib/styles/overrides/_mat-form-field-overrides.scss +148 -0
  119. package/src/lib/styles/overrides/_mat-icon-button-overrides.scss +20 -0
  120. package/src/lib/styles/overrides/_mat-list-overrides.scss +59 -0
  121. package/src/lib/styles/overrides/_mat-slide-toggle-overrides.scss +33 -0
  122. package/src/lib/styles/overrides/_mat-table-overrides.scss +259 -0
  123. package/src/lib/styles/overrides/_mat-tabs-overrides.scss +116 -0
  124. package/src/lib/styles/scrollbar.scss +40 -0
  125. package/src/lib/styles/text-classes.scss +116 -0
  126. package/src/lib/styles/typography.scss +14 -0
  127. package/tsconfig.json +30 -0
  128. package/tsconfig.lib.json +20 -0
@@ -0,0 +1,139 @@
1
+ import { inject, Injectable, signal, WritableSignal } from '@angular/core';
2
+ import { Dialog, DialogRef } from '@angular/cdk/dialog';
3
+ import { Overlay } from '@angular/cdk/overlay';
4
+ import { ConfirmModal, ConfirmModalData } from './confirm-modal';
5
+ import { NavigationStart, Router } from '@angular/router';
6
+
7
+ export interface ConfirmModalOpenOptions {
8
+ description?: string;
9
+ showTopIcon?: boolean;
10
+ topIconName?: string;
11
+ variant?: ConfirmModalData['variant'];
12
+ listItems?: ConfirmModalData['listItems'];
13
+ height?: string;
14
+ }
15
+
16
+ @Injectable({
17
+ providedIn: 'root'
18
+ })
19
+ export class ConfirmModalStore {
20
+ readonly dialog = inject(Dialog);
21
+ private readonly overlay = inject(Overlay);
22
+ protected dialogState: WritableSignal<'open' | 'closed'> = signal('open');
23
+ private readonly router = inject(Router);
24
+ private currentDialogRef?: DialogRef<string, unknown>;
25
+
26
+ open(
27
+ title: string,
28
+ labelButtonConfirm: string,
29
+ reference = '',
30
+ content = '',
31
+ width = '19.5rem',
32
+ labelButtonCancel = 'Cancelar',
33
+ options: ConfirmModalOpenOptions = {}
34
+ ): DialogRef<string, unknown> {
35
+ this.dialogState.set('open');
36
+ const positionBuilder = this.overlay.position();
37
+ const strategy = positionBuilder.global().centerHorizontally().centerVertically();
38
+
39
+ this.currentDialogRef = this.dialog.open<string>(ConfirmModal, {
40
+ width,
41
+ height: options.height,
42
+ disableClose: true,
43
+ autoFocus: false,
44
+ positionStrategy: strategy,
45
+ panelClass: 'lib-confirm-modal-panel',
46
+ backdropClass: 'lib-confirm-modal-backdrop',
47
+ data: {
48
+ title: title,
49
+ reference: reference,
50
+ content: content,
51
+ description: options.description,
52
+ showTopIcon: options.showTopIcon,
53
+ topIconName: options.topIconName,
54
+ variant: options.variant,
55
+ listItems: options.listItems,
56
+ labelButtonConfirm: labelButtonConfirm,
57
+ labelButtonCancel: labelButtonCancel,
58
+ },
59
+ closeOnNavigation: true
60
+ });
61
+ const sub = this.router.events.subscribe(event => {
62
+ if (event instanceof NavigationStart) {
63
+ this.close();
64
+ sub.unsubscribe();
65
+ }
66
+ });
67
+ return this.currentDialogRef
68
+ }
69
+
70
+ openBasic(title: string, confirmLabel: string, cancelLabel = 'Cancelar'): DialogRef<string, unknown> {
71
+ return this.open(title, confirmLabel, '', '', '19.5rem', cancelLabel);
72
+ }
73
+
74
+ openWithDescription(
75
+ title: string,
76
+ description: string,
77
+ confirmLabel: string,
78
+ cancelLabel = 'Cancelar'
79
+ ): DialogRef<string, unknown> {
80
+ return this.open(title, confirmLabel, '', '', '19.5rem', cancelLabel, {
81
+ description,
82
+ });
83
+ }
84
+
85
+ openWithIcon(
86
+ title: string,
87
+ description: string,
88
+ confirmLabel: string,
89
+ cancelLabel = 'Cancelar',
90
+ topIconName = 'check_box'
91
+ ): DialogRef<string, unknown> {
92
+ return this.open(title, confirmLabel, '', '', '19.5rem', cancelLabel, {
93
+ description,
94
+ showTopIcon: true,
95
+ topIconName,
96
+ });
97
+ }
98
+
99
+ openWithList(
100
+ title: string,
101
+ description: string,
102
+ listItems: ConfirmModalData['listItems'],
103
+ confirmLabel: string,
104
+ cancelLabel = 'Cancelar',
105
+ showTopIcon = false
106
+ ): DialogRef<string, unknown> {
107
+ return this.open(title, confirmLabel, '', '', '19.5rem', cancelLabel, {
108
+ description,
109
+ showTopIcon,
110
+ variant: 'list',
111
+ listItems,
112
+ });
113
+ }
114
+
115
+ openWithScrollableList(
116
+ title: string,
117
+ description: string,
118
+ listItems: ConfirmModalData['listItems'],
119
+ confirmLabel: string,
120
+ cancelLabel = 'Cancelar',
121
+ showTopIcon = false
122
+ ): DialogRef<string, unknown> {
123
+ return this.open(title, confirmLabel, '', '', '19.5rem', cancelLabel, {
124
+ description,
125
+ showTopIcon,
126
+ variant: 'scrollable-list',
127
+ listItems,
128
+ height: 'auto',
129
+ });
130
+ }
131
+
132
+ close(): void {
133
+ if (this.currentDialogRef) {
134
+ this.currentDialogRef.close();
135
+ this.currentDialogRef = undefined;
136
+ }
137
+ this.dialogState.set('closed');
138
+ }
139
+ }
@@ -0,0 +1,63 @@
1
+ import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';
2
+ import { Component, inject, signal } from '@angular/core';
3
+ import { MatIconModule } from '@angular/material/icon';
4
+
5
+ import { LibButtonComponent } from '../../button/button';
6
+
7
+ export type ConfirmModalVariant = 'basic' | 'list' | 'scrollable-list';
8
+
9
+ export interface ConfirmModalListItem {
10
+ id: string;
11
+ label: string;
12
+ supportingText?: string;
13
+ amount?: string;
14
+ selected?: boolean;
15
+ }
16
+
17
+ export interface ConfirmModalData {
18
+ title: string;
19
+ reference?: string;
20
+ content?: string;
21
+ description?: string;
22
+ showTopIcon?: boolean;
23
+ topIconName?: string;
24
+ variant?: ConfirmModalVariant;
25
+ listItems?: ConfirmModalListItem[];
26
+ labelButtonCancel?: string;
27
+ labelButtonConfirm: string;
28
+ }
29
+
30
+ @Component({
31
+ selector: 'lib-confirm',
32
+ templateUrl: './confirm-modal.html',
33
+ imports: [LibButtonComponent, MatIconModule],
34
+ styleUrl: './confirm-modal.css',
35
+ })
36
+ export class ConfirmModal {
37
+ readonly dialogRef = inject(DialogRef);
38
+ readonly data: ConfirmModalData = inject(DIALOG_DATA) as ConfirmModalData;
39
+ readonly listItems = signal<ConfirmModalListItem[]>(this.data.listItems ?? []);
40
+
41
+ readonly labelButtonCancel = this.data.labelButtonCancel ?? 'Cancelar';
42
+
43
+ readonly supportingText = this.data.description ?? this.data.content ?? this.data.reference ?? '';
44
+
45
+ readonly isListVariant = this.data.variant === 'list' || this.data.variant === 'scrollable-list';
46
+ readonly isScrollableList = this.data.variant === 'scrollable-list';
47
+
48
+ readonly topIconName = this.data.topIconName ?? 'check_box';
49
+
50
+ toggleListItem(itemId: string): void {
51
+ this.listItems.update((items) =>
52
+ items.map((item) => (item.id === itemId ? { ...item, selected: !item.selected } : item))
53
+ );
54
+ }
55
+
56
+ onCancel(): void {
57
+ this.dialogRef.close(false);
58
+ }
59
+
60
+ onConfirm(): void {
61
+ this.dialogRef.close(true);
62
+ }
63
+ }
@@ -0,0 +1,11 @@
1
+ .container{
2
+ width: 100%;
3
+ display: flex;
4
+ flex-direction: column;
5
+ background-color: white;
6
+ border-radius: 8px;
7
+ }
8
+
9
+ .content{
10
+ width: 100%;
11
+ }
@@ -0,0 +1,3 @@
1
+ <div class="container">
2
+ <ng-content class="content" *ngComponentOutlet="content; injector: injector" ></ng-content>
3
+ </div>
@@ -0,0 +1,37 @@
1
+ import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';
2
+ import { NgComponentOutlet } from '@angular/common';
3
+ import { Component, effect, inject, Injector, Type, WritableSignal } from '@angular/core';
4
+
5
+ @Component({
6
+ selector: 'lib-container-custom, app-container-custom',
7
+ imports: [NgComponentOutlet],
8
+ templateUrl: './container-custom.html',
9
+ styleUrl: './container-custom.css'
10
+ })
11
+ export class ContainerCustom {
12
+ private readonly dialogData = inject(DIALOG_DATA);
13
+ readonly content: Type<any> = this.dialogData.content;
14
+ readonly dialogState: WritableSignal<'open' | 'closed'> = this.dialogData.dialogState;
15
+ readonly injector:Injector;
16
+ private readonly dialogRef = inject(DialogRef);
17
+
18
+ constructor() {
19
+ effect(() => {
20
+ const state = this.dialogState();
21
+ if (state === 'closed') {
22
+ this.dialogRef.close();
23
+ }
24
+ });
25
+
26
+ this.injector = Injector.create({
27
+ providers: [
28
+ { provide: DIALOG_DATA, useValue: this.dialogData.modalData }
29
+ ]
30
+ });
31
+ }
32
+
33
+
34
+
35
+
36
+
37
+ }
@@ -0,0 +1,57 @@
1
+ import { Dialog, DialogRef } from '@angular/cdk/dialog';
2
+ import { Overlay } from '@angular/cdk/overlay';
3
+ import { inject, Injectable, signal, Type, WritableSignal } from '@angular/core';
4
+ import { NavigationStart, Router } from '@angular/router';
5
+ import { ContainerCustom } from './container-custom';
6
+
7
+ export interface ModalData {
8
+ [key: string]: any;
9
+ }
10
+
11
+ @Injectable({
12
+ providedIn: 'root'
13
+ })
14
+ export class CustomModalState {
15
+ private readonly dialog = inject(Dialog);
16
+ private readonly overlay = inject(Overlay);
17
+ readonly dialogState: WritableSignal<'open' | 'closed'> = signal('open');
18
+ private currentDialogRef?: DialogRef<any>;
19
+ private readonly router = inject(Router);
20
+
21
+ constructor() { }
22
+
23
+ openCustomModal(content: Type<any>, width: string, modalData?: {}): DialogRef<string, any> {
24
+ this.dialogState.set('open');
25
+ const positionBuilder = this.overlay.position();
26
+ const strategy = positionBuilder.global().centerHorizontally().centerVertically();
27
+
28
+ this.currentDialogRef = this.dialog.open<string>(ContainerCustom, {
29
+ width: width,
30
+ height: 'max-content',
31
+ disableClose: true,
32
+ positionStrategy: strategy,
33
+ data: {
34
+ content,
35
+ modalData,
36
+ dialogState: this.dialogState // Pasar el estado como dato en lugar de inyectar el servicio
37
+ },
38
+ closeOnNavigation: true
39
+ });
40
+ const sub = this.router.events.subscribe(event => {
41
+ if (event instanceof NavigationStart) {
42
+ this.closeCustomModal();
43
+ sub.unsubscribe();
44
+ }
45
+ });
46
+ return this.currentDialogRef;
47
+ }
48
+
49
+ closeCustomModal(): void {
50
+ if (this.currentDialogRef) {
51
+ this.currentDialogRef.close();
52
+ this.currentDialogRef = undefined;
53
+ }
54
+ this.dialogState.set('closed');
55
+ }
56
+
57
+ }
@@ -0,0 +1,53 @@
1
+ .container{
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ background-color: #ffffff;
7
+ width: 100%;
8
+ height: 100%;
9
+ outline: none;
10
+ border: none;
11
+ padding: 40px 48px;
12
+ border-radius: 8px;
13
+ }
14
+
15
+ .container > *:not(:last-child):not(:first-child){
16
+ margin-top: 24px;
17
+ }
18
+
19
+ .container > *:last-child{
20
+ margin-top: 40px;
21
+ }
22
+
23
+ .container h5{
24
+ font-size: 24px;
25
+ font-weight: 700;
26
+ color: #3E3E3E;
27
+ }
28
+
29
+ .container p{
30
+ flex: 1;
31
+ font-size: 16px;
32
+ font-weight: 400;
33
+ color: #3E3E3E;
34
+ text-align: center;
35
+ font-style: normal;
36
+ line-height: 24px;
37
+ }
38
+
39
+ .container .icon{
40
+ width: 90px;
41
+ height: 90px;
42
+ font-size: 90px;
43
+ color: #FF4965;
44
+ }
45
+
46
+ .container button{
47
+ height: 56px;
48
+ width: 160px;
49
+ border-radius: 16px;
50
+ font-size: 16px;
51
+ font-style: normal;
52
+ font-weight: 500;
53
+ }
@@ -0,0 +1,17 @@
1
+ <div class="container">
2
+ <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="90" height="90" viewBox="0 0 90 90" fill="none">
3
+ <path d="M49.5 58.5L40.5 58.5L40.5 67.5H49.5L49.5 58.5ZM45 9C52.1201 9 59.0803 11.1114 65.0005 15.0671C70.9207 19.0228 75.5349 24.6453 78.2596 31.2234C80.9844 37.8015 81.6973 45.0399 80.3082 52.0233C78.9192 59.0066 75.4905 65.4212 70.4558 70.4558C65.4211 75.4905 59.0065 78.9192 52.0232 80.3083C45.0399 81.6973 37.8015 80.9844 31.2234 78.2597C24.6452 75.5349 19.0228 70.9207 15.0671 65.0005C11.1113 59.0804 8.99998 52.1201 8.99998 45C9.01093 35.4556 12.8073 26.3052 19.5562 19.5563C26.3052 12.8073 35.4555 9.01096 45 9ZM45 90C53.9001 90 62.6004 87.3608 70.0006 82.4161C77.4009 77.4715 83.1686 70.4434 86.5746 62.2208C89.9805 53.9981 90.8717 44.9501 89.1353 36.2209C87.399 27.4918 83.1131 19.4736 76.8198 13.1802C70.5264 6.88683 62.5082 2.601 53.779 0.864662C45.0499 -0.871674 36.0019 0.0194702 27.7792 3.42542C19.5565 6.83136 12.5285 12.5991 7.58385 19.9993C2.63918 27.3996 -2.28882e-05 36.0998 -2.28882e-05 45C-2.28882e-05 56.9347 4.74104 68.3807 13.1802 76.8198C21.6193 85.2589 33.0652 90 45 90V90ZM49.5 22.5H40.5V49.5H49.5V22.5Z" fill="#FF4965"/>
4
+ </svg>
5
+ <h5>Ocurrió un error inesperado</h5>
6
+ <p style="white-space: pre-wrap;" >
7
+ {{data.message}}
8
+ </p>
9
+ @if(data.detail){
10
+ <p>
11
+ Detalle: {{data.detail}}
12
+ </p>
13
+ }
14
+ <button matButton="filled" (click)="onConfirm()" >
15
+ Entendido
16
+ </button>
17
+ </div>
@@ -0,0 +1,20 @@
1
+ import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';
2
+ import { Component, inject } from '@angular/core';
3
+ import { MatButtonModule } from '@angular/material/button';
4
+
5
+ @Component({
6
+ selector: 'lib-error-modal, app-error-modal',
7
+ imports: [MatButtonModule],
8
+ templateUrl: './error-modal.html',
9
+ styleUrl: './error-modal.css'
10
+ })
11
+ export class ErrorModal {
12
+ private readonly dialogRef = inject(DialogRef);
13
+ readonly data = inject(DIALOG_DATA);
14
+
15
+ onConfirm(): void {
16
+ this.dialogRef.close(true);
17
+
18
+ }
19
+
20
+ }
@@ -0,0 +1,80 @@
1
+ .container {
2
+ height: 100dvh;
3
+ width: 100%;
4
+ max-height: 100dvh;
5
+ box-sizing: border-box;
6
+ background-color: var(--side-sheets-enabled-container-sheet-side-docked-standard-container-color, #f8f9fa);
7
+ border-radius: 8px 0px 0px 8px;
8
+ display: flex;
9
+ flex-direction: column;
10
+ overflow: hidden;
11
+ animation: animationDialog 0.5s ease;
12
+ }
13
+
14
+ .side-modal__header {
15
+ display: flex;
16
+ justify-content: space-between;
17
+ align-items: center;
18
+ gap: 8px;
19
+ margin-bottom: 1.5rem;
20
+ padding: 1rem 1rem 0;
21
+ }
22
+
23
+ .title {
24
+ color: var(--side-sheets-enabled-headline-sheet-side-docked-headline-color, #434749);
25
+ font-family: var(--side-sheets-enabled-headline-sheet-side-docked-headline-font, 'Heebo'), sans-serif;
26
+ font-size: var(--side-sheets-enabled-headline-sheet-side-docked-headline-size, 22px);
27
+ font-style: normal;
28
+ font-weight: var(--side-sheets-enabled-headline-sheet-side-docked-headline-weight, 400);
29
+ line-height: calc(var(--side-sheets-enabled-headline-sheet-side-docked-headline-line-height, 28) * 1px);
30
+ letter-spacing: var(--side-sheets-enabled-headline-sheet-side-docked-headline-tracking, 0px);
31
+ margin: 0;
32
+ }
33
+
34
+ .side-modal__header button {
35
+ background-color: transparent;
36
+ border: none;
37
+ height: 40px;
38
+ width: 40px;
39
+ min-width: 40px;
40
+ border-radius: 999px;
41
+ display: inline-flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ cursor: pointer;
45
+ color: #696D6F;
46
+ }
47
+
48
+ .side-modal__header button mat-icon {
49
+ font-size: 24px;
50
+ }
51
+
52
+ .side-modal__icon-btn svg {
53
+ display: block;
54
+ }
55
+
56
+ .side-modal__content {
57
+ width: 100%;
58
+ box-sizing: border-box;
59
+ flex: 1 1 auto;
60
+ min-height: 0;
61
+ overflow-y: auto;
62
+ overflow-x: hidden;
63
+ padding-top: 0;
64
+ padding-bottom: 0;
65
+ }
66
+
67
+ .side-modal__footer {
68
+ width: 100%;
69
+ flex: 0 0 auto;
70
+ }
71
+
72
+ @keyframes animationDialog {
73
+ from {
74
+ transform: translateX(100%);
75
+ }
76
+
77
+ to {
78
+ transform: translateX(0);
79
+ }
80
+ }
@@ -0,0 +1,30 @@
1
+ <div class="container" [@dialogAnimation]="dialogState()" (@dialogAnimation.done)="onAnimationDone($event)">
2
+ <header class="side-modal__header">
3
+ <div style="display: flex; align-items: center;">
4
+ @if (shouldShowBack()) {
5
+ <button type="button" class="side-modal__icon-btn" (click)="onBackClick()" aria-label="Volver">
6
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
7
+ <path d="M14 6H3.83L8.41 1.41L7 0L0 7L7 14L8.41 12.59L3.83 8H14V6Z" fill="#434749" />
8
+ </svg>
9
+ </button>
10
+ }
11
+ <h4 class="title">{{title}}</h4>
12
+ </div>
13
+
14
+ <button type="button" class="side-modal__icon-btn" (click)="closeDialog()" aria-label="Cerrar">
15
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none">
16
+ <path d="M1.4 14L0 12.6L5.6 7L0 1.4L1.4 0L7 5.6L12.6 0L14 1.4L8.4 7L14 12.6L12.6 14L7 8.4L1.4 14Z"
17
+ fill="#434749" />
18
+ </svg>
19
+ </button>
20
+ </header>
21
+
22
+ <main class="side-modal__content container-content app-scrollbar-figma">
23
+ <ng-container *ngComponentOutlet="content"></ng-container>
24
+ </main>
25
+ @if (footer) {
26
+ <footer class="side-modal__footer">
27
+ <ng-container *ngComponentOutlet="footer"></ng-container>
28
+ </footer>
29
+ }
30
+ </div>
@@ -0,0 +1,78 @@
1
+ import { Dialog, DialogRef } from '@angular/cdk/dialog';
2
+ import { Overlay } from '@angular/cdk/overlay';
3
+ import { inject, Injectable, signal, Type, WritableSignal } from '@angular/core';
4
+ import { NavigationStart, Router } from '@angular/router';
5
+ import { SideModal } from './side-modal';
6
+
7
+ export interface SideModalHeaderConfig {
8
+ showBackButton?: () => boolean;
9
+ onBack?: () => void;
10
+ }
11
+
12
+ @Injectable({
13
+ providedIn: 'root'
14
+ })
15
+ export class SideModalStore {
16
+ private readonly dialog = inject(Dialog);
17
+ private readonly overlay = inject(Overlay);
18
+ private readonly dialogState: WritableSignal<'open' | 'closed' | 'action'> = signal('open');
19
+ private currentDialogRef?: DialogRef<unknown, unknown>;
20
+ private readonly router = inject(Router);
21
+
22
+ openSideModal(
23
+ content: Type<unknown>,
24
+ title: string,
25
+ width: string,
26
+ footer?: Type<unknown>,
27
+ headerConfig?: SideModalHeaderConfig
28
+ ): DialogRef<unknown, unknown> {
29
+ this.dialogState.set('open');
30
+ const positionBuilder = this.overlay.position();
31
+ const strategy = positionBuilder.global().end();
32
+
33
+ this.currentDialogRef = this.dialog.open<unknown>(SideModal, {
34
+ width: width,
35
+ height: '100%',
36
+ disableClose: true,
37
+ hasBackdrop: true,
38
+ backdropClass: 'lib-side-modal-backdrop',
39
+ positionStrategy: strategy,
40
+ data: {
41
+ title: title,
42
+ content,
43
+ dialogState: this.dialogState,
44
+ footer,
45
+ headerConfig,
46
+ },
47
+ closeOnNavigation: true
48
+ });
49
+
50
+ const sub = this.router.events.subscribe(event => {
51
+ if (event instanceof NavigationStart) {
52
+ this.closeSideModal();
53
+ sub.unsubscribe();
54
+ }
55
+ });
56
+
57
+ return this.currentDialogRef;
58
+ }
59
+
60
+ isOnAction(): boolean {
61
+ return this.dialogState() === 'action';
62
+ }
63
+
64
+ closeSideModal(_data?: unknown): void {
65
+ void _data;
66
+ if (this.currentDialogRef) {
67
+ this.currentDialogRef.close();
68
+ this.currentDialogRef = undefined;
69
+ }
70
+ this.dialogState.set('closed');
71
+ }
72
+
73
+ actionSideModal(): void {
74
+ this.dialogState.set('action');
75
+ }
76
+
77
+
78
+ }
@@ -0,0 +1,50 @@
1
+ import { animate, state, style, transition, trigger,AnimationEvent } from '@angular/animations';
2
+ import { DialogRef,DIALOG_DATA } from '@angular/cdk/dialog';
3
+ import { CommonModule, NgComponentOutlet } from '@angular/common';
4
+ import { Component, inject, Type, WritableSignal } from '@angular/core';
5
+ import { SideModalHeaderConfig } from './side-modal.state';
6
+
7
+
8
+ @Component({
9
+ selector: 'lib-side-modal, app-side-modal',
10
+ imports: [CommonModule, NgComponentOutlet],
11
+ templateUrl: './side-modal.html',
12
+ styleUrl: './side-modal.css',
13
+ animations: [
14
+ trigger('dialogAnimation',[
15
+ state('closed', style({ transform: 'translateX(100%)' })),
16
+ state('open', style({ transform: 'translateX(0)'})),
17
+ transition('open => closed', [animate('0.5s ease')]),
18
+ ])
19
+ ]
20
+ })
21
+ export class SideModal {
22
+ readonly dialogData = inject(DIALOG_DATA);
23
+ readonly dialogRef = inject(DialogRef);
24
+
25
+ readonly content: Type<any> = this.dialogData.content;
26
+ readonly title:string = this.dialogData.title;
27
+ readonly footer: Type<any> | undefined = this.dialogData.footer;
28
+ readonly headerConfig: SideModalHeaderConfig | undefined = this.dialogData.headerConfig;
29
+ readonly dialogState:WritableSignal<'open' | 'closed'> = this.dialogData.dialogState;
30
+
31
+ closeDialog(): void {
32
+ this.dialogState.set('closed');
33
+ }
34
+
35
+ shouldShowBack(): boolean {
36
+ return this.headerConfig?.showBackButton?.() ?? false;
37
+ }
38
+
39
+ onBackClick(): void {
40
+ this.headerConfig?.onBack?.();
41
+ }
42
+
43
+ onAnimationDone(event: AnimationEvent): void {
44
+ if (event.toState === 'action' || event.toState === 'closed') {
45
+ this.dialogRef.close(true);
46
+ }
47
+ }
48
+
49
+
50
+ }
@@ -0,0 +1,24 @@
1
+ /* Host como flex para que el divisor vertical (align-self: stretch) tome la altura del padre. */
2
+ :host {
3
+ display: flex;
4
+ align-items: stretch;
5
+ }
6
+
7
+ .ui-divider {
8
+ flex-shrink: 0;
9
+ background: var(--divider-enabled-container-divider-color, #c3c7c9);
10
+ }
11
+
12
+ .ui-divider--horizontal {
13
+ width: 100%;
14
+ height: var(--divider-enabled-container-divider-thickness, 0.0625rem);
15
+ min-height: 0.0625rem;
16
+ }
17
+
18
+ .ui-divider--vertical {
19
+ width: var(--divider-enabled-container-divider-thickness, 0.0625rem);
20
+ min-width: 0.0625rem;
21
+ align-self: stretch;
22
+ /* Permite que stretch funcione en contenedores flex con min-height */
23
+ min-height: 0;
24
+ }
@@ -0,0 +1,7 @@
1
+ <div
2
+ class="ui-divider"
3
+ [class.ui-divider--horizontal]="orientation() === 'horizontal'"
4
+ [class.ui-divider--vertical]="orientation() === 'vertical'"
5
+ role="separator"
6
+ [attr.aria-orientation]="orientation()"
7
+ ></div>