1- import React , { ComponentProps } from 'react' ;
2- import { Meta } from '@storybook/react' ;
1+ import React from 'react' ;
2+ import { Meta , StoryObj } from '@storybook/react' ;
33import { BADGE } from '@geometricpanda/storybook-addon-badges' ;
44import { RadiusAutoLayout } from './auto-layout' ;
5- import { Stories , Title , Description } from '@storybook/addon-docs ' ;
5+ import { AutoLayoutExtendedProps } from './auto-layout.types ' ;
66
7+ const alignmentOptions = [
8+ 'topLeft' ,
9+ 'topCenter' ,
10+ 'topRight' ,
11+ 'left' ,
12+ 'center' ,
13+ 'right' ,
14+ 'bottomLeft' ,
15+ 'bottomCenter' ,
16+ 'bottomRight' ,
17+ ] as const ;
18+
19+ /**
20+ * The RadiusAutoLayout component duplicates the behaviour of Figma AutoLayout's
21+ * Alignment property. This deviates from how CSS flexbox works in some cases -
22+ * for example when the `direction` is changed, the alignment of the children
23+ * remains the same instead of being dependent on the flex-direction. Also, when
24+ * the `space` property is set to `auto`, this is equivalent to writing
25+ * `justify-content: space-between`, which evenly spaces children regardless of
26+ * direction.
27+ *
28+ * Please see the examples of the different behaviours below.
29+ *
30+ * ## Resources
31+ * [How Figma Alignment Works](https://help.figma.com/hc/en-us/articles/360040451373-Explore-auto-layout-properties#alignment)
32+ */
733const meta : Meta < typeof RadiusAutoLayout > = {
834 component : RadiusAutoLayout ,
935 title : 'Component Development Kit / Auto Layout/Alignment' ,
@@ -19,194 +45,180 @@ const meta: Meta<typeof RadiusAutoLayout> = {
1945 patch : process . env . COMPONENT_VERSION ?. [ 2 ] ,
2046 } ,
2147 badges : [ BADGE . BETA ] ,
22- docs : {
23- page : ( ) => (
24- < >
25- < Title > Alignment</ Title >
26- < Description children = "We duplicate the way Figma aligns in Auto Layout components." > </ Description >
27- < Stories includePrimary = { true } />
28- </ >
29- ) ,
48+ controls : {
49+ // only show controls relevant to this story
50+ include : [ 'alignment' , 'direction' , 'space' ] ,
3051 } ,
3152 } ,
32- } ;
33-
34- export default meta ;
35- // type Story = StoryObj<typeof RadiusAutoLayout>;
36- // TODO: apply `Story` type to all stories - causes issues due to parent and children args not existing in original component
37-
38- const ThreeBoxesTemplateAlignmentHor = {
39- render : ( args : {
40- parent : ComponentProps < typeof RadiusAutoLayout > ;
41- children : ComponentProps < typeof RadiusAutoLayout > ;
42- } ) => (
43- < RadiusAutoLayout direction = "vertical" >
44- < RadiusAutoLayout
45- direction = { args . parent . direction }
46- space = { args . parent . space }
47- alignment = { args . parent . alignment }
48- width = "fill-parent"
49- height = {
50- args . parent . direction === 'horizontal' ? 'fill-parent' : '100px'
51- }
52- padding = { { css : '12px' } }
53- >
54- < RadiusAutoLayout
55- width = { args . children . width }
56- height = { 20 }
57- fill = { { css : '#D44527' } }
58- />
59- < RadiusAutoLayout
60- width = { args . children . width }
61- height = { 40 }
62- fill = { { css : '#D44527' } }
63- />
64- < RadiusAutoLayout
65- width = { args . children . width }
66- height = { 60 }
67- fill = { { css : '#D44527' } }
68- />
69- </ RadiusAutoLayout >
70- </ RadiusAutoLayout >
71- ) ,
72- } ;
73-
74- export const AlignmentTop = {
75- ...ThreeBoxesTemplateAlignmentHor ,
76- args : {
77- parent : {
78- direction : 'horizontal' ,
79- space : 'auto' ,
80- alignment : 'top' ,
53+ argTypes : {
54+ alignment : {
55+ options : alignmentOptions ,
8156 } ,
82- children : {
83- width : 100 ,
57+ direction : {
58+ options : [ 'horizontal' , 'vertical' ] ,
8459 } ,
85- } ,
86- parameters : {
87- controls : {
88- disable : true ,
60+ space : {
61+ options : {
62+ auto : 'auto' ,
63+ fixed : { css : '10px' } ,
64+ } ,
65+ table : { defaultValue : { summary : '10px' } } ,
8966 } ,
9067 } ,
91- } ;
92-
93- export const AlignmentCenter = {
94- ...ThreeBoxesTemplateAlignmentHor ,
9568 args : {
96- parent : {
97- direction : 'horizontal' ,
98- space : 'auto' ,
99- alignment : 'center' ,
100- } ,
101- children : {
102- width : 100 ,
103- } ,
104- } ,
105- parameters : {
106- controls : {
107- disable : true ,
108- } ,
69+ alignment : 'topLeft' ,
70+ direction : 'vertical' ,
10971 } ,
11072} ;
11173
112- export const AlignmentBottom = {
113- ...ThreeBoxesTemplateAlignmentHor ,
114- args : {
115- parent : {
116- direction : 'horizontal' ,
117- space : 'auto' ,
118- alignment : 'bottom' ,
119- } ,
120- children : {
121- width : 100 ,
122- } ,
123- } ,
124- parameters : {
125- controls : {
126- disable : true ,
127- } ,
128- sidebar : { disabled : true } ,
129- } ,
74+ export default meta ;
75+ type Story = StoryObj < typeof RadiusAutoLayout > ;
76+
77+ const PADDING = 24 ;
78+ const CIRCLE_SIZE = 12 ;
79+
80+ /** A circle to show the alignment of the child AutoLayouts */
81+ const Circle = ( {
82+ top,
83+ left,
84+ bottom,
85+ right,
86+ } : {
87+ top ?: number | string ;
88+ left ?: number | string ;
89+ bottom ?: number | string ;
90+ right ?: number | string ;
91+ } ) => {
92+ return (
93+ < div
94+ style = { {
95+ backgroundColor : '#D9D9D9' ,
96+ height : CIRCLE_SIZE ,
97+ width : CIRCLE_SIZE ,
98+ borderRadius : '50%' ,
99+ position : 'absolute' ,
100+ top,
101+ left,
102+ bottom,
103+ right,
104+ } }
105+ > </ div >
106+ ) ;
130107} ;
131108
132- const ThreeBoxesTemplateAlignmentVert = {
133- render : ( args : {
134- parent : ComponentProps < typeof RadiusAutoLayout > ;
135- children : ComponentProps < typeof RadiusAutoLayout > ;
136- } ) => (
137- < RadiusAutoLayout direction = "vertical" >
109+ /** The positions of each of the circles */
110+ const circles = [
111+ { top : PADDING , left : PADDING } ,
112+ { top : PADDING , left : `calc(50% - ${ CIRCLE_SIZE / 2 } px)` } ,
113+ { top : PADDING , right : PADDING } ,
114+ { top : `calc(50% - ${ CIRCLE_SIZE / 2 } px)` , left : PADDING } ,
115+ {
116+ top : `calc(50% - ${ CIRCLE_SIZE / 2 } px)` ,
117+ left : `calc(50% - ${ CIRCLE_SIZE / 2 } px)` ,
118+ } ,
119+ { top : `calc(50% - ${ CIRCLE_SIZE / 2 } px)` , right : PADDING } ,
120+ { bottom : PADDING , left : PADDING } ,
121+ { bottom : PADDING , left : `calc(50% - ${ CIRCLE_SIZE / 2 } px)` } ,
122+ { bottom : PADDING , right : PADDING } ,
123+ ] ;
124+
125+ const AlignmentDemo = ( {
126+ alignment,
127+ direction,
128+ space,
129+ } : {
130+ alignment : AutoLayoutExtendedProps [ 'alignment' ] ;
131+ direction : AutoLayoutExtendedProps [ 'direction' ] ;
132+ space : AutoLayoutExtendedProps [ 'space' ] ;
133+ } ) => {
134+ return (
135+ < RadiusAutoLayout
136+ width = "284px"
137+ height = "284px"
138+ stroke = { { css : '#A6A6A6' } }
139+ strokeWidth = { { css : '1px' } }
140+ padding = { { css : `${ PADDING } px` } }
141+ alignment = { alignment }
142+ direction = { direction }
143+ space = { space }
144+ isParent
145+ >
146+ < RadiusAutoLayout
147+ width = { direction === 'vertical' ? '80px' : '12px' }
148+ height = { direction === 'vertical' ? '12px' : '80px' }
149+ fill = { { css : '#F7856E' } }
150+ style = { { zIndex : 1 } }
151+ />
138152 < RadiusAutoLayout
139- direction = { args . parent . direction }
140- space = { args . parent . space }
141- alignment = { args . parent . alignment }
142- width = "fill-parent"
143- height = {
144- args . parent . direction === 'horizontal' ? 'fill-parent' : '100px'
145- }
146- padding = { { css : '12px' } }
147- >
148- < RadiusAutoLayout width = "25%" height = { 10 } fill = { { css : '#D44527' } } />
149- < RadiusAutoLayout width = "50%" height = { 10 } fill = { { css : '#D44527' } } />
150- < RadiusAutoLayout width = "75%" height = { 10 } fill = { { css : '#D44527' } } />
151- </ RadiusAutoLayout >
153+ width = { direction === 'vertical' ? '113px' : '12px' }
154+ height = { direction === 'vertical' ? '12px' : '113px' }
155+ fill = { { css : '#F7856E' } }
156+ style = { { zIndex : 1 } }
157+ />
158+ < RadiusAutoLayout
159+ width = { direction === 'vertical' ? '65px' : '12px' }
160+ height = { direction === 'vertical' ? '12px' : '65px' }
161+ fill = { { css : '#F7856E' } }
162+ style = { { zIndex : 1 } }
163+ />
164+ { circles . map ( ( positionProps ) => (
165+ < Circle { ...positionProps } />
166+ ) ) }
152167 </ RadiusAutoLayout >
168+ ) ;
169+ } ;
170+
171+ export const Alignment : Story = {
172+ // @ts -expect-error - bug with `args` type inference due to polymorphism
173+ render : ( { alignment, direction, space } : AutoLayoutExtendedProps ) => (
174+ < AlignmentDemo alignment = { alignment } direction = { direction } space = { space } />
153175 ) ,
154176} ;
155177
156- export const AlignmentLeft = {
157- ...ThreeBoxesTemplateAlignmentVert ,
158- args : {
159- parent : {
160- direction : 'vertical' ,
161- space : 'auto' ,
162- alignment : 'left' ,
163- } ,
164- children : {
165- width : 100 ,
166- } ,
167- } ,
168- parameters : {
169- controls : {
170- disable : true ,
171- } ,
172- } ,
178+ const GridTemplate = ( { direction, space } : AutoLayoutExtendedProps ) => {
179+ return (
180+ < div
181+ style = { {
182+ width : '100%' ,
183+ display : 'grid' ,
184+ gridTemplateColumns : 'repeat(3, 1fr)' ,
185+ gap : 20 ,
186+ } }
187+ >
188+ { alignmentOptions . map ( ( alignmentOption ) => (
189+ < div
190+ style = { {
191+ display : 'flex' ,
192+ flexDirection : 'column' ,
193+ fontSize : 12 ,
194+ fontFamily : 'Riforma LL' ,
195+ textAlign : 'center' ,
196+ } }
197+ >
198+ < h3 > Alignment { alignmentOption } </ h3 >
199+ < AlignmentDemo
200+ alignment = { alignmentOption }
201+ direction = { direction }
202+ space = { space }
203+ />
204+ </ div >
205+ ) ) }
206+ </ div >
207+ ) ;
173208} ;
174209
175- export const AlignmentCenterVertically = {
176- ...ThreeBoxesTemplateAlignmentVert ,
177- args : {
178- parent : {
179- direction : 'vertical' ,
180- space : 'auto' ,
181- alignment : 'center' ,
182- } ,
183- children : {
184- width : 100 ,
185- } ,
186- } ,
187- parameters : {
188- controls : {
189- disable : true ,
190- } ,
191- } ,
210+ export const VerticalWithFixedSpacing : Story = {
211+ render : ( ) => < GridTemplate direction = "vertical" /> ,
192212} ;
193213
194- export const AlignmentRight = {
195- ...ThreeBoxesTemplateAlignmentVert ,
196- args : {
197- parent : {
198- direction : 'vertical' ,
199- space : 'auto' ,
200- alignment : 'right' ,
201- } ,
202- } ,
203- parameters : {
204- name : 'Right' ,
205- Title : 'Right' ,
206- namespace : 'Right' ,
207- controls : {
208- disable : true ,
209- } ,
210- sidebar : { disabled : true } ,
211- } ,
214+ export const HorizontalWithFixedSpacing : Story = {
215+ render : ( ) => < GridTemplate direction = "horizontal" /> ,
216+ } ;
217+
218+ export const VerticalWithAutoSpacing : Story = {
219+ render : ( ) => < GridTemplate direction = "vertical" space = "auto" /> ,
220+ } ;
221+
222+ export const HorizontalWithAutoSpacing : Story = {
223+ render : ( ) => < GridTemplate direction = "horizontal" space = "auto" /> ,
212224} ;
0 commit comments