@block-auth.io/angular 0.1.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 (148) hide show
  1. package/.turbo/turbo-build.log +37 -0
  2. package/.turbo/turbo-lint.log +4 -0
  3. package/.turbo/turbo-test.log +82 -0
  4. package/.turbo/turbo-typecheck.log +4 -0
  5. package/CHANGELOG.md +10 -0
  6. package/ng-package.json +6 -0
  7. package/package.json +50 -0
  8. package/scripts/css-to-ts.mjs +14 -0
  9. package/src/lib/__tests__/integration.test.ts +45 -0
  10. package/src/lib/block-auth.service.test.ts +69 -0
  11. package/src/lib/block-auth.service.ts +81 -0
  12. package/src/lib/components/btns/btn-base-provider.component.test.ts +22 -0
  13. package/src/lib/components/btns/btn-base-provider.component.ts +55 -0
  14. package/src/lib/components/btns/btn-block-auth.component.test.ts +79 -0
  15. package/src/lib/components/btns/btn-block-auth.component.ts +104 -0
  16. package/src/lib/components/btns/btn-gmail.component.test.ts +16 -0
  17. package/src/lib/components/btns/btn-gmail.component.ts +41 -0
  18. package/src/lib/components/btns/btn-google-base.component.test.ts +16 -0
  19. package/src/lib/components/btns/btn-google-base.component.ts +73 -0
  20. package/src/lib/components/btns/btn-metamask.component.test.ts +20 -0
  21. package/src/lib/components/btns/btn-metamask.component.ts +98 -0
  22. package/src/lib/components/btns/btn-microsoft.component.test.ts +16 -0
  23. package/src/lib/components/btns/btn-microsoft.component.ts +77 -0
  24. package/src/lib/components/btns/btn-phantom.component.test.ts +20 -0
  25. package/src/lib/components/btns/btn-phantom.component.ts +93 -0
  26. package/src/lib/components/btns/btn-signin.component.test.ts +55 -0
  27. package/src/lib/components/btns/btn-signin.component.ts +108 -0
  28. package/src/lib/components/btns/btn-wallet-connect.component.test.ts +20 -0
  29. package/src/lib/components/btns/btn-wallet-connect.component.ts +109 -0
  30. package/src/lib/components/btns/index.ts +11 -0
  31. package/src/lib/components/contents/content-signin.component.test.ts +33 -0
  32. package/src/lib/components/contents/content-signin.component.ts +68 -0
  33. package/src/lib/components/contents/content-signup.component.test.ts +78 -0
  34. package/src/lib/components/contents/content-signup.component.ts +225 -0
  35. package/src/lib/components/dds/change-account.component.test.ts +66 -0
  36. package/src/lib/components/dds/change-account.component.ts +112 -0
  37. package/src/lib/components/dds/dropdown-profile-btn.component.test.ts +66 -0
  38. package/src/lib/components/dds/dropdown-profile-btn.component.ts +185 -0
  39. package/src/lib/components/dds/dropdown-profile-item.component.test.ts +75 -0
  40. package/src/lib/components/dds/dropdown-profile-item.component.ts +74 -0
  41. package/src/lib/components/dds/dropdown-profile.component.test.ts +98 -0
  42. package/src/lib/components/dds/dropdown-profile.component.ts +258 -0
  43. package/src/lib/components/flow-block-auth.component.test.ts +93 -0
  44. package/src/lib/components/flow-block-auth.component.ts +226 -0
  45. package/src/lib/components/modals/modal-overlay.component.test.ts +81 -0
  46. package/src/lib/components/modals/modal-overlay.component.ts +43 -0
  47. package/src/lib/components/modals/modal-restoration-expired.component.test.ts +71 -0
  48. package/src/lib/components/modals/modal-restoration-expired.component.ts +83 -0
  49. package/src/lib/components/modals/modal-restore.component.test.ts +74 -0
  50. package/src/lib/components/modals/modal-restore.component.ts +104 -0
  51. package/src/lib/components/modals/modal-signin.component.test.ts +66 -0
  52. package/src/lib/components/modals/modal-signin.component.ts +44 -0
  53. package/src/lib/components/modals/modal-signup.component.test.ts +56 -0
  54. package/src/lib/components/modals/modal-signup.component.ts +40 -0
  55. package/src/lib/components/sections/footer-section.component.test.ts +19 -0
  56. package/src/lib/components/sections/footer-section.component.ts +49 -0
  57. package/src/lib/components/sections/internals/providers-buttons.component.test.ts +27 -0
  58. package/src/lib/components/sections/internals/providers-buttons.component.ts +290 -0
  59. package/src/lib/components/sections/internals/providers-filters.component.test.ts +25 -0
  60. package/src/lib/components/sections/internals/providers-filters.component.ts +139 -0
  61. package/src/lib/components/sections/internals/selected-button.component.test.ts +36 -0
  62. package/src/lib/components/sections/internals/selected-button.component.ts +92 -0
  63. package/src/lib/components/sections/login-section.component.test.ts +49 -0
  64. package/src/lib/components/sections/login-section.component.ts +120 -0
  65. package/src/lib/components/sections/providers-section.component.test.ts +22 -0
  66. package/src/lib/components/sections/providers-section.component.ts +187 -0
  67. package/src/lib/components/txns/internals/permissions-required-modal.component.test.ts +14 -0
  68. package/src/lib/components/txns/internals/permissions-required-modal.component.ts +35 -0
  69. package/src/lib/components/txns/internals/solicited-data-modal.component.test.ts +72 -0
  70. package/src/lib/components/txns/internals/solicited-data-modal.component.ts +187 -0
  71. package/src/lib/components/txns/internals/txn-error.component.test.ts +100 -0
  72. package/src/lib/components/txns/internals/txn-error.component.ts +121 -0
  73. package/src/lib/components/txns/internals/txn-type.component.test.ts +52 -0
  74. package/src/lib/components/txns/internals/txn-type.component.ts +51 -0
  75. package/src/lib/components/txns/internals/txn.component.test.ts +188 -0
  76. package/src/lib/components/txns/internals/txn.component.ts +298 -0
  77. package/src/lib/components/txns/txns-overview.component.test.ts +107 -0
  78. package/src/lib/components/txns/txns-overview.component.ts +229 -0
  79. package/src/lib/icons/ai-outline-disconnect.component.ts +21 -0
  80. package/src/lib/icons/bi-logo-gmail.component.ts +21 -0
  81. package/src/lib/icons/cg-profile.component.ts +31 -0
  82. package/src/lib/icons/check-icon.component.ts +27 -0
  83. package/src/lib/icons/ci-clock2.component.ts +31 -0
  84. package/src/lib/icons/fa-arrow-right.component.ts +21 -0
  85. package/src/lib/icons/fa-times.component.ts +21 -0
  86. package/src/lib/icons/fa-undo.component.ts +21 -0
  87. package/src/lib/icons/icons.test.ts +25 -0
  88. package/src/lib/icons/index.ts +22 -0
  89. package/src/lib/icons/io-ios-arrow-back.component.ts +21 -0
  90. package/src/lib/icons/io-ios-arrow-forward.component.ts +21 -0
  91. package/src/lib/icons/io-md-arrow-back.component.ts +19 -0
  92. package/src/lib/icons/io-md-arrow-forward.component.ts +19 -0
  93. package/src/lib/icons/pi-warning-fill.component.ts +21 -0
  94. package/src/lib/icons/tb-arrows-exchange2.component.ts +30 -0
  95. package/src/lib/icons/tb-copy-check-filled.component.ts +21 -0
  96. package/src/lib/icons/tb-copy.component.ts +34 -0
  97. package/src/lib/icons/ti-vendor-microsoft.component.ts +21 -0
  98. package/src/lib/inject-store.test.ts +26 -0
  99. package/src/lib/inject-store.ts +16 -0
  100. package/src/lib/primitives/arrow-icon.component.test.ts +12 -0
  101. package/src/lib/primitives/arrow-icon.component.ts +38 -0
  102. package/src/lib/primitives/btn-arrow-dir.component.test.ts +22 -0
  103. package/src/lib/primitives/btn-arrow-dir.component.ts +65 -0
  104. package/src/lib/primitives/btn-base.component.test.ts +38 -0
  105. package/src/lib/primitives/btn-base.component.ts +140 -0
  106. package/src/lib/primitives/divider-base.component.test.ts +12 -0
  107. package/src/lib/primitives/divider-base.component.ts +74 -0
  108. package/src/lib/primitives/dropdown-arrow.component.test.ts +12 -0
  109. package/src/lib/primitives/dropdown-arrow.component.ts +46 -0
  110. package/src/lib/primitives/dropdown-base.component.test.ts +49 -0
  111. package/src/lib/primitives/dropdown-base.component.ts +329 -0
  112. package/src/lib/primitives/helpers.ts +151 -0
  113. package/src/lib/primitives/horizontal-loader.component.test.ts +19 -0
  114. package/src/lib/primitives/horizontal-loader.component.ts +70 -0
  115. package/src/lib/primitives/icon-base.component.test.ts +19 -0
  116. package/src/lib/primitives/icon-base.component.ts +58 -0
  117. package/src/lib/primitives/img-loader.component.test.ts +12 -0
  118. package/src/lib/primitives/img-loader.component.ts +118 -0
  119. package/src/lib/primitives/index.ts +29 -0
  120. package/src/lib/primitives/input-base.component.test.ts +20 -0
  121. package/src/lib/primitives/input-base.component.ts +210 -0
  122. package/src/lib/primitives/lifetime-slider-base.component.test.ts +88 -0
  123. package/src/lib/primitives/lifetime-slider-base.component.ts +75 -0
  124. package/src/lib/primitives/oval-spinner.component.test.ts +9 -0
  125. package/src/lib/primitives/oval-spinner.component.ts +158 -0
  126. package/src/lib/primitives/pickers/dropdown-picker-animated-base.component.ts +220 -0
  127. package/src/lib/primitives/pickers/picker-button.component.ts +74 -0
  128. package/src/lib/primitives/pickers/time-picker-dropdown-selector.component.ts +188 -0
  129. package/src/lib/primitives/pickers/time-picker.component.ts +124 -0
  130. package/src/lib/primitives/pickers/time-unit-selector.component.ts +82 -0
  131. package/src/lib/primitives/progressbar.component.test.ts +18 -0
  132. package/src/lib/primitives/progressbar.component.ts +93 -0
  133. package/src/lib/primitives/providersStyles.ts +268 -0
  134. package/src/lib/primitives/slider-base.component.ts +56 -0
  135. package/src/lib/provide-block-auth.test.ts +43 -0
  136. package/src/lib/provide-block-auth.ts +43 -0
  137. package/src/lib/runtime/block-auth-runtime.directive.test.ts +89 -0
  138. package/src/lib/runtime/block-auth-runtime.directive.ts +68 -0
  139. package/src/lib/teleport-body.directive.test.ts +29 -0
  140. package/src/lib/teleport-body.directive.ts +21 -0
  141. package/src/lib/testing.ts +15 -0
  142. package/src/lib/transitions.css +23 -0
  143. package/src/public-api.ts +85 -0
  144. package/src/vitest.setup.ts +8 -0
  145. package/tailwind.config.cjs +6 -0
  146. package/tsconfig.json +15 -0
  147. package/tsconfig.lib.json +9 -0
  148. package/vite.config.mts +44 -0
