From bcf7a9c6777771671553d3aa173ad96e5713cea9 Mon Sep 17 00:00:00 2001 From: Alexandr Isaev Date: Fri, 12 Apr 2024 19:56:05 +0300 Subject: [PATCH] fix(layout): ability to override breakpoint during theme --- src/components/layout/Col/Col.scss | 16 ++---- src/components/layout/Col/Col.tsx | 14 +++-- .../layout/Col/__stories__/Col.stories.tsx | 55 +++++++++++++++++++ .../layout/Container/Container.scss | 6 -- src/components/layout/Container/Container.tsx | 14 ++++- .../Container/useContainerThemeProps.ts | 1 + .../layout/LayoutProvider/LayoutProvider.tsx | 2 +- .../LayoutProvider/__stories__/Layout.mdx | 15 +++++ .../demo/LayoutPresenter/LayoutPresenter.tsx | 14 +++-- src/components/layout/types.ts | 2 - src/components/layout/utils/index.ts | 2 +- src/components/layout/variables.scss | 45 --------------- 12 files changed, 108 insertions(+), 78 deletions(-) diff --git a/src/components/layout/Col/Col.scss b/src/components/layout/Col/Col.scss index a83cf97801..080bca32ed 100644 --- a/src/components/layout/Col/Col.scss +++ b/src/components/layout/Col/Col.scss @@ -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; } } } diff --git a/src/components/layout/Col/Col.tsx b/src/components/layout/Col/Col.tsx index eed4ef374d..863f7ef9de 100644 --- a/src/components/layout/Col/Col.tsx +++ b/src/components/layout/Col/Col.tsx @@ -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'; @@ -41,14 +42,15 @@ export interface ColProps extends MediaPartial, 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>((acc, [mod, modSize]) => { - acc[`s-${mod}`] = makeCssMod(modSize); - - return acc; - }, {}); + const {getClosestMediaProps} = useLayoutContext(); + const sizeModValue = getClosestMediaProps(media); return ( -
+
{children}
); diff --git a/src/components/layout/Col/__stories__/Col.stories.tsx b/src/components/layout/Col/__stories__/Col.stories.tsx index 3b7e67bca0..f92fc64b2c 100644 --- a/src/components/layout/Col/__stories__/Col.stories.tsx +++ b/src/components/layout/Col/__stories__/Col.stories.tsx @@ -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, +}) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export const DynamicWithOverriddenBreakpoints = DynamicWithOverriddenBreakpointsTemplate.bind({}); + +DynamicWithOverriddenBreakpoints.args = { + space: '2', +}; + const AllModsTemplate: StoryFn = ({ space = '3', spaceRow, diff --git a/src/components/layout/Container/Container.scss b/src/components/layout/Container/Container.scss index d121825a9b..bcbbb922f9 100644 --- a/src/components/layout/Container/Container.scss +++ b/src/components/layout/Container/Container.scss @@ -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} { diff --git a/src/components/layout/Container/Container.tsx b/src/components/layout/Container/Container.tsx index c0eb580bc5..957e0803f0 100644 --- a/src/components/layout/Container/Container.tsx +++ b/src/components/layout/Container/Container.tsx @@ -63,7 +63,7 @@ export interface ContainerProps extends QAProps { */ export const Container = ({ children, - style, + style: propsStyle, as: Tag = 'div', className, maxWidth, @@ -71,7 +71,16 @@ export const Container = ({ spaceRow, qa, }: ContainerProps) => { - const {getClosestMediaProps, containerThemeProps} = useContainerThemeProps(); + const {getClosestMediaProps, containerThemeProps, breakpoints} = useContainerThemeProps(); + + const style = { + ...(maxWidth + ? { + maxWidth: breakpoints[maxWidth], + } + : {}), + ...propsStyle, + }; let sr: string | undefined; @@ -90,7 +99,6 @@ export const Container = ({ style={style} className={b( { - mw: maxWidth, sr, }, gutters === false diff --git a/src/components/layout/Container/useContainerThemeProps.ts b/src/components/layout/Container/useContainerThemeProps.ts index 3f2a18521f..b31480037b 100644 --- a/src/components/layout/Container/useContainerThemeProps.ts +++ b/src/components/layout/Container/useContainerThemeProps.ts @@ -34,5 +34,6 @@ export const useContainerThemeProps = () => { return { getClosestMediaProps, containerThemeProps, + breakpoints: theme.breakpoints, }; }; diff --git a/src/components/layout/LayoutProvider/LayoutProvider.tsx b/src/components/layout/LayoutProvider/LayoutProvider.tsx index 70c63bd9b2..2152a7dbe1 100644 --- a/src/components/layout/LayoutProvider/LayoutProvider.tsx +++ b/src/components/layout/LayoutProvider/LayoutProvider.tsx @@ -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 ( diff --git a/src/components/layout/LayoutProvider/__stories__/Layout.mdx b/src/components/layout/LayoutProvider/__stories__/Layout.mdx index 3d25f6e380..1e9ff003ca 100644 --- a/src/components/layout/LayoutProvider/__stories__/Layout.mdx +++ b/src/components/layout/LayoutProvider/__stories__/Layout.mdx @@ -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 and LayoutTheme Through `LayoutProvider` components can get default props which are corresponding to different screen sizes. diff --git a/src/components/layout/demo/LayoutPresenter/LayoutPresenter.tsx b/src/components/layout/demo/LayoutPresenter/LayoutPresenter.tsx index 87dc2eaccd..af3b47e93b 100644 --- a/src/components/layout/demo/LayoutPresenter/LayoutPresenter.tsx +++ b/src/components/layout/demo/LayoutPresenter/LayoutPresenter.tsx @@ -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'; @@ -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 ( {title && ( @@ -21,15 +26,16 @@ function Title({title}: {title?: string}) { )} - Active media query: {activeMediaQuery} + Active media query: {activeMediaQuery}, breakpoint value:{' '} + {breakpoints[activeMediaQuery]} ); } -export const LayoutPresenter = ({children, title}: LayoutPresenterProps) => { +export const LayoutPresenter = ({children, title, theme}: LayoutPresenterProps) => { return ( - + <div style={{ diff --git a/src/components/layout/types.ts b/src/components/layout/types.ts index a6b6a19ba0..71eb93c1e0 100644 --- a/src/components/layout/types.ts +++ b/src/components/layout/types.ts @@ -83,8 +83,6 @@ interface ComponentProps { export interface LayoutTheme { /** * Override default breakpoints values. - * - * @important **you must override corresponding scss variables** */ breakpoints: MediaProps<number>; /** diff --git a/src/components/layout/utils/index.ts b/src/components/layout/utils/index.ts index 0026a363aa..02bcc640d8 100644 --- a/src/components/layout/utils/index.ts +++ b/src/components/layout/utils/index.ts @@ -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; } diff --git a/src/components/layout/variables.scss b/src/components/layout/variables.scss index 45fed229be..fc67016263 100644 --- a/src/components/layout/variables.scss +++ b/src/components/layout/variables.scss @@ -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%, @@ -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; - } - } -}