@acontplus/ng-components 3.2.1 → 4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acontplus/ng-components",
3
- "version": "3.2.1",
3
+ "version": "4.0.0",
4
4
  "description": "Comprehensive Angular Material UI component library featuring dynamic Tabulator tables, theme toggle with dark mode, dialog wrappers, autocomplete components, cards, buttons, icons, input chips, spinners, directives, pipes, and SCSS styling utilities.",
5
5
  "peerDependencies": {
6
6
  "@acontplus/ui-kit": "^1.0.2",
@@ -1,225 +1,238 @@
1
+ @use 'sass:list';
1
2
  @use '@angular/material' as mat;
2
3
 
3
- // Card component styling with Material Design tokens
4
- // Using mat.card-overrides to customize card-specific design tokens
4
+ // Public CSS custom properties (set them on `acp-card` or any ancestor):
5
+ // --acp-card-shape, --acp-card-elevation, --acp-card-padding,
6
+ // --acp-card-container-color, --acp-card-on-color, --acp-card-subtitle-color,
7
+ // --acp-card-outline-color
8
+ $shape: var(--acp-card-shape, var(--mat-sys-corner-small));
9
+
10
+ :host {
11
+ --acp-card-padding: 16px;
12
+ display: block;
13
+ border-radius: $shape;
14
+
15
+ &:focus-visible {
16
+ outline: 2px solid var(--mat-sys-primary);
17
+ outline-offset: 2px;
18
+ }
19
+ }
20
+
5
21
  .acp-card {
6
22
  @include mat.card-overrides(
7
23
  (
8
- elevated-container-color: light-dark(#ffffff, #1a1b1f),
9
- outlined-container-color: light-dark(#ffffff, #1a1b1f),
10
- title-text-line-height: 1.6rem,
24
+ elevated-container-color: var(
25
+ --acp-card-container-color,
26
+ var(--mat-sys-surface-container-low)
27
+ ),
28
+ outlined-container-color: var(--acp-card-container-color, var(--mat-sys-surface)),
29
+ filled-container-color: var(
30
+ --acp-card-container-color,
31
+ var(--mat-sys-surface-container-highest)
32
+ ),
33
+ elevated-container-shape: $shape,
34
+ outlined-container-shape: $shape,
35
+ filled-container-shape: $shape,
36
+ elevated-container-elevation: var(--acp-card-elevation, var(--mat-sys-level1)),
37
+ outlined-outline-color: var(--acp-card-outline-color, var(--mat-sys-outline-variant)),
38
+ title-text-size: var(--mat-sys-title-large-size),
39
+ title-text-line-height: var(--mat-sys-title-large-line-height),
11
40
  title-text-weight: 500,
41
+ subtitle-text-size: var(--mat-sys-body-medium-size),
12
42
  subtitle-text-weight: 400,
13
- elevated-container-shape: var(--mat-sys-corner-small),
14
- outlined-container-shape: var(--mat-sys-corner-small),
15
- // elevated-container-color: var(--mat-sys-surface-container),
16
- // elevated-container-shape: var(--mat-sys-corner-large),
17
- // outlined-container-shape: var(--mat-sys-corner-large),
18
- outlined-outline-color: var(--mat-sys-outline-variant),
19
- filled-container-color: var(--mat-sys-surface-container-highest),
20
- title-text-size: var(--mat-sys-title-large),
21
- subtitle-text-size: var(--mat-sys-body-medium),
22
- subtitle-text-color: var(--mat-sys-on-surface-variant),
23
- elevated-container-elevation: 0 4px 12px rgba(0, 0, 0, 0.08),
43
+ subtitle-text-color: var(--acp-card-subtitle-color, var(--mat-sys-on-surface-variant)),
24
44
  )
25
45
  );
26
- }
27
-
28
- // Custom styles for card sections
29
- .acp-card-media {
30
- width: 100%;
31
- object-fit: cover;
32
- border-radius: var(--mat-sys-corner-large) var(--mat-sys-corner-large) 0 0;
33
- }
34
-
35
- // Footer padding
36
- .mat-mdc-card-footer {
37
- padding: 16px;
38
- }
39
-
40
- // Actions gap
41
- .mat-mdc-card-actions {
42
- gap: 8px;
43
- }
44
-
45
- // Host wrapper styles
46
- .acp-card-wrapper {
47
- display: block;
48
- transition: box-shadow 0.2s ease-in-out;
49
-
50
- // Hover effect
51
- &.acp-card--hover:hover {
52
- box-shadow: var(--mat-sys-level3);
53
- }
54
-
55
- // Clickable state
56
- &.acp-card--clickable {
57
- cursor: pointer;
58
- user-select: none;
59
-
60
- &:hover {
61
- box-shadow: var(--mat-sys-level2);
62
- }
63
-
64
- &:active {
65
- box-shadow: var(--mat-sys-level1);
66
- }
67
- }
68
-
69
- // Disabled state
70
- &.acp-card--disabled {
71
- opacity: 0.6;
72
- pointer-events: none;
73
- }
74
46
 
75
- // Border radius variants
76
- &.acp-card--rounded-4 {
77
- .acp-card,
78
- .acp-card-media {
79
- border-radius: 4px;
80
- }
81
- }
82
-
83
- &.acp-card--rounded-8 {
84
- .acp-card,
85
- .acp-card-media {
86
- border-radius: 8px;
87
- }
88
- }
89
-
90
- &.acp-card--rounded-12 {
91
- .acp-card,
92
- .acp-card-media {
93
- border-radius: 12px;
94
- }
95
- }
96
-
97
- &.acp-card--rounded-16 {
98
- .acp-card,
99
- .acp-card-media {
100
- border-radius: 16px;
101
- }
102
- }
47
+ color: var(--acp-card-on-color, var(--mat-sys-on-surface));
48
+ transition: box-shadow 200ms ease-in-out;
103
49
 
104
- &.acp-card--rounded-20 {
105
- .acp-card,
106
- .acp-card-media {
107
- border-radius: 20px;
108
- }
50
+ .mat-mdc-card-content {
51
+ padding: var(--acp-card-padding);
109
52
  }
110
53
 
111
- &.acp-card--rounded-24 {
112
- .acp-card,
113
- .acp-card-media {
114
- border-radius: 24px;
115
- }
54
+ .mat-mdc-card-actions {
55
+ gap: 8px;
116
56
  }
117
57
 
118
- // Padding variants
119
- &.acp-card--padding-small {
120
- .mat-mdc-card-content {
121
- padding: 12px;
122
- }
58
+ .mat-mdc-card-footer {
59
+ padding: 16px;
123
60
  }
61
+ }
124
62
 
125
- &.acp-card--padding-medium {
126
- .mat-mdc-card-content {
127
- padding: 16px;
128
- }
129
- }
63
+ .acp-card__progress {
64
+ position: absolute;
65
+ inset: 0 0 auto;
66
+ z-index: 1;
67
+ border-top-left-radius: inherit;
68
+ border-top-right-radius: inherit;
69
+ overflow: hidden;
70
+ }
130
71
 
131
- &.acp-card--padding-large {
132
- .mat-mdc-card-content {
133
- padding: 24px;
134
- }
135
- }
72
+ .acp-card__media {
73
+ overflow: hidden;
136
74
 
137
- // Full height
138
- &.acp-card--full-height {
139
- height: 100%;
75
+ &:first-child {
76
+ border-top-left-radius: inherit;
77
+ border-top-right-radius: inherit;
140
78
  }
141
79
 
142
- // Full width
143
- &.acp-card--full-width {
80
+ &--ratio > :is(img, video, picture, iframe) {
81
+ display: block;
144
82
  width: 100%;
83
+ height: 100%;
84
+ object-fit: cover;
145
85
  }
146
86
  }
147
87
 
148
- // Material Design background color utility classes
149
- // Primary
150
- .acp-card--primary {
151
- color: var(--mat-sys-on-primary);
152
- background-color: var(--mat-sys-primary);
153
- }
154
-
155
- .acp-card--primary-container {
156
- color: var(--mat-sys-on-primary-container);
157
- background-color: var(--mat-sys-primary-container);
88
+ // Padding
89
+ :host(.acp-card--padding-none) {
90
+ --acp-card-padding: 0;
158
91
  }
159
92
 
160
- // Secondary
161
- .acp-card--secondary {
162
- color: var(--mat-sys-on-secondary);
163
- background-color: var(--mat-sys-secondary);
93
+ :host(.acp-card--padding-small) {
94
+ --acp-card-padding: 12px;
164
95
  }
165
96
 
166
- .acp-card--secondary-container {
167
- color: var(--mat-sys-on-secondary-container);
168
- background-color: var(--mat-sys-secondary-container);
97
+ :host(.acp-card--padding-large) {
98
+ --acp-card-padding: 24px;
169
99
  }
170
100
 
171
- // Error
172
- .acp-card--error {
173
- color: var(--mat-sys-on-error);
174
- background-color: var(--mat-sys-error);
101
+ // Interaction states
102
+ :host(.acp-card--hover) .acp-card:hover {
103
+ box-shadow: var(--mat-sys-level3);
175
104
  }
176
105
 
177
- .acp-card--error-container {
178
- color: var(--mat-sys-on-error-container);
179
- background-color: var(--mat-sys-error-container);
180
- }
106
+ :host(.acp-card--clickable) {
107
+ cursor: pointer;
108
+ user-select: none;
181
109
 
182
- // Surfaces
183
- .acp-card--surface {
184
- color: var(--mat-sys-on-surface);
185
- background-color: var(--mat-sys-surface);
186
- }
110
+ .acp-card:hover {
111
+ box-shadow: var(--mat-sys-level2);
112
+ }
187
113
 
188
- .acp-card--surface-variant {
189
- color: var(--mat-sys-on-surface-variant);
190
- background-color: var(--mat-sys-surface-variant);
114
+ .acp-card:active {
115
+ box-shadow: var(--mat-sys-level1);
116
+ }
191
117
  }
192
118
 
193
- .acp-card--surface-container-highest {
194
- color: var(--mat-sys-on-surface);
195
- background-color: var(--mat-sys-surface-container-highest);
119
+ :host(.acp-card--disabled) {
120
+ opacity: 0.6;
121
+ pointer-events: none;
196
122
  }
197
123
 
198
- .acp-card--surface-container-high {
199
- color: var(--mat-sys-on-surface);
200
- background-color: var(--mat-sys-surface-container-high);
124
+ :host(.acp-card--loading) {
125
+ cursor: progress;
201
126
  }
202
127
 
203
- .acp-card--surface-container {
204
- color: var(--mat-sys-on-surface);
205
- background-color: var(--mat-sys-surface-container);
206
- }
128
+ // Layout
129
+ :host(.acp-card--full-height) {
130
+ height: 100%;
207
131
 
208
- .acp-card--surface-container-low {
209
- color: var(--mat-sys-on-surface);
210
- background-color: var(--mat-sys-surface-container-low);
132
+ .acp-card {
133
+ height: 100%;
134
+ }
211
135
  }
212
136
 
213
- .acp-card--surface-container-lowest {
214
- background-color: var(--mat-sys-surface-container-lowest);
137
+ :host(.acp-card--full-width) {
138
+ width: 100%;
215
139
  }
216
140
 
217
- .acp-card--inverse-surface {
218
- color: var(--mat-sys-inverse-on-surface);
219
- background-color: var(--mat-sys-inverse-surface);
141
+ // Color variants: container role, content role, subtitle role
142
+ $colors: (
143
+ primary: (
144
+ primary,
145
+ on-primary,
146
+ on-primary,
147
+ ),
148
+ primary-container: (
149
+ primary-container,
150
+ on-primary-container,
151
+ on-primary-container,
152
+ ),
153
+ secondary: (
154
+ secondary,
155
+ on-secondary,
156
+ on-secondary,
157
+ ),
158
+ secondary-container: (
159
+ secondary-container,
160
+ on-secondary-container,
161
+ on-secondary-container,
162
+ ),
163
+ tertiary: (
164
+ tertiary,
165
+ on-tertiary,
166
+ on-tertiary,
167
+ ),
168
+ tertiary-container: (
169
+ tertiary-container,
170
+ on-tertiary-container,
171
+ on-tertiary-container,
172
+ ),
173
+ error: (
174
+ error,
175
+ on-error,
176
+ on-error,
177
+ ),
178
+ error-container: (
179
+ error-container,
180
+ on-error-container,
181
+ on-error-container,
182
+ ),
183
+ surface: (
184
+ surface,
185
+ on-surface,
186
+ on-surface-variant,
187
+ ),
188
+ surface-variant: (
189
+ surface-variant,
190
+ on-surface-variant,
191
+ on-surface-variant,
192
+ ),
193
+ surface-container-highest: (
194
+ surface-container-highest,
195
+ on-surface,
196
+ on-surface-variant,
197
+ ),
198
+ surface-container-high: (
199
+ surface-container-high,
200
+ on-surface,
201
+ on-surface-variant,
202
+ ),
203
+ surface-container: (
204
+ surface-container,
205
+ on-surface,
206
+ on-surface-variant,
207
+ ),
208
+ surface-container-low: (
209
+ surface-container-low,
210
+ on-surface,
211
+ on-surface-variant,
212
+ ),
213
+ surface-container-lowest: (
214
+ surface-container-lowest,
215
+ on-surface,
216
+ on-surface-variant,
217
+ ),
218
+ inverse-surface: (
219
+ inverse-surface,
220
+ inverse-on-surface,
221
+ inverse-on-surface,
222
+ ),
223
+ );
224
+
225
+ @each $name, $roles in $colors {
226
+ :host(.acp-card--#{$name}) {
227
+ --acp-card-container-color: var(--mat-sys-#{list.nth($roles, 1)});
228
+ --acp-card-on-color: var(--mat-sys-#{list.nth($roles, 2)});
229
+ --acp-card-subtitle-color: var(--mat-sys-#{list.nth($roles, 3)});
230
+ --acp-card-outline-color: transparent;
231
+ }
220
232
  }
221
233
 
222
- // Disabled
223
- .acp-card--disabled-bg {
224
- background-color: color-mix(in srgb, var(--mat-sys-on-surface) 12%, transparent);
234
+ :host(.acp-card--disabled-bg) {
235
+ --acp-card-container-color: color-mix(in srgb, var(--mat-sys-on-surface) 12%, transparent);
236
+ --acp-card-on-color: color-mix(in srgb, var(--mat-sys-on-surface) 38%, transparent);
237
+ --acp-card-subtitle-color: var(--acp-card-on-color);
225
238
  }
@@ -3,90 +3,75 @@
3
3
  @use '../../../core/tokens/m3-utils';
4
4
  @use '../../../core/tokens/m3';
5
5
 
6
+ // Token model per color:
7
+ // kpi-card-<color>-bg solid container (default, elevated, filled variants)
8
+ // kpi-card-<color>-color content on the solid container
9
+ // kpi-card-<color>-accent emphasis color on a surface (outlined, tonal variants, progress)
10
+ // Delta badge tokens are independent from the card color, so a trend stays readable on any card.
6
11
  @function get-tokens($theme: m3.$sys-theme) {
7
12
  $system: m3-utils.get-system($theme);
8
13
 
9
- // Semantic color palettes for professional appearance
10
- // Using more subtle tones for enterprise dashboard aesthetics
11
- $semantic-palettes: (
12
- success-light: mat.$green-palette,
13
- warning-light: mat.$orange-palette,
14
- error-light: mat.$red-palette,
15
- info-light: mat.$azure-palette,
14
+ $semantic: (
15
+ success: mat.$green-palette,
16
+ warning: mat.$orange-palette,
17
+ info: mat.$azure-palette,
16
18
  );
17
19
 
18
20
  $color-tokens: ();
19
- @each $name, $palette in $semantic-palettes {
21
+
22
+ @each $name, $palette in $semantic {
23
+ $accent: light-dark(map.get($palette, 40), map.get($palette, 80));
20
24
  $color-tokens: map.merge(
21
25
  $color-tokens,
22
26
  (
23
- // Use on-surface for better contrast and professional appearance
24
- kpi-card-#{$name}-color: map.get($system, on-surface),
25
- // Use subtle background with semantic color accent (95 for light, 25 for dark)
26
- kpi-card-#{$name}-bg: light-dark(map.get($palette, 95), map.get($palette, 25))
27
+ kpi-card-#{$name}-bg: light-dark(map.get($palette, 50), map.get($palette, 70)),
28
+ kpi-card-#{$name}-color: light-dark(#ffffff, map.get($palette, 20)),
29
+ kpi-card-#{$name}-accent: $accent,
30
+ kpi-card-#{$name}-light-bg: light-dark(map.get($palette, 95), map.get($palette, 25)),
31
+ kpi-card-#{$name}-light-color: map.get($system, on-surface)
27
32
  )
28
33
  );
29
34
  }
30
35
 
31
- // Add success (bright) color using green palette
32
- $success-palette: mat.$green-palette;
33
- $color-tokens: map.merge(
34
- $color-tokens,
35
- (
36
- // Use white text for bright success color for better contrast
37
- kpi-card-success-color: light-dark(#ffffff, map.get($success-palette, 20)),
38
- kpi-card-success-bg: light-dark(map.get($success-palette, 50), map.get($success-palette, 70))
39
- )
40
- );
41
-
42
- // Add warning (bright) color - use Material Design warning/error color
43
- // Material Design uses error color for warnings in some contexts, but we'll use orange palette
44
- // to match Material button warning color
45
- $warning-palette: mat.$orange-palette;
46
- $color-tokens: map.merge(
47
- $color-tokens,
48
- (
49
- // Use white text for bright warning color for better contrast
50
- kpi-card-warning-color: light-dark(#ffffff, map.get($warning-palette, 20)),
51
- // Use orange 60 for light mode (similar to Material button warning), 80 for dark mode
52
- kpi-card-warning-bg: light-dark(map.get($warning-palette, 60), map.get($warning-palette, 80))
53
- )
54
- );
55
-
56
- // Add info (bright) color using azure palette
57
- $info-palette: mat.$azure-palette;
58
- $color-tokens: map.merge(
59
- $color-tokens,
60
- (
61
- // Use white text for bright info color for better contrast
62
- kpi-card-info-color: light-dark(#ffffff, map.get($info-palette, 20)),
63
- kpi-card-info-bg: light-dark(map.get($info-palette, 50), map.get($info-palette, 70))
64
- )
65
- );
36
+ $red: mat.$red-palette;
37
+ $green: mat.$green-palette;
66
38
 
67
39
  $tokens: (
68
40
  base: (
69
41
  kpi-card-container-shape: map.get($system, corner-medium),
70
- kpi-card-container-height: 200px,
71
- kpi-card-container-elevation: 1,
72
42
  ),
73
43
  color: map.merge(
74
44
  (
75
- // Primary: Use primary theme color with on-primary text
76
- kpi-card-primary-color: map.get($system, on-primary),
77
45
  kpi-card-primary-bg: map.get($system, primary),
78
- // Secondary: Use secondary theme color with on-secondary text
79
- kpi-card-secondary-color: map.get($system, on-secondary),
46
+ kpi-card-primary-color: map.get($system, on-primary),
47
+ kpi-card-primary-accent: map.get($system, primary),
80
48
  kpi-card-secondary-bg: map.get($system, secondary),
81
- // Error: Use error theme color with on-error text (Material Design 3 standard)
82
- kpi-card-error-color: map.get($system, on-error),
49
+ kpi-card-secondary-color: map.get($system, on-secondary),
50
+ kpi-card-secondary-accent: map.get($system, secondary),
83
51
  kpi-card-error-bg: map.get($system, error),
84
- // Neutral: Minimal styling for subtle cards
85
- kpi-card-neutral-color: map.get($system, on-surface-variant),
52
+ kpi-card-error-color: map.get($system, on-error),
53
+ kpi-card-error-accent: map.get($system, error),
54
+ kpi-card-error-light-bg: light-dark(map.get($red, 95), map.get($red, 25)),
55
+ kpi-card-error-light-color: map.get($system, on-surface),
86
56
  kpi-card-neutral-bg: map.get($system, surface-variant),
87
- // Custom: Allow full customization
57
+ kpi-card-neutral-color: map.get($system, on-surface-variant),
58
+ kpi-card-neutral-accent: map.get($system, on-surface-variant),
59
+ kpi-card-surface-bg: map.get($system, surface-container-lowest),
60
+ kpi-card-surface-color: map.get($system, on-surface),
61
+ kpi-card-surface-accent: map.get($system, primary),
62
+ kpi-card-custom-bg: map.get($system, surface-container),
88
63
  kpi-card-custom-color: map.get($system, on-surface),
89
- kpi-card-custom-bg: map.get($system, surface-container)
64
+ kpi-card-custom-accent: map.get($system, primary),
65
+ kpi-card-delta-positive-bg: color-mix(
66
+ in srgb,
67
+ light-dark(map.get($green, 40), map.get($green, 80)) 16%,
68
+ var(#{map.get($system, surface-container-lowest)})
69
+ ),
70
+ kpi-card-delta-positive-color: light-dark(map.get($green, 30), map.get($green, 90)),
71
+ kpi-card-delta-negative-bg: map.get($system, error-container),
72
+ kpi-card-delta-negative-color: map.get($system, on-error-container),
73
+ kpi-card-delta-neutral-bg: map.get($system, surface-container-highest),
74
+ kpi-card-delta-neutral-color: map.get($system, on-surface-variant),
90
75
  ),
91
76
  $color-tokens
92
77
  ),