Merge pull request #29564 from backstage/canon-breakpoint-helpers

Canon - Add new breakpoint helpers `up()`, `down()` and current breakpoint
This commit is contained in:
Charles de Dreuille
2025-04-14 13:03:08 +02:00
committed by GitHub
5 changed files with 45 additions and 10 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
Add new breakpoint helpers up(), down() and current breakpoint to help you use our breakpoints in your React components.
+7
View File
@@ -1221,6 +1221,13 @@ export const Tooltip: {
>;
};
// @public (undocumented)
export const useBreakpoint: () => {
breakpoint: Breakpoint;
up: (key: Breakpoint) => boolean;
down: (key: Breakpoint) => boolean;
};
// @public (undocumented)
export const useIcons: () => IconContextProps;
+28 -6
View File
@@ -25,18 +25,40 @@ export const breakpoints: { name: string; id: Breakpoint; value: number }[] = [
{ name: 'Extra Large', id: 'xl', value: 1536 },
];
export const useBreakpoint = (): Breakpoint => {
// TODO: Perhaps refactor for useMediaQuery to accept an array of queries
/** @public */
export const useBreakpoint = () => {
// Call all media queries at the top level
const matches = breakpoints.map(breakpoint => {
const match = useMediaQuery(`(min-width: ${breakpoint.value}px)`);
return match;
return useMediaQuery(`(min-width: ${breakpoint.value}px)`);
});
// Pre-calculate all the up/down values we need
const upMatches = new Map(
breakpoints.map(bp => [bp.id, useMediaQuery(`(min-width: ${bp.value}px)`)]),
);
const downMatches = new Map(
breakpoints.map(bp => [
bp.id,
useMediaQuery(`(max-width: ${bp.value - 1}px)`),
]),
);
let breakpoint: Breakpoint = breakpoints[0].id;
for (let i = matches.length - 1; i >= 0; i--) {
if (matches[i]) {
return breakpoints[i].id;
breakpoint = breakpoints[i].id;
break;
}
}
return breakpoints[0].id;
return {
breakpoint,
up: (key: Breakpoint): boolean => {
return upMatches.get(key) ?? false;
},
down: (key: Breakpoint): boolean => {
return downMatches.get(key) ?? false;
},
};
};
@@ -20,12 +20,10 @@ import { useBreakpoint, breakpoints } from './useBreakpoint';
type ResponsiveValue = string | Partial<Record<Breakpoint, string>>;
export const useResponsiveValue = (value: ResponsiveValue) => {
const currentBreakpoint = useBreakpoint();
const { breakpoint } = useBreakpoint();
if (typeof value === 'object') {
const index = breakpoints.findIndex(
breakpoint => breakpoint.id === currentBreakpoint,
);
const index = breakpoints.findIndex(b => b.id === breakpoint);
for (let i = index; i >= 0; i--) {
if (value[breakpoints[i].id]) {
+3
View File
@@ -48,3 +48,6 @@ export * from './components/Select';
// Types
export * from './types';
export * from './props';
// Hooks
export { useBreakpoint } from './hooks/useBreakpoint';