From 8a18123061994d91a1eb23dd25faeec70132045a Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Wed, 13 Sep 2023 16:35:02 +0200 Subject: [PATCH 01/18] :sparkles: add Bleed --- @navikt/core/css/primitives/bleed.css | 24 ++++++ @navikt/core/css/primitives/index.css | 1 + .../react/src/layout/bleed/Bleed.stories.tsx | 30 ++++++++ @navikt/core/react/src/layout/bleed/Bleed.tsx | 76 +++++++++++++++++++ @navikt/core/react/src/layout/bleed/index.ts | 1 + @navikt/core/react/src/layout/box/Box.tsx | 1 + .../core/react/src/layout/utilities/css.ts | 25 ++++-- 7 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 @navikt/core/css/primitives/bleed.css create mode 100644 @navikt/core/react/src/layout/bleed/Bleed.stories.tsx create mode 100644 @navikt/core/react/src/layout/bleed/Bleed.tsx create mode 100644 @navikt/core/react/src/layout/bleed/index.ts diff --git a/@navikt/core/css/primitives/bleed.css b/@navikt/core/css/primitives/bleed.css new file mode 100644 index 0000000000..0a6748a8b1 --- /dev/null +++ b/@navikt/core/css/primitives/bleed.css @@ -0,0 +1,24 @@ +.navds-bleed { + --__ac-bleed-margin-xs: initial; + --__ac-bleed-margin-sm: initial; + --__ac-bleed-margin-md: initial; + --__ac-bleed-margin-lg: initial; + --__ac-bleed-margin-xl: initial; + --__ac-bleed-margin-block-xs: initial; + --__ac-bleed-margin-inline-xs: initial; + --__ac-bleed-margin-block-sm: initial; + --__ac-bleed-margin-inline-sm: initial; + --__ac-bleed-margin-block-md: initial; + --__ac-bleed-margin-inline-md: initial; + --__ac-bleed-margin-block-lg: initial; + --__ac-bleed-margin-inline-lg: initial; + --__ac-bleed-margin-block-xl: initial; + --__ac-bleed-margin-inline-xl: initial; + --__ac-bleed-margin: var(--__ac-bleed-margin-xs); + --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xs); + --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xs); + + margin: var(--__ac-bleed-margin); + margin-inline: var(--__ac-bleed-margin-inline); + margin-block: var(--__ac-bleed-margin-block); +} diff --git a/@navikt/core/css/primitives/index.css b/@navikt/core/css/primitives/index.css index ce09333bc2..9a228b1625 100644 --- a/@navikt/core/css/primitives/index.css +++ b/@navikt/core/css/primitives/index.css @@ -1,4 +1,5 @@ @import "box.css"; +@import "bleed.css"; @import "hgrid.css"; @import "stack.css"; @import "responsive.css"; diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx new file mode 100644 index 0000000000..42e99295bb --- /dev/null +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import type { Meta } from "@storybook/react"; +import { BodyLong } from "../../typography"; +import { Bleed } from "./Bleed"; +import { Box } from "../.."; + +export default { + title: "ds-react/Primitives/Bleed", + component: Bleed, +} satisfies Meta; + +export const Default = { + render: () => ( + + + + + + This is inside a Bleed. Deserunt veniam eu fugiat ad est occaecat + aliqua nisi aliquip. Aute amet occaecat ex aliqua irure elit + labore pariatur. Proident pariatur proident pariatur magna + consequat velit id commodo quis sunt tempor ullamco aliquip + pariatur. + + + + + + ), +}; diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx new file mode 100644 index 0000000000..fb2a6c0d5c --- /dev/null +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -0,0 +1,76 @@ +import cl from "clsx"; +import React, { forwardRef } from "react"; +import { + ResponsiveProp, + SpacingScale, + getResponsiveProps, +} from "../utilities/css"; + +export interface BleedProps extends React.HTMLAttributes { + /** **Negative** margin around children. */ + margin?: ResponsiveProp; + /** **Negative** horizontal margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. + * @example + * marginInline='4' + * marginInline='4 5' + * marginInline={{xs: '0 32', sm: '3', md: '4 5', lg: '5', xl: '6'}} + */ + marginInline?: ResponsiveProp< + SpacingScale | `${SpacingScale} ${SpacingScale}` + >; + /** **Negative** vertical margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. + * @example + * marginBlock='4' + * marginBlock='4 5' + * marginBlock={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}} + */ + marginBlock?: ResponsiveProp< + SpacingScale | `${SpacingScale} ${SpacingScale}` + >; +} + +/** + * Foundational Layout-primitive for generic encapsulation & styling. + * + * @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/Bleed) + * @see 🏷️ {@link BleedProps} + * @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support + * + * @example // TODO + */ +export const Bleed = forwardRef( + ( + { className, margin, marginInline, marginBlock, style: _style, ...rest }, + ref + ) => { + const style: React.CSSProperties = { + ..._style, + ...getResponsiveProps("bleed", "margin", "spacing", margin, true, ["0"]), + ...getResponsiveProps( + "bleed", + "margin-inline", + "spacing", + marginInline, + true, + ["0"] + ), + ...getResponsiveProps( + "bleed", + "margin-block", + "spacing", + marginBlock, + true, + ["0"] + ), + }; + + return ( +
+ ); + } +); diff --git a/@navikt/core/react/src/layout/bleed/index.ts b/@navikt/core/react/src/layout/bleed/index.ts new file mode 100644 index 0000000000..102f10d905 --- /dev/null +++ b/@navikt/core/react/src/layout/bleed/index.ts @@ -0,0 +1 @@ +export { Bleed, type BleedProps } from "./Bleed"; diff --git a/@navikt/core/react/src/layout/box/Box.tsx b/@navikt/core/react/src/layout/box/Box.tsx index 6e4cea1ea1..ab5651dfb7 100644 --- a/@navikt/core/react/src/layout/box/Box.tsx +++ b/@navikt/core/react/src/layout/box/Box.tsx @@ -129,6 +129,7 @@ export const Box: OverridableComponent = forwardRef( "border-radius", "border-radius", borderRadius, + false, ["0"] ), ...getResponsiveProps("box", "padding", "spacing", padding), diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index f534d2a931..7659350755 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -63,6 +63,7 @@ export function getResponsiveProps( componentProp: string, tokenSubgroup: string, responsiveProp?: ResponsiveProp, + invert = false, tokenExceptions: string[] = [] ) { if (!responsiveProp) { @@ -73,9 +74,15 @@ export function getResponsiveProps( return { [`--__ac-${componentName}-${componentProp}-xs`]: responsiveProp .split(" ") - .map((x) => - tokenExceptions.includes(x) ? x : `var(--a-${tokenSubgroup}-${x})` - ) + .map((x) => { + if (tokenExceptions.includes(x)) { + return x; + } + if (invert) { + return `calc(-1 * var(--a-${tokenSubgroup}-${x}))`; + } + return `var(--a-${tokenSubgroup}-${x})`; + }) .join(" "), }; } @@ -86,9 +93,15 @@ export function getResponsiveProps( `--__ac-${componentName}-${componentProp}-${breakpointAlias}`, aliasOrScale .split(" ") - .map((x) => - tokenExceptions.includes(x) ? x : `var(--a-${tokenSubgroup}-${x})` - ) + .map((x) => { + if (tokenExceptions.includes(x)) { + return x; + } + if (invert) { + return `calc(-1 * var(--a-${tokenSubgroup}-${x}))`; + } + return `var(--a-${tokenSubgroup}-${x})`; + }) .join(" "), ]; }) From 6639529c98758f210deb43ae242c161387fc0a5a Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Thu, 14 Sep 2023 13:08:05 +0200 Subject: [PATCH 02/18] :construction: WIP on Bleed --- .../react/src/layout/bleed/Bleed.stories.tsx | 105 ++++++++++++++++-- @navikt/core/react/src/layout/bleed/Bleed.tsx | 29 +++-- .../core/react/src/layout/utilities/css.ts | 71 ++++++++---- 3 files changed, 165 insertions(+), 40 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 42e99295bb..701bc0bfa7 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -2,7 +2,7 @@ import React from "react"; import type { Meta } from "@storybook/react"; import { BodyLong } from "../../typography"; import { Bleed } from "./Bleed"; -import { Box } from "../.."; +import { Box, HStack, VStack } from "../.."; export default { title: "ds-react/Primitives/Bleed", @@ -10,21 +10,108 @@ export default { } satisfies Meta; export const Default = { + render: () => ( + <> + + + + + + + marginInline="20 0" + + + + + + + + + marginInline="0 20" + + + + + + + + + marginBlock="20 0" + + + + + + + + + + marginBlock="0 20" + + + + + + + + ), +}; + +export const px = { render: () => ( - + - - This is inside a Bleed. Deserunt veniam eu fugiat ad est occaecat - aliqua nisi aliquip. Aute amet occaecat ex aliqua irure elit - labore pariatur. Proident pariatur proident pariatur magna - consequat velit id commodo quis sunt tempor ullamco aliquip - pariatur. - + marginInline="20 0" ), }; + +export const full = { + render: () => ( + + + + + + margin="full" + + + + + + + + + marginInline="full" + + + + + + + + + marginInline="full 0" + + + + + + ), +}; diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index fb2a6c0d5c..a2dc4bba3e 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -6,9 +6,20 @@ import { getResponsiveProps, } from "../utilities/css"; -export interface BleedProps extends React.HTMLAttributes { +type AllowedSpacing = "0" | "full" | "px" | SpacingScale; + +interface AsChild { + /** + * If true, the children of the component will be rendered in place of itself. The rendered child(ren) will respect all props applied to it/them via a parent using the `asChild` prop. This removes mostly empty "wrapper" components from the DOM tree. + */ + asChild?: boolean; +} + +export interface BleedProps + extends React.HTMLAttributes, + AsChild { /** **Negative** margin around children. */ - margin?: ResponsiveProp; + margin?: ResponsiveProp; /** **Negative** horizontal margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example * marginInline='4' @@ -16,7 +27,7 @@ export interface BleedProps extends React.HTMLAttributes { * marginInline={{xs: '0 32', sm: '3', md: '4 5', lg: '5', xl: '6'}} */ marginInline?: ResponsiveProp< - SpacingScale | `${SpacingScale} ${SpacingScale}` + AllowedSpacing | `${AllowedSpacing} ${AllowedSpacing}` >; /** **Negative** vertical margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example @@ -25,7 +36,7 @@ export interface BleedProps extends React.HTMLAttributes { * marginBlock={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}} */ marginBlock?: ResponsiveProp< - SpacingScale | `${SpacingScale} ${SpacingScale}` + AllowedSpacing | `${AllowedSpacing} ${AllowedSpacing}` >; } @@ -45,14 +56,18 @@ export const Bleed = forwardRef( ) => { const style: React.CSSProperties = { ..._style, - ...getResponsiveProps("bleed", "margin", "spacing", margin, true, ["0"]), + ...getResponsiveProps("bleed", "margin", "spacing", margin, true, [ + "0", + "full", + "px", + ]), ...getResponsiveProps( "bleed", "margin-inline", "spacing", marginInline, true, - ["0"] + ["0", "full", "px"] ), ...getResponsiveProps( "bleed", @@ -60,7 +75,7 @@ export const Bleed = forwardRef( "spacing", marginBlock, true, - ["0"] + ["0", "full", "px"] ), }; diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index 7659350755..cbf7b17746 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -58,6 +58,40 @@ export function getResponsiveValue( ); } +const translateExceptionToCSS = (exception: string) => { + switch (exception) { + case "full": + return "100%"; + case "px": + return "1px"; + } + return exception; +}; + +const translateTokenStringToCSS = ( + tokenString: string, + tokenSubgroup: string, + tokenExceptions: string[], + invert: boolean +) => { + return tokenString + .split(" ") + .map((x) => { + let output = `var(--a-${tokenSubgroup}-${x})`; + if (tokenExceptions.includes(x)) { + output = translateExceptionToCSS(x); + } + if (invert) { + if (x === "0") { + return `0`; + } + return `calc(-1 * ${output})`; + } + return output; + }) + .join(" "); +}; + export function getResponsiveProps( componentName: string, componentProp: string, @@ -72,18 +106,13 @@ export function getResponsiveProps( if (typeof responsiveProp === "string") { return { - [`--__ac-${componentName}-${componentProp}-xs`]: responsiveProp - .split(" ") - .map((x) => { - if (tokenExceptions.includes(x)) { - return x; - } - if (invert) { - return `calc(-1 * var(--a-${tokenSubgroup}-${x}))`; - } - return `var(--a-${tokenSubgroup}-${x})`; - }) - .join(" "), + [`--__ac-${componentName}-${componentProp}-xs`]: + translateTokenStringToCSS( + responsiveProp, + tokenSubgroup, + tokenExceptions, + invert + ), }; } @@ -91,18 +120,12 @@ export function getResponsiveProps( Object.entries(responsiveProp).map(([breakpointAlias, aliasOrScale]) => { return [ `--__ac-${componentName}-${componentProp}-${breakpointAlias}`, - aliasOrScale - .split(" ") - .map((x) => { - if (tokenExceptions.includes(x)) { - return x; - } - if (invert) { - return `calc(-1 * var(--a-${tokenSubgroup}-${x}))`; - } - return `var(--a-${tokenSubgroup}-${x})`; - }) - .join(" "), + translateTokenStringToCSS( + aliasOrScale, + tokenSubgroup, + tokenExceptions, + invert + ), ]; }) ); From 9dde205b0d9dff1288b24789087e4e16c3236c0a Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Thu, 14 Sep 2023 15:44:01 +0200 Subject: [PATCH 03/18] :construction: fix the weirdness of margin-block-end by adding padding --- .../react/src/layout/bleed/Bleed.stories.tsx | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 701bc0bfa7..37ca02d464 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -14,6 +14,9 @@ export const Default = { <> - - - - - marginInline="20 0" + + + + + marginInline="10 0" - - - - - marginInline="0 20" + + + + + marginInline="0 10" - - - - - marginBlock="20 0" + + + + + marginBlock="10 0" - - - - + + + + - marginBlock="0 20" + marginBlock="0 10" From bb308d126b74111a84cc50e6ded8f4b29528ffcc Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Fri, 15 Sep 2023 11:01:56 +0200 Subject: [PATCH 04/18] :construction: wip for bleed calculation of "full" --- .../react/src/layout/bleed/Bleed.stories.tsx | 79 +++++++++++++------ .../core/react/src/layout/utilities/css.ts | 16 +++- 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 37ca02d464..dd7105b85d 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -86,35 +86,62 @@ export const px = { }; export const full = { + parameters: { + layout: "fullscreen", + }, render: () => ( - - - - - - margin="full" - - + <> + + + + + + + marginInline="full" + + + - - - - - - marginInline="full" - - + + + + + marginInline="full 0" + + + - - - - - - marginInline="full 0" - - + + + + + marginInline="full 0" + + + - - + + ), }; diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index cbf7b17746..8a7c04f8ec 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -60,8 +60,6 @@ export function getResponsiveValue( const translateExceptionToCSS = (exception: string) => { switch (exception) { - case "full": - return "100%"; case "px": return "1px"; } @@ -69,6 +67,7 @@ const translateExceptionToCSS = (exception: string) => { }; const translateTokenStringToCSS = ( + componentProp: string, tokenString: string, tokenSubgroup: string, tokenExceptions: string[], @@ -76,7 +75,16 @@ const translateTokenStringToCSS = ( ) => { return tokenString .split(" ") - .map((x) => { + .map((x, _, arr) => { + if (componentProp === "margin-inline" && x === "full") { + const width = 100 / arr.length; + return `calc((100vw - ${width}%)/2)`; + } + if (componentProp === "margin-block" && x === "full") { + const height = 100 / arr.length; + return `calc((100vh - ${height}%)/2)`; + } + let output = `var(--a-${tokenSubgroup}-${x})`; if (tokenExceptions.includes(x)) { output = translateExceptionToCSS(x); @@ -108,6 +116,7 @@ export function getResponsiveProps( return { [`--__ac-${componentName}-${componentProp}-xs`]: translateTokenStringToCSS( + componentProp, responsiveProp, tokenSubgroup, tokenExceptions, @@ -121,6 +130,7 @@ export function getResponsiveProps( return [ `--__ac-${componentName}-${componentProp}-${breakpointAlias}`, translateTokenStringToCSS( + componentProp, aliasOrScale, tokenSubgroup, tokenExceptions, From 04484e04432c59511bb3215f9261068fb1e44d78 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 18 Sep 2023 10:22:00 +0200 Subject: [PATCH 05/18] Bleed working "full" horizontal margin --- @navikt/core/react/src/layout/bleed/Bleed.stories.tsx | 2 +- @navikt/core/react/src/layout/utilities/css.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index dd7105b85d..24940c96be 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -136,7 +136,7 @@ export const full = { - marginInline="full 0" + marginBlock="full" diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index 8a7c04f8ec..c8e5ae1781 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -78,7 +78,7 @@ const translateTokenStringToCSS = ( .map((x, _, arr) => { if (componentProp === "margin-inline" && x === "full") { const width = 100 / arr.length; - return `calc((100vw - ${width}%)/2)`; + return `calc((100vw - ${width}%)/-2)`; } if (componentProp === "margin-block" && x === "full") { const height = 100 / arr.length; From e8d7e1601095f3c7609c34be2ce3f4acfee17e47 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 18 Sep 2023 16:10:44 +0200 Subject: [PATCH 06/18] :construction: wip on reflectivePadding --- .../react/src/layout/bleed/Bleed.stories.tsx | 58 +++++++++++-- @navikt/core/react/src/layout/bleed/Bleed.tsx | 35 ++++---- .../core/react/src/layout/utilities/css.ts | 85 +++++++++++++++++++ 3 files changed, 154 insertions(+), 24 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 24940c96be..17b754910b 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -32,7 +32,7 @@ export const Default = { - marginInline="10 0" + marginInline="10 0" @@ -41,7 +41,7 @@ export const Default = { - marginInline="0 10" + marginInline="0 10" @@ -50,7 +50,7 @@ export const Default = { - marginBlock="10 0" + marginBlock="10 0" @@ -60,7 +60,7 @@ export const Default = { - marginBlock="0 10" + marginBlock="0 10" @@ -77,7 +77,7 @@ export const px = { - marginInline="20 0" + marginInline="20 0" @@ -110,7 +110,7 @@ export const full = { - marginInline="full" + marginInline="full" @@ -123,7 +123,7 @@ export const full = { - marginInline="full 0" + marginInline="full 0" @@ -134,9 +134,9 @@ export const full = { padding="10" > - + - marginBlock="full" + marginInline="0 full" @@ -145,3 +145,43 @@ export const full = { ), }; + +export const reflectivePadding = { + render: () => ( + <> +

+ Only really works
when asChild is implemented +

+ + + + + + before Bleed + + + + + + + without reflectivePadding + + + + + + + with reflectivePadding + + + + + + ), +}; diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index a2dc4bba3e..27e8505dad 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -4,22 +4,14 @@ import { ResponsiveProp, SpacingScale, getResponsiveProps, + mirrorMargin, } from "../utilities/css"; -type AllowedSpacing = "0" | "full" | "px" | SpacingScale; +export type BleedSpacing = "0" | "full" | "px" | SpacingScale; -interface AsChild { - /** - * If true, the children of the component will be rendered in place of itself. The rendered child(ren) will respect all props applied to it/them via a parent using the `asChild` prop. This removes mostly empty "wrapper" components from the DOM tree. - */ - asChild?: boolean; -} - -export interface BleedProps - extends React.HTMLAttributes, - AsChild { +export interface BleedProps extends React.HTMLAttributes { /** **Negative** margin around children. */ - margin?: ResponsiveProp; + margin?: ResponsiveProp; /** **Negative** horizontal margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example * marginInline='4' @@ -27,7 +19,7 @@ export interface BleedProps * marginInline={{xs: '0 32', sm: '3', md: '4 5', lg: '5', xl: '6'}} */ marginInline?: ResponsiveProp< - AllowedSpacing | `${AllowedSpacing} ${AllowedSpacing}` + BleedSpacing | `${BleedSpacing} ${BleedSpacing}` >; /** **Negative** vertical margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example @@ -36,8 +28,12 @@ export interface BleedProps * marginBlock={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}} */ marginBlock?: ResponsiveProp< - AllowedSpacing | `${AllowedSpacing} ${AllowedSpacing}` + BleedSpacing | `${BleedSpacing} ${BleedSpacing}` >; + /** + * When true, set the padding to mirror the margin. This maintains the apparent width of the element prior to adding Bleed. + */ + reflectivePadding?: boolean; } /** @@ -51,7 +47,15 @@ export interface BleedProps */ export const Bleed = forwardRef( ( - { className, margin, marginInline, marginBlock, style: _style, ...rest }, + { + className, + margin, + marginInline, + marginBlock, + reflectivePadding, + style: _style, + ...rest + }, ref ) => { const style: React.CSSProperties = { @@ -77,6 +81,7 @@ export const Bleed = forwardRef( true, ["0", "full", "px"] ), + ...mirrorMargin(reflectivePadding, margin, marginInline, marginBlock), }; return ( diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index d7c39490a7..87e3e53441 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -1,3 +1,5 @@ +import { BleedSpacing } from "../bleed/Bleed"; + export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl"; export type SpacingScale = @@ -139,3 +141,86 @@ export function getResponsiveProps( }) ); } + +export const mirrorMargin = ( + reflectivePadding: boolean | undefined, + margin: ResponsiveProp | undefined, + marginInline: + | ResponsiveProp + | undefined, + marginBlock: + | ResponsiveProp + | undefined +): + | { paddingInline: string | undefined; paddingBlock: string | undefined } + | undefined => { + if (!reflectivePadding) { + return undefined; + } + + let currentMarginInline = ""; + let currentMarginBlock = ""; + + // margin + // the 4 string cases we need to handle: + // N [E=N] [S=N] [W=N] + // N E [S=N] [W=E] + // N E S [W=E] + // N E S W + + // marginInline, string cases + // W [E=W] + // W E + + // marginBlock, string cases + // N [S=N] + // N S + + // then do the same thing above for each breakpoint in object + + if (margin) { + if (typeof margin === "string") { + // string cases + const directions = margin.split(" "); + + if (directions.length === 1) { + currentMarginInline = margin; + currentMarginBlock = margin; + } else if (directions.length === 2) { + currentMarginInline = directions[1]; + currentMarginBlock = directions[0]; + } else if (directions.length === 3) { + currentMarginInline = directions[1]; + currentMarginBlock = [directions[0], directions[2]].join(" "); + } else { + currentMarginInline = [directions[1], directions[3]].join(" "); + currentMarginBlock = [directions[0], directions[2]].join(" "); + } + } + } + if (marginInline) { + if (typeof marginInline === "string") { + currentMarginInline = marginInline; + } + } + if (marginBlock) { + if (typeof marginBlock === "string") { + currentMarginBlock = marginBlock; + } + } + + return { + paddingInline: !currentMarginInline + ? undefined + : currentMarginInline + .split(" ") + .map((x) => (x === "0" ? "0" : `var(--a-spacing-${x})`)) + .join(" "), + paddingBlock: !currentMarginBlock + ? undefined + : currentMarginBlock + .split(" ") + .map((x) => (x === "0" ? "0" : `var(--a-spacing-${x})`)) + .join(" "), + }; +}; From 9c3c0aee04d35d85ea39114f0a07566414a954da Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Tue, 19 Sep 2023 11:24:49 +0200 Subject: [PATCH 07/18] :construction: wip breakpoints for bleed reflectivePadding --- @navikt/core/css/primitives/bleed.css | 60 +++++++-- .../react/src/layout/bleed/Bleed.stories.tsx | 118 ++++++++++++++---- 2 files changed, 139 insertions(+), 39 deletions(-) diff --git a/@navikt/core/css/primitives/bleed.css b/@navikt/core/css/primitives/bleed.css index 0a6748a8b1..3bd5089369 100644 --- a/@navikt/core/css/primitives/bleed.css +++ b/@navikt/core/css/primitives/bleed.css @@ -1,19 +1,21 @@ .navds-bleed { --__ac-bleed-margin-xs: initial; - --__ac-bleed-margin-sm: initial; - --__ac-bleed-margin-md: initial; - --__ac-bleed-margin-lg: initial; - --__ac-bleed-margin-xl: initial; - --__ac-bleed-margin-block-xs: initial; + --__ac-bleed-margin-sm: var(--__ac-bleed-margin-xs); + --__ac-bleed-margin-md: var(--__ac-bleed-margin-sm); + --__ac-bleed-margin-lg: var(--__ac-bleed-margin-md); + --__ac-bleed-margin-xl: var(--__ac-bleed-margin-lg); --__ac-bleed-margin-inline-xs: initial; - --__ac-bleed-margin-block-sm: initial; - --__ac-bleed-margin-inline-sm: initial; - --__ac-bleed-margin-block-md: initial; - --__ac-bleed-margin-inline-md: initial; - --__ac-bleed-margin-block-lg: initial; - --__ac-bleed-margin-inline-lg: initial; - --__ac-bleed-margin-block-xl: initial; - --__ac-bleed-margin-inline-xl: initial; + --__ac-bleed-margin-inline-sm: var(--__ac-bleed-margin-inline-xs); + --__ac-bleed-margin-inline-md: var(--__ac-bleed-margin-inline-sm); + --__ac-bleed-margin-inline-lg: var(--__ac-bleed-margin-inline-md); + --__ac-bleed-margin-inline-xl: var(--__ac-bleed-margin-inline-lg); + --__ac-bleed-margin-block-xs: initial; + --__ac-bleed-margin-block-sm: var(--__ac-bleed-margin-block-xs); + --__ac-bleed-margin-block-md: var(--__ac-bleed-margin-block-sm); + --__ac-bleed-margin-block-lg: var(--__ac-bleed-margin-block-md); + --__ac-bleed-margin-block-xl: var(--__ac-bleed-margin-block-lg); + + /** --- */ --__ac-bleed-margin: var(--__ac-bleed-margin-xs); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xs); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xs); @@ -22,3 +24,35 @@ margin-inline: var(--__ac-bleed-margin-inline); margin-block: var(--__ac-bleed-margin-block); } + +@media (min-width: 480px) { + .navds-bleed { + --__ac-bleed-margin: var(--__ac-bleed-margin-sm); + --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-sm); + --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-sm); + } +} + +@media (min-width: 768px) { + .navds-bleed { + --__ac-bleed-margin: var(--__ac-bleed-margin-md); + --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-md); + --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-md); + } +} + +@media (min-width: 1024px) { + .navds-bleed { + --__ac-bleed-margin: var(--__ac-bleed-margin-lg); + --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-lg); + --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-lg); + } +} + +@media (min-width: 1280px) { + .navds-bleed { + --__ac-bleed-margin: var(--__ac-bleed-margin-xl); + --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xl); + --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xl); + } +} diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 17b754910b..14fffa6acd 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -71,7 +71,7 @@ export const Default = { ), }; -export const px = { +export const Px = { render: () => ( @@ -85,7 +85,7 @@ export const px = { ), }; -export const full = { +export const Full = { parameters: { layout: "fullscreen", }, @@ -146,42 +146,108 @@ export const full = { ), }; -export const reflectivePadding = { +export const ReflectivePadding = { render: () => ( <> -

- Only really works
when asChild is implemented -

- - - - - before Bleed - +

+ Note: reflectivePadding Only really works
when asChild is + implemented +

+

Note2: "full" is not supported for marginBlock

+ + +

CSS string

+ + + + before Bleed + + -
- - - - without reflectivePadding - + + + + without reflectivePadding + + - - - - - with reflectivePadding - + + + + with reflectivePadding + + - -
+ + + +

breakpoints

+ + + + before Bleed + + + + + + + without reflectivePadding + + + + + + + with reflectivePadding + + + +
+ ), }; From a327b9a006b2864b59f28de1d52fd8e42ee02409 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Wed, 20 Sep 2023 11:28:53 +0200 Subject: [PATCH 08/18] working reflectivePadding --- @navikt/core/css/primitives/bleed.css | 53 +++++- .../react/src/layout/bleed/Bleed.stories.tsx | 2 +- @navikt/core/react/src/layout/bleed/Bleed.tsx | 6 +- .../core/react/src/layout/utilities/css.ts | 164 ++++++------------ 4 files changed, 111 insertions(+), 114 deletions(-) diff --git a/@navikt/core/css/primitives/bleed.css b/@navikt/core/css/primitives/bleed.css index 3bd5089369..8f6c506422 100644 --- a/@navikt/core/css/primitives/bleed.css +++ b/@navikt/core/css/primitives/bleed.css @@ -15,7 +15,7 @@ --__ac-bleed-margin-block-lg: var(--__ac-bleed-margin-block-md); --__ac-bleed-margin-block-xl: var(--__ac-bleed-margin-block-lg); - /** --- */ + /** defaults */ --__ac-bleed-margin: var(--__ac-bleed-margin-xs); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xs); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xs); @@ -25,12 +25,45 @@ margin-block: var(--__ac-bleed-margin-block); } +.navds-bleed--padding { + --__ac-bleed-padding-xs: initial; + --__ac-bleed-padding-sm: var(--__ac-bleed-padding-xs); + --__ac-bleed-padding-md: var(--__ac-bleed-padding-sm); + --__ac-bleed-padding-lg: var(--__ac-bleed-padding-md); + --__ac-bleed-padding-xl: var(--__ac-bleed-padding-lg); + --__ac-bleed-padding-inline-xs: initial; + --__ac-bleed-padding-inline-sm: var(--__ac-bleed-padding-inline-xs); + --__ac-bleed-padding-inline-md: var(--__ac-bleed-padding-inline-sm); + --__ac-bleed-padding-inline-lg: var(--__ac-bleed-padding-inline-md); + --__ac-bleed-padding-inline-xl: var(--__ac-bleed-padding-inline-lg); + --__ac-bleed-padding-block-xs: initial; + --__ac-bleed-padding-block-sm: var(--__ac-bleed-padding-block-xs); + --__ac-bleed-padding-block-md: var(--__ac-bleed-padding-block-sm); + --__ac-bleed-padding-block-lg: var(--__ac-bleed-padding-block-md); + --__ac-bleed-padding-block-xl: var(--__ac-bleed-padding-block-lg); + + /** defaults */ + --__ac-bleed-padding: var(--__ac-bleed-padding-xs); + --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-xs); + --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-xs); + + padding: var(--__ac-bleed-padding); + padding-inline: var(--__ac-bleed-padding-inline); + padding-block: var(--__ac-bleed-padding-block); +} + @media (min-width: 480px) { .navds-bleed { --__ac-bleed-margin: var(--__ac-bleed-margin-sm); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-sm); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-sm); } + + .navds-bleed--padding { + --__ac-bleed-padding: var(--__ac-bleed-padding-sm); + --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-sm); + --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-sm); + } } @media (min-width: 768px) { @@ -39,6 +72,12 @@ --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-md); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-md); } + + .navds-bleed--padding { + --__ac-bleed-padding: var(--__ac-bleed-padding-md); + --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-md); + --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-md); + } } @media (min-width: 1024px) { @@ -47,6 +86,12 @@ --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-lg); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-lg); } + + .navds-bleed--padding { + --__ac-bleed-padding: var(--__ac-bleed-padding-lg); + --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-lg); + --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-lg); + } } @media (min-width: 1280px) { @@ -55,4 +100,10 @@ --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xl); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xl); } + + .navds-bleed--padding { + --__ac-bleed-padding: var(--__ac-bleed-padding-xl); + --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-xl); + --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-xl); + } } diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 14fffa6acd..e325a29ccd 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -158,7 +158,7 @@ export const ReflectivePadding = { `}

- Note: reflectivePadding Only really works
when asChild is + Note: reflectivePadding Only really works
well when asChild is implemented

Note2: "full" is not supported for marginBlock

diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index 27e8505dad..a1d7c7e68f 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -4,7 +4,6 @@ import { ResponsiveProp, SpacingScale, getResponsiveProps, - mirrorMargin, } from "../utilities/css"; export type BleedSpacing = "0" | "full" | "px" | SpacingScale; @@ -81,13 +80,14 @@ export const Bleed = forwardRef( true, ["0", "full", "px"] ), - ...mirrorMargin(reflectivePadding, margin, marginInline, marginBlock), }; return (
diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index 87e3e53441..fa9f31d5be 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -1,5 +1,3 @@ -import { BleedSpacing } from "../bleed/Bleed"; - export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl"; export type SpacingScale = @@ -114,113 +112,61 @@ export function getResponsiveProps( } if (typeof responsiveProp === "string") { - return { - [`--__ac-${componentName}-${componentProp}-xs`]: - translateTokenStringToCSS( - componentProp, - responsiveProp, - tokenSubgroup, - tokenExceptions, - invert - ), - }; - } - - return Object.fromEntries( - Object.entries(responsiveProp).map(([breakpointAlias, aliasOrScale]) => { - return [ - `--__ac-${componentName}-${componentProp}-${breakpointAlias}`, - translateTokenStringToCSS( - componentProp, - aliasOrScale, - tokenSubgroup, - tokenExceptions, - invert - ), - ]; - }) - ); -} - -export const mirrorMargin = ( - reflectivePadding: boolean | undefined, - margin: ResponsiveProp | undefined, - marginInline: - | ResponsiveProp - | undefined, - marginBlock: - | ResponsiveProp - | undefined -): - | { paddingInline: string | undefined; paddingBlock: string | undefined } - | undefined => { - if (!reflectivePadding) { - return undefined; - } - - let currentMarginInline = ""; - let currentMarginBlock = ""; - - // margin - // the 4 string cases we need to handle: - // N [E=N] [S=N] [W=N] - // N E [S=N] [W=E] - // N E S [W=E] - // N E S W - - // marginInline, string cases - // W [E=W] - // W E - - // marginBlock, string cases - // N [S=N] - // N S - - // then do the same thing above for each breakpoint in object - - if (margin) { - if (typeof margin === "string") { - // string cases - const directions = margin.split(" "); - - if (directions.length === 1) { - currentMarginInline = margin; - currentMarginBlock = margin; - } else if (directions.length === 2) { - currentMarginInline = directions[1]; - currentMarginBlock = directions[0]; - } else if (directions.length === 3) { - currentMarginInline = directions[1]; - currentMarginBlock = [directions[0], directions[2]].join(" "); - } else { - currentMarginInline = [directions[1], directions[3]].join(" "); - currentMarginBlock = [directions[0], directions[2]].join(" "); - } - } - } - if (marginInline) { - if (typeof marginInline === "string") { - currentMarginInline = marginInline; - } - } - if (marginBlock) { - if (typeof marginBlock === "string") { - currentMarginBlock = marginBlock; + const styleProps = {}; + styleProps[`--__ac-${componentName}-${componentProp}-xs`] = + translateTokenStringToCSS( + componentProp, + responsiveProp, + tokenSubgroup, + tokenExceptions, + invert + ); + // re-calculate purely to add the inverse of resulting margin as padding + // but only do this in the case where reflectivePadding is true + if (["margin", "margin-inline", "margin-block"].includes(componentProp)) { + styleProps[ + `--__ac-${componentName}-${componentProp.replace( + "margin", + "padding" + )}-xs` + ] = translateTokenStringToCSS( + componentProp, + responsiveProp, + tokenSubgroup, + tokenExceptions, + !invert + ); } + return styleProps; } - return { - paddingInline: !currentMarginInline - ? undefined - : currentMarginInline - .split(" ") - .map((x) => (x === "0" ? "0" : `var(--a-spacing-${x})`)) - .join(" "), - paddingBlock: !currentMarginBlock - ? undefined - : currentMarginBlock - .split(" ") - .map((x) => (x === "0" ? "0" : `var(--a-spacing-${x})`)) - .join(" "), - }; -}; + const styleProps = {}; + Object.entries(responsiveProp).forEach(([breakpointAlias, aliasOrScale]) => { + styleProps[`--__ac-${componentName}-${componentProp}-${breakpointAlias}`] = + translateTokenStringToCSS( + componentProp, + aliasOrScale, + tokenSubgroup, + tokenExceptions, + invert + ); + // re-calculate purely to add the inverse of resulting margin as padding + // but only do this in the case where reflectivePadding is true + if (["margin", "margin-inline", "margin-block"].includes(componentProp)) { + styleProps[ + `--__ac-${componentName}-${componentProp.replace( + "margin", + "padding" + )}-${breakpointAlias}` + ] = translateTokenStringToCSS( + componentProp, + aliasOrScale, + tokenSubgroup, + tokenExceptions, + !invert + ); + } + return Object.entries(styleProps); + }); + return styleProps; +} From 779990af3a6f4d035db825385ea91d1c6082fa9e Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Wed, 20 Sep 2023 13:28:00 +0200 Subject: [PATCH 09/18] :memo: add jsdoc --- @navikt/core/react/src/layout/bleed/Bleed.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index a1d7c7e68f..cccdc76eeb 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -42,7 +42,12 @@ export interface BleedProps extends React.HTMLAttributes { * @see 🏷️ {@link BleedProps} * @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support * - * @example // TODO + * @example + * + * + * Some content + * + * */ export const Bleed = forwardRef( ( From 25c9faf7bb28696529b090c262bb25f1919bf3fa Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 11:00:18 +0200 Subject: [PATCH 10/18] :recycle: refactor css.ts --- .../react/src/layout/bleed/Bleed.stories.tsx | 1 - @navikt/core/react/src/layout/bleed/Bleed.tsx | 42 +++++++++++++------ .../core/react/src/layout/utilities/css.ts | 36 ---------------- 3 files changed, 29 insertions(+), 50 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index e325a29ccd..2a33e3dd2e 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -161,7 +161,6 @@ export const ReflectivePadding = { Note: reflectivePadding Only really works
well when asChild is implemented -

Note2: "full" is not supported for marginBlock

CSS string

diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index cccdc76eeb..c9f8f39100 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -6,11 +6,10 @@ import { getResponsiveProps, } from "../utilities/css"; -export type BleedSpacing = "0" | "full" | "px" | SpacingScale; +export type BleedSpacingInline = "0" | "full" | "px" | SpacingScale; +export type BleedSpacingBlock = "0" | "px" | SpacingScale; export interface BleedProps extends React.HTMLAttributes { - /** **Negative** margin around children. */ - margin?: ResponsiveProp; /** **Negative** horizontal margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example * marginInline='4' @@ -18,7 +17,7 @@ export interface BleedProps extends React.HTMLAttributes { * marginInline={{xs: '0 32', sm: '3', md: '4 5', lg: '5', xl: '6'}} */ marginInline?: ResponsiveProp< - BleedSpacing | `${BleedSpacing} ${BleedSpacing}` + BleedSpacingInline | `${BleedSpacingInline} ${BleedSpacingInline}` >; /** **Negative** vertical margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example @@ -27,7 +26,7 @@ export interface BleedProps extends React.HTMLAttributes { * marginBlock={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}} */ marginBlock?: ResponsiveProp< - BleedSpacing | `${BleedSpacing} ${BleedSpacing}` + BleedSpacingBlock | `${BleedSpacingBlock} ${BleedSpacingBlock}` >; /** * When true, set the padding to mirror the margin. This maintains the apparent width of the element prior to adding Bleed. @@ -53,7 +52,6 @@ export const Bleed = forwardRef( ( { className, - margin, marginInline, marginBlock, reflectivePadding, @@ -62,13 +60,8 @@ export const Bleed = forwardRef( }, ref ) => { - const style: React.CSSProperties = { + let style: React.CSSProperties = { ..._style, - ...getResponsiveProps("bleed", "margin", "spacing", margin, true, [ - "0", - "full", - "px", - ]), ...getResponsiveProps( "bleed", "margin-inline", @@ -77,16 +70,39 @@ export const Bleed = forwardRef( true, ["0", "full", "px"] ), + ...getResponsiveProps( "bleed", "margin-block", "spacing", marginBlock, true, - ["0", "full", "px"] + ["0", "px"] ), }; + if (reflectivePadding) { + style = { + ...style, + ...getResponsiveProps( + "bleed", + "padding-inline", + "spacing", + marginInline, + false, + ["0", "full", "px"] + ), + ...getResponsiveProps( + "bleed", + "padding-block", + "spacing", + marginBlock, + false, + ["0", "px"] + ), + }; + } + return (
( tokenExceptions, invert ); - // re-calculate purely to add the inverse of resulting margin as padding - // but only do this in the case where reflectivePadding is true - if (["margin", "margin-inline", "margin-block"].includes(componentProp)) { - styleProps[ - `--__ac-${componentName}-${componentProp.replace( - "margin", - "padding" - )}-xs` - ] = translateTokenStringToCSS( - componentProp, - responsiveProp, - tokenSubgroup, - tokenExceptions, - !invert - ); - } return styleProps; } @@ -150,22 +130,6 @@ export function getResponsiveProps( tokenExceptions, invert ); - // re-calculate purely to add the inverse of resulting margin as padding - // but only do this in the case where reflectivePadding is true - if (["margin", "margin-inline", "margin-block"].includes(componentProp)) { - styleProps[ - `--__ac-${componentName}-${componentProp.replace( - "margin", - "padding" - )}-${breakpointAlias}` - ] = translateTokenStringToCSS( - componentProp, - aliasOrScale, - tokenSubgroup, - tokenExceptions, - !invert - ); - } return Object.entries(styleProps); }); return styleProps; From 0455d58db5bcf9688d5635ca3d2f5807e8857a86 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 11:11:51 +0200 Subject: [PATCH 11/18] :recycle: refactor style for Bleed --- .../react/src/layout/bleed/Bleed.stories.tsx | 73 +++++++++++++++++++ .../core/react/src/layout/utilities/css.ts | 21 +++--- 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 2a33e3dd2e..ca7b4b9fdf 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -70,6 +70,79 @@ export const Default = { ), }; +export const Breakpoints = { + render: () => ( + <> + + + + + + + marginInline="10 0" + + + + + + + + + marginInline="0 10" + + + + + + + + + marginBlock="10 0" + + + + + + + + + + marginBlock="0 10" + + + + + + + + ), +}; export const Px = { render: () => ( diff --git a/@navikt/core/react/src/layout/utilities/css.ts b/@navikt/core/react/src/layout/utilities/css.ts index 3a6aa90fcc..f8369192a8 100644 --- a/@navikt/core/react/src/layout/utilities/css.ts +++ b/@navikt/core/react/src/layout/utilities/css.ts @@ -108,16 +108,16 @@ export function getResponsiveProps( } if (typeof responsiveProp === "string") { - const styleProps = {}; - styleProps[`--__ac-${componentName}-${componentProp}-xs`] = - translateTokenStringToCSS( - componentProp, - responsiveProp, - tokenSubgroup, - tokenExceptions, - invert - ); - return styleProps; + return { + [`--__ac-${componentName}-${componentProp}-xs`]: + translateTokenStringToCSS( + componentProp, + responsiveProp, + tokenSubgroup, + tokenExceptions, + invert + ), + }; } const styleProps = {}; @@ -130,7 +130,6 @@ export function getResponsiveProps( tokenExceptions, invert ); - return Object.entries(styleProps); }); return styleProps; } From 45b29bd4e8613798ff78c041c698ba5080c6c2e0 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 11:24:27 +0200 Subject: [PATCH 12/18] improve jsdoc, remove unused CSS --- @navikt/core/css/primitives/bleed.css | 22 ------------------- @navikt/core/react/src/layout/bleed/Bleed.tsx | 10 ++++++--- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/@navikt/core/css/primitives/bleed.css b/@navikt/core/css/primitives/bleed.css index 8f6c506422..4046b9b732 100644 --- a/@navikt/core/css/primitives/bleed.css +++ b/@navikt/core/css/primitives/bleed.css @@ -1,9 +1,4 @@ .navds-bleed { - --__ac-bleed-margin-xs: initial; - --__ac-bleed-margin-sm: var(--__ac-bleed-margin-xs); - --__ac-bleed-margin-md: var(--__ac-bleed-margin-sm); - --__ac-bleed-margin-lg: var(--__ac-bleed-margin-md); - --__ac-bleed-margin-xl: var(--__ac-bleed-margin-lg); --__ac-bleed-margin-inline-xs: initial; --__ac-bleed-margin-inline-sm: var(--__ac-bleed-margin-inline-xs); --__ac-bleed-margin-inline-md: var(--__ac-bleed-margin-inline-sm); @@ -16,21 +11,14 @@ --__ac-bleed-margin-block-xl: var(--__ac-bleed-margin-block-lg); /** defaults */ - --__ac-bleed-margin: var(--__ac-bleed-margin-xs); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xs); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xs); - margin: var(--__ac-bleed-margin); margin-inline: var(--__ac-bleed-margin-inline); margin-block: var(--__ac-bleed-margin-block); } .navds-bleed--padding { - --__ac-bleed-padding-xs: initial; - --__ac-bleed-padding-sm: var(--__ac-bleed-padding-xs); - --__ac-bleed-padding-md: var(--__ac-bleed-padding-sm); - --__ac-bleed-padding-lg: var(--__ac-bleed-padding-md); - --__ac-bleed-padding-xl: var(--__ac-bleed-padding-lg); --__ac-bleed-padding-inline-xs: initial; --__ac-bleed-padding-inline-sm: var(--__ac-bleed-padding-inline-xs); --__ac-bleed-padding-inline-md: var(--__ac-bleed-padding-inline-sm); @@ -43,24 +31,20 @@ --__ac-bleed-padding-block-xl: var(--__ac-bleed-padding-block-lg); /** defaults */ - --__ac-bleed-padding: var(--__ac-bleed-padding-xs); --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-xs); --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-xs); - padding: var(--__ac-bleed-padding); padding-inline: var(--__ac-bleed-padding-inline); padding-block: var(--__ac-bleed-padding-block); } @media (min-width: 480px) { .navds-bleed { - --__ac-bleed-margin: var(--__ac-bleed-margin-sm); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-sm); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-sm); } .navds-bleed--padding { - --__ac-bleed-padding: var(--__ac-bleed-padding-sm); --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-sm); --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-sm); } @@ -68,13 +52,11 @@ @media (min-width: 768px) { .navds-bleed { - --__ac-bleed-margin: var(--__ac-bleed-margin-md); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-md); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-md); } .navds-bleed--padding { - --__ac-bleed-padding: var(--__ac-bleed-padding-md); --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-md); --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-md); } @@ -82,13 +64,11 @@ @media (min-width: 1024px) { .navds-bleed { - --__ac-bleed-margin: var(--__ac-bleed-margin-lg); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-lg); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-lg); } .navds-bleed--padding { - --__ac-bleed-padding: var(--__ac-bleed-padding-lg); --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-lg); --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-lg); } @@ -96,13 +76,11 @@ @media (min-width: 1280px) { .navds-bleed { - --__ac-bleed-margin: var(--__ac-bleed-margin-xl); --__ac-bleed-margin-inline: var(--__ac-bleed-margin-inline-xl); --__ac-bleed-margin-block: var(--__ac-bleed-margin-block-xl); } .navds-bleed--padding { - --__ac-bleed-padding: var(--__ac-bleed-padding-xl); --__ac-bleed-padding-inline: var(--__ac-bleed-padding-inline-xl); --__ac-bleed-padding-block: var(--__ac-bleed-padding-block-xl); } diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index c9f8f39100..6db84ff22f 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -10,7 +10,8 @@ export type BleedSpacingInline = "0" | "full" | "px" | SpacingScale; export type BleedSpacingBlock = "0" | "px" | SpacingScale; export interface BleedProps extends React.HTMLAttributes { - /** **Negative** horizontal margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. + /** **Negative** horizontal margin around children. + * Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example * marginInline='4' * marginInline='4 5' @@ -19,7 +20,8 @@ export interface BleedProps extends React.HTMLAttributes { marginInline?: ResponsiveProp< BleedSpacingInline | `${BleedSpacingInline} ${BleedSpacingInline}` >; - /** **Negative** vertical margin around children. Accepts a spacing token or an object of spacing tokens for different breakpoints. + /** **Negative** vertical margin around children. + * Accepts a spacing token or an object of spacing tokens for different breakpoints. * @example * marginBlock='4' * marginBlock='4 5' @@ -29,7 +31,9 @@ export interface BleedProps extends React.HTMLAttributes { BleedSpacingBlock | `${BleedSpacingBlock} ${BleedSpacingBlock}` >; /** - * When true, set the padding to mirror the margin. This maintains the apparent width of the element prior to adding Bleed. + * When true, set the padding to mirror the margin. + * This maintains the apparent width of the element prior to adding Bleed. + * When this is used with `asChild`, it will overwrite the padding of the child. */ reflectivePadding?: boolean; } From ff69e910a7f9e390a64eb82283595f375741f729 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 11:25:21 +0200 Subject: [PATCH 13/18] :memo: fix docs for px story --- @navikt/core/react/src/layout/bleed/Bleed.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index ca7b4b9fdf..d2721886f2 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -150,7 +150,7 @@ export const Px = { - marginInline="20 0" + marginInline="px 0" From 8778a2c747341a7e23cb36f3099e324ff6da44e0 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 11:32:22 +0200 Subject: [PATCH 14/18] :sparkles: add asChild prop --- .../react/src/layout/bleed/Bleed.stories.tsx | 63 +++++++++++++++++++ @navikt/core/react/src/layout/bleed/Bleed.tsx | 8 ++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index d2721886f2..1c20d6a690 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -70,6 +70,69 @@ export const Default = { ), }; + +export const AsChild = { + render: () => ( + <> + + + + + + + marginInline="10 0" + + + + + + + + + marginInline="0 10" + + + + + + + + + marginBlock="10 0" + + + + + + + + + + marginBlock="0 10" + + + + + + + + ), +}; + export const Breakpoints = { render: () => ( <> diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index 6db84ff22f..7f00535cc5 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -5,6 +5,7 @@ import { SpacingScale, getResponsiveProps, } from "../utilities/css"; +import { Slot } from "../../util/Slot"; export type BleedSpacingInline = "0" | "full" | "px" | SpacingScale; export type BleedSpacingBlock = "0" | "px" | SpacingScale; @@ -36,6 +37,8 @@ export interface BleedProps extends React.HTMLAttributes { * When this is used with `asChild`, it will overwrite the padding of the child. */ reflectivePadding?: boolean; + + asChild?: boolean; } /** @@ -60,6 +63,7 @@ export const Bleed = forwardRef( marginBlock, reflectivePadding, style: _style, + asChild, ...rest }, ref @@ -107,8 +111,10 @@ export const Bleed = forwardRef( }; } + const Comp = asChild ? Slot : "div"; + return ( -
Date: Mon, 25 Sep 2023 11:35:02 +0200 Subject: [PATCH 15/18] :memo: add changeset --- .changeset/tender-taxis-enjoy.md | 6 ++++++ @navikt/core/react/src/layout/bleed/Bleed.tsx | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/tender-taxis-enjoy.md diff --git a/.changeset/tender-taxis-enjoy.md b/.changeset/tender-taxis-enjoy.md new file mode 100644 index 0000000000..b425207f77 --- /dev/null +++ b/.changeset/tender-taxis-enjoy.md @@ -0,0 +1,6 @@ +--- +"@navikt/ds-react": minor +"@navikt/ds-css": minor +--- + +Primitives: ny komponent Bleed diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index 7f00535cc5..a6686818dd 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -117,7 +117,7 @@ export const Bleed = forwardRef( Date: Mon, 25 Sep 2023 11:38:12 +0200 Subject: [PATCH 16/18] :memo: add jsdoc --- @navikt/core/react/src/layout/bleed/Bleed.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.tsx b/@navikt/core/react/src/layout/bleed/Bleed.tsx index a6686818dd..d83f2ccd99 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.tsx @@ -38,6 +38,9 @@ export interface BleedProps extends React.HTMLAttributes { */ reflectivePadding?: boolean; + /** + * When true, the Bleed will render as its child. This merges classes, styles and event handlers. + */ asChild?: boolean; } From 2861f12c15e10a3828c2d4bba170e4d43ad476a0 Mon Sep 17 00:00:00 2001 From: Julian Nymark Date: Mon, 25 Sep 2023 11:41:04 +0200 Subject: [PATCH 17/18] :recycle: refactor stories --- .../react/src/layout/bleed/Bleed.stories.tsx | 66 ++++++------------- 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index 1c20d6a690..cbfcba6912 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -9,24 +9,28 @@ export default { component: Bleed, } satisfies Meta; +const style = ( + +); + export const Default = { render: () => ( <> - + {style} @@ -74,21 +78,7 @@ export const Default = { export const AsChild = { render: () => ( <> - + {style} @@ -136,21 +126,7 @@ export const AsChild = { export const Breakpoints = { render: () => ( <> - + {style} Date: Tue, 26 Sep 2023 15:26:00 +0200 Subject: [PATCH 18/18] :memo: fix erroneous story text --- .../react/src/layout/bleed/Bleed.stories.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx index cbfcba6912..6f768ea5d3 100644 --- a/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx +++ b/@navikt/core/react/src/layout/bleed/Bleed.stories.tsx @@ -135,7 +135,9 @@ export const Breakpoints = { > - marginInline="10 0" + + {'marginInline={{ xs: "10 0", md: "20 0" }}'} + @@ -147,7 +149,9 @@ export const Breakpoints = { > - marginInline="0 10" + + {'marginInline={{ xs: "0 10", md: "0 20" }}'} + @@ -159,7 +163,9 @@ export const Breakpoints = { > - marginBlock="10 0" + + {'marginBlock={{ xs: "10 0", md: "20 0" }}'} + @@ -172,7 +178,9 @@ export const Breakpoints = { - marginBlock="0 10" + + {'marginBlock={{ xs: "0 10", md: "0 20" }}'} +