Skip to content

Commit

Permalink
Grid layouts and items margin and paddings (#4637)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fercas123 authored Feb 6, 2025
1 parent 114df0b commit 7510f56
Show file tree
Hide file tree
Showing 21 changed files with 351 additions and 31 deletions.
13 changes: 13 additions & 0 deletions .changeset/polite-llamas-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@salt-ds/core": minor
---

Add `padding` and `margin` to `GridLayout`, `GridItem`, `BorderLayout` and `BorderItem`

```tsx
<GridLayout padding={1} margin={1}>
<GridItem padding={2} margin={2}>
Item
</GridItem>
</GridLayout>
```
9 changes: 9 additions & 0 deletions packages/core/src/border-item/BorderItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { GridItem, type GridItemProps } from "../grid-item";
import {
type PolymorphicComponentPropWithRef,
type PolymorphicRef,
type ResponsiveProp,
makePrefixer,
} from "../utils";
import borderItemCss from "./BorderItem.css";
Expand Down Expand Up @@ -40,6 +41,14 @@ export type BorderItemProps<T extends ElementType> =
* Defines if the item should stick to the edges of its container. Defaults to "false"
*/
sticky?: boolean;
/**
* Defines the margin around the component. It can be specified as a number (which acts as a multiplier) or a string representing the margin value. Default is `0`.
*/
margin?: ResponsiveProp<number | string>;
/**
* Defines the padding within the component. It can be specified as a number (which acts as a multiplier) or a string representing the padding value. Default is `0`.
*/
padding?: ResponsiveProp<number | string>;
}
>;

Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/border-layout/BorderLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { GridLayout, type GridLayoutProps } from "../grid-layout";
import {
type PolymorphicComponentPropWithRef,
type PolymorphicRef,
type ResponsiveProp,
makePrefixer,
} from "../utils";

Expand All @@ -35,6 +36,14 @@ export type BorderLayoutProps<T extends ElementType> =
* Border item components to be rendered.
*/
children: ReactElement<BorderItemProps<T>>[];
/**
* Defines the margin around the component. It can be specified as a number (which acts as a multiplier) or a string representing the margin value. Default is `0`.
*/
margin?: ResponsiveProp<number | string>;
/**
* Defines the padding within the component. It can be specified as a number (which acts as a multiplier) or a string representing the padding value. Default is `0`.
*/
padding?: ResponsiveProp<number | string>;
}
>;

