Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#779] Add some layout primitives (stack) #781

Merged
merged 6 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### Added

- Badge with Label, added an example showing a text label rendered next to a badge component, to the badge docs.
- A new layout component at `atoms/switcher`, that lays out its children in a horizontal row with consistent spacing between children. The layout switches to a vertical stack once the width of the component passes below a threshold, or the number of children goes over a limit.
- A new layout component at `atoms/stack`, that lays out its children vertically, with consistent spacing between children.

## [[6.0.0]](https://github.com/bitcrowd/bitstyles/releases/tag/v6.0.0) - 2023-06-08

Expand Down Expand Up @@ -46,7 +48,6 @@
- It is now possible to import bitstyles on a per-layer basis, instead of per-module or all at once. It is still possible to override all modules inside each layer in the normal way.
- There are now design tokens as `design-tokens/focus` to describe a consistent `:focus` appearance, that are currently used in `base/anchor/`, `atoms/buttons`, and `atoms/links`.
- Anchor elements and `atoms/link` components now have a disabled state, applied using the `aria-disabled` attribute.
- A new layout component at `atoms/switcher`, that lays out its children in a horizontal row with consistent spacing between children. The layout switches to a vertical stack once the width of the component passes below a threshold, or the number of children goes over a limit.

## [[5.0.0]](https://github.com/bitcrowd/bitstyles/releases/tag/v5.0.0) - 2023-01-03

Expand Down
1 change: 1 addition & 0 deletions scss/bitstyles/atoms/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
@forward './link' as link-*;
@forward './skip-link' as skip-link-*;
@forward './switcher' as switcher-*;
@forward './stack' as stack-*;
@forward './topbar' as topbar-*;
4 changes: 2 additions & 2 deletions scss/bitstyles/atoms/button/Button.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { generateLabel } from '../../../../.storybook/helpers';
import { generateButtonLabel } from '../../../../.storybook/helpers';

