ui-ux-consultant-cli 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 (30) hide show
  1. package/assets/ui-ux-consultant/SKILL.md +844 -0
  2. package/assets/ui-ux-consultant/references/accessibility.md +175 -0
  3. package/assets/ui-ux-consultant/references/alt-libraries.md +90 -0
  4. package/assets/ui-ux-consultant/references/animations.md +448 -0
  5. package/assets/ui-ux-consultant/references/catalog/colors.md +91 -0
  6. package/assets/ui-ux-consultant/references/catalog/fonts.md +363 -0
  7. package/assets/ui-ux-consultant/references/catalog/products.md +340 -0
  8. package/assets/ui-ux-consultant/references/catalog/styles.md +165 -0
  9. package/assets/ui-ux-consultant/references/components.md +1116 -0
  10. package/assets/ui-ux-consultant/references/patterns.md +600 -0
  11. package/assets/ui-ux-consultant/references/performance.md +198 -0
  12. package/assets/ui-ux-consultant/references/stacks/astro.md +382 -0
  13. package/assets/ui-ux-consultant/references/stacks/flutter.md +308 -0
  14. package/assets/ui-ux-consultant/references/stacks/html-tailwind.md +415 -0
  15. package/assets/ui-ux-consultant/references/stacks/jetpack-compose.md +333 -0
  16. package/assets/ui-ux-consultant/references/stacks/laravel.md +521 -0
  17. package/assets/ui-ux-consultant/references/stacks/nextjs.md +275 -0
  18. package/assets/ui-ux-consultant/references/stacks/nuxt-ui.md +384 -0
  19. package/assets/ui-ux-consultant/references/stacks/nuxtjs.md +264 -0
  20. package/assets/ui-ux-consultant/references/stacks/react-native.md +346 -0
  21. package/assets/ui-ux-consultant/references/stacks/react.md +268 -0
  22. package/assets/ui-ux-consultant/references/stacks/shadcn.md +485 -0
  23. package/assets/ui-ux-consultant/references/stacks/svelte.md +429 -0
  24. package/assets/ui-ux-consultant/references/stacks/swiftui.md +336 -0
  25. package/assets/ui-ux-consultant/references/stacks/threejs.md +366 -0
  26. package/assets/ui-ux-consultant/references/stacks/vue.md +272 -0
  27. package/assets/ui-ux-consultant/references/theming.md +701 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +130 -0
  30. package/package.json +51 -0