@@ -0,0 +1,229 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ computed,
5
+ effect,
6
+ input,
7
+ signal,
8
+ } from '@angular/core';
9
+ import { injectBlockAuthClient } from '../../provide-block-auth';
10
+ import { injectStore } from '../../inject-store';
11
+ import { TxnComponent } from './internals/txn.component';
12
+ import { TxnTypeComponent } from './internals/txn-type.component';
13
+ import { TxnErrorComponent } from './internals/txn-error.component';
14
+ import { PermissionsRequiredModalComponent } from './internals/permissions-required-modal.component';
15
+ import { SolicitedDataModalComponent, type ParamChange } from './internals/solicited-data-modal.component';
16
+
17
+ // Orquestador de txns: lee las solicitudes pendientes de `$ws.requests` y la
18
+ // config de UI de `$ui.uiConfig` (vía injectStore). Se conserva la navegación
19
+ // prev/next, la composición de overlays permisos/datos-solicitados, la
20
+ // derivación de required/optional params desde `uiConfig` y las clases `bas-`.
21
+ // Se elimina `useLocale` (textos inline) y los wrappers framer-motion.
22
+ interface TxnPreParams {
23
+ iconUrl?: string;
24
+ domain?: string;
25
+ appName?: string;
26
+ txnType?: string;
27
+ appKey?: string;
28
+ to?: string;
29
+ lifetime?: { value?: number; min?: number; max?: number };
30
+ [key: string]: unknown;
31
+ }
32
+
33
+ const accountShort = (addr: string | null | undefined): string =>
34
+ addr && addr.length > 10 ? `${addr.slice(0, 6)}…${addr.slice(-4)}` : (addr ?? '');
35
+
36
+ const TXN_ERROR_TEXTS: Record<string, string> = {
37
+ no_transactions_found: 'No transactions found',
38
+ no_app_key_found: 'No application key found',
39
+ no_contract_address_found: 'No contract address found',
40
+ no_transactions_params_found: 'No transaction params found',
41
+ unknown: 'Something went wrong',
42
+ };
43
+
44
+ @Component({
45
+ selector: 'ba-txns-overview',
46
+ standalone: true,
47
+ changeDetection: ChangeDetectionStrategy.OnPush,
48
+ imports: [
49
+ TxnComponent,
50
+ TxnTypeComponent,
51
+ TxnErrorComponent,
52
+ PermissionsRequiredModalComponent,
53
+ SolicitedDataModalComponent,
54
+ ],
55
+ template: `
56
+ <div
57
+ data-testid="txns-overview"
58
+ class="bas-flex bas-box-border bas-relative bas-h-full bas-w-full bas-gap-6 bas-flex-col bas-items-center bas-p-6 bas-font-medium bas-justify-center"
59
+ >
60
+ @if (isEmpty() && isSigning()) {
61
+ <ba-txn-error
62
+ errorMessageTxt="No transactions found"
63
+ errorMessageSlug="no_transactions_found"
64
+ [closeTxns]="closeTxns()"
65
+ [isCountdown]="false"
66
+ />
67
+ } @else if (!isEmpty() && error().value) {
68
+ <ba-txn-error
69
+ [errorMessageTxt]="errorText()"
70
+ [errorMessageSlug]="error().messageSlug"
71
+ [closeTxns]="closeTxns()"
72
+ [isCountdown]="false"
73
+ />
74
+ } @else if (!isEmpty()) {
75
+ <div class="bas-flex bas-flex-col bas-items-center bas-gap-3">
76
+ <img
77
+ [src]="preParams().iconUrl || 'https://dashboard.block-auth.io/img/blockauth_logo.png'"
78
+ class="bas-h-16"
79
+ alt="app logo"
80
+ />
81
+ <h2 class="bas-m-0 bas-text-base bas-text-[var(--bal-primary-600)]">
82
+ {{ preParams().domain || 'dashboard.block-auth.io' }}
83
+ </h2>
84
+ <p class="bas-m-0 bas-text-lg bas-text-[var(--bal-primary-800)]">
85
+ {{ preParams().appName || 'Block-Auth' }}
86
+ <span class="bas-text-base bas-text-[var(--bal-primary-500)]">solicits to</span>
87
+ {{ accountShort(did()) }}
88
+ </p>
89
+ </div>
90
+ <ba-txn-type
91
+ [txnType]="preParams().txnType || 'Log In'"
92
+ [txnsLength]="txns().length"
93
+ (prevTxnClicked)="onPrevTxnClicked()"
94
+ (nextTxnClicked)="onNextTxnClicked()"
95
+ />
96
+ <div class="bas-h-[334px] bas-w-full bas-max-w-[330px]">
97
+ <ba-txn
98
+ [hasSolicitedData]="hasSolicitedData()"
99
+ [allRequiredFilled]="allRequiredFilled()"
100
+ [closeTxns]="closeTxns()"
101
+ [selectedTxnPreParams]="preParams()"
102
+ [userParamValues]="userParamValues()"
103
+ [addError]="addError"
104
+ (permissionsRequiredClicked)="showPermissions.set(true)"
105
+ (solicitedDataClicked)="showSolicitedData.set(true)"
106
+ />
107
+ </div>
108
+ }
109
+
110
+ @if (showPermissions()) {
111
+ <div
112
+ class="bal-ba-transition-2 bal-ba-backdrop-blur-base bal-ba-backdrop-blur-sm bas-absolute bas-z-30 bas-box-border bas-h-full bas-w-full"
113
+ (click)="showPermissions.set(false)"
114
+ ></div>
115
+ <div class="bas-absolute bas-top-44 bas-z-40">
116
+ <ba-permissions-required-modal />
117
+ </div>
118
+ }
119
+
120
+ @if (showSolicitedData()) {
121
+ <div
122
+ class="bal-ba-transition-2 bal-ba-backdrop-blur-base bal-ba-backdrop-blur-sm bas-absolute bas-z-30 bas-box-border bas-h-full bas-w-full"
123
+ (click)="showSolicitedData.set(false)"
124
+ ></div>
125
+ <div class="bas-absolute bas-top-32 bas-z-40">
126
+ <ba-solicited-data-modal
127
+ [requiredParams]="requiredParams()"
128
+ [optionalParams]="optionalParams()"
129
+ [userParamValues]="userParamValues()"
130
+ (paramChange)="handleParamChange($event)"
131
+ (validationChange)="allRequiredFilled.set($event)"
132
+ />
133
+ </div>
134
+ }
135
+ </div>
136
+ `,
137
+ })
138
+ export class TxnsOverviewComponent {
139
+ closeTxns = input<() => void>(() => {});
140
+
141
+ private readonly client = injectBlockAuthClient();
142
+ private readonly ws = injectStore(this.client.state.$ws);
143
+ private readonly ui = injectStore(this.client.state.$ui);
144
+
145
+ protected readonly accountShort = accountShort;
146
+
147
+ protected readonly selectedIndex = signal(0);
148
+ protected readonly showPermissions = signal(false);
149
+ protected readonly showSolicitedData = signal(false);
150
+ protected readonly userParamValues = signal<Record<string, string>>({});
151
+ protected readonly allRequiredFilled = signal(false);
152
+ protected readonly error = signal<{ value: boolean; messageSlug: string }>({
153
+ value: false,
154
+ messageSlug: '',
155
+ });
156
+
157
+ protected readonly txns = computed(() => this.ws().requests ?? []);
158
+ protected readonly did = computed(() => this.ws().did);
159
+ protected readonly isSigning = computed(() => this.ui().isSigning);
160
+ protected readonly isEmpty = computed(() => this.txns().length === 0);
161
+ protected readonly errorText = computed(
162
+ () => TXN_ERROR_TEXTS[this.error().messageSlug] ?? TXN_ERROR_TEXTS['unknown'],
163
+ );
164
+
165
+ private readonly selectedTxn = computed(
166
+ () => this.txns()[this.selectedIndex()] ?? this.txns()[0],
167
+ );
168
+ protected readonly preParams = computed<TxnPreParams>(() => {
169
+ const raw = this.selectedTxn()?.['pre_params'] as string | undefined;
170
+ if (!raw) return {};
171
+ try {
172
+ return JSON.parse(raw) as TxnPreParams;
173
+ } catch {
174
+ return {};
175
+ }
176
+ });
177
+
178
+ private readonly requiredOptionalParams = computed(() => {
179
+ const cfg =
180
+ (this.ui().uiConfig as { config?: Record<string, unknown> } | null)?.config ?? {};
181
+ const required: string[] = [];
182
+ const optional: string[] = [];
183
+ const kycMode = (cfg['modules'] as { kyc?: { mode?: string } } | undefined)?.kyc?.mode;
184
+ if (kycMode === 'required') required.push('modules-kyc');
185
+ else if (kycMode === 'optional') optional.push('modules-kyc');
186
+ Object.entries((cfg['params'] as Record<string, { mode?: string }>) || {}).forEach(
187
+ ([slug, paramCfg]) => {
188
+ if (paramCfg.mode === 'required') required.push(slug);
189
+ else if (paramCfg.mode === 'optional') optional.push(slug);
190
+ },
191
+ );
192
+ return { requiredParams: required, optionalParams: optional };
193
+ });
194
+ protected readonly requiredParams = computed(() => this.requiredOptionalParams().requiredParams);
195
+ protected readonly optionalParams = computed(() => this.requiredOptionalParams().optionalParams);
196
+ protected readonly hasSolicitedData = computed(
197
+ () => this.requiredParams().length > 0 || this.optionalParams().length > 0,
198
+ );
199
+
200
+ constructor() {
201
+ // ACCEPT is gated on `allRequiredFilled`. With no required params there's
202
+ // nothing to fill, so it must default to true.
203
+ effect(() => {
204
+ const params = this.requiredParams();
205
+ this.allRequiredFilled.set(params.length === 0);
206
+ });
207
+ }
208
+
209
+ // Surfaces an accept-validation error and clears the accepting loader.
210
+ addError = (messageSlug = 'unknown'): void => {
211
+ this.error.set({ value: true, messageSlug });
212
+ this.client.state.$ui.setKey('isAcceptingTxn', false);
213
+ };
214
+
215
+ handleParamChange({ slug, value }: ParamChange): void {
216
+ this.userParamValues.update((prev) => ({ ...prev, [slug]: value }));
217
+ }
218
+
219
+ onPrevTxnClicked(): void {
220
+ const len = this.txns().length;
221
+ if (len === 0) return;
222
+ this.selectedIndex.update((i) => (i === 0 ? len - 1 : i - 1));
223
+ }
224
+ onNextTxnClicked(): void {
225
+ const len = this.txns().length;
226
+ if (len === 0) return;
227
+ this.selectedIndex.update((i) => (i === len - 1 ? 0 : i + 1));
228
+ }
229
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/ai (AiOutlineDisconnect), espejo de
4
+ // packages/vue/src/icons/AiOutlineDisconnect.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-ai-outline-disconnect',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 1024 1024" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M832.6 191.4c-84.6-84.6-221.5-84.6-306 0l-96.9 96.9 51 51 96.9-96.9c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204l-96.9 96.9 51.1 51.1 96.9-96.9c84.4-84.6 84.4-221.5-.1-306.1zM446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l96.9-96.9-51.1-51.1-96.9 96.9c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l96.9-96.9-51-51-96.8 97zM260.3 209.4a8.03 8.03 0 0 0-11.3 0L209.4 249a8.03 8.03 0 0 0 0 11.3l554.4 554.4c3.1 3.1 8.2 3.1 11.3 0l39.6-39.6c3.1-3.1 3.1-8.2 0-11.3L260.3 209.4z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class AiOutlineDisconnectComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/bi (BiLogoGmail), espejo de
4
+ // packages/vue/src/icons/BiLogoGmail.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-bi-logo-gmail',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="m18.73 5.41-1.28 1L12 10.46 6.55 6.37l-1.28-1A2 2 0 0 0 2 7.05v11.59A1.36 1.36 0 0 0 3.36 20h3.19v-7.72L12 16.37l5.45-4.09V20h3.19A1.36 1.36 0 0 0 22 18.64V7.05a2 2 0 0 0-3.27-1.64z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class BiLogoGmailComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,31 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/cg (CgProfile), espejo de
4
+ // packages/vue/src/icons/CgProfile.vue (mismo `viewBox`/`d`, 2 `<path>` con
5
+ // `fill-rule`/`clip-rule`).
6
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
7
+ @Component({
8
+ selector: 'ba-cg-profile',
9
+ standalone: true,
10
+ changeDetection: ChangeDetectionStrategy.OnPush,
11
+ host: { style: 'display: contents' },
12
+ template: `
13
+ <svg [class]="class()" viewBox="0 0 24 24" fill="none" aria-hidden="true">
14
+ <path
15
+ fill-rule="evenodd"
16
+ clip-rule="evenodd"
17
+ d="M16 9C16 11.2091 14.2091 13 12 13C9.79086 13 8 11.2091 8 9C8 6.79086 9.79086 5 12 5C14.2091 5 16 6.79086 16 9ZM14 9C14 10.1046 13.1046 11 12 11C10.8954 11 10 10.1046 10 9C10 7.89543 10.8954 7 12 7C13.1046 7 14 7.89543 14 9Z"
18
+ fill="currentColor"
19
+ />
20
+ <path
21
+ fill-rule="evenodd"
22
+ clip-rule="evenodd"
23
+ d="M12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1ZM3 12C3 14.0902 3.71255 16.014 4.90798 17.5417C6.55245 15.3889 9.14627 14 12.0645 14C14.9448 14 17.5092 15.3531 19.1565 17.4583C20.313 15.9443 21 14.0524 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12ZM12 21C9.84977 21 7.87565 20.2459 6.32767 18.9878C7.59352 17.1812 9.69106 16 12.0645 16C14.4084 16 16.4833 17.1521 17.7538 18.9209C16.1939 20.2191 14.1881 21 12 21Z"
24
+ fill="currentColor"
25
+ />
26
+ </svg>
27
+ `,
28
+ })
29
+ export class CgProfileComponent {
30
+ class = input('');
31
+ }
@@ -0,0 +1,27 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de @heroicons/react/20/solid (CheckIcon), espejo de
4
+ // packages/vue/src/icons/CheckIcon.vue (mismo `viewBox`/`d`, ver Task V6).
5
+ // `:host { display: contents }` hace que el elemento `ba-check-icon` no
6
+ // participe en el layout; el `class` que un consumidor le pase se enruta al
7
+ // input `class` (declarado explícitamente) en vez de al atributo del host, y
8
+ // se aplica al `<svg>` interno — así el resultado visual/DOM es equivalente
9
+ // al de la SFC Vue, donde la clase cae directamente sobre el `<svg>`.
10
+ @Component({
11
+ selector: 'ba-check-icon',
12
+ standalone: true,
13
+ changeDetection: ChangeDetectionStrategy.OnPush,
14
+ host: { style: 'display: contents' },
15
+ template: `
16
+ <svg [class]="class()" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
17
+ <path
18
+ fill-rule="evenodd"
19
+ clip-rule="evenodd"
20
+ d="M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z"
21
+ />
22
+ </svg>
23
+ `,
24
+ })
25
+ export class CheckIconComponent {
26
+ class = input('');
27
+ }
@@ -0,0 +1,31 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de `react-icons/ci` (CiClock2), usado por
4
+ // `pickers/time-picker.component`. Espejo 1:1 de packages/vue/src/icons/CiClock2.vue
5
+ // (mismo viewBox 0 0 24 24, mismos paths) para que un `grep` sobre el nombre
6
+ // original siga encontrando el equivalente Angular.
7
+ // `:host { display: contents }` + `class` input enrutado al `<svg>`: mismo
8
+ // patrón que el resto de iconos (ver check-icon.component).
9
+ @Component({
10
+ selector: 'ba-ci-clock2',
11
+ standalone: true,
12
+ changeDetection: ChangeDetectionStrategy.OnPush,
13
+ host: { style: 'display: contents' },
14
+ template: `
15
+ <svg [class]="class()" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
16
+ <g id="Clock_2">
17
+ <g>
18
+ <path
19
+ d="M12,21.933A9.933,9.933,0,1,1,21.933,12,9.944,9.944,0,0,1,12,21.933ZM12,3.067A8.933,8.933,0,1,0,20.933,12,8.943,8.943,0,0,0,12,3.067Z"
20
+ />
21
+ <path
22
+ d="M18,12.5H12a.429.429,0,0,1-.34-.14c-.01,0-.01-.01-.02-.02A.429.429,0,0,1,11.5,12V6a.5.5,0,0,1,1,0v5.5H18A.5.5,0,0,1,18,12.5Z"
23
+ />
24
+ </g>
25
+ </g>
26
+ </svg>
27
+ `,
28
+ })
29
+ export class CiClock2Component {
30
+ class = input('');
31
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/fa (FaArrowRight), espejo de
4
+ // packages/vue/src/icons/FaArrowRight.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-fa-arrow-right',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 448 512" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class FaArrowRightComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/fa (FaTimes), espejo de
4
+ // packages/vue/src/icons/FaTimes.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-fa-times',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 352 512" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class FaTimesComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/fa (FaUndo), espejo de
4
+ // packages/vue/src/icons/FaUndo.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-fa-undo',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 512 512" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M212.333 224.333H12c-6.627 0-12-5.373-12-12V12C0 5.373 5.373 0 12 0h48c6.627 0 12 5.373 12 12v78.112C117.773 39.279 184.26 7.47 258.175 8.007c136.906.994 246.448 111.623 246.157 248.532C504.041 393.258 393.12 504 256.333 504c-64.089 0-122.496-24.313-166.51-64.215-5.099-4.622-5.334-12.554-.467-17.42l33.967-33.967c4.474-4.474 11.662-4.717 16.401-.525C170.76 415.336 211.58 432 256.333 432c97.268 0 176-78.716 176-176 0-97.267-78.716-176-176-176-58.496 0-110.28 28.476-142.274 72.333h98.274c6.627 0 12 5.373 12 12v48c0 6.627-5.373 12-12 12z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class FaUndoComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,25 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { render } from '@testing-library/angular';
3
+ import type { Type } from '@angular/core';
4
+ import * as icons from './index';
5
+
6
+ // Espejo de packages/vue/src/icons/icons.test.ts: cada icono debe renderizar
7
+ // un <svg> con `viewBox` y al menos un <path> con `d`. El host de cada
8
+ // componente usa `display: contents` (ver check-icon.component.ts), así que
9
+ // se consulta el `<svg>` dentro del `container`, no el host.
10
+ describe('icons', () => {
11
+ it.each(Object.entries(icons))(
12
+ '%s renderiza un <svg> con viewBox y al menos un <path>',
13
+ async (_name, IconComponent) => {
14
+ const { container } = await render(IconComponent as Type<unknown>);
15
+ const svg = container.querySelector('svg');
16
+ expect(svg).not.toBeNull();
17
+ expect(svg?.getAttribute('viewBox')).toBeTruthy();
18
+ const paths = container.querySelectorAll('path');
19
+ expect(paths.length).toBeGreaterThan(0);
20
+ paths.forEach((path) => {
21
+ expect(path.getAttribute('d')).toBeTruthy();
22
+ });
23
+ },
24
+ );
25
+ });
@@ -0,0 +1,22 @@
1
+ // Barrel de iconos inline (Task A6). Cada componente reproduce fielmente el
2
+ // SVG del icono de react-icons/heroicons homónimo (mismo nombre de export),
3
+ // espejo 1:1 de packages/vue/src/icons/*.vue (mismo `viewBox`/`d`/`stroke`)
4
+ // para que un futuro `grep` sobre el nombre original siga encontrando el
5
+ // equivalente Angular sin fricción de traducción. Exports alfabetizados.
6
+ export { AiOutlineDisconnectComponent } from './ai-outline-disconnect.component';
7
+ export { BiLogoGmailComponent } from './bi-logo-gmail.component';
8
+ export { CgProfileComponent } from './cg-profile.component';
9
+ export { CheckIconComponent } from './check-icon.component';
10
+ export { CiClock2Component } from './ci-clock2.component';
11
+ export { FaArrowRightComponent } from './fa-arrow-right.component';
12
+ export { FaTimesComponent } from './fa-times.component';
13
+ export { FaUndoComponent } from './fa-undo.component';
14
+ export { IoIosArrowBackComponent } from './io-ios-arrow-back.component';
15
+ export { IoIosArrowForwardComponent } from './io-ios-arrow-forward.component';
16
+ export { IoMdArrowBackComponent } from './io-md-arrow-back.component';
17
+ export { IoMdArrowForwardComponent } from './io-md-arrow-forward.component';
18
+ export { PiWarningFillComponent } from './pi-warning-fill.component';
19
+ export { TbArrowsExchange2Component } from './tb-arrows-exchange2.component';
20
+ export { TbCopyComponent } from './tb-copy.component';
21
+ export { TbCopyCheckFilledComponent } from './tb-copy-check-filled.component';
22
+ export { TiVendorMicrosoftComponent } from './ti-vendor-microsoft.component';
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/io (IoIosArrowBack), espejo de
4
+ // packages/vue/src/icons/IoIosArrowBack.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-io-ios-arrow-back',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 512 512" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M217.9 256L345 129c9.4-9.4 9.4-24.6 0-33.9-9.4-9.4-24.6-9.3-34 0L167 239c-9.1 9.1-9.3 23.7-.7 33.1L310.9 417c4.7 4.7 10.9 7 17 7s12.3-2.3 17-7c9.4-9.4 9.4-24.6 0-33.9L217.9 256z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class IoIosArrowBackComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/io (IoIosArrowForward), espejo de
4
+ // packages/vue/src/icons/IoIosArrowForward.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-io-ios-arrow-forward',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 512 512" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M294.1 256L167 129c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.3 34 0L345 239c9.1 9.1 9.3 23.7.7 33.1L201.1 417c-4.7 4.7-10.9 7-17 7s-12.3-2.3-17-7c-9.4-9.4-9.4-24.6 0-33.9l127-127.1z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class IoIosArrowForwardComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,19 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/io (IoMdArrowBack), espejo de
4
+ // packages/vue/src/icons/IoMdArrowBack.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-io-md-arrow-back',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 512 512" fill="currentColor" aria-hidden="true">
13
+ <path d="M427 234.625H167.296l119.702-119.702L256 85 85 256l171 171 29.922-29.924-118.626-119.701H427v-42.75z" />
14
+ </svg>
15
+ `,
16
+ })
17
+ export class IoMdArrowBackComponent {
18
+ class = input('');
19
+ }
@@ -0,0 +1,19 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/io (IoMdArrowForward), espejo de
4
+ // packages/vue/src/icons/IoMdArrowForward.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-io-md-arrow-forward',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 512 512" fill="currentColor" aria-hidden="true">
13
+ <path d="M85 277.375h259.704L225.002 397.077 256 427l171-171L256 85l-29.922 29.924 118.626 119.701H85v42.75z" />
14
+ </svg>
15
+ `,
16
+ })
17
+ export class IoMdArrowForwardComponent {
18
+ class = input('');
19
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/pi (PiWarningFill), espejo de
4
+ // packages/vue/src/icons/PiWarningFill.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-pi-warning-fill',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 256 256" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM120,104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm8,88a12,12,0,1,1,12-12A12,12,0,0,1,128,192Z"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class PiWarningFillComponent {
20
+ class = input('');
21
+ }
@@ -0,0 +1,30 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/tb (TbArrowsExchange2), espejo de
4
+ // packages/vue/src/icons/TbArrowsExchange2.vue (mismo `viewBox`/`d`, trazo en
5
+ // vez de relleno: `fill="none"` + `stroke="currentColor"`).
6
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
7
+ @Component({
8
+ selector: 'ba-tb-arrows-exchange2',
9
+ standalone: true,
10
+ changeDetection: ChangeDetectionStrategy.OnPush,
11
+ host: { style: 'display: contents' },
12
+ template: `
13
+ <svg
14
+ [class]="class()"
15
+ viewBox="0 0 24 24"
16
+ fill="none"
17
+ stroke="currentColor"
18
+ stroke-width="2"
19
+ stroke-linecap="round"
20
+ stroke-linejoin="round"
21
+ aria-hidden="true"
22
+ >
23
+ <path d="M17 10h-14l4 -4" />
24
+ <path d="M7 14h14l-4 4" />
25
+ </svg>
26
+ `,
27
+ })
28
+ export class TbArrowsExchange2Component {
29
+ class = input('');
30
+ }
@@ -0,0 +1,21 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ // Icono inline extraído de react-icons/tb (TbCopyCheckFilled), espejo de
4
+ // packages/vue/src/icons/TbCopyCheckFilled.vue (mismo `viewBox`/`d`).
5
+ // Ver check-icon.component.ts para la explicación del enrutado de `class`.
6
+ @Component({
7
+ selector: 'ba-tb-copy-check-filled',
8
+ standalone: true,
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ host: { style: 'display: contents' },
11
+ template: `
12
+ <svg [class]="class()" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
13
+ <path
14
+ d="M18.333 6a3.667 3.667 0 0 1 3.667 3.667v8.666a3.667 3.667 0 0 1 -3.667 3.667h-8.666a3.667 3.667 0 0 1 -3.667 -3.667v-8.666a3.667 3.667 0 0 1 3.667 -3.667zm-3.333 -4c1.094 0 1.828 .533 2.374 1.514a1 1 0 1 1 -1.748 .972c-.221 -.398 -.342 -.486 -.626 -.486h-10c-.548 0 -1 .452 -1 1v9.998c0 .32 .154 .618 .407 .805l.1 .065a1 1 0 1 1 -.99 1.738a3 3 0 0 1 -1.517 -2.606v-10c0 -1.652 1.348 -3 3 -3zm1.293 9.293l-3.293 3.292l-1.293 -1.292a1 1 0 0 0 -1.414 1.414l2 2a1 1 0 0 0 1.414 0l4 -4a1 1 0 0 0 -1.414 -1.414"
15
+ />
16
+ </svg>
17
+ `,
18
+ })
19
+ export class TbCopyCheckFilledComponent {
20
+ class = input('');
21
+ }