export default ({
children,
Expand All @@ -16,7 +16,7 @@ export default ({
const button = document.createElement(element);
button.innerHTML =
children ||
generateLabel(
generateButtonLabel(
shapeVariant,
colorVariant,
disabled || ariaDisabled,
Expand Down
50 changes: 50 additions & 0 deletions scss/bitstyles/atoms/stack/Stack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { generateLabel } from '../../../../.storybook/helpers';

const StackItem = ({
children,
backgroundColor = 'var(--bs-color-grayscale-light-2)',
}) => {
const stackItem = document.createElement('div');
stackItem.style.backgroundColor = backgroundColor;
stackItem.style.padding = 'var(--bs-content-padding-base)';
stackItem.style.borderRadius = 'var(--bs-size-s3)';
stackItem.style.minHeight = '6rem';
stackItem.innerHTML = children;
return stackItem;
};

const Stack = ({
length = 3,
classname = [],
sizeVariant = '',
itemColor,
labelPrefix = 'stack',
children = [],
}) => {
const stack = document.createElement('div');
stack.classList.add('a-stack');
if (sizeVariant) {
stack.classList.add(`a-stack--${sizeVariant}`);
}

classname.forEach((cls) => {
stack.classList.add(cls);
});

if (children.length) {
children.forEach((child) => stack.append(child));
} else {
for (let child = 0; child < length; child += 1) {
stack.append(
StackItem({
children: generateLabel([labelPrefix, 'child', child + 1]),
backgroundColor: itemColor,
})
);
}
}

return stack;
};

export { StackItem, Stack };
45 changes: 45 additions & 0 deletions scss/bitstyles/atoms/stack/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@forward 'settings';
@use './settings';
@use '../../tools/classname';
@use '../../tools/design-token';
@use '../../tools/media-query';

#{classname.get($classname-items: 'stack', $layer: 'atom')} {
display: flex;
flex-direction: column;
justify-content: flex-start;

&:only-child {
height: 100%;
}

> * {
margin-top: 0;
margin-bottom: 0;
}

> * + * {
margin-top: var(design-token.get('stack', 'spacing'));
}
}

@each $breakpoint, $size-variants in settings.$size-variants {
@include media-query.get($breakpoint) {
@each $size-variant-name, $padding in ($size-variants) {
$class: '';
@if $size-variant-name == '' {
$class: 'stack';
} @else {
$class: 'stack--#{$size-variant-name}';
}

#{classname.get($classname-items: $class, $layer: 'atom')} {
/* stylelint-disable max-nesting-depth */
> * + * {
#{design-token.get('stack', 'spacing')}: $padding;
}
/* stylelint-enable max-nesting-depth */
}
}
}
}
11 changes: 11 additions & 0 deletions scss/bitstyles/atoms/stack/_settings.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@use '../../settings/setup';
@use '../../tools/design-token';

$size-variants: (
'#{setup.$no-media-query}': (
'': var(design-token.get('content', 'padding', 'base')),
),
'm': (
'': var(design-token.get('content', 'padding', 'l')),
),
) !default;
34 changes: 34 additions & 0 deletions scss/bitstyles/atoms/stack/stack.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Stack, StackItem } from './Stack';
import { generateLabel } from '../../../../.storybook/helpers';

export default {
title: 'Atoms/Stack',
component: Stack,
argTypes: {},
};

const Template = (args) => Stack(args);

// ***** Size variants ****************** //

export const Base = Template.bind({});
Base.args = { length: 4 };

export const Nested = () => {
const innerStack = Stack({
length: 2,
itemColor: 'var(--bs-color-grayscale-light-4)',
labelPrefix: 'stack 1 child 3 — stack 2',
});
const children = [
StackItem({ children: generateLabel(['stack 1', 'child 1']) }),
StackItem({ children: generateLabel(['stack 1', 'child 2']) }),
innerStack,
StackItem({ children: generateLabel(['stack 1', 'child 4']) }),
StackItem({ children: generateLabel(['stack 1', 'child 5']) }),
];
const outerStack = Stack({ children });

outerStack.insertBefore(innerStack, outerStack.childNodes[2]);
return outerStack;
};
69 changes: 69 additions & 0 deletions scss/bitstyles/atoms/stack/stack.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Canvas, Meta, Story } from '@storybook/addon-docs';

<Meta title="Atoms/Stack/Overview" />

<Canvas>
<Story id="atoms-stack--base" />
</Canvas>

# Stack

A layout atom that stacks its children vertically and ensures consistent space between each. This component is responsive, applying larger spacing between children when rendered on larger viewports.

This layout is suitable for large blocks of content, such as the sections in the main content of a page.

The spacing and the breakpoints the component responds to can be [customized](#customization). You can also add extra size variants of the stack, that apply different spacing, but the default configuration provides only one.

Stacks can be nested — children of a stack can themselves be stacks — while the spacing will remain consistent:

<Canvas>
<Story id="atoms-stack--nested" />
</Canvas>

## Customization

The component expects a Sass list of Sass maps, with the keys being the name of the breakpoint (use `setup.$no-media-query` for the base mobile-first styles) and the values being the name of the stack variant. You can change the breakpoint names or add new breakpoints if you want the component to apply different spacing at extra breakpoints (in which case you probably also want to [edit the available `content` padding design tokens](/docs/design-tokens-content--page) available to you, though you can also pass `size` design tokens directly)

```scss
@use '~bitstyles/scss/bitstyles/atoms/stack' with (
$size-variants: (
'#{setup.$no-media-query}': (
'': var(design-token.get('content', 'padding', 'base')),
),
'm': (
'': var(design-token.get('content', 'padding', 'l')),
),
'l': (
'': var(design-token.get('content', 'padding', 'xl')),
// this value of content-padding would need to be added to the content design tokens
),
)
);
```

### Extra size variants

The keys of the spacing values above are deliberately left blank — that results in those spacing values being applied to the base `a-stack` component. If you provide a key, that will be used to create a stack variant:

```scss
@use '~bitstyles/scss/bitstyles/atoms/stack' with (
$size-variants: (
'#{setup.$no-media-query}': (
'': var(design-token.get('content', 'padding', 'base')),
'large': var(design-token.get('content', 'padding', 'l')),
),
)
);
```

Produces CSS similar to the following:

```css
.a-stack > * + * {
margin-top: var(--bs-content-padding-base);
}

.a-stack--large > * + * {
margin-top: var(--bs-content-padding-l);
}
```
26 changes: 26 additions & 0 deletions test/scss/fixtures/bitstyles-overrides.css
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,32 @@ table {
--bscpn-switcher-spacing: var(--bscpn-content-padding-l1);
}
}
.bs-at-stack {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.bs-at-stack:only-child {
height: 100%;
}
.bs-at-stack > * {
margin-bottom: 0;
margin-top: 0;
}
.bs-at-stack > * + * {
margin-top: var(--bscpn-stack-spacing);
}
.bs-at-stack > * + * {
--bscpn-stack-spacing: var(--bscpn-content-padding-base);
}
.bs-at-stack--large > * + * {
--bscpn-stack-spacing: var(--bscpn-content-padding-l);
}
@media screen and (min-width: 30em) {
.bs-at-stack > * + * {
--bscpn-stack-spacing: var(--bscpn-content-padding-l);
}
}
.bs-at-topbar {
left: 0;
padding: 10rem var(--bscpn-size-s1);
Expand Down
23 changes: 23 additions & 0 deletions test/scss/fixtures/bitstyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,29 @@ table {
--bs-switcher-spacing: var(--bs-size-s3);
}
}
.a-stack {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.a-stack:only-child {
height: 100%;
}
.a-stack > * {
margin-bottom: 0;
margin-top: 0;
}
.a-stack > * + * {
margin-top: var(--bs-stack-spacing);
}
.a-stack > * + * {
--bs-stack-spacing: var(--bs-content-padding-base);
}
@media screen and (min-width: 30em) {
.a-stack > * + * {
--bs-stack-spacing: var(--bs-content-padding-l);
}
}
.a-topbar {
left: 0;
padding: var(--bs-size-s3) var(--bs-size-s1);
Expand Down
9 changes: 9 additions & 0 deletions test/scss/test-use-all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@
)
),
$icon-sizes: ('s': 10rem),
$stack-size-variants: (
'no-mq': (
'': var(--bscpn-content-padding-base),
'large': var(--bscpn-content-padding-l),
),
'm': (
'': var(--bscpn-content-padding-l),
)
),
$skip-link-color: #f00,
$switcher-size-variants: (
'no-mq': (
Expand Down
11 changes: 11 additions & 0 deletions test/scss/test-use-each.scss
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,17 @@
),
)
);
@use '../../scss/bitstyles/atoms/stack' with (
$size-variants: (
'no-mq': (
'': var(--bscpn-content-padding-base),
'large': var(--bscpn-content-padding-l),
),
'm': (
'': var(--bscpn-content-padding-l),
),
)
);
@use '../../scss/bitstyles/atoms/topbar' with (
$vertical-padding: 10rem
);
Expand Down
9 changes: 9 additions & 0 deletions test/scss/test-use-layers.scss
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@
),
),
),
$stack-size-variants: (
'no-mq': (
'': var(--bscpn-content-padding-base),
'large': var(--bscpn-content-padding-l),
),
'm': (
'': var(--bscpn-content-padding-l),
),
),
$topbar-vertical-padding: 10rem
);
@use '../../scss/bitstyles/organisms' with (
Expand Down