Skip to content

Commit b200aae

Browse files
mg901claude
andauthored
fix: 🐛 preserve breakpoints.keys in the validated theme (#2272)
withBreakpointValidation replaced theme.breakpoints wholesale with an object built only from the validator names (up, down, between, only), so `keys` was dropped from the public API. The spread of `...theme` did not help, since `breakpoints` is the only top-level key. Consumers of the public entry point got `undefined` for `theme.breakpoints.keys` while ThemeBreakpoints still typed it as `readonly string[]`, so TypeScript accepted code that crashed at runtime. Existing tests missed this because they cover create-theme (the raw module) and with-validation (against a mock) separately, never the composition that ships. Add a spec on the public entry point. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent fa8ac2c commit b200aae

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { createStyledBreakpointsTheme } from '.';
2+
3+
describe('public entry point', () => {
4+
it('exposes the full breakpoints API', () => {
5+
const theme = createStyledBreakpointsTheme();
6+
7+
expect(theme.breakpoints.keys).toEqual([
8+
'xs',
9+
'sm',
10+
'md',
11+
'lg',
12+
'xl',
13+
'xxl',
14+
]);
15+
expect(theme.breakpoints.up).toBeTypeOf('function');
16+
expect(theme.breakpoints.down).toBeTypeOf('function');
17+
expect(theme.breakpoints.between).toBeTypeOf('function');
18+
expect(theme.breakpoints.only).toBeTypeOf('function');
19+
});
20+
21+
it('keeps keys of a custom config', () => {
22+
const theme = createStyledBreakpointsTheme({
23+
breakpoints: {
24+
values: {
25+
mobile: '0px',
26+
tablet: '768px',
27+
desktop: '1200px',
28+
},
29+
},
30+
});
31+
32+
expect(theme.breakpoints.keys).toEqual(['mobile', 'tablet', 'desktop']);
33+
});
34+
35+
it('builds media queries', () => {
36+
const theme = createStyledBreakpointsTheme();
37+
38+
expect(theme.breakpoints.up('md')).toBe('@media (width >= 768px)');
39+
});
40+
41+
it('still validates through the wrapper', () => {
42+
const theme = createStyledBreakpointsTheme();
43+
44+
expect(() =>
45+
// @ts-expect-error
46+
theme.breakpoints.up('nope')
47+
).toThrow(/does not exist/);
48+
});
49+
});

src/styled-breakpoints/validation/breakpoints-validation.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ export const withBreakpointValidation = <T extends Values>(
175175

176176
return {
177177
...theme,
178-
breakpoints: Object.fromEntries(entries),
178+
breakpoints: {
179+
...theme.breakpoints,
180+
...Object.fromEntries(entries),
181+
},
179182
};
180183
};

0 commit comments

Comments
 (0)