Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tangy-facts-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

Remove unused getBreakpointDeclarations function and any related code.
100 changes: 1 addition & 99 deletions packages/react/src/PageHeader/PageHeader.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {render} from '@testing-library/react'
import {PageHeader} from '.'
import MatchMediaMock from 'jest-matchmedia-mock'
import {behavesAsComponent, checkExports, renderStyles} from '../utils/testing'
import {IconButton} from '../Button'
import {SidebarExpandIcon} from '@primer/octicons-react'
import {mediaQueries} from '../utils/layout'
import {behavesAsComponent, checkExports} from '../utils/testing'

let matchmedia: MatchMediaMock
describe('PageHeader', () => {
Expand Down Expand Up @@ -40,101 +37,6 @@ describe('PageHeader', () => {
default: undefined,
PageHeader,
})
/** These 3 tests below are not following the user behavioural pattern testing paradigm.
* They are testing the internal implementation of the component and checking if the component
* is rendering the correct styles.This approach was necessary due to the impracticality of CSS media queries testing with Jest.
*/
it.skip('respects default visibility of ContextArea and renders CSS media styles correctly', () => {
const expectedStyles = {
'-ms-flex-align': 'center',
'-ms-flex-direction': 'row',
'-webkit-align-items': 'center',
'-webkit-box-align': 'center',
'-webkit-flex-direction': 'row',
[`@media screen and (max-width:calc(768px - 0.02px))`]: {
display: 'flex',
},
[`${mediaQueries.regular.replace(': ', ':')}`]: {
display: 'none',
},
'align-items': 'center',
display: 'flex',
'flex-direction': 'row',
gap: '0.5rem',
'grid-area': 'context-area',
'padding-bottom': '0.5rem',
'grid-row': '1',
}

expect(renderStyles(<PageHeader.ContextArea>ContextArea</PageHeader.ContextArea>)).toEqual(
expect.objectContaining(expectedStyles),
)
})
it.skip('respects the hidden prop of ContextArea and renders CSS media styles correctly', () => {
const expectedStyles = {
'-ms-flex-align': 'center',
'-ms-flex-direction': 'row',
'-webkit-align-items': 'center',
'-webkit-box-align': 'center',
'-webkit-flex-direction': 'row',
[`@media screen and (max-width:calc(768px - 0.02px))`]: {
display: 'flex',
},
[`${mediaQueries.regular.replace(': ', ':')}`]: {
display: 'flex',
},
[`${mediaQueries.wide.replace(': ', ':')}`]: {
display: 'none',
},
'align-items': 'center',
display: 'flex',
'flex-direction': 'row',
gap: '0.5rem',
'grid-area': 'context-area',
'grid-row': '1',
'padding-bottom': '0.5rem',
}

expect(
renderStyles(
<PageHeader.ContextArea
hidden={{
narrow: false,
regular: false,
wide: true,
}}
>
ContextArea
</PageHeader.ContextArea>,
),
).toEqual(expect.objectContaining(expectedStyles))
})
it.skip('respects default visibility of LeadingAction and TrailingAction and renders CSS media styles correctly', () => {
const expectedStyles = {
'-ms-flex-align': 'center',
'-webkit-align-items': 'center',
'-webkit-box-align': 'center',
[`@media screen and (max-width:calc(768px - 0.02px))`]: {
display: 'none',
},
[`${mediaQueries.regular.replace(': ', ':')}`]: {
display: 'flex',
},
'align-items': 'center',
display: 'flex',
'grid-area': 'leading-action',
'grid-row': '2',
'padding-right': '0.5rem',
}

expect(
renderStyles(
<PageHeader.LeadingAction>
<IconButton aria-label="Expand" data-testid="LeadingAction" icon={SidebarExpandIcon} variant="invisible" />
</PageHeader.LeadingAction>,
),
).toEqual(expect.objectContaining(expectedStyles))
})
it('respects the title variant prop', () => {
const {getByText} = render(
<PageHeader role="banner" aria-label="Title">
Expand Down
148 changes: 0 additions & 148 deletions packages/react/src/utils/getBreakpointDeclarations.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import type {ResponsiveValue} from '../hooks/useResponsiveValue'
import {isResponsiveValue} from '../hooks/useResponsiveValue'
import type {BetterSystemStyleObject} from '../sx'
import type {Properties as CSSProperties} from 'csstype'
import {mediaQueries} from './layout'

export function areAllValuesTheSame(responsiveValue: ResponsiveValue<boolean | number | string>): boolean {
if ('narrow' in responsiveValue && 'regular' in responsiveValue && 'wide' in responsiveValue) {
Expand All @@ -17,147 +13,3 @@ export function haveRegularAndWideSameValue(responsiveValue: ResponsiveValue<boo
}
return false
}

/**
* This function is inspired by the `useResponsiveValue` hook and it's used to render responsive values with CSS.
* @param value - The value that needs to be rendered responsively
* @param cssProperty - The CSS property whoes value needs to be rendered responsively
* @param mapFn - A function that maps the given value to a CSS value
*
* If the value is responsive, it will only return the given viewports' breakpoints as CSS rules
* with the given CSS property and their mapped value. For viewports that are not specified,
* we need to provide a fallback CSS declaration in the component's sx prop along with the styles
* that will return from this function.
*
* @example
* getBreakpointDeclarations({narrow: true, regular: true, wide: false}, 'display', value => {
return value ? 'none' : 'flex'
})
* @returns
* {
* "@media screen and (max-width: 768px)": {
* "display": "none"
* },
* "@media screen and (min-width: 768px)": {
* "display": "none"
* },
* "@media screen and (min-width: 1440px)": {
* "display": "flex"
* }
* }
*
* * @example
* getBreakpointDeclarations({regular: 'border.default', wide: 'canvas.inset'}, 'backgroundColor', (value): string => {
return value
})
* @returns
* {
* "@media screen and (min-width: 768px)": {
* "backgroundColor": "border.default"
* },
* "@media screen and (min-width: 1440px)": {
* "backgroundColor": "canvas.inset"
* }
* }
*
* * @example
* getBreakpointDeclarations({narrow: 'filled', regular: 'line'}, 'height', (value): string => {
return {
filled: 8,
line: 1,
}[value]
})
* @returns
* {
* "@media screen and (max-width: 768px)": {
* "height": 8
* }
* "@media screen and (min-width: 768px)": {
* "height": 1
* },
* }
*
* If multiple CSS properties need to be rendered responsively in the same CSS rule, this function
* can be called multiple times but make sure to deep merge the CSS declaration objects returned from this function.
*
* * @example
* const mediaQueryStyles = merge<BetterSystemStyleObject>(
getBreakpointDeclarations(hidden, 'display', value => {
return value ? 'none' : 'flex'
}),
getBreakpointDeclarations(
{
narrow: 'none',
regular: 'line',
wide: 'filled',
},
'backgroundColor',
(value): string => {
return {
none: 'pink',
line: 'salmon',
filled: 'blue',
}[value]
},
),
)
*/
export function getBreakpointDeclarations<TInput, TOutput>(
value: TInput | ResponsiveValue<TInput>,
cssProperty: keyof CSSProperties,
mapFn: (value: TInput) => TOutput,
): BetterSystemStyleObject {
if (isResponsiveValue(value)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const responsiveValue = value as Extract<TInput, ResponsiveValue<any>>

// Build media queries with the giving cssProperty and mapFn
const narrowMediaQuery =
'narrow' in responsiveValue
? {
[mediaQueries.narrow]: {
[cssProperty]: mapFn(responsiveValue.narrow),
},
}
: {}

const regularMediaQuery =
'regular' in responsiveValue
? {
[mediaQueries.regular]: {
[cssProperty]: mapFn(responsiveValue.regular),
},
}
: {}

const wideMediaQuery =
'wide' in responsiveValue
? {
[mediaQueries.wide]: {
[cssProperty]: mapFn(responsiveValue.wide),
},
}
: {}

// check if all values are the same - this is not a recommended practise but we still should check for it
if (areAllValuesTheSame(responsiveValue)) {
// if all the values are the same, we can just use one of the value to determine the CSS property's value
return {[cssProperty]: mapFn(responsiveValue.narrow)}
// check if regular and wide have the same value, if so we can just return the narrow and regular media queries
} else if (haveRegularAndWideSameValue(responsiveValue)) {
return {
...narrowMediaQuery,
...regularMediaQuery,
}
} else {
return {
...narrowMediaQuery,
...regularMediaQuery,
...wideMediaQuery,
}
}
} else {
// If the given value is not a responsive value
return {[cssProperty]: mapFn(value)}
}
}
15 changes: 0 additions & 15 deletions packages/react/src/utils/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,3 @@ export const PrimerBreakpoints = {
width: '1400px',
},
}

export function breakpointHigher(width: string): string {
return `@media screen and (min-width: ${width})`
}

export function breakpointLower(width: string): string {
return `@media screen and (max-width: calc(${width} - 0.02px))`
}

// Media queries associated with Primer viewport ranges.
export const mediaQueries = {
narrow: breakpointLower(PrimerBreakpoints.medium.width), // @media screen and (max-width: 768px - 0.02px) // < 768px (max-with is inclusive)
regular: breakpointHigher(PrimerBreakpoints.medium.width), // @media screen and (min-width: 768) // >= 768px
wide: breakpointHigher(PrimerBreakpoints.xxlarge.width), // (min-width: 1400px) // >= 1400px
}
Loading