@@ -0,0 +1,701 @@
1
+ # Angular Material 3 Theming Guide
2
+
3
+ Comprehensive reference for theming Angular Material 3 applications. Covers the M3 theming architecture, complete setup, dark mode, typography, design token overrides, density, and custom brand colors.
4
+
5
+ ---
6
+
7
+ ## 1. M3 Theming Architecture
8
+
9
+ Angular Material 3 theming operates across three layers:
10
+
11
+ | Layer | Controls | API |
12
+ |---|---|---|
13
+ | **Color** | Primary, secondary, tertiary, neutral, error palettes | `color:` key in `define-theme()` |
14
+ | **Typography** | Font families, weights, and the 15-role type scale | `typography:` key in `define-theme()` |
15
+ | **Density** | Component spacing and size compactness | `density:` key in `define-theme()` |
16
+
17
+ **How it works:**
18
+ 1. `mat.define-theme()` computes a complete M3 theme object from your configuration.
19
+ 2. `mat.all-component-themes($theme)` (or individual `mat.*-theme()` mixins) emit CSS custom properties (`--mat-*`) scoped to the selector where you include them.
20
+ 3. Every Material component reads those CSS custom properties at runtime — no Sass variables leak into component styles.
21
+
22
+ This means you can:
23
+ - Override any token by setting `--mat-*` in CSS without touching Sass.
24
+ - Scope a theme to a CSS class (e.g., `.dark-theme`) and toggle it dynamically.
25
+ - Apply different densities per section of the UI.
26
+
27
+ ---
28
+
29
+ ## 2. Complete Theme Setup
30
+
31
+ ### Install Dependencies
32
+
33
+ ```bash
34
+ ng add @angular/material
35
+ # or manual:
36
+ npm install @angular/material @angular/cdk
37
+ ```
38
+
39
+ ### `styles.scss` — Full Setup
40
+
41
+ ```scss
42
+ @use '@angular/material' as mat;
43
+
44
+ // ─── Step 1: Include core styles once at root ───────────────────────────────
45
+ // Emits baseline resets and typography utilities. Must be called exactly once.
46
+ @include mat.core();
47
+
48
+ // ─── Step 2: Define your theme ──────────────────────────────────────────────
49
+ $my-theme: mat.define-theme((
50
+ color: (
51
+ theme-type: light, // 'light' | 'dark'
52
+ primary: mat.$azure-palette, // Main brand color (buttons, links, focus rings)
53
+ tertiary: mat.$orange-palette, // CTA / accent color (FAB, selected states)
54
+ // 'secondary' defaults to a neutral tonal palette — usually leave unset
55
+ ),
56
+ typography: (
57
+ brand-family: 'Inter, sans-serif', // Display, Headline, Title roles
58
+ plain-family: 'Inter, sans-serif', // Body, Label roles
59
+ bold-weight: 700,
60
+ medium-weight: 500,
61
+ regular-weight: 400,
62
+ ),
63
+ density: (
64
+ scale: 0, // 0 = default; -1 = compact; -2 = very compact; -3 = minimum
65
+ ),
66
+ ));
67
+
68
+ // ─── Step 3: Apply theme to all components ──────────────────────────────────
69
+ html {
70
+ @include mat.all-component-themes($my-theme);
71
+ }
72
+
73
+ // ─── Alternatively: apply only to components you use (smaller CSS output) ───
74
+ // html {
75
+ // @include mat.core-theme($my-theme);
76
+ // @include mat.button-theme($my-theme);
77
+ // @include mat.form-field-theme($my-theme);
78
+ // @include mat.input-theme($my-theme);
79
+ // @include mat.select-theme($my-theme);
80
+ // @include mat.dialog-theme($my-theme);
81
+ // @include mat.snack-bar-theme($my-theme);
82
+ // @include mat.table-theme($my-theme);
83
+ // @include mat.paginator-theme($my-theme);
84
+ // @include mat.card-theme($my-theme);
85
+ // @include mat.toolbar-theme($my-theme);
86
+ // @include mat.sidenav-theme($my-theme);
87
+ // @include mat.list-theme($my-theme);
88
+ // @include mat.tabs-theme($my-theme);
89
+ // @include mat.progress-bar-theme($my-theme);
90
+ // @include mat.progress-spinner-theme($my-theme);
91
+ // @include mat.checkbox-theme($my-theme);
92
+ // @include mat.radio-theme($my-theme);
93
+ // @include mat.slide-toggle-theme($my-theme);
94
+ // @include mat.chips-theme($my-theme);
95
+ // @include mat.badge-theme($my-theme);
96
+ // @include mat.icon-theme($my-theme);
97
+ // @include mat.tooltip-theme($my-theme);
98
+ // @include mat.menu-theme($my-theme);
99
+ // @include mat.datepicker-theme($my-theme);
100
+ // @include mat.autocomplete-theme($my-theme);
101
+ // @include mat.stepper-theme($my-theme);
102
+ // @include mat.expansion-theme($my-theme);
103
+ // @include mat.tree-theme($my-theme);
104
+ // @include mat.bottom-sheet-theme($my-theme);
105
+ // }
106
+ ```
107
+
108
+ ### `angular.json` — Register the stylesheet
109
+
110
+ ```json
111
+ {
112
+ "projects": {
113
+ "my-app": {
114
+ "architect": {
115
+ "build": {
116
+ "options": {
117
+ "styles": ["src/styles.scss"]
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ ### `index.html` — Icon font
127
+
128
+ ```html
129
+ <!-- Material Symbols (M3, variable font — recommended) -->
130
+ <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet" />
131
+
132
+ <!-- If using a Google Font for typography, add it here too -->
133
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet" />
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 3. Available M3 Color Palettes
139
+
140
+ All built-in palettes ship with `@angular/material`. Each generates a full M3 tonal palette (10 steps from 0–100 in HCT color space).
141
+
142
+ | Palette Variable | Color Family | Best For |
143
+ |---|---|---|
144
+ | `mat.$red-palette` | Red | Destructive actions, error states, alerts |
145
+ | `mat.$orange-palette` | Orange | CTA buttons, energy, warmth, food apps |
146
+ | `mat.$yellow-palette` | Yellow | Warnings, highlights |
147
+ | `mat.$green-palette` | Green | Success states, health, sustainability, finance |
148
+ | `mat.$teal-palette` | Teal | Healthcare, fintech, calm productivity |
149
+ | `mat.$cyan-palette` | Cyan | Tech, data, modern SaaS |
150
+ | `mat.$azure-palette` | Blue (lighter) | SaaS, productivity, trust |
151
+ | `mat.$blue-palette` | Blue (deeper) | Finance, enterprise, authority |
152
+ | `mat.$violet-palette` | Purple | Creative tools, premium, AI |
153
+ | `mat.$magenta-palette` | Pink/Magenta | Consumer, playful, fashion |
154
+
155
+ **Usage tip:** Set `primary` to your main brand color. Set `tertiary` to a complementary accent used for FABs, selected chips, and highlighted states. Never set all three (primary, secondary, tertiary) to the same palette — it will look flat.
156
+
157
+ ```scss
158
+ // Example: Healthcare app
159
+ $health-theme: mat.define-theme((
160
+ color: (
161
+ theme-type: light,
162
+ primary: mat.$teal-palette,
163
+ tertiary: mat.$green-palette,
164
+ ),
165
+ ));
166
+
167
+ // Example: Creative / AI app
168
+ $creative-theme: mat.define-theme((
169
+ color: (
170
+ theme-type: light,
171
+ primary: mat.$violet-palette,
172
+ tertiary: mat.$magenta-palette,
173
+ ),
174
+ ));
175
+ ```
176
+
177
+ ---
178
+
179
+ ## 4. Dark Mode Implementation
180
+
181
+ ### Option A: CSS Class Toggle (Recommended)
182
+
183
+ Allows runtime switching without page reload. Works with SSR.
184
+
185
+ ```scss
186
+ // styles.scss
187
+ $light-theme: mat.define-theme((
188
+ color: (theme-type: light, primary: mat.$azure-palette)
189
+ ));
190
+
191
+ $dark-theme: mat.define-theme((
192
+ color: (theme-type: dark, primary: mat.$azure-palette)
193
+ ));
194
+
195
+ html {
196
+ @include mat.all-component-themes($light-theme);
197
+ }
198
+
199
+ // Override colors when .dark-theme class is on html or body
200
+ .dark-theme {
201
+ @include mat.all-component-colors($dark-theme);
202
+ // Note: use all-component-colors (not all-component-themes) to avoid
203
+ // re-emitting typography and density tokens unnecessarily.
204
+ }
205
+ ```
206
+
207
+ ```typescript
208
+ // theme.service.ts
209
+ import { Injectable, signal, effect } from '@angular/core';
210
+
211
+ @Injectable({ providedIn: 'root' })
212
+ export class ThemeService {
213
+ readonly isDark = signal(
214
+ window.matchMedia('(prefers-color-scheme: dark)').matches
215
+ );
216
+
217
+ constructor() {
218
+ // Persist preference
219
+ const saved = localStorage.getItem('theme');
220
+ if (saved) this.isDark.set(saved === 'dark');
221
+
222
+ // Apply on change
223
+ effect(() => {
224
+ const dark = this.isDark();
225
+ document.documentElement.classList.toggle('dark-theme', dark);
226
+ localStorage.setItem('theme', dark ? 'dark' : 'light');
227
+ });
228
+ }
229
+
230
+ toggle() {
231
+ this.isDark.update(v => !v);
232
+ }
233
+ }
234
+ ```
235
+
236
+ ```html
237
+ <!-- Theme toggle button in toolbar -->
238
+ <button mat-icon-button (click)="themeService.toggle()"
239
+ [attr.aria-label]="themeService.isDark() ? 'Switch to light mode' : 'Switch to dark mode'">
240
+ <mat-icon>{{ themeService.isDark() ? 'light_mode' : 'dark_mode' }}</mat-icon>
241
+ </button>
242
+ ```
243
+
244
+ ### Option B: CSS Media Query (System preference only)
245
+
246
+ ```scss
247
+ // styles.scss
248
+ html {
249
+ @include mat.all-component-themes($light-theme);
250
+ }
251
+
252
+ @media (prefers-color-scheme: dark) {
253
+ html {
254
+ @include mat.all-component-colors($dark-theme);
255
+ }
256
+ }
257
+ ```
258
+
259
+ ### Option C: Separate stylesheets (lazy-loaded)
260
+
261
+ For very large apps where dark mode CSS size matters:
262
+
263
+ ```typescript
264
+ // In app bootstrap or a service
265
+ function loadDarkTheme() {
266
+ const link = document.createElement('link');
267
+ link.rel = 'stylesheet';
268
+ link.href = 'dark-theme.css'; // Built as separate stylesheet
269
+ document.head.appendChild(link);
270
+ }
271
+ ```
272
+
273
+ ---
274
+
275
+ ## 5. Typography Scale
276
+
277
+ Angular Material 3 defines 15 typographic roles. Apply them as CSS classes or use the Sass typography functions.
278
+
279
+ | Role | CSS Class | Typical Size | Usage |
280
+ |---|---|---|---|
281
+ | Display Large | `.mat-display-large` | 57px | Marketing hero headlines |
282
+ | Display Medium | `.mat-display-medium` | 45px | Large section titles |
283
+ | Display Small | `.mat-display-small` | 36px | Feature section titles |
284
+ | Headline Large | `.mat-headline-large` | 32px | Page H1 |
285
+ | Headline Medium | `.mat-headline-medium` | 28px | Section H2 |
286
+ | Headline Small | `.mat-headline-small` | 24px | Card or panel H2 |
287
+ | Title Large | `.mat-title-large` | 22px | Dialog titles, drawer headers |
288
+ | Title Medium | `.mat-title-medium` | 16px | List item primary text |
289
+ | Title Small | `.mat-title-small` | 14px | Chip labels, tab labels |
290
+ | Body Large | `.mat-body-large` | 16px | Primary body copy |
291
+ | Body Medium | `.mat-body-medium` | 14px | Secondary body, descriptions |
292
+ | Body Small | `.mat-body-small` | 12px | Captions, metadata |
293
+ | Label Large | `.mat-label-large` | 14px | Button text (built-in) |
294
+ | Label Medium | `.mat-label-medium` | 12px | Form field labels |
295
+ | Label Small | `.mat-label-small` | 11px | Helper text, overlines |
296
+
297
+ **Usage in templates:**
298
+
299
+ ```html
300
+ <h1 class="mat-display-small">Welcome Back</h1>
301
+ <h2 class="mat-headline-medium">Recent Activity</h2>
302
+ <p class="mat-body-large">Your account summary for this month.</p>
303
+ <span class="mat-body-small mat-hint">Last updated 2 minutes ago</span>
304
+ ```
305
+
306
+ **Customizing the type scale in your theme:**
307
+
308
+ ```scss
309
+ $my-theme: mat.define-theme((
310
+ typography: (
311
+ brand-family: '"Playfair Display", serif', // Display, Headline roles
312
+ plain-family: '"Inter", sans-serif', // Body, Label, Title roles
313
+ bold-weight: 700,
314
+ medium-weight: 500,
315
+ regular-weight: 400,
316
+ ),
317
+ ));
318
+ ```
319
+
320
+ **Applying typography separately** (when you want to update fonts without re-emitting colors):
321
+
322
+ ```scss
323
+ html {
324
+ @include mat.all-component-typographies($my-theme);
325
+ }
326
+ ```
327
+
328
+ ---
329
+
330
+ ## 6. CSS Custom Properties (Design Token Overrides)
331
+
332
+ Angular Material emits hundreds of `--mat-*` custom properties. Override them directly in CSS for fine-grained control without touching Sass. This is the recommended approach for one-off adjustments.
333
+
334
+ **Token naming pattern:** `--mat-{component}-{slot}`
335
+
336
+ ### App-level tokens
337
+
338
+ ```scss
339
+ html {
340
+ // Background and surface colors
341
+ --mat-app-background-color: #F8FAFC;
342
+ --mat-app-on-background-color: #1E293B;
343
+ --mat-app-surface-color: #FFFFFF;
344
+ --mat-app-on-surface-color: #1E293B;
345
+ }
346
+ ```
347
+
348
+ ### Button tokens
349
+
350
+ ```scss
351
+ html {
352
+ // Filled button
353
+ --mat-filled-button-container-color: #2563EB;
354
+ --mat-filled-button-label-text-color: #FFFFFF;
355
+ --mat-filled-button-container-shape: 8px; // Override pill shape
356
+
357
+ // Outlined button
358
+ --mat-outlined-button-outline-color: #CBD5E1;
359
+
360
+ // Text button
361
+ --mat-text-button-label-text-color: #2563EB;
362
+ }
363
+ ```
364
+
365
+ ### Form field tokens
366
+
367
+ ```scss
368
+ html {
369
+ --mat-form-field-container-height: 48px;
370
+ --mat-form-field-container-vertical-padding: 12px;
371
+ --mat-outlined-form-field-outline-color: #CBD5E1;
372
+ --mat-outlined-form-field-focus-outline-color: #2563EB;
373
+ --mat-form-field-label-text-size: 14px;
374
+ }
375
+ ```
376
+
377
+ ### Card tokens
378
+
379
+ ```scss
380
+ html {
381
+ --mat-card-elevated-container-color: #FFFFFF;
382
+ --mat-card-elevated-container-elevation: 1;
383
+ --mat-card-outlined-container-color: #FFFFFF;
384
+ --mat-card-outlined-outline-color: #E2E8F0;
385
+ --mat-card-title-text-size: 18px;
386
+ }
387
+ ```
388
+
389
+ ### Table tokens
390
+
391
+ ```scss
392
+ html {
393
+ --mat-table-background-color: #FFFFFF;
394
+ --mat-table-header-headline-color: #64748B;
395
+ --mat-table-header-headline-size: 12px;
396
+ --mat-table-header-headline-weight: 600;
397
+ --mat-table-row-item-label-text-color: #1E293B;
398
+ --mat-table-row-item-outline-color: #F1F5F9;
399
+ }
400
+ ```
401
+
402
+ ### Toolbar tokens
403
+
404
+ ```scss
405
+ html {
406
+ --mat-toolbar-container-background-color: #FFFFFF;
407
+ --mat-toolbar-container-text-color: #1E293B;
408
+ }
409
+ ```
410
+
411
+ ### Dialog tokens
412
+
413
+ ```scss
414
+ html {
415
+ --mat-dialog-container-color: #FFFFFF;
416
+ --mat-dialog-container-elevation: 3;
417
+ --mat-dialog-container-shape: 16px;
418
+ }
419
+ ```
420
+
421
+ ### Snackbar tokens
422
+
423
+ ```scss
424
+ html {
425
+ --mat-snack-bar-button-color: #93C5FD; // Action button color in dark snackbar
426
+ --mdc-snackbar-container-color: #1E293B;
427
+ --mdc-snackbar-supporting-text-color: #F8FAFC;
428
+ }
429
+ ```
430
+
431
+ **How to find token names:** Open DevTools, inspect a Material component, and look for `--mat-*` properties in the computed styles. The Angular Material source also documents tokens per component at `https://material.angular.io`.
432
+
433
+ ---
434
+
435
+ ## 7. Component-Level Color Overrides
436
+
437
+ Use the `color` input on individual components to apply the primary, accent (tertiary), or warn color from your theme.
438
+
439
+ ```html
440
+ <!-- Buttons -->
441
+ <button mat-flat-button color="primary">Primary Action</button>
442
+ <button mat-flat-button color="accent">Accent (Tertiary)</button>
443
+ <button mat-flat-button color="warn">Destructive</button>
444
+
445
+ <!-- Progress indicators -->
446
+ <mat-progress-bar color="primary" mode="indeterminate" />
447
+ <mat-progress-spinner color="accent" mode="indeterminate" diameter="40" />
448
+
449
+ <!-- Form controls -->
450
+ <mat-checkbox color="primary" [formControl]="ctrl">Agree</mat-checkbox>
451
+ <mat-slide-toggle color="primary" [formControl]="ctrl">Enable</mat-slide-toggle>
452
+ <mat-radio-button color="primary" value="a">Option A</mat-radio-button>
453
+
454
+ <!-- Toolbar (sets background from palette) -->
455
+ <mat-toolbar color="primary">App Name</mat-toolbar>
456
+ ```
457
+
458
+ **M3 note:** `color="accent"` maps to the tertiary palette in M3 (not a separate "accent" concept). `color="warn"` maps to the error palette.
459
+
460
+ ---
461
+
462
+ ## 8. Density
463
+
464
+ Density scale controls the minimum height and padding of interactive components. Useful for data-dense admin UIs.
465
+
466
+ | Scale | Effect | Use Case |
467
+ |---|---|---|
468
+ | `0` | Default M3 sizing | Consumer apps, landing pages |
469
+ | `-1` | Slightly compact | Productivity tools |
470
+ | `-2` | Compact | Admin dashboards |
471
+ | `-3` | Very compact (minimum) | Data grids, developer tools |
472
+
473
+ ### Global density
474
+
475
+ ```scss
476
+ $compact-theme: mat.define-theme((
477
+ color: (theme-type: light, primary: mat.$azure-palette),
478
+ density: (scale: -2),
479
+ ));
480
+
481
+ html {
482
+ @include mat.all-component-themes($compact-theme);
483
+ }
484
+ ```
485
+
486
+ ### Scoped density (recommended for admin panels)
487
+
488
+ Apply compact density only to specific sections, keeping content areas readable:
489
+
490
+ ```scss
491
+ // Global theme at default density
492
+ html {
493
+ @include mat.all-component-themes($default-theme);
494
+ }
495
+
496
+ // Compact density only inside .data-table-section
497
+ $compact-theme: mat.define-theme((
498
+ color: (theme-type: light, primary: mat.$azure-palette),
499
+ density: (scale: -2),
500
+ ));
501
+
502
+ .data-table-section {
503
+ @include mat.table-density($compact-theme);
504
+ @include mat.paginator-density($compact-theme);
505
+ @include mat.form-field-density($compact-theme);
506
+ @include mat.button-density($compact-theme);
507
+ }
508
+ ```
509
+
510
+ ### Per-component density mixins
511
+
512
+ ```scss
513
+ // Apply density to individual component types
514
+ @include mat.button-density($compact-theme);
515
+ @include mat.form-field-density($compact-theme);
516
+ @include mat.table-density($compact-theme);
517
+ @include mat.paginator-density($compact-theme);
518
+ @include mat.list-density($compact-theme);
519
+ @include mat.checkbox-density($compact-theme);
520
+ @include mat.radio-density($compact-theme);
521
+ @include mat.slide-toggle-density($compact-theme);
522
+ @include mat.select-density($compact-theme);
523
+ @include mat.autocomplete-density($compact-theme);
524
+ @include mat.datepicker-density($compact-theme);
525
+ @include mat.tabs-density($compact-theme);
526
+ @include mat.stepper-density($compact-theme);
527
+ @include mat.expansion-density($compact-theme);
528
+ @include mat.toolbar-density($compact-theme);
529
+ @include mat.tree-density($compact-theme);
530
+ ```
531
+
532
+ ---
533
+
534
+ ## 9. Custom Color Palette (Brand Colors)
535
+
536
+ When your brand color isn't in the built-in palettes, generate an M3 tonal palette from it.
537
+
538
+ ### Option A: Material Theme Builder (No-code)
539
+
540
+ 1. Go to https://m3.material.io/theme-builder
541
+ 2. Enter your brand hex color.
542
+ 3. Export as CSS or Web (tokens).
543
+ 4. Paste the generated `--md-sys-color-*` custom properties into your `styles.scss`.
544
+
545
+ ```scss
546
+ // Paste generated tokens directly:
547
+ html {
548
+ --md-sys-color-primary: #6366F1;
549
+ --md-sys-color-on-primary: #FFFFFF;
550
+ --md-sys-color-primary-container: #E0E7FF;
551
+ --md-sys-color-on-primary-container: #1E1B4B;
552
+ /* ... all generated tokens ... */
553
+ }
554
+ ```
555
+
556
+ ### Option B: `@material/material-color-utilities` (Programmatic)
557
+
558
+ Generates the full tonal palette at runtime from a source color. Useful for user-customizable themes.
559
+
560
+ ```bash
561
+ npm install @material/material-color-utilities
562
+ ```
563
+
564
+ ```typescript
565
+ // theme-generator.service.ts
566
+ import {
567
+ argbFromHex,
568
+ themeFromSourceColor,
569
+ applyTheme,
570
+ hexFromArgb
571
+ } from '@material/material-color-utilities';
572
+
573
+ @Injectable({ providedIn: 'root' })
574
+ export class ThemeGeneratorService {
575
+
576
+ applyBrandColor(hexColor: string, isDark = false) {
577
+ const argb = argbFromHex(hexColor);
578
+ const theme = themeFromSourceColor(argb);
579
+
580
+ applyTheme(theme, {
581
+ target: document.documentElement,
582
+ isDark,
583
+ });
584
+ }
585
+
586
+ // Get specific tonal values from a color
587
+ getPalette(hexColor: string) {
588
+ const theme = themeFromSourceColor(argbFromHex(hexColor));
589
+ const { primary } = theme.palettes;
590
+ return {
591
+ tone10: hexFromArgb(primary.tone(10)),
592
+ tone20: hexFromArgb(primary.tone(20)),
593
+ tone40: hexFromArgb(primary.tone(40)),
594
+ tone80: hexFromArgb(primary.tone(80)),
595
+ tone90: hexFromArgb(primary.tone(90)),
596
+ };
597
+ }
598
+ }
599
+ ```
600
+
601
+ ```typescript
602
+ // In a component or app init
603
+ readonly #themeGen = inject(ThemeGeneratorService);
604
+
605
+ // Apply a custom brand color on startup
606
+ ngOnInit() {
607
+ this.#themeGen.applyBrandColor('#6366F1', false);
608
+ }
609
+
610
+ // Let users pick their brand color
611
+ onColorChange(hex: string) {
612
+ this.#themeGen.applyBrandColor(hex, this.isDark());
613
+ }
614
+ ```
615
+
616
+ ### Option C: Sass map (static custom palette)
617
+
618
+ Define tonal values manually as a Sass map for use with `mat.define-theme()`:
619
+
620
+ ```scss
621
+ // _custom-palette.scss
622
+ // Generate tones using https://m3.material.io/theme-builder or material-color-utilities
623
+ $indigo-palette: (
624
+ 0: #000000,
625
+ 10: #1B0060,
626
+ 20: #2D0086,
627
+ 25: #360099,
628
+ 30: #4000AD,
629
+ 35: #4A12BB,
630
+ 40: #5424C9,
631
+ 50: #6D3DE5,
632
+ 60: #8A5EFF,
633
+ 70: #A882FF,
634
+ 80: #C5A8FF,
635
+ 90: #E6DEFF,
636
+ 95: #F4EEFF,
637
+ 98: #FDF7FF,
638
+ 99: #FFFBFF,
639
+ 100: #FFFFFF,
640
+ );
641
+
642
+ // styles.scss
643
+ @use './custom-palette' as custom;
644
+
645
+ $my-theme: mat.define-theme((
646
+ color: (
647
+ theme-type: light,
648
+ primary: custom.$indigo-palette,
649
+ ),
650
+ ));
651
+ ```
652
+
653
+ ---
654
+
655
+ ## 10. Multi-Theme Support
656
+
657
+ For applications requiring per-tenant or per-section theming:
658
+
659
+ ```scss
660
+ // Theme A: Default (blue)
661
+ $theme-a: mat.define-theme((color: (theme-type: light, primary: mat.$azure-palette)));
662
+
663
+ // Theme B: Green (e.g., a different product)
664
+ $theme-b: mat.define-theme((color: (theme-type: light, primary: mat.$green-palette)));
665
+
666
+ // Theme C: Dark violet
667
+ $theme-c: mat.define-theme((color: (theme-type: dark, primary: mat.$violet-palette)));
668
+
669
+ html {
670
+ @include mat.all-component-themes($theme-a); // Default
671
+ }
672
+
673
+ [data-theme="b"] {
674
+ @include mat.all-component-colors($theme-b);
675
+ }
676
+
677
+ [data-theme="c"] {
678
+ @include mat.all-component-colors($theme-c);
679
+ }
680
+ ```
681
+
682
+ ```typescript
683
+ // Apply theme to root element
684
+ setTheme(theme: 'a' | 'b' | 'c') {
685
+ document.documentElement.dataset['theme'] = theme;
686
+ }
687
+ ```
688
+
689
+ ---
690
+
691
+ ## 11. Common Theming Mistakes
692
+
693
+ | Mistake | Fix |
694
+ |---|---|
695
+ | Calling `@include mat.core()` more than once | Call it once in `styles.scss`, never in component styles |
696
+ | Using `mat.define-light-theme()` (v14 API) | Use `mat.define-theme()` with `theme-type: light` |
697
+ | Importing `MatNativeDateModule` and `MatMomentDateModule` both | Pick one date adapter and import it once in app config |
698
+ | Setting `color="primary"` on `mat-icon` to get brand color | Use `--mat-icon-color` token or a CSS class instead |
699
+ | Overriding `--mdc-*` tokens directly | Prefer `--mat-*` tokens; MDC tokens are lower-level and less stable |
700
+ | Not including component themes (components look unstyled in M3) | Ensure `mat.all-component-themes()` is called or each component's theme mixin is included |
701
+ | Forgetting `@include mat.core-theme($theme)` when using selective includes | `core-theme` is required alongside component themes — it emits ripple and option styles |
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};