Skip to content

Commit

Permalink
fix(layout): ability to override breakpoint during theme (#1512)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexandr Isaev <[email protected]>
  • Loading branch information
IsaevAlexandr and IsaevAlexandr authored Apr 16, 2024
1 parent f93496c commit bad4fa9
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 78 deletions.
16 changes: 6 additions & 10 deletions src/components/layout/Col/Col.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@
flex-basis: 0;
max-width: 100%;

@each $media, $_ in v.$MEDIA_TO_BREAKPOINT_WIDTH {
@each $size, $value in v.$COL_SIZE {
@include v.use-media($media) {
&_s-#{$media}_#{$size} {
box-sizing: border-box;
flex-grow: 0;
flex-basis: $value;
max-width: $value;
}
}
@each $size, $value in v.$COL_SIZE {
&_size_#{$size} {
box-sizing: border-box;
flex-grow: 0;
flex-basis: $value;
max-width: $value;
}
}
}
14 changes: 8 additions & 6 deletions src/components/layout/Col/Col.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';

import type {QAProps} from '../../types';
import {block} from '../../utils/cn';
import {useLayoutContext} from '../hooks/useLayoutContext';
import type {ColSize, MediaPartial} from '../types';
import {makeCssMod} from '../utils';

Expand Down Expand Up @@ -41,14 +42,15 @@ export interface ColProps extends MediaPartial<ColSize>, QAProps {
* Storybook - https://preview.gravity-ui.com/uikit/?path=/docs/layout--playground#col
*/
export const Col = ({children, style, className, qa, ...media}: ColProps) => {
const mods = Object.entries(media).reduce<Record<string, string>>((acc, [mod, modSize]) => {
acc[`s-${mod}`] = makeCssMod(modSize);

return acc;
}, {});
const {getClosestMediaProps} = useLayoutContext();
const sizeModValue = getClosestMediaProps(media);

return (
<div style={style} className={b(mods, className)} data-qa={qa}>
<div
style={style}
className={b({size: sizeModValue ? makeCssMod(sizeModValue) : undefined}, className)}
data-qa={qa}
>
{children}
</div>
);
Expand Down
55 changes: 55 additions & 0 deletions src/components/layout/Col/__stories__/Col.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,61 @@ Dynamic.args = {
space: '2',
};

const theme = {
breakpoints: {
s: 500,
m: 500,
l: 1200,
xl: 1200,
xxl: 1900,
xxxl: 1900,
},
};

const DynamicWithOverriddenBreakpointsTemplate: StoryFn<{space?: Space; spaceRow?: Space}> = ({
space = '2',
spaceRow,
}) => (
<LayoutPresenter theme={theme}>
<Container spaceRow="8">
<Row {...{space, spaceRow}}>
<ColPresenter s="1" l="12" />
<ColPresenter s="1" l="12" />
<ColPresenter s="1" l="11" />
<ColPresenter s="1" l="1" />
<ColPresenter s="1" l="10" />
<ColPresenter s="1" l="2" />
<ColPresenter s="1" l="9" />
<ColPresenter s="1" l="3" />
<ColPresenter s="1" l="8" />
<ColPresenter s="1" l="4" />
<ColPresenter s="1" l="7" />
<ColPresenter s="1" l="5" />
</Row>
<Row {...{space, spaceRow}}>
<ColPresenter s="7" l="1" />
<ColPresenter s="5" l="1" />
<ColPresenter s="8" l="1" />
<ColPresenter s="4" l="1" />
<ColPresenter s="9" l="1" />
<ColPresenter s="3" l="1" />
<ColPresenter s="10" l="1" />
<ColPresenter s="2" l="1" />
<ColPresenter s="11" l="1" />
<ColPresenter s="1" l="1" />
<ColPresenter s="12" l="1" />
<ColPresenter s="12" l="1" />
</Row>
</Container>
</LayoutPresenter>
);

export const DynamicWithOverriddenBreakpoints = DynamicWithOverriddenBreakpointsTemplate.bind({});

DynamicWithOverriddenBreakpoints.args = {
space: '2',
};

const AllModsTemplate: StoryFn<ColProps & {space?: Space; spaceRow?: Space}> = ({
space = '3',
spaceRow,
Expand Down
6 changes: 0 additions & 6 deletions src/components/layout/Container/Container.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@
max-width: 100%;
height: 100%;

@each $media, $breakpoint-width in v.$MEDIA_TO_BREAKPOINT_WIDTH {
&_mw_#{$media} {
max-width: $breakpoint-width;
}
}

@each $space, $value in v.$SPACE {
// space row - space between Row components
&_sr_#{$space} {
Expand Down
14 changes: 11 additions & 3 deletions src/components/layout/Container/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,24 @@ export interface ContainerProps extends QAProps {
*/
export const Container = ({
children,
style,
style: propsStyle,
as: Tag = 'div',
className,
maxWidth,
gutters,
spaceRow,
qa,
}: ContainerProps) => {
const {getClosestMediaProps, containerThemeProps} = useContainerThemeProps();
const {getClosestMediaProps, containerThemeProps, breakpoints} = useContainerThemeProps();

const style = {
...(maxWidth
? {
maxWidth: breakpoints[maxWidth],
}
: {}),
...propsStyle,
};

let sr: string | undefined;

Expand All @@ -90,7 +99,6 @@ export const Container = ({
style={style}
className={b(
{
mw: maxWidth,
sr,
},
gutters === false
Expand Down
1 change: 1 addition & 0 deletions src/components/layout/Container/useContainerThemeProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ export const useContainerThemeProps = () => {
return {
getClosestMediaProps,
containerThemeProps,
breakpoints: theme.breakpoints,
};
};
2 changes: 1 addition & 1 deletion src/components/layout/LayoutProvider/LayoutProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function LayoutProvider({
theme: override,
initialMediaQuery,
}: LayoutProviderProps) {
const theme = makeLayoutDefaultTheme({override});
const theme = React.useMemo(() => makeLayoutDefaultTheme({override}), [override]);
const activeMediaQuery = useCurrentActiveMediaQuery(theme.breakpoints, initialMediaQuery);

return (
Expand Down
15 changes: 15 additions & 0 deletions src/components/layout/LayoutProvider/__stories__/Layout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,21 @@ We use `mobile-first` approach. It means that you should adapt you app to deskto
- `xxl` - 1400px;
- `xxxl` - 1920px;

> To override breakpoint use `theme` breakpoints property;
```tsx
export const APP_LAYOUT_THEME: LayoutTheme = {
breakpoints: {
s: 320,
l: 980,
}
};

<LayoutProvider theme={APP_LAYOUT_THEME}>
{...}
</LayoutProvider>
```

## LayoutProvider and LayoutTheme

Through `LayoutProvider` components can get default props which are corresponding to different screen sizes.
Expand Down
14 changes: 10 additions & 4 deletions src/components/layout/demo/LayoutPresenter/LayoutPresenter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';

import {Text} from '../../../Text';
import type {LayoutTheme} from '../../../layout';
import {Flex} from '../../Flex/Flex';
import {LayoutProvider} from '../../LayoutProvider/LayoutProvider';
import {useLayoutContext} from '../../hooks/useLayoutContext';
Expand All @@ -9,10 +10,14 @@ import {sp} from '../../spacing/spacing';
interface LayoutPresenterProps {
children?: React.ReactNode;
title?: string;
theme?: LayoutTheme;
}

function Title({title}: {title?: string}) {
const {activeMediaQuery} = useLayoutContext();
const {
activeMediaQuery,
theme: {breakpoints},
} = useLayoutContext();
return (
<Flex direction="column" space="5" className={sp({mb: '5'})}>
{title && (
Expand All @@ -21,15 +26,16 @@ function Title({title}: {title?: string}) {
</Text>
)}
<Text color="secondary" as="div">
Active media query: {activeMediaQuery}
Active media query: {activeMediaQuery}, breakpoint value:{' '}
{breakpoints[activeMediaQuery]}
</Text>
</Flex>
);
}

export const LayoutPresenter = ({children, title}: LayoutPresenterProps) => {
export const LayoutPresenter = ({children, title, theme}: LayoutPresenterProps) => {
return (
<LayoutProvider>
<LayoutProvider theme={theme}>
<Title title={title} />
<div
style={{
Expand Down
2 changes: 0 additions & 2 deletions src/components/layout/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ interface ComponentProps {
export interface LayoutTheme {
/**
* Override default breakpoints values.
*
* @important **you must override corresponding scss variables**
*/
breakpoints: MediaProps<number>;
/**
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const mediaOrder = ['s', 'm', 'l', 'xl', 'xxl', 'xxxl'] as const;

export const getClosestMediaPropsFactory =
(currentActive: MediaType) =>
<T = unknown>(medias: MediaPartial<T> = {}): T | undefined => {
<T>(medias: MediaPartial<T> = {}): T | undefined => {
if (!currentActive) {
return undefined;
}
Expand Down
45 changes: 0 additions & 45 deletions src/components/layout/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ $flexBlock: '.#{variables.$ns}flex';
$containerBlock: '.#{variables.$ns}container';
$spacingBlock: '.#{variables.$ns}s';

$breakpoint-s: 576px !default;
$breakpoint-m: 768px !default;
$breakpoint-l: 1080px !default;
$breakpoint-xl: 1200px !default;
$breakpoint-xxl: 1400px !default;
$breakpoint-xxxl: 1920px !default;

$COL_SIZE: (
1: 8.33333333%,
2: 16.66666667%,
Expand Down Expand Up @@ -43,41 +36,3 @@ $SPACE: (
9: var(--g-spacing-9),
10: var(--g-spacing-10),
);

$MEDIA_TO_BREAKPOINT_WIDTH: (
's' $breakpoint-s,
'm' $breakpoint-m,
'l' $breakpoint-l,
'xl' $breakpoint-xl,
'xxl' $breakpoint-xxl,
'xxxl' $breakpoint-xxxl
);

// mobile first
// for example if we set `m` breakpoint condition, then the same condition will be applied to `l`, `xl`, `xxl` and 'xxxl' breakpoints

@mixin use-media($size) {
@if $size == s {
@content;
} @else if $size == m {
@media (min-width: $breakpoint-m) {
@content;
}
} @else if $size == l {
@media (min-width: $breakpoint-l) {
@content;
}
} @else if $size == xl {
@media (min-width: $breakpoint-xl) {
@content;
}
} @else if $size == xxl {
@media (min-width: $breakpoint-xxl) {
@content;
}
} @else if $size == xxxl {
@media (min-width: $breakpoint-xxxl) {
@content;
}
}
}

0 comments on commit bad4fa9

Please sign in to comment.