Skip to content

Commit

Permalink
PLASMA-3865: Flow api draft & example
Browse files Browse the repository at this point in the history
  • Loading branch information
vadim-kudr committed Dec 18, 2024
1 parent 3084852 commit 43dacf3
Showing 1 changed file with 305 additions and 0 deletions.
305 changes: 305 additions & 0 deletions packages/plasma-new-hope/src/components/Flow/Flow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
import React, { CSSProperties, useState } from 'react';
import cls from 'classnames';
import { styled } from '@linaria/react';

import { Select, Slider } from '@salutejs/plasma-web';

const Header = styled.header`
position: sticky;
top: 0;
display: flex;
padding-bottom: 1rem;
gap: 0 1rem;
background: white;
`;

const SliderStyled = styled(Slider)`
width: 300px;
height: 3rem;
`;

const Item = styled.div`
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background: lightblue;
display: flex;
align-items: center;
justify-content: center;
`;

const arrangements = ['start', 'center', 'end', 'spaceBetween', 'spaceAround'];
const alignments = ['start', 'center', 'end'];

const horizontalItemsWidth = [120, 215, 57, 164, 60, 76];
const verticalItemsWidth = [100, 32, 171, 74, 179, 55];
const heights = [10, 50, 45, 33, 14, 55];

const Wrapper = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
border-radius: 0.5rem;
background-color: tomato;
&.vertical {
flex-direction: column;
}
&.grid {
display: grid;
grid-template-columns: repeat(var(--plasma-private-items), auto);
grid-auto-flow: row;
&:not(.vertical) {
&[data-arrangement='start'] {
justify-items: start;
}
&[data-arrangement='center'] {
justify-items: center;
}
&[data-arrangement='end'] {
justify-items: end;
}
&[data-arrangement='spaceBetween'] {
justify-content: space-between;
}
&[data-arrangement='spaceAround'] {
justify-content: space-around;
}
&[data-alignment='start'] {
align-items: start;
}
&[data-alignment='center'] {
align-items: center;
}
&[data-alignment='end'] {
align-items: end;
}
}
&.vertical {
grid-template-rows: repeat(var(--plasma-private-items), auto);
grid-auto-flow: column;
&[data-arrangement='start'] {
align-content: start;
}
&[data-arrangement='center'] {
align-content: center;
}
&[data-arrangement='end'] {
align-content: end;
}
&[data-arrangement='spaceBetween'] {
align-content: space-between;
}
&[data-arrangement='spaceAround'] {
align-content: space-around;
}
&[data-alignment='start'] {
justify-items: start;
}
&[data-alignment='center'] {
justify-items: center;
}
&[data-alignment='end'] {
justify-items: end;
}
}
}
&:not(&.grid) {
&[data-arrangement='start'] {
justify-content: start;
}
&[data-arrangement='center'] {
justify-content: center;
}
&[data-arrangement='end'] {
justify-content: end;
}
&[data-arrangement='spaceBetween'] {
justify-content: space-between;
}
&[data-arrangement='spaceAround'] {
justify-content: space-around;
}
&[data-alignment='start'] {
align-items: start;
}
&[data-alignment='center'] {
align-items: center;
}
&[data-alignment='end'] {
align-items: end;
}
}
`;

const horizontalItems = horizontalItemsWidth.map((width, index) => (
<Item
style={{
width,
height: heights[index],
}}
>
{index + 1}
</Item>
));

const verticalItems = verticalItemsWidth.map((width, index) => (
<Item
style={{
width: width,
minHeight: `${heights[index]}px`,
}}
>
{index + 1}
</Item>
));

interface Props {
className?: string;
style?: CSSProperties;
orientation?: 'horizontal' | 'vertical';
arrangement?: 'start' | 'center' | 'end' | 'spaceBetween' | 'spaceAround';
alignment?: 'start' | 'center' | 'end';
mainAxisGap?: string;
crossAxisGap?: string;
itemsPerLine?: number;
}

export const Flow: React.FC<Props> = ({
children,
className,
style,
orientation = 'horizontal',
arrangement,
alignment,
mainAxisGap = '0',
crossAxisGap = '0',
itemsPerLine,
}) => {
const needGrid = Boolean(itemsPerLine);

return (
<Wrapper
className={cls(className, {
vertical: orientation === 'vertical',
grid: needGrid,
})}
style={{
...style,
'--plasma-private-gap': `${mainAxisGap} ${crossAxisGap}`,
'--plasma-private-items': String(itemsPerLine),
}}
data-arrangement={arrangement}
data-alignment={alignment}
>
{children}
</Wrapper>
);
};

export const App: React.FC = () => {
const [itemsCount, setItemsCount] = useState(3);
const [arrangement, setArrangement] = useState<Props['arrangement']>();
const [alignment, setAlignment] = useState<Props['alignment']>();

return (
<>
<Header>
<SliderStyled
label="items count"
min={0}
max={heights.length}
value={itemsCount}
showCurrentValue
onChange={setItemsCount}
onChangeCommitted={setItemsCount}
/>
<Select
label="arrangement"
helperText="Расположение элементов относительно выбранной ориентации"
items={arrangements.map((a) => ({ value: a, label: a }))}
onChange={setArrangement}
/>
<Select
label="alignment"
helperText="Выравнивание элементов внутри строк по вертикали при горизонтальной ориентации, или внутри столбцов по горизонтали при вертикальной."
items={alignments.map((a) => ({ value: a, label: a }))}
onChange={setAlignment}
/>
</Header>
<hr />
<Flow arrangement={arrangement} alignment={alignment} style={{ width: '34rem', height: '12rem' }}>
{horizontalItems}
</Flow>
<hr />
<Flow
arrangement={arrangement}
alignment={alignment}
style={{ width: '40rem', height: '12rem' }}
itemsPerLine={itemsCount}
>
{horizontalItems}
</Flow>
<hr />
<Flow arrangement={arrangement} alignment={alignment} orientation="vertical" style={{ width: '28rem' }}>
{verticalItems}
</Flow>
<hr />
<Flow
arrangement={arrangement}
alignment={alignment}
orientation="vertical"
style={{ width: '28rem', height: '12rem' }}
>
{verticalItems}
</Flow>
<hr />
<Flow
arrangement={arrangement}
alignment={alignment}
orientation="vertical"
style={{ width: '28rem' }}
itemsPerLine={itemsCount}
>
{verticalItems}
</Flow>
<hr />
<Flow
arrangement={arrangement}
alignment={alignment}
orientation="vertical"
style={{ width: '28rem', height: '12rem' }}
itemsPerLine={itemsCount}
>
{verticalItems}
</Flow>
</>
);
};

0 comments on commit 43dacf3

Please sign in to comment.