@lukfel/ng-scaffold 22.1.9 → 22.1.13

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": "@lukfel/ng-scaffold",
3
- "version": "22.1.9",
3
+ "version": "22.1.13",
4
4
  "description": "This Angular library provides a basic UI scaffold and services for modern web and mobile apps",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -1,247 +1,378 @@
1
- @use '@angular/material' as mat;
2
- @include mat.elevation-classes();
3
- @include mat.app-background();
4
-
5
- // ============================================================================
6
- // Material 2 (M2) Theming
7
- // ============================================================================
8
-
9
- // Default M2 theme
10
- $lf-default-theme: (
11
- primary: mat.m2-define-palette(mat.$m2-blue-palette),
12
- accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400),
13
- warn: mat.m2-define-palette(mat.$m2-red-palette),
14
- dark: false,
15
- font-family: 'Roboto'
16
- );
17
-
18
- // Set M2 theme
19
- // Material requires to split up the mat.all-component-themes and mat.all-component-colors
20
- // since mat.all-component-themes should also be imported once, but mat.all-component-colors
21
- // can be imported multiple times
22
- @mixin scaffold-theme($theme: $lf-default-theme) {
23
- $theme: map-merge($lf-default-theme, $theme);
24
-
25
- @if(map-get($theme, 'dark') == false) {
26
- $mat-theme: mat.m2-define-light-theme((
27
- color: (
28
- primary: map-get($theme, 'primary'),
29
- accent: map-get($theme, 'accent'),
30
- warn: map-get($theme, 'warn'),
31
- ),
32
- typography: mat.m2-define-typography-config(
33
- $font-family: map-get($theme, 'font-family')
34
- ),
35
- density: 0,
36
- ));
37
- @include mat.all-component-themes($mat-theme);
38
- } @else {
39
- $mat-theme: mat.m2-define-dark-theme((
40
- color: (
41
- primary: map-get($theme, 'primary'),
42
- accent: map-get($theme, 'accent'),
43
- warn: map-get($theme, 'warn'),
44
- ),
45
- typography: mat.m2-define-typography-config(
46
- $font-family: map-get($theme, 'font-family')
47
- ),
48
- density: 0,
49
- ));
50
- @include mat.all-component-themes($mat-theme);
51
- }
52
- @include color-variables($theme, 'body');
53
- }
54
-
55
- // Set M2 colors
56
- @mixin scaffold-colors($theme: $lf-default-theme, $class) {
57
- $theme: map-merge($lf-default-theme, $theme);
58
-
59
- .#{$class} {
60
- @if(map-get($theme, 'dark') == false) {
61
- $mat-theme: mat.m2-define-light-theme((
62
- color: (
63
- primary: map-get($theme, 'primary'),
64
- accent: map-get($theme, 'accent'),
65
- warn: map-get($theme, 'warn'),
66
- )
67
- ));
68
- @include mat.all-component-colors($mat-theme);
69
- } @else {
70
- $mat-theme: mat.m2-define-dark-theme((
71
- color: (
72
- primary: map-get($theme, 'primary'),
73
- accent: map-get($theme, 'accent'),
74
- warn: map-get($theme, 'warn'),
75
- )
76
- ));
77
- @include mat.all-component-colors($mat-theme);
78
- }
79
- }
80
-
81
- @include color-variables($theme, #{'body.'+$class});
82
- }
83
-
84
- // Set M2 variables
85
- @mixin color-variables($theme, $scope) {
86
- #{$scope}{
87
- --color-primary: #{mat.m2-get-color-from-palette(map-get($theme, 'primary'))};
88
- --color-accent: #{mat.m2-get-color-from-palette(map-get($theme, 'accent'))};
89
- --color-warn: #{mat.m2-get-color-from-palette(map-get($theme, 'warn'))};
90
-
91
- @for $i from 0 through 9 {
92
- $hue: $i * 100;
93
- @if ($hue == 0) {
94
- $hue: 50
95
- }
96
-
97
- --color-primary-#{$hue}: #{mat.m2-get-color-from-palette(map-get($theme, 'primary'), $hue)};
98
- --color-accent-#{$hue}: #{mat.m2-get-color-from-palette(map-get($theme, 'accent'), $hue)};
99
- --color-warn-#{$hue}: #{mat.m2-get-color-from-palette(map-get($theme, 'warn'), $hue)};
100
- }
101
- }
102
-
103
- // Utility classes
104
- @each $palette in ('primary', 'accent', 'warn') {
105
- .color-#{$palette} { color: var(--color-#{$palette}) !important; }
106
- .color-bg-#{$palette} { background-color: var(--color-#{$palette}) !important; }
107
-
108
- @for $i from 0 through 9 {
109
- $hue: $i * 100;
110
- @if ($hue == 0) { $hue: 50; }
111
-
112
- .color-#{$palette}-#{$hue} { color: var(--color-#{$palette}-#{$hue}) !important; }
113
- .color-bg-#{$palette}-#{$hue} { background-color: var(--color-#{$palette}-#{$hue}) !important; }
114
- }
115
- }
116
- }
117
-
118
- // ============================================================================
119
- // Material 3 (M3) Theming
120
- // ============================================================================
121
-
122
- // Default M3 theme
123
- // M3 uses: primary, tertiary (instead of accent), and error (instead of warn)
124
- // theme-type: 'light', 'dark', or 'color-scheme' (auto light/dark based on user preference)
125
- $lf-default-theme-m3: (
126
- primary: mat.$blue-palette,
127
- tertiary: mat.$rose-palette,
128
- theme-type: color-scheme,
129
- font-family: 'Roboto',
130
- density: 0,
131
- );
132
-
133
- // Set M3 theme
134
- // Uses mat.theme() which outputs CSS variables (design tokens) instead of static styles.
135
- // Includes color-variants-backwards-compatibility so that component [color] inputs
136
- // (color="primary", color="accent", color="warn") continue to work.
137
- @mixin scaffold-theme-m3($theme: $lf-default-theme-m3) {
138
- $theme: map-merge($lf-default-theme-m3, $theme);
139
-
140
- $color-config: (
141
- primary: map-get($theme, 'primary'),
142
- tertiary: map-get($theme, 'tertiary'),
143
- theme-type: map-get($theme, 'theme-type'),
144
- );
145
-
146
- html {
147
- @include mat.theme((
148
- color: $color-config,
149
- typography: map-get($theme, 'font-family'),
150
- density: map-get($theme, 'density'),
151
- ));
152
- @include mat.color-variants-backwards-compatibility($theme: mat.define-theme((
153
- color: $color-config,
154
- )));
155
- @include mat.system-classes();
156
- }
157
-
158
- @include toolbar-color-compat();
159
- @include color-variables-m3('body');
160
- }
161
-
162
- // Set M3 colors (scoped to a class, for multi-theme support)
163
- // Only overrides color tokens; typography and density are inherited from the base theme.
164
- @mixin scaffold-colors-m3($theme: $lf-default-theme-m3, $class) {
165
- $theme: map-merge($lf-default-theme-m3, $theme);
166
-
167
- $color-config: (
168
- primary: map-get($theme, 'primary'),
169
- tertiary: map-get($theme, 'tertiary'),
170
- theme-type: map-get($theme, 'theme-type'),
171
- );
172
-
173
- .#{$class} {
174
- @include mat.theme((
175
- color: $color-config,
176
- ));
177
- @include mat.color-variants-backwards-compatibility($theme: mat.define-theme((
178
- color: $color-config,
179
- )));
180
- }
181
-
182
- @include toolbar-color-compat(#{'.' + $class});
183
- @include color-variables-m3(#{'body.'+$class});
184
- }
185
-
186
- // Toolbar color backwards compatibility
187
- // M3's color-variants-backwards-compatibility does not cover mat-toolbar.
188
- // This mixin restores [color] input support for toolbar and ensures icons/buttons
189
- // inside colored toolbars use the correct contrast color.
190
- @mixin toolbar-color-compat($scope: null) {
191
- $prefix: '';
192
- @if ($scope) {
193
- $prefix: '#{$scope} ';
194
- }
195
-
196
- #{$prefix}.mat-toolbar.mat-primary {
197
- background-color: var(--mat-sys-primary);
198
- color: var(--mat-sys-on-primary);
199
-
200
- .mat-icon,
201
- .mat-mdc-icon-button,
202
- .mat-mdc-button {
203
- color: var(--mat-sys-on-primary);
204
- }
205
- }
206
-
207
- #{$prefix}.mat-toolbar.mat-accent {
208
- background-color: var(--mat-sys-tertiary);
209
- color: var(--mat-sys-on-tertiary);
210
-
211
- .mat-icon,
212
- .mat-mdc-icon-button,
213
- .mat-mdc-button {
214
- color: var(--mat-sys-on-tertiary);
215
- }
216
- }
217
-
218
- #{$prefix}.mat-toolbar.mat-warn {
219
- background-color: var(--mat-sys-error);
220
- color: var(--mat-sys-on-error);
221
-
222
- .mat-icon,
223
- .mat-mdc-icon-button,
224
- .mat-mdc-button {
225
- color: var(--mat-sys-on-error);
226
- }
227
- }
228
- }
229
-
230
- // Set M3 variables
231
- // Bridges the M3 system tokens to the same --color-* CSS variables that existing
232
- // components use, so all library components work without template changes.
233
- // Note: M3 does not have numbered hue variants (50-900). Only the base semantic
234
- // colors are bridged. Hue-specific variables are not available in M3.
235
- @mixin color-variables-m3($scope) {
236
- #{$scope} {
237
- --color-primary: var(--mat-sys-primary);
238
- --color-accent: var(--mat-sys-tertiary);
239
- --color-warn: var(--mat-sys-error);
240
- }
241
-
242
- // Utility classes (same API as M2, backed by M3 tokens)
243
- @each $palette in ('primary', 'accent', 'warn') {
244
- .color-#{$palette} { color: var(--color-#{$palette}) !important; }
245
- .color-bg-#{$palette} { background-color: var(--color-#{$palette}) !important; }
246
- }
247
- }
1
+ @use '@angular/material' as mat;
2
+ @include mat.elevation-classes();
3
+ @include mat.app-background();
4
+
5
+ // ============================================================================
6
+ // Material 2 (M2) Theming
7
+ // ============================================================================
8
+
9
+ // Default M2 theme
10
+ $lf-default-theme: (
11
+ primary: mat.m2-define-palette(mat.$m2-blue-palette),
12
+ accent: mat.m2-define-palette(mat.$m2-pink-palette, A200, A100, A400),
13
+ warn: mat.m2-define-palette(mat.$m2-red-palette),
14
+ dark: false,
15
+ font-family: 'Roboto'
16
+ );
17
+
18
+ // Set M2 theme
19
+ // Material requires to split up the mat.all-component-themes and mat.all-component-colors
20
+ // since mat.all-component-themes should also be imported once, but mat.all-component-colors
21
+ // can be imported multiple times
22
+ @mixin scaffold-theme($theme: $lf-default-theme) {
23
+ $theme: map-merge($lf-default-theme, $theme);
24
+
25
+ @if(map-get($theme, 'dark') == false) {
26
+ $mat-theme: mat.m2-define-light-theme((
27
+ color: (
28
+ primary: map-get($theme, 'primary'),
29
+ accent: map-get($theme, 'accent'),
30
+ warn: map-get($theme, 'warn'),
31
+ ),
32
+ typography: mat.m2-define-typography-config(
33
+ $font-family: map-get($theme, 'font-family')
34
+ ),
35
+ density: 0,
36
+ ));
37
+ @include mat.all-component-themes($mat-theme);
38
+ } @else {
39
+ $mat-theme: mat.m2-define-dark-theme((
40
+ color: (
41
+ primary: map-get($theme, 'primary'),
42
+ accent: map-get($theme, 'accent'),
43
+ warn: map-get($theme, 'warn'),
44
+ ),
45
+ typography: mat.m2-define-typography-config(
46
+ $font-family: map-get($theme, 'font-family')
47
+ ),
48
+ density: 0,
49
+ ));
50
+ @include mat.all-component-themes($mat-theme);
51
+ }
52
+ @include color-variables($theme, 'body');
53
+ }
54
+
55
+ // Set M2 colors
56
+ @mixin scaffold-colors($theme: $lf-default-theme, $class) {
57
+ $theme: map-merge($lf-default-theme, $theme);
58
+
59
+ .#{$class} {
60
+ @if(map-get($theme, 'dark') == false) {
61
+ $mat-theme: mat.m2-define-light-theme((
62
+ color: (
63
+ primary: map-get($theme, 'primary'),
64
+ accent: map-get($theme, 'accent'),
65
+ warn: map-get($theme, 'warn'),
66
+ )
67
+ ));
68
+ @include mat.all-component-colors($mat-theme);
69
+ } @else {
70
+ $mat-theme: mat.m2-define-dark-theme((
71
+ color: (
72
+ primary: map-get($theme, 'primary'),
73
+ accent: map-get($theme, 'accent'),
74
+ warn: map-get($theme, 'warn'),
75
+ )
76
+ ));
77
+ @include mat.all-component-colors($mat-theme);
78
+ }
79
+ }
80
+
81
+ @include color-variables($theme, #{'body.'+$class});
82
+ }
83
+
84
+ // Set M2 variables
85
+ @mixin color-variables($theme, $scope) {
86
+ #{$scope}{
87
+ --color-primary: #{mat.m2-get-color-from-palette(map-get($theme, 'primary'))};
88
+ --color-accent: #{mat.m2-get-color-from-palette(map-get($theme, 'accent'))};
89
+ --color-warn: #{mat.m2-get-color-from-palette(map-get($theme, 'warn'))};
90
+
91
+ @for $i from 0 through 9 {
92
+ $hue: $i * 100;
93
+ @if ($hue == 0) {
94
+ $hue: 50
95
+ }
96
+
97
+ --color-primary-#{$hue}: #{mat.m2-get-color-from-palette(map-get($theme, 'primary'), $hue)};
98
+ --color-accent-#{$hue}: #{mat.m2-get-color-from-palette(map-get($theme, 'accent'), $hue)};
99
+ --color-warn-#{$hue}: #{mat.m2-get-color-from-palette(map-get($theme, 'warn'), $hue)};
100
+ }
101
+ }
102
+
103
+ // Utility classes
104
+ @each $palette in ('primary', 'accent', 'warn') {
105
+ .color-#{$palette} { color: var(--color-#{$palette}) !important; }
106
+ .color-bg-#{$palette} { background-color: var(--color-#{$palette}) !important; }
107
+
108
+ @for $i from 0 through 9 {
109
+ $hue: $i * 100;
110
+ @if ($hue == 0) { $hue: 50; }
111
+
112
+ .color-#{$palette}-#{$hue} { color: var(--color-#{$palette}-#{$hue}) !important; }
113
+ .color-bg-#{$palette}-#{$hue} { background-color: var(--color-#{$palette}-#{$hue}) !important; }
114
+ }
115
+ }
116
+ }
117
+
118
+ // ============================================================================
119
+ // Material 3 (M3) Theming
120
+ // ============================================================================
121
+
122
+ // Default M3 theme
123
+ // M3 uses: primary, tertiary (instead of accent), and error (instead of warn)
124
+ // theme-type: 'light', 'dark', or 'color-scheme' (auto light/dark based on user preference)
125
+ // m2-compat takes the M2 palettes an app already has (primary/accent/warn) and opts
126
+ // it into M2 colour behaviour; null leaves everything at stock M3.
127
+ $lf-default-theme-m3: (
128
+ primary: mat.$blue-palette,
129
+ tertiary: mat.$rose-palette,
130
+ theme-type: color-scheme,
131
+ font-family: 'Roboto',
132
+ density: 0,
133
+ m2-compat: null,
134
+ );
135
+
136
+ // Main hue of an M2 palette, and the contrast colour M2 paired with it
137
+ @function m2-main($m2, $key) {
138
+ $palette: map-get($m2, $key);
139
+ @return if($palette, map-get($palette, 500), null);
140
+ }
141
+
142
+ @function m2-contrast($m2, $key) {
143
+ $palette: map-get($m2, $key);
144
+ @return if($palette, map-get(map-get($palette, 'contrast'), 500), null);
145
+ }
146
+
147
+ // M3 reads tone 40 for the light base role and tone 80 for the dark one, and a
148
+ // generated ramp puts neither at the M2 500 it was seeded from. Splicing the 500
149
+ // into both slots is what carries the branding through to the baked [color]
150
+ // variants, which hold literal values and so ignore any later token override.
151
+ // Both slots, not just 40: a theme-invariant main hue is what lets a brand fill
152
+ // keep one fixed foreground, the way it did under M2. Tone 20 carries that
153
+ // foreground - it is the dark theme's on- slot, and nothing else reads it, so
154
+ // without this a dark theme pairs the mid-tone brand with near-black text.
155
+ @function m2-compat-palettes($theme) {
156
+ $m2: map-get($theme, 'm2-compat');
157
+ @if ($m2 == null) {
158
+ @return $theme;
159
+ }
160
+
161
+ $primary: map-get($theme, 'primary');
162
+ $tertiary: map-get($theme, 'tertiary');
163
+
164
+ @if (m2-main($m2, 'primary')) {
165
+ $primary: map-merge($primary, (40: m2-main($m2, 'primary'), 80: m2-main($m2, 'primary'), 20: m2-contrast($m2, 'primary')));
166
+ }
167
+ @if (m2-main($m2, 'accent')) {
168
+ $tertiary: map-merge($tertiary, (40: m2-main($m2, 'accent'), 80: m2-main($m2, 'accent'), 20: m2-contrast($m2, 'accent')));
169
+ }
170
+ @if (m2-main($m2, 'warn') and map-has-key($primary, 'error')) {
171
+ $error: map-merge(map-get($primary, 'error'), (40: m2-main($m2, 'warn'), 80: m2-main($m2, 'warn'), 20: m2-contrast($m2, 'warn')));
172
+ $primary: map-merge($primary, (error: $error));
173
+ }
174
+
175
+ @return map-merge($theme, (primary: $primary, tertiary: $tertiary));
176
+ }
177
+
178
+ // Set M3 theme
179
+ // Uses mat.theme() which outputs CSS variables (design tokens) instead of static styles.
180
+ // Includes color-variants-backwards-compatibility so that component [color] inputs
181
+ // (color="primary", color="accent", color="warn") continue to work.
182
+ @mixin scaffold-theme-m3($theme: $lf-default-theme-m3) {
183
+ $theme: map-merge($lf-default-theme-m3, $theme);
184
+ $theme: m2-compat-palettes($theme);
185
+ $m2: map-get($theme, 'm2-compat');
186
+
187
+ $color-config: (
188
+ primary: map-get($theme, 'primary'),
189
+ tertiary: map-get($theme, 'tertiary'),
190
+ theme-type: map-get($theme, 'theme-type'),
191
+ );
192
+
193
+ html {
194
+ @include mat.theme((
195
+ color: $color-config,
196
+ typography: map-get($theme, 'font-family'),
197
+ density: map-get($theme, 'density'),
198
+ ));
199
+ @include mat.color-variants-backwards-compatibility($theme: mat.define-theme((
200
+ color: $color-config,
201
+ )));
202
+ @include mat.system-classes();
203
+ }
204
+
205
+ @include shape-variables-m3();
206
+ @include toolbar-color-compat();
207
+ @include container-color-compat($m2);
208
+ @include color-variables-m3('body', $m2);
209
+ }
210
+
211
+ // Set M3 colors (scoped to a class, for multi-theme support)
212
+ // Only overrides color tokens; typography and density are inherited from the base theme.
213
+ @mixin scaffold-colors-m3($theme: $lf-default-theme-m3, $class) {
214
+ $theme: map-merge($lf-default-theme-m3, $theme);
215
+ $theme: m2-compat-palettes($theme);
216
+ $m2: map-get($theme, 'm2-compat');
217
+
218
+ $color-config: (
219
+ primary: map-get($theme, 'primary'),
220
+ tertiary: map-get($theme, 'tertiary'),
221
+ theme-type: map-get($theme, 'theme-type'),
222
+ );
223
+
224
+ .#{$class} {
225
+ @include mat.theme((
226
+ color: $color-config,
227
+ ));
228
+ @include mat.color-variants-backwards-compatibility($theme: mat.define-theme((
229
+ color: $color-config,
230
+ )));
231
+ }
232
+
233
+ @include toolbar-color-compat(#{'.' + $class});
234
+ @include container-color-compat($m2, #{'.' + $class});
235
+ @include color-variables-m3(#{'body.'+$class}, $m2);
236
+ }
237
+
238
+ // Toolbar color backwards compatibility
239
+ // M3's color-variants-backwards-compatibility does not cover mat-toolbar.
240
+ // This mixin restores [color] input support for toolbar and ensures icons/buttons
241
+ // inside colored toolbars use the correct contrast color.
242
+ @mixin toolbar-color-compat($scope: null) {
243
+ $prefix: '';
244
+ @if ($scope) {
245
+ $prefix: '#{$scope} ';
246
+ }
247
+
248
+ #{$prefix}.mat-toolbar.mat-primary {
249
+ background-color: var(--mat-sys-primary);
250
+ color: var(--mat-sys-on-primary);
251
+
252
+ .mat-icon,
253
+ .mat-mdc-icon-button,
254
+ .mat-mdc-button {
255
+ color: var(--mat-sys-on-primary);
256
+ }
257
+ }
258
+
259
+ #{$prefix}.mat-toolbar.mat-accent {
260
+ background-color: var(--mat-sys-tertiary);
261
+ color: var(--mat-sys-on-tertiary);
262
+
263
+ .mat-icon,
264
+ .mat-mdc-icon-button,
265
+ .mat-mdc-button {
266
+ color: var(--mat-sys-on-tertiary);
267
+ }
268
+ }
269
+
270
+ #{$prefix}.mat-toolbar.mat-warn {
271
+ background-color: var(--mat-sys-error);
272
+ color: var(--mat-sys-on-error);
273
+
274
+ .mat-icon,
275
+ .mat-mdc-icon-button,
276
+ .mat-mdc-button {
277
+ color: var(--mat-sys-on-error);
278
+ }
279
+ }
280
+ }
281
+
282
+ // M3 shape scale
283
+ // M3 gives the drawer a 16px trailing edge, which reads as a floating panel
284
+ // rather than the flush sidebar the scaffold lays out; M2 kept it square.
285
+ // --border-radius needs no override here, it reads the scale itself.
286
+ @mixin shape-variables-m3() {
287
+ :root {
288
+ --mat-sidenav-container-shape: 0;
289
+ }
290
+ }
291
+
292
+ // Container colour backwards compatibility
293
+ // M3 renders FABs and selected chips on a *container* tone, where M2 used the main
294
+ // hue. Container and foreground are restored as a pair: the container alone would
295
+ // leave M3's dark on-container text sitting on a saturated fill.
296
+ @mixin container-color-compat($m2, $scope: null) {
297
+ @if ($m2) {
298
+ $prefix: 'html ';
299
+ @if ($scope) {
300
+ $prefix: '#{$scope} ';
301
+ }
302
+
303
+ @each $name in ('primary', 'accent', 'warn') {
304
+ $container: m2-main($m2, $name);
305
+ $foreground: m2-contrast($m2, $name);
306
+
307
+ // The M2 500 is used literally rather than via --color-*: the base role
308
+ // flips to a light tone in dark themes, which the M2 contrast colour,
309
+ // fixed against the 500, would then be unreadable on.
310
+ @if ($container and $foreground) {
311
+ #{$prefix}.mat-mdc-fab.mat-#{$name},
312
+ #{$prefix}.mat-mdc-mini-fab.mat-#{$name} {
313
+ --mat-fab-container-color: #{$container};
314
+ --mat-fab-foreground-color: #{$foreground};
315
+ --mat-fab-state-layer-color: #{$foreground};
316
+ --mat-fab-ripple-color: color-mix(in srgb, #{$foreground} 12%, transparent);
317
+ --mat-fab-small-container-color: #{$container};
318
+ --mat-fab-small-foreground-color: #{$foreground};
319
+ --mat-fab-small-state-layer-color: #{$foreground};
320
+ --mat-fab-small-ripple-color: color-mix(in srgb, #{$foreground} 12%, transparent);
321
+ }
322
+
323
+ #{$prefix}.mat-mdc-standard-chip.mat-#{$name} {
324
+ --mat-chip-elevated-selected-container-color: #{$container};
325
+ --mat-chip-selected-label-text-color: #{$foreground};
326
+ --mat-chip-selected-trailing-icon-color: #{$foreground};
327
+ }
328
+ }
329
+ }
330
+ }
331
+ }
332
+
333
+ // Set M3 variables
334
+ // Bridges the M3 system tokens to the same --color-* CSS variables that existing
335
+ // components use, so all library components work without template changes.
336
+ // Note: M3 does not have numbered hue variants (50-900). Only the base semantic
337
+ // colors are bridged. Hue-specific variables are not available in M3.
338
+ @mixin color-variables-m3($scope, $m2: null) {
339
+ #{$scope} {
340
+ --color-primary: var(--mat-sys-primary);
341
+ --color-accent: var(--mat-sys-tertiary);
342
+ --color-warn: var(--mat-sys-error);
343
+
344
+ // M3 has no numbered hues, so under m2-compat they come from the M2 ramps
345
+ @if ($m2) {
346
+ @each $name in ('primary', 'accent', 'warn') {
347
+ $palette: map-get($m2, $name);
348
+
349
+ @if ($palette) {
350
+ @for $i from 0 through 9 {
351
+ $hue: $i * 100;
352
+ @if ($hue == 0) {
353
+ $hue: 50;
354
+ }
355
+
356
+ --color-#{$name}-#{$hue}: #{map-get($palette, $hue)};
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+
363
+ // Utility classes (same API as M2, backed by M3 tokens)
364
+ @each $palette in ('primary', 'accent', 'warn') {
365
+ .color-#{$palette} { color: var(--color-#{$palette}) !important; }
366
+ .color-bg-#{$palette} { background-color: var(--color-#{$palette}) !important; }
367
+
368
+ @if ($m2 and map-get($m2, $palette)) {
369
+ @for $i from 0 through 9 {
370
+ $hue: $i * 100;
371
+ @if ($hue == 0) { $hue: 50; }
372
+
373
+ .color-#{$palette}-#{$hue} { color: var(--color-#{$palette}-#{$hue}) !important; }
374
+ .color-bg-#{$palette}-#{$hue} { background-color: var(--color-#{$palette}-#{$hue}) !important; }
375
+ }
376
+ }
377
+ }
378
+ }