Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
import React, { ComponentProps } from 'react';
import { Meta } from '@storybook/react';
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { BADGE } from '@geometricpanda/storybook-addon-badges';
import { RadiusAutoLayout } from './auto-layout';
import { Stories, Title, Description } from '@storybook/addon-docs';
import { AutoLayoutExtendedProps } from './auto-layout.types';

const alignmentOptions = [
'topLeft',
'topCenter',
'topRight',
'left',
'center',
'right',
'bottomLeft',
'bottomCenter',
'bottomRight',
] as const;

/**
* The RadiusAutoLayout component duplicates the behaviour of Figma AutoLayout's
* Alignment property. This deviates from how CSS flexbox works in some cases -
* for example when the `direction` is changed, the alignment of the children
* remains the same instead of being dependent on the flex-direction. Also, when
* the `space` property is set to `auto`, this is equivalent to writing
* `justify-content: space-between`, which evenly spaces children regardless of
* direction.
*
* Please see the examples of the different behaviours below.
*
* ## Resources
* [How Figma Alignment Works](https://help.figma.com/hc/en-us/articles/360040451373-Explore-auto-layout-properties#alignment)
*
* [RadiusAutoLayout Figma Specs](https://www.figma.com/file/ODAUZaQxH8oH2GI0A9MAVb/Radius-Booster---Auto-Layout?type=design&node-id=1302-3736&t=Fh2ap7gIybG92aBU-0)
*/
const meta: Meta<typeof RadiusAutoLayout> = {
component: RadiusAutoLayout,
title: 'Component Development Kit / Auto Layout / Alignment',
Expand All @@ -15,194 +43,180 @@ const meta: Meta<typeof RadiusAutoLayout> = {
patch: process.env.COMPONENT_VERSION?.[2],
},
badges: [BADGE.BETA],
docs: {
page: () => (
<>
<Title>Alignment</Title>
<Description children="We duplicate the way Figma aligns in Auto Layout components."></Description>
<Stories includePrimary={true} />
</>
),
controls: {
// only show controls relevant to this story
include: ['alignment', 'direction', 'space'],
},
},
};

export default meta;
// type Story = StoryObj<typeof RadiusAutoLayout>;
// TODO: apply `Story` type to all stories - causes issues due to parent and children args not existing in original component

const ThreeBoxesTemplateAlignmentHor = {
render: (args: {
parent: ComponentProps<typeof RadiusAutoLayout>;
children: ComponentProps<typeof RadiusAutoLayout>;
}) => (
<RadiusAutoLayout direction="vertical">
<RadiusAutoLayout
direction={args.parent.direction}
space={args.parent.space}
alignment={args.parent.alignment}
width="fill-parent"
height={
args.parent.direction === 'horizontal' ? 'fill-parent' : '100px'
}
padding={{ css: '12px' }}
>
<RadiusAutoLayout
width={args.children.width}
height={20}
fill={{ css: '#D44527' }}
/>
<RadiusAutoLayout
width={args.children.width}
height={40}
fill={{ css: '#D44527' }}
/>
<RadiusAutoLayout
width={args.children.width}
height={60}
fill={{ css: '#D44527' }}
/>
</RadiusAutoLayout>
</RadiusAutoLayout>
),
};

