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,285 @@
1
+ :host {
2
+ display: block;
3
+ }
4
+
5
+ :host(.lib-card-host--full-width) {
6
+ width: 100%;
7
+ min-width: 0;
8
+ }
9
+
10
+ .ui-card {
11
+ display: flex;
12
+ align-items: stretch;
13
+ overflow: hidden;
14
+ border-radius: calc(var(--app-cards-outlined-enabled-container-outlined-card-container-shape, 12) * 1px);
15
+ color: var(--app-pallete-scheme-surface-on-surface, #181c1e);
16
+ box-sizing: border-box;
17
+ cursor: pointer;
18
+ transition: box-shadow 180ms ease, background-color 180ms ease, border-color 180ms ease;
19
+ position: relative;
20
+ isolation: isolate;
21
+ }
22
+
23
+ .ui-card:focus-visible {
24
+ outline: none;
25
+ }
26
+
27
+ .ui-card:focus-visible .ui-card__focus-indicator {
28
+ display: block;
29
+ }
30
+
31
+ .ui-card--outlined {
32
+ border: 0;
33
+ outline: calc(var(--app-cards-outlined-enabled-outline-outlined-card-outline-width, 1) * 1px) solid
34
+ var(--app-cards-outlined-enabled-outline-outlined-card-outline-color, #c3c7c9);
35
+ outline-offset: -1px;
36
+ background: var(--app-cards-outlined-enabled-container-outlined-card-container-color, #f7fafc);
37
+ }
38
+
39
+ .ui-card--elevated {
40
+ border: 0;
41
+ background: var(--app-cards-elevated-enabled-container-elevated-card-container-color, #f1f4f6);
42
+ box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
43
+ }
44
+
45
+ .ui-card--filled {
46
+ border: 0;
47
+ background: var(--app-cards-filled-enabled-container-filled-card-container-color, #e0e3e5);
48
+ }
49
+
50
+ .ui-card--active {
51
+ outline-color: var(--app-pallete-scheme-surface-outline-variant, #d4d7db);
52
+ background: var(--app-pallete-scheme-surface-outline-variant, #d4d7db);
53
+ }
54
+
55
+ .ui-card--disabled {
56
+ opacity: 0.7;
57
+ cursor: not-allowed;
58
+ }
59
+
60
+ .ui-card__content {
61
+ flex: 1 1 auto;
62
+ min-width: 0;
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 16px;
66
+ padding: 16px;
67
+ position: relative;
68
+ z-index: 2;
69
+ }
70
+
71
+ .ui-card__avatar {
72
+ width: 2.5rem;
73
+ height: 2.5rem;
74
+ flex: 0 0 auto;
75
+ border-radius: 100px;
76
+ display: inline-flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ background: var(--app-pallete-scheme-primary-primary, #e42313);
80
+ color: var(--app-pallete-scheme-primary-on-primary, #fff);
81
+ font-family: var(--app-typescale-title-medium-font, Heebo), sans-serif;
82
+ font-size: 1rem;
83
+ font-weight: 500;
84
+ line-height: 1.5rem;
85
+ letter-spacing: 0.00625rem;
86
+ }
87
+
88
+ .ui-card__leading {
89
+ width: 2.5rem;
90
+ height: 2.5rem;
91
+ flex: 0 0 auto;
92
+ display: inline-flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ }
96
+
97
+ .ui-card__leading--icon img,
98
+ .ui-card__leading--icon svg {
99
+ width: 2.08331rem;
100
+ height: 2.08331rem;
101
+ display: block;
102
+ }
103
+
104
+ .ui-card__leading--icon svg {
105
+ fill: currentColor;
106
+ }
107
+
108
+ .ui-card__text {
109
+ display: flex;
110
+ flex-direction: column;
111
+ gap: 4px;
112
+ min-width: 0;
113
+ color: inherit;
114
+ }
115
+
116
+ .ui-card__title,
117
+ .ui-card__subhead {
118
+ margin: 0;
119
+ }
120
+
121
+ .ui-card__title {
122
+ font-family: var(--app-typescale-title-medium-font, Heebo), sans-serif;
123
+ font-size: calc(var(--app-typescale-title-medium-size, 16) * 1px);
124
+ font-weight: var(--app-typescale-title-medium-weight, 500);
125
+ line-height: calc(var(--app-typescale-title-medium-line-height, 24) * 1px);
126
+ letter-spacing: calc(var(--app-typescale-title-medium-tracking, 0.15) * 1px);
127
+ }
128
+
129
+ .ui-card--title-emphasized .ui-card__title {
130
+ font-weight: var(--app-typescale-title-medium-weight-emphasized, 700);
131
+ }
132
+
133
+ .ui-card__subhead {
134
+ font-family: var(--app-typescale-body-medium-font, Heebo), sans-serif;
135
+ font-size: calc(var(--app-typescale-body-medium-size, 14) * 1px);
136
+ font-weight: var(--app-typescale-body-medium-weight, 400);
137
+ line-height: calc(var(--app-typescale-body-medium-line-height, 20) * 1px);
138
+ letter-spacing: calc(var(--app-typescale-body-medium-tracking, 0.25) * 1px);
139
+ }
140
+
141
+ .ui-card__media {
142
+ width: 5rem;
143
+ flex: 0 0 5rem;
144
+ display: inline-flex;
145
+ align-items: center;
146
+ justify-content: center;
147
+ border-left: 1px solid var(--app-pallete-scheme-surface-outline-variant, #c3c7c9);
148
+ background: var(--app-schemes-surface-container-high, #ebe7e7);
149
+ position: relative;
150
+ z-index: 2;
151
+ }
152
+
153
+ .ui-card__media img,
154
+ .ui-card__media svg {
155
+ width: 2.08331rem;
156
+ height: 2.08331rem;
157
+ display: block;
158
+ }
159
+
160
+ .ui-card__media svg {
161
+ fill: var(--app-schemes-outline, #b5b5b5);
162
+ }
163
+
164
+ .ui-card__media--empty {
165
+ opacity: 0.45;
166
+ }
167
+
168
+ .ui-card__state-layer {
169
+ position: absolute;
170
+ inset: 0;
171
+ pointer-events: none;
172
+ z-index: 1;
173
+ opacity: 0;
174
+ background: transparent;
175
+ }
176
+
177
+ .ui-card__focus-indicator {
178
+ display: none;
179
+ position: absolute;
180
+ inset: -3px;
181
+ border-radius: 14px;
182
+ border: 3px solid var(--app-cards-outlined-focused-focus-indicator-outlined-card-focus-indicator-color, #5b5f61);
183
+ pointer-events: none;
184
+ z-index: 3;
185
+ }
186
+
187
+ .ui-card--state-focused .ui-card__focus-indicator {
188
+ display: block;
189
+ }
190
+
191
+ .ui-card--state-hovered .ui-card__state-layer,
192
+ .ui-card:hover .ui-card__state-layer {
193
+ opacity: 1;
194
+ }
195
+
196
+ .ui-card--state-focused .ui-card__state-layer,
197
+ .ui-card--state-pressed .ui-card__state-layer,
198
+ .ui-card--state-dragged .ui-card__state-layer {
199
+ opacity: 1;
200
+ }
201
+
202
+ .ui-card--outlined.ui-card--state-hovered,
203
+ .ui-card--outlined:hover {
204
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.15);
205
+ }
206
+
207
+ .ui-card--outlined.ui-card--state-dragged {
208
+ box-shadow: 0 4px 8px 3px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.3);
209
+ }
210
+
211
+ .ui-card--elevated.ui-card--state-hovered,
212
+ .ui-card--elevated:hover {
213
+ box-shadow: 0 2px 6px 2px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
214
+ }
215
+
216
+ .ui-card--elevated.ui-card--state-pressed {
217
+ box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
218
+ }
219
+
220
+ .ui-card--elevated.ui-card--state-dragged {
221
+ box-shadow: 0 6px 10px 4px rgba(0, 0, 0, 0.15), 0 2px 3px rgba(0, 0, 0, 0.3);
222
+ }
223
+
224
+ .ui-card--filled.ui-card--state-hovered {
225
+ box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.3);
226
+ }
227
+
228
+ .ui-card--filled.ui-card--state-dragged {
229
+ box-shadow: 0 4px 8px 3px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.3);
230
+ }
231
+
232
+ .ui-card--outlined.ui-card--state-hovered .ui-card__state-layer,
233
+ .ui-card--outlined:hover .ui-card__state-layer {
234
+ background: rgba(24, 28, 30, 0.08);
235
+ }
236
+
237
+ .ui-card--outlined.ui-card--state-focused .ui-card__state-layer {
238
+ background: rgba(24, 28, 30, 0.1);
239
+ }
240
+
241
+ .ui-card--outlined.ui-card--state-pressed .ui-card__state-layer {
242
+ background: rgba(24, 28, 30, 0.1);
243
+ }
244
+
245
+ .ui-card--outlined.ui-card--state-dragged .ui-card__state-layer {
246
+ background: rgba(24, 28, 30, 0.16);
247
+ }
248
+
249
+ .ui-card--elevated.ui-card--state-hovered .ui-card__state-layer,
250
+ .ui-card--elevated:hover .ui-card__state-layer {
251
+ background: rgba(24, 28, 30, 0.08);
252
+ }
253
+
254
+ .ui-card--elevated.ui-card--state-focused .ui-card__state-layer {
255
+ background: rgba(24, 28, 30, 0.1);
256
+ }
257
+
258
+ .ui-card--elevated.ui-card--state-pressed .ui-card__state-layer {
259
+ background: rgba(24, 28, 30, 0.1);
260
+ }
261
+
262
+ .ui-card--elevated.ui-card--state-dragged .ui-card__state-layer {
263
+ background: rgba(24, 28, 30, 0.16);
264
+ }
265
+
266
+ .ui-card--filled.ui-card--state-hovered .ui-card__state-layer,
267
+ .ui-card--filled:hover .ui-card__state-layer {
268
+ background: rgba(24, 28, 30, 0.08);
269
+ }
270
+
271
+ .ui-card--filled.ui-card--state-focused .ui-card__state-layer {
272
+ background: rgba(24, 28, 30, 0.1);
273
+ }
274
+
275
+ .ui-card--filled.ui-card--state-pressed .ui-card__state-layer {
276
+ background: rgba(24, 28, 30, 0.1);
277
+ }
278
+
279
+ .ui-card--filled.ui-card--state-dragged .ui-card__state-layer {
280
+ background: rgba(24, 28, 30, 0.16);
281
+ }
282
+
283
+ .ui-card--disabled .ui-card__state-layer {
284
+ display: none;
285
+ }
@@ -0,0 +1,69 @@
1
+ <div
2
+ [ngClass]="classes()"
3
+ [style.width]="fullWidth() ? '100%' : width()"
4
+ [style.min-width]="fullWidth() ? '0rem' : width()"
5
+ [style.height]="height()"
6
+ [style.min-height]="height()"
7
+ [attr.aria-disabled]="disabled()"
8
+ role="button"
9
+ tabindex="0"
10
+ (click)="onCardClick()"
11
+ (keydown)="onCardKeydown($event)"
12
+ >
13
+ <div class="ui-card__content">
14
+ @if (leadingKind() === 'icon') {
15
+ <div
16
+ class="ui-card__leading ui-card__leading--icon"
17
+ aria-hidden="true"
18
+ [style.width]="leadingContainerSize()"
19
+ [style.height]="leadingContainerSize()"
20
+ >
21
+ @if (hasLeadingIcon()) {
22
+ @if (isLeadingImage()) {
23
+ <img [src]="leadingIcon()" alt="" [style.width]="leadingIconSize()" [style.height]="leadingIconSize()" />
24
+ } @else {
25
+ <svg
26
+ viewBox="0 0 24 24"
27
+ [style.width]="leadingIconSize()"
28
+ [style.height]="leadingIconSize()"
29
+ >
30
+ <g [innerHTML]="leadingIcon()"></g>
31
+ </svg>
32
+ }
33
+ } @else {
34
+ <span>{{ initial() }}</span>
35
+ }
36
+ </div>
37
+ } @else {
38
+ <div class="ui-card__avatar" aria-hidden="true">
39
+ {{ initial() }}
40
+ </div>
41
+ }
42
+
43
+ <div class="ui-card__text">
44
+ <p class="ui-card__title">{{ title() }}</p>
45
+ @if (subhead()) {
46
+ <p class="ui-card__subhead">{{ subhead() }}</p>
47
+ }
48
+ </div>
49
+ </div>
50
+
51
+ @if (showMedia()) {
52
+ <div class="ui-card__media" [class.ui-card__media--empty]="!hasMedia()">
53
+ @if (hasMedia()) {
54
+ @if (isMediaImage()) {
55
+ <img [src]="mediaIcon()" [alt]="mediaAlt()" />
56
+ } @else {
57
+ <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
58
+ <g [innerHTML]="mediaIcon()"></g>
59
+ </svg>
60
+ }
61
+ }
62
+ </div>
63
+ }
64
+
65
+ <span class="ui-card__state-layer" aria-hidden="true"></span>
66
+ @if (state() === 'focused') {
67
+ <span class="ui-card__focus-indicator" aria-hidden="true"></span>
68
+ }
69
+ </div>
@@ -0,0 +1,93 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ computed,
5
+ input,
6
+ output,
7
+ } from '@angular/core';
8
+ import { NgClass } from '@angular/common';
9
+
10
+ export type LibCardVariant = 'outlined' | 'elevated' | 'filled';
11
+ export type LibCardState = 'enabled' | 'hovered' | 'focused' | 'pressed' | 'dragged';
12
+ export type LibCardLeadingKind = 'avatar' | 'icon';
13
+
14
+ @Component({
15
+ selector: 'lib-card',
16
+ standalone: true,
17
+ imports: [NgClass],
18
+ templateUrl: './card.html',
19
+ styleUrl: './card.css',
20
+ changeDetection: ChangeDetectionStrategy.OnPush,
21
+ host: {
22
+ '[class.lib-card-host--full-width]': 'fullWidth()',
23
+ },
24
+ })
25
+ export class LibCardComponent {
26
+ title = input('Header');
27
+ subhead = input('');
28
+ variant = input<LibCardVariant>('outlined');
29
+ state = input<LibCardState>('enabled');
30
+ leadingKind = input<LibCardLeadingKind>('avatar');
31
+ leadingIcon = input<string>('');
32
+ /** Tamaño del contenedor leading (Figma suele usar 2.5rem). */
33
+ leadingContainerSize = input('2.5rem');
34
+ /** Tamaño del icono leading. */
35
+ leadingIconSize = input('2.08331rem');
36
+ mediaIcon = input<string>('');
37
+ mediaAlt = input('Card media');
38
+ showMedia = input(false);
39
+ avatarText = input('');
40
+ width = input('20.5rem');
41
+ /** Alto del card. */
42
+ height = input('4.5rem');
43
+ /** Si es true, el card toma el 100% del ancho del contenedor padre. */
44
+ fullWidth = input(false);
45
+ active = input(false);
46
+ disabled = input(false);
47
+
48
+ readonly cardClick = output<void>();
49
+
50
+ readonly initial = computed(() => {
51
+ const text = this.avatarText().trim();
52
+ if (text.length) return text.slice(0, 1).toUpperCase();
53
+ const title = this.title().trim();
54
+ return title.length ? title.slice(0, 1).toUpperCase() : 'A';
55
+ });
56
+
57
+ readonly hasMedia = computed(() => this.mediaIcon().trim().length > 0);
58
+ readonly isMediaImage = computed(() => this.mediaIcon().trim().endsWith('.svg'));
59
+ readonly hasLeadingIcon = computed(() => this.leadingIcon().trim().length > 0);
60
+ readonly isLeadingImage = computed(() => this.leadingIcon().trim().endsWith('.svg'));
61
+ readonly hasSubhead = computed(() => this.subhead().trim().length > 0);
62
+
63
+ readonly classes = computed(() => ({
64
+ 'ui-card': true,
65
+ 'ui-card--outlined': this.variant() === 'outlined',
66
+ 'ui-card--elevated': this.variant() === 'elevated',
67
+ 'ui-card--filled': this.variant() === 'filled',
68
+ 'ui-card--state-enabled': this.state() === 'enabled',
69
+ 'ui-card--state-hovered': this.state() === 'hovered',
70
+ 'ui-card--state-focused': this.state() === 'focused',
71
+ 'ui-card--state-pressed': this.state() === 'pressed',
72
+ 'ui-card--state-dragged': this.state() === 'dragged',
73
+ 'ui-card--leading-avatar': this.leadingKind() === 'avatar',
74
+ 'ui-card--leading-icon': this.leadingKind() === 'icon',
75
+ 'ui-card--with-media': this.showMedia() && this.hasMedia(),
76
+ 'ui-card--title-emphasized': !this.hasSubhead(),
77
+ 'ui-card--active': this.active(),
78
+ 'ui-card--disabled': this.disabled(),
79
+ }));
80
+
81
+ onCardClick(): void {
82
+ if (this.disabled()) return;
83
+ this.cardClick.emit();
84
+ }
85
+
86
+ onCardKeydown(event: KeyboardEvent): void {
87
+ if (this.disabled()) return;
88
+ if (event.code === 'Enter' || event.code === 'Space') {
89
+ event.preventDefault();
90
+ this.cardClick.emit();
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,42 @@
1
+ .lib-checkbox-showcase {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 1.5rem;
5
+ }
6
+
7
+ .lib-checkbox-showcase__title {
8
+ margin: 0 0 0.5rem;
9
+ font-size: 1.25rem;
10
+ font-weight: 600;
11
+ }
12
+
13
+ .lib-checkbox-showcase__group {
14
+ display: flex;
15
+ flex-direction: column;
16
+ gap: 0.5rem;
17
+ }
18
+
19
+ .lib-checkbox-showcase__group > h3 {
20
+ margin: 0;
21
+ font-size: 1rem;
22
+ font-weight: 500;
23
+ }
24
+
25
+ .lib-checkbox-showcase__hint {
26
+ margin: 0;
27
+ font-size: 0.875rem;
28
+ color: #696d6f;
29
+ }
30
+
31
+ .lib-checkbox-showcase__row {
32
+ display: flex;
33
+ flex-wrap: wrap;
34
+ align-items: center;
35
+ gap: 1rem 2.5rem;
36
+ }
37
+
38
+ .lib-checkbox-showcase__row lib-checkbox {
39
+ display: inline-flex;
40
+ align-items: center;
41
+ gap: 0.5rem;
42
+ }
@@ -0,0 +1,36 @@
1
+ <section class="lib-checkbox-showcase">
2
+ <h2 class="lib-checkbox-showcase__title">Checkbox – estados (tokens Figma)</h2>
3
+
4
+ <div class="lib-checkbox-showcase__group">
5
+ <h3>Enabled</h3>
6
+ <div class="lib-checkbox-showcase__row">
7
+ <lib-checkbox>Unselected</lib-checkbox>
8
+ <lib-checkbox [checked]="true">Selected</lib-checkbox>
9
+ <lib-checkbox [indeterminate]="true">Indeterminate</lib-checkbox>
10
+ <lib-checkbox [error]="true">Error (unselected)</lib-checkbox>
11
+ <lib-checkbox [checked]="true" [error]="true">Error (selected)</lib-checkbox>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="lib-checkbox-showcase__group">
16
+ <h3>Disabled</h3>
17
+ <div class="lib-checkbox-showcase__row">
18
+ <lib-checkbox [disabled]="true">Unselected</lib-checkbox>
19
+ <lib-checkbox [disabled]="true" [checked]="true">Selected</lib-checkbox>
20
+ <lib-checkbox [disabled]="true" [indeterminate]="true">Indeterminate</lib-checkbox>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="lib-checkbox-showcase__group">
25
+ <h3>Interactive (hover / pressed)</h3>
26
+ <p class="lib-checkbox-showcase__hint">
27
+ Pasa el mouse y haz click para ver hover / pressed según tokens de Figma.
28
+ </p>
29
+ <div class="lib-checkbox-showcase__row">
30
+ <lib-checkbox>Unselected (hover / pressed)</lib-checkbox>
31
+ <lib-checkbox [checked]="true">Selected (hover / pressed)</lib-checkbox>
32
+ <lib-checkbox [indeterminate]="true">Indeterminate (hover / pressed)</lib-checkbox>
33
+ </div>
34
+ </div>
35
+ </section>
36
+
@@ -0,0 +1,13 @@
1
+ import { ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { LibCheckboxComponent } from './checkbox';
3
+
4
+ @Component({
5
+ selector: 'lib-checkbox-showcase',
6
+ standalone: true,
7
+ imports: [LibCheckboxComponent],
8
+ templateUrl: './checkbox-showcase.component.html',
9
+ styleUrls: ['./checkbox-showcase.component.css'],
10
+ changeDetection: ChangeDetectionStrategy.OnPush,
11
+ })
12
+ export class LibCheckboxShowcaseComponent {}
13
+
@@ -0,0 +1,10 @@
1
+ /* Wrapper del mat-checkbox; solo ripple nativo de Material */
2
+ .lib-checkbox__wrapper {
3
+ position: relative;
4
+ display: inline-flex;
5
+ }
6
+
7
+ .lib-checkbox__wrapper .mat-mdc-checkbox {
8
+ position: relative;
9
+ z-index: 1;
10
+ }
@@ -0,0 +1,13 @@
1
+ <div
2
+ class="lib-checkbox__wrapper"
3
+ [class.lib-checkbox--disabled]="disabled()"
4
+ >
5
+ <mat-checkbox
6
+ [checked]="checked()"
7
+ [indeterminate]="indeterminate()"
8
+ [disabled]="disabled()"
9
+ (change)="onMatCheckboxChange($event)"
10
+ >
11
+ <ng-content />
12
+ </mat-checkbox>
13
+ </div>
@@ -0,0 +1,64 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ input,
5
+ output,
6
+ computed,
7
+ HostBinding,
8
+ } from '@angular/core';
9
+ import { MatCheckboxChange } from '@angular/material/checkbox';
10
+ import { MatCheckboxModule } from '@angular/material/checkbox';
11
+
12
+ @Component({
13
+ selector: 'lib-checkbox',
14
+ standalone: true,
15
+ imports: [MatCheckboxModule],
16
+ templateUrl: './checkbox.html',
17
+ styleUrl: './checkbox.css',
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ })
20
+ export class LibCheckboxComponent {
21
+ checked = input(false);
22
+ indeterminate = input(false);
23
+ disabled = input(false);
24
+ error = input(false);
25
+ /** Id para asociar label (accesibilidad). Si no se pasa, se genera uno interno. */
26
+ labelId = input<string | null>(null);
27
+
28
+ readonly checkedChange = output<boolean>();
29
+ readonly indeterminateChange = output<boolean>();
30
+
31
+ @HostBinding('attr.aria-disabled') get ariaDisabled(): boolean | null {
32
+ return this.disabled() ? true : null;
33
+ }
34
+
35
+ protected readonly ariaChecked = computed(() => {
36
+ if (this.indeterminate()) return 'mixed';
37
+ return this.checked() ? 'true' : 'false';
38
+ });
39
+
40
+ protected onAction(event: Event): void {
41
+ event.preventDefault();
42
+ if (this.disabled()) return;
43
+ if (this.indeterminate()) {
44
+ this.indeterminateChange.emit(false);
45
+ this.checkedChange.emit(true);
46
+ } else {
47
+ this.checkedChange.emit(!this.checked());
48
+ }
49
+ }
50
+
51
+ protected onKeydown(event: KeyboardEvent): void {
52
+ if (event.key === ' ' || event.key === 'Enter') {
53
+ event.preventDefault();
54
+ this.onAction(event);
55
+ }
56
+ }
57
+
58
+ protected onMatCheckboxChange(event: MatCheckboxChange): void {
59
+ this.checkedChange.emit(event.checked);
60
+ if (event.checked && this.indeterminate()) {
61
+ this.indeterminateChange.emit(false);
62
+ }
63
+ }
64
+ }