Skip to content

Commit 94c5d59

Browse files
committed
WIP: add validation for <component>-extend-theme functions
Adds a test to validate that the individual extend-theme functions do not have issues with unhandled overlapping short token names, and fixes issues that were uncovered.
1 parent f6bd22c commit 94c5d59

File tree

2 files changed

+142
-86
lines changed

2 files changed

+142
-86
lines changed

src/material/core/theming/tests/m3-theme.spec.ts

Lines changed: 130 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -185,95 +185,147 @@ describe('M3 theme', () => {
185185
expect(css).toContain('--mdc-checkbox-selected-checkmark-color: magenta');
186186
expect(css).toContain('--mdc-checkbox-selected-checkmark-color: cyan');
187187
});
188-
});
189-
190-
it('should error if used on M2 theme', () => {
191-
expect(() =>
192-
transpile(`
193-
@use '../../tokens/token-utils';
194188

195-
$theme: mat.m2-define-light-theme(mat.$m2-red-palette, mat.$m2-red-palette);
196-
197-
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbox)), (
198-
selected-checkmark-color: magenta
199-
));
189+
it('should error if used on M2 theme', () => {
190+
expect(() =>
191+
transpile(`
192+
@use '../../tokens/token-utils';
200193
201-
html {
202-
@include mat.checkbox-theme($theme);
203-
}
204-
`),
205-
).toThrowError(/The `extend-theme` functions are only supported for M3 themes/);
206-
});
207-
208-
it('should error on invalid namespace', () => {
209-
expect(() =>
210-
transpile(`
211-
@use '../../tokens/token-utils';
194+
$theme: mat.m2-define-light-theme(mat.$m2-red-palette, mat.$m2-red-palette);
212195
213-
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbocks)), (
214-
selected-checkmark-color: magenta
215-
));
216-
217-
html {
218-
@include mat.checkbox-theme($theme);
219-
}
220-
`),
221-
).toThrowError(
222-
/Error extending theme: Theme does not have tokes for namespace `\(mat, checkbocks\)`/,
223-
);
224-
});
196+
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbox)), (
197+
selected-checkmark-color: magenta
198+
));
225199
226-
it('should error on ambiguous shorthand token name', () => {
227-
expect(() =>
228-
transpile(`
229-
@use '../../tokens/token-utils';
200+
html {
201+
@include mat.checkbox-theme($theme);
202+
}
203+
`),
204+
).toThrowError(/The `extend-theme` functions are only supported for M3 themes/);
205+
});
230206

231-
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mdc, radio)), (
232-
selected-checkmark-color: magenta
233-
));
207+
it('should error on invalid namespace', () => {
208+
expect(() =>
209+
transpile(`
210+
@use '../../tokens/token-utils';
234211
235-
html {
236-
@include mat.checkbox-theme($theme);
237-
}
238-
`),
239-
).toThrowError(
240-
/Error extending theme: Ambiguous token name `.*` exists in multiple namespaces: `\(mdc, checkbox\)` and `\(mdc, radio\)`/,
241-
);
242-
});
212+
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbocks)), (
213+
selected-checkmark-color: magenta
214+
));
215+
216+
html {
217+
@include mat.checkbox-theme($theme);
218+
}
219+
`),
220+
).toThrowError(
221+
/Error extending theme: Theme does not have tokens for namespace `\(mat, checkbocks\)`/,
222+
);
223+
});
243224

244-
it('should error on unknown variant', () => {
245-
expect(() =>
246-
transpile(`
247-
@use '../../tokens/token-utils';
225+
it('should error on ambiguous shorthand token name', () => {
226+
expect(() =>
227+
transpile(`
228+
@use '../../tokens/token-utils';
248229
249-
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbox)), (
250-
accent: (
230+
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mdc, radio)), (
251231
selected-checkmark-color: magenta
252-
)
253-
));
254-
255-
html {
256-
@include mat.checkbox-theme($theme);
257-
}
258-
`),
259-
).toThrowError(
260-
/Error extending theme: Unrecognized color variant `accent`. Allowed variants are: primary, secondary, tertiary, error, surface/,
261-
);
262-
});
232+
));
233+
234+
html {
235+
@include mat.checkbox-theme($theme);
236+
}
237+
`),
238+
).toThrowError(
239+
/Error extending theme: Ambiguous token name `.*` exists in multiple namespaces: `\(mdc, checkbox\)` and `\(mdc, radio\)`/,
240+
);
241+
});
263242