export const AlignmentTop = {
...ThreeBoxesTemplateAlignmentHor,
args: {
parent: {
direction: 'horizontal',
space: 'auto',
alignment: 'top',
argTypes: {
alignment: {
options: alignmentOptions,
},
children: {
width: 100,
direction: {
options: ['horizontal', 'vertical'],
},
},
parameters: {
controls: {
disable: true,
space: {
options: {
auto: 'auto',
fixed: { css: '10px' },
},
table: { defaultValue: { summary: '10px' } },
},
},
};

export const AlignmentCenter = {
...ThreeBoxesTemplateAlignmentHor,
args: {
parent: {
direction: 'horizontal',
space: 'auto',
alignment: 'center',
},
children: {
width: 100,
},
},
parameters: {
controls: {
disable: true,
},
alignment: 'topLeft',
direction: 'horizontal',
},
};

export const AlignmentBottom = {
...ThreeBoxesTemplateAlignmentHor,
args: {
parent: {
direction: 'horizontal',
space: 'auto',
alignment: 'bottom',
},
children: {
width: 100,
},
},
parameters: {
controls: {
disable: true,
},
sidebar: { disabled: true },
},
export default meta;
type Story = StoryObj<typeof RadiusAutoLayout>;

const PADDING = 24;
const CIRCLE_SIZE = 12;

/** A circle to show the alignment of the child AutoLayouts */
const Circle = ({
top,
left,
bottom,
right,
}: {
top?: number | string;
left?: number | string;
bottom?: number | string;
right?: number | string;
}) => {
return (
<div
style={{
backgroundColor: '#D9D9D9',
height: CIRCLE_SIZE,
width: CIRCLE_SIZE,
borderRadius: '50%',
position: 'absolute',
top,
left,
bottom,
right,
}}
></div>
);
};

const ThreeBoxesTemplateAlignmentVert = {
render: (args: {
parent: ComponentProps<typeof RadiusAutoLayout>;
children: ComponentProps<typeof RadiusAutoLayout>;
}) => (
<RadiusAutoLayout direction="vertical">
/** The positions of each of the circles */
const circles = [
{ top: PADDING, left: PADDING },
{ top: PADDING, left: `calc(50% - ${CIRCLE_SIZE / 2}px)` },
{ top: PADDING, right: PADDING },
{ top: `calc(50% - ${CIRCLE_SIZE / 2}px)`, left: PADDING },
{
top: `calc(50% - ${CIRCLE_SIZE / 2}px)`,
left: `calc(50% - ${CIRCLE_SIZE / 2}px)`,
},
{ top: `calc(50% - ${CIRCLE_SIZE / 2}px)`, right: PADDING },
{ bottom: PADDING, left: PADDING },
{ bottom: PADDING, left: `calc(50% - ${CIRCLE_SIZE / 2}px)` },
{ bottom: PADDING, right: PADDING },
];

const AlignmentDemo = ({
alignment,
direction,
space,
}: {
alignment: AutoLayoutExtendedProps['alignment'];
direction: AutoLayoutExtendedProps['direction'];
space: AutoLayoutExtendedProps['space'];
}) => {
return (
<RadiusAutoLayout
width="284px"
height="284px"
stroke={{ css: '#A6A6A6' }}
strokeWidth={{ css: '1px' }}
padding={{ css: `${PADDING}px` }}
alignment={alignment}
direction={direction}
space={space}
isParent
>
<RadiusAutoLayout
width={25}
height={25}
fill={{ css: '#F7856E' }}
style={{ zIndex: 1 }}
/>
<RadiusAutoLayout
direction={args.parent.direction}
space={args.parent.space}
alignment={args.parent.alignment}
width="fill-parent"
height={
args.parent.direction === 'horizontal' ? 'fill-parent' : '100px'
}
padding={{ css: '12px' }}
>
<RadiusAutoLayout width="25%" height={10} fill={{ css: '#D44527' }} />
<RadiusAutoLayout width="50%" height={10} fill={{ css: '#D44527' }} />
<RadiusAutoLayout width="75%" height={10} fill={{ css: '#D44527' }} />
</RadiusAutoLayout>
width={25}
height={25}
fill={{ css: '#F7856E' }}
style={{ zIndex: 1 }}
/>
<RadiusAutoLayout
width={25}
height={25}
fill={{ css: '#F7856E' }}
style={{ zIndex: 1 }}
/>
{circles.map((positionProps) => (
<Circle {...positionProps} />
))}
</RadiusAutoLayout>
);
};

export const Alignment: Story = {
// @ts-expect-error - bug with `args` type inference due to polymorphism
render: ({ alignment, direction, space }: AutoLayoutExtendedProps) => (
<AlignmentDemo alignment={alignment} direction={direction} space={space} />
),
};

export const AlignmentLeft = {
...ThreeBoxesTemplateAlignmentVert,
args: {
parent: {
direction: 'vertical',
space: 'auto',
alignment: 'left',
},
children: {
width: 100,
},
},
parameters: {
controls: {
disable: true,
},
},
const GridTemplate = ({ direction, space }: AutoLayoutExtendedProps) => {
return (
<div
style={{
width: '100%',
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: 20,
}}
>
{alignmentOptions.map((alignmentOption) => (
<div
style={{
display: 'flex',
flexDirection: 'column',
fontSize: 12,
fontFamily: 'Riforma LL',
textAlign: 'center',
}}
>
<h3>Alignment {alignmentOption}</h3>
<AlignmentDemo
alignment={alignmentOption}
direction={direction}
space={space}
/>
</div>
))}
</div>
);
};

export const AlignmentCenterVertically = {
...ThreeBoxesTemplateAlignmentVert,
args: {
parent: {
direction: 'vertical',
space: 'auto',
alignment: 'center',
},
children: {
width: 100,
},
},
parameters: {
controls: {
disable: true,
},
},
export const VerticalWithFixedSpacing: Story = {
render: () => <GridTemplate direction="vertical" />,
};

export const AlignmentRight = {
...ThreeBoxesTemplateAlignmentVert,
args: {
parent: {
direction: 'vertical',
space: 'auto',
alignment: 'right',
},
},
parameters: {
name: 'Right',
Title: 'Right',
namespace: 'Right',
controls: {
disable: true,
},
sidebar: { disabled: true },
},
export const HorizontalWithFixedSpacing: Story = {
render: () => <GridTemplate direction="horizontal" />,
};

export const VerticalWithAutoSpacing: Story = {
render: () => <GridTemplate direction="vertical" space="auto" />,
};

export const HorizontalWithAutoSpacing: Story = {
render: () => <GridTemplate direction="horizontal" space="auto" />,
};
Loading