Expand Down
8 changes: 1 addition & 7 deletions packages/core/src/flex-item/FlexItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
forwardRef,
} from "react";
import { useBreakpoint } from "../breakpoints";
import { parseSpacing } from "../flex-layout/parseSpacing";
import {
type PolymorphicComponentPropWithRef,
type PolymorphicRef,
Expand Down Expand Up @@ -62,13 +63,6 @@ type FlexItemComponent = <T extends ElementType = "div">(
props: FlexItemProps<T>,
) => ReactElement | null;

function parseSpacing(value: number | string | undefined) {
if (value === undefined || typeof value === "string") {
return value;
}

return `calc(var(--salt-spacing-100) * ${value})`;
}
export const FlexItem: FlexItemComponent = forwardRef(
<T extends ElementType = "div">(
{
Expand Down
9 changes: 1 addition & 8 deletions packages/core/src/flex-layout/FlexLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
resolveResponsiveValue,
} from "../utils";
import flexLayoutCss from "./FlexLayout.css";
import { parseSpacing } from "./parseSpacing";

const withBaseName = makePrefixer("saltFlexLayout");

Expand Down Expand Up @@ -77,14 +78,6 @@ function parseAlignment(style: string | undefined) {
return style === "start" || style === "end" ? `flex-${style}` : style;
}

function parseSpacing(value: number | string | undefined) {
if (value === undefined || typeof value === "string") {
return value;
}

return `calc(var(--salt-spacing-100) * ${value})`;
}

export const FlexLayout: FlexLayoutComponent = forwardRef(
<T extends ElementType = "div">(
{
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/flex-layout/parseSpacing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function parseSpacing(value: number | string | undefined) {
if (value === undefined || typeof value === "string") {
return value;
}

return `calc(var(--salt-spacing-100) * ${value})`;
}
2 changes: 2 additions & 0 deletions packages/core/src/grid-item/GridItem.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
grid-column-start: var(--gridItem-gridColumnStart);
grid-row-end: var(--gridItem-gridRowEnd);
grid-column-end: var(--gridItem-gridColumnEnd);
margin: var(--gridItem-margin);
padding: var(--gridItem-padding);
}

.saltGridItem-area {
Expand Down
16 changes: 15 additions & 1 deletion packages/core/src/grid-item/GridItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type ElementType, type ReactElement, forwardRef } from "react";
import { useComponentCssInjection } from "@salt-ds/styles";
import { useWindow } from "@salt-ds/window";
import { useBreakpoint } from "../breakpoints";
import { parseSpacing } from "../flex-layout/parseSpacing";
import {
type PolymorphicComponentPropWithRef,
type PolymorphicRef,
Expand Down Expand Up @@ -43,6 +44,14 @@ export type GridItemProps<T extends ElementType> =
* Aligns a grid item inside a cell along the block (column) axis. Defaults to "stretch"
*/
verticalAlignment?: GridAlignment;
/**
* Defines the margin around the component. It can be specified as a number (which acts as a multiplier) or a string representing the margin value. Default is `0`.
*/
margin?: ResponsiveProp<number | string>;
/**
* Defines the padding within the component. It can be specified as a number (which acts as a multiplier) or a string representing the padding value. Default is `0`.
*/
padding?: ResponsiveProp<number | string>;
}
>;

Expand All @@ -63,6 +72,8 @@ export const GridItem: GridItemComponent = forwardRef(
as,
children,
className,
margin = 0,
padding = 0,
colSpan = "auto",
rowSpan = "auto",
horizontalAlignment = "stretch",
Expand All @@ -85,7 +96,8 @@ export const GridItem: GridItemComponent = forwardRef(
const gridItemColSpan = resolveResponsiveValue(colSpan, matchedBreakpoints);

const gridItemRowSpan = resolveResponsiveValue(rowSpan, matchedBreakpoints);

const gridItemMargin = resolveResponsiveValue(margin, matchedBreakpoints);
const gridItemPadding = resolveResponsiveValue(padding, matchedBreakpoints);
const gridColumnStart = gridItemColSpan
? `span ${gridItemColSpan}`
: colStart;
Expand All @@ -97,6 +109,8 @@ export const GridItem: GridItemComponent = forwardRef(
const gridRowEnd = gridItemRowSpan ? `span ${gridItemRowSpan}` : rowEnd;

const gridStyles = {
"--gridItem-margin": parseSpacing(gridItemMargin),
"--gridItem-padding": parseSpacing(gridItemPadding),
...style,
"--gridItem-justifySelf": horizontalAlignment,
"--gridItem-alignSelf": verticalAlignment,
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/grid-layout/GridLayout.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
row-gap: var(--gridLayout-rowGap);
grid-template-columns: var(--gridLayout-columns);
grid-template-rows: var(--gridLayout-rows);
margin: var(--gridLayout-margin);
padding: var(--gridLayout-padding);
grid-auto-columns: auto;
grid-auto-rows: auto;
}
Expand Down
24 changes: 15 additions & 9 deletions packages/core/src/grid-layout/GridLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { useComponentCssInjection } from "@salt-ds/styles";
import { useWindow } from "@salt-ds/window";
import { useBreakpoint } from "../breakpoints";
import { parseSpacing } from "../flex-layout/parseSpacing";
import gridLayoutCss from "./GridLayout.css";

export type GridLayoutProps<T extends ElementType> =
Expand All @@ -38,6 +39,14 @@ export type GridLayoutProps<T extends ElementType> =
* Defines the size of the gutter between the rows by setting a density multiplier. Defaults to 1
*/
rowGap?: ResponsiveProp<number | string>;
/**
* Defines the margin around the component. It can be specified as a number (which acts as a multiplier) or a string representing the margin value. Default is `0`.
*/
margin?: ResponsiveProp<number | string>;
/**
* Defines the padding within the component. It can be specified as a number (which acts as a multiplier) or a string representing the padding value. Default is `0`.
*/
padding?: ResponsiveProp<number | string>;
}
>;

Expand All @@ -55,14 +64,6 @@ function parseGridValue(value: number | string | undefined) {
return `repeat(${value}, 1fr)`;
}

function parseSpacing(value: number | string | undefined) {
if (value === undefined || typeof value === "string") {
return value;
}

return `calc(var(--salt-spacing-100) * ${value})`;
}

export const GridLayout: GridLayoutComponent = forwardRef(
<T extends ElementType = "div">(
{
Expand All @@ -72,6 +73,8 @@ export const GridLayout: GridLayoutComponent = forwardRef(
columns = 12,
rows = 1,
gap = 3,
margin = 0,
padding = 0,
columnGap,
rowGap,
style,
Expand All @@ -98,8 +101,11 @@ export const GridLayout: GridLayoutComponent = forwardRef(
const gridColumnGap = resolveResponsiveValue(columnGap, matchedBreakpoints);

const gridRowGap = resolveResponsiveValue(rowGap, matchedBreakpoints);

const gridMargin = resolveResponsiveValue(margin, matchedBreakpoints);
const gridPadding = resolveResponsiveValue(padding, matchedBreakpoints);
const gridLayoutStyles = {
"--gridLayout-margin": parseSpacing(gridMargin),
"--gridLayout-padding": parseSpacing(gridPadding),
...style,
"--gridLayout-columns": parseGridValue(gridColumns),
"--gridLayout-rows": parseGridValue(gridRows),
Expand Down
25 changes: 24 additions & 1 deletion packages/core/stories/grid-layout/grid-layout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,30 @@ export const Default = Template.bind({});
Default.args = {
columns: { xs: 1, sm: 3, md: 6, lg: 9, xl: 12 },
};

const PaddingAndMargins: StoryFn<typeof GridLayout> = (args) => {
return (
<div className="spacing-example-margin">
<GridLayout className="spacing-example-padding" {...args}>
{Array.from({ length: 12 }, (_, index) => (
<GridItem
className="spacing-example-gap"
key={`item-${index + 1}`}
padding={1}
>
<p>Item {index + 1}</p>
</GridItem>
))}
</GridLayout>
</div>
);
};
export const WithPaddingAndMargins = PaddingAndMargins.bind({});
WithPaddingAndMargins.args = {
wrap: false,
gap: 1,
padding: 2,
margin: 2,
};
const ResponsiveView: StoryFn<typeof GridLayout> = (args) => {
return (
<SaltProvider breakpoints={customBreakpoints}>
Expand Down
16 changes: 13 additions & 3 deletions packages/core/stories/layout/layout.stories.css
Original file line number Diff line number Diff line change
Expand Up @@ -131,23 +131,33 @@
animation: fade-out-back 1s ease-out both;
}

.spacing-example-gap.saltFlexItem:not(:last-child):after {
.spacing-example-gap.saltFlexItem:not(:last-child):after,
.spacing-example-gap.saltGridItem:not(:last-child):after {
content: "";
background: var(--salt-category-5-subtle-background);
height: 100%;
position: absolute;
top: 0;
right: 0;
border: dotted 1px var(--salt-category-3-subtle-borderColor);
}
.spacing-example-gap {
position: relative;
}
.spacing-example-gap.saltFlexItem:not(:last-child):after {
width: calc(var(--flexLayout-gap) - 2px);
transform: translate(calc(var(--flexLayout-gap) + 1px), -1px);
border: dotted 1px var(--salt-category-3-subtle-borderColor);
}
.spacing-example-gap.saltGridItem:not(:last-child):after {
width: calc(var(--gridLayout-rowGap) - 2px);
transform: translate(calc(var(--gridLayout-rowGap) + 1px), -1px);
}
.spacing-example-gap {
border: solid 1px var(--salt-container-primary-borderColor);
background: var(--salt-container-primary-background);
}
.spacing-example-padding {
border: dotted min(1px, var(--flexLayout-padding)) var(--salt-category-3-subtle-borderColor);
border: dotted 1px var(--salt-category-3-subtle-borderColor);
background: var(--salt-category-3-subtle-background);
}
.spacing-example-margin {
Expand Down
5 changes: 5 additions & 0 deletions site/docs/components/border-layout/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,10 @@ Use the `sticky` prop of the border item wrapper to define a region as sticky. W
This is particularly useful if you require a region to remain visible at all times. For more information, see [CSS `position: sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky).

</LivePreview>
<LivePreview componentName="border-layout" exampleName="Spacing">

## Inner and Outer Spacing
The spacing properties `padding` and `margin` are set to 0 by default and can be used to control the layout's inner and outer spacing as multiples of the [Salt base unit](/salt/foundations/spacing).

</LivePreview>
</LivePreviewControls>
2 changes: 1 addition & 1 deletion site/docs/components/flex-layout/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ In contrast to the `grow` prop, the `shrink` prop makes a specific item as small

## Spacing
Flex layout displays items with a gap between items that is a multiple of the [Salt base unit](/salt/foundations/spacing) controlled by the `gap` property and is by default set to 3.
The spacing properties `padding` and `margin` are set to 0 by default and can be used to control the layout's inner and outer spacing also as multiples of the Salt base unit.
The spacing properties `padding` and `margin` are set to 0 by default and can be used to control the layout's inner and outer spacing (also as multiples of the Salt base unit).

</LivePreview>

Expand Down
10 changes: 9 additions & 1 deletion site/docs/components/grid-layout/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ data:

## Default

`GridLayout` defaults to a 12-column grid with one row. The spacing between rows and columns depends on the prop `gap`, which is 3 by default.
`GridLayout` defaults to a 12-column grid with one row.

Content in `GridLayout` is inside `GridItem` components. This helps control the size and position of content.

Expand Down Expand Up @@ -89,6 +89,14 @@ Use the `verticalAlignment` and `horizontalAlignment` props to control the posit

The `columns` and `rows` props allow you to pass a string to define a column or row template.

</LivePreview>
<LivePreview componentName="grid-layout" exampleName="Spacing">

## Spacing

Grid layout displays items with a gap between items that is a multiple of the [Salt base unit](/salt/foundations/spacing) controlled by the `gap`, `columnGap` and `rowGap` properties and is by default set to 3.
The spacing properties `padding` and `margin` are set to 0 by default and can be used to control the layout's inner and outer spacing (also as multiples of the Salt base unit).

</LivePreview>

</LivePreviewControls>
26 changes: 26 additions & 0 deletions site/src/examples/border-layout/Spacing.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.spacingExampleGap:not(:last-child):after {
content: "";
background: var(--salt-category-5-subtle-background);
height: 100%;
position: absolute;
top: 0;
right: 0;
width: calc(var(--gridLayout-rowGap) - 2px);
transform: translate(calc(var(--gridLayout-rowGap) + 1px), -1px);
border: dotted 1px var(--salt-category-3-subtle-borderColor);
}
.item {
position: relative;
border: solid 1px var(--salt-container-primary-borderColor);
background: var(--salt-container-primary-background);
align-items: center;
justify-content: center;
}
.spacingExamplePadding {
border: dotted 1px var(--salt-category-3-subtle-borderColor);
background: var(--salt-category-3-subtle-background);
}
.spacingExampleMargin {
border: dotted 1px var(--salt-category-4-subtle-borderColor);
background: var(--salt-category-4-subtle-background);
}
Loading

0 comments on commit 7510f56

Please sign in to comment.