264-
it('should error on unknown token', () => {
265-
expect(() =>
266-
transpile(`
267-
@use '../../tokens/token-utils';
243+
it('should error on unknown variant', () => {
244+
expect(() =>
245+
transpile(`
246+
@use '../../tokens/token-utils';
247+
248+
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbox)), (
249+
accent: (
250+
selected-checkmark-color: magenta
251+
)
252+
));
253+
254+
html {
255+
@include mat.checkbox-theme($theme);
256+
}
257+
`),
258+
).toThrowError(
259+
/Error extending theme: Unrecognized color variant `accent`. Allowed variants are: primary, secondary, tertiary, error, surface/,
260+
);
261+
});
268262

269-
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbox)), (
270-
fake-token: red
271-
));
263+
it('should error on unknown token', () => {
264+
expect(() =>
265+
transpile(`
266+
@use '../../tokens/token-utils';
267+
268+
$theme: token-utils.extend-theme($theme, ((mdc, checkbox), (mat, checkbox)), (
269+
fake-token: red
270+
));
271+
272+
html {
273+
@include mat.checkbox-theme($theme);
274+
}
275+
`),
276+
).toThrowError(
277+
/Error extending theme: Unrecognized token `fake-token`. Allowed tokens are: /,
278+
);
279+
});
272280

273-
html {
274-
@include mat.checkbox-theme($theme);
275-
}
276-
`),
277-
).toThrowError(/Error extending theme: Unrecognized token `fake-token`. Allowed tokens are: /);
281+
it('should not error when calling component extend-theme functions', () => {
282+
// Ensures that no components have issues with ambiguous token names.
283+
expect(() =>
284+
transpile(`
285+
$theme: mat.core-extend-theme($theme, ());
286+
$theme: mat.ripple-extend-theme($theme, ());
287+
$theme: mat.option-extend-theme($theme, ());
288+
$theme: mat.optgroup-extend-theme($theme, ());
289+
$theme: mat.pseudo-checkbox-extend-theme($theme, ());
290+
$theme: mat.autocomplete-extend-theme($theme, ());
291+
$theme: mat.badge-extend-theme($theme, ());
292+
$theme: mat.bottom-sheet-extend-theme($theme, ());
293+
$theme: mat.button-extend-theme($theme, ());
294+
$theme: mat.fab-extend-theme($theme, ());
295+
$theme: mat.icon-button-extend-theme($theme, ());
296+
$theme: mat.button-toggle-extend-theme($theme, ());
297+
$theme: mat.card-extend-theme($theme, ());
298+
$theme: mat.checkbox-extend-theme($theme, ());
299+
$theme: mat.chips-extend-theme($theme, ());
300+
$theme: mat.datepicker-extend-theme($theme, ());
301+
$theme: mat.dialog-extend-theme($theme, ());
302+
$theme: mat.divider-extend-theme($theme, ());
303+
$theme: mat.expansion-extend-theme($theme, ());
304+
$theme: mat.form-field-extend-theme($theme, ());
305+
$theme: mat.grid-list-extend-theme($theme, ());
306+
$theme: mat.icon-extend-theme($theme, ());
307+
$theme: mat.list-extend-theme($theme, ());
308+
$theme: mat.menu-extend-theme($theme, ());
309+
$theme: mat.paginator-extend-theme($theme, ());
310+
$theme: mat.progress-bar-extend-theme($theme, ());
311+
$theme: mat.progress-spinner-extend-theme($theme, ());
312+
$theme: mat.radio-extend-theme($theme, ());
313+
$theme: mat.select-extend-theme($theme, ());
314+
$theme: mat.sidenav-extend-theme($theme, ());
315+
$theme: mat.slide-toggle-extend-theme($theme, ());
316+
$theme: mat.slider-extend-theme($theme, ());
317+
$theme: mat.snack-bar-extend-theme($theme, ());
318+
$theme: mat.sort-extend-theme($theme, ());
319+
$theme: mat.stepper-extend-theme($theme, ());
320+
$theme: mat.table-extend-theme($theme, ());
321+
$theme: mat.tabs-extend-theme($theme, ());
322+
$theme: mat.toolbar-extend-theme($theme, ());
323+
$theme: mat.tooltip-extend-theme($theme, ());
324+
$theme: mat.tree-extend-theme($theme, ());
325+
326+
@include mat.all-component-themes($theme);
327+
`),
328+
).not.toThrow();
329+
});
278330
});
279331
});

src/material/core/tokens/_token-utils.scss

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,21 +437,25 @@ $_component-prefix: null;
437437
// Determine which system and namespace each shorthand token belongs to.
438438
$seen-tokens: ();
439439
@each $namespace in $extend-namespaces {
440+
$namespace-found: false;
440441
@each $system in $systems {
441442
$tokens: map.get($theme, $internals, $system, $namespace);
442-
@if $tokens == null {
443-
@error #{'Error extending theme: Theme does not have tokes for namespace `('}#{$namespace}#{
444-
')`'};
445-
}
446-
@each $name, $value in $tokens {
447-
@if map.has-key($seen-tokens, $name) {
448-
@error #{'Error extending theme: Ambiguous token name `'}#{$name}#{
443+
@if ($tokens != null) {
444+
$namespace-found: true;
445+
@each $name, $value in $tokens {
446+
@if map.has-key($seen-tokens, $name) {
447+
@error #{'Error extending theme: Ambiguous token name `'}#{$name}#{
449448
'` exists in multiple namespaces: `('}#{list.nth(map.get($seen-tokens, $name), 1)}#{
450449
')` and `('}#{$namespace}#{')`'};
450+
}
451+
$seen-tokens: map.set($seen-tokens, $name, ($namespace, $system));
451452
}
452-
$seen-tokens: map.set($seen-tokens, $name, ($namespace, $system));
453453
}
454454
}
455+
@if not $namespace-found {
456+
@error #{'Error extending theme: Theme does not have tokens for namespace `('}#{
457+
$namespace}#{')`'};
458+
}
455459
}
456460

457461
// Update internal tokens based on given overrides.

0 commit comments

Comments
 (0)