Skip to content

Commit

Permalink
fix(plasma-core): PopupBase refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
kayman233 committed Sep 27, 2023
1 parent c9bf34a commit 2406189
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 127 deletions.
52 changes: 17 additions & 35 deletions packages/plasma-b2c/src/components/PopupBase/PopupBase.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import styled, { keyframes } from 'styled-components';
import styled from 'styled-components';
import { Story, Meta } from '@storybook/react';
import { InSpacingDecorator } from '@salutejs/plasma-sb-utils';
import { surfaceSolid03 } from '@salutejs/plasma-tokens-web';
import { surfaceSolid03, surfaceSolid02 } from '@salutejs/plasma-tokens-web';

import { SSRProvider } from '../SSRProvider';
import { Button } from '../Button';
Expand All @@ -13,7 +13,7 @@ export default {
title: 'Controls/PopupBase',
decorators: [InSpacingDecorator],
argTypes: {
position: {
placement: {
options: [
'center',
'top',
Expand All @@ -32,30 +32,7 @@ export default {
},
} as Meta;

type PopupBaseStoryProps = { position: string; offsetX: number; offsetY: number };

const showAnimation = keyframes`
0% {
transform: translateX(100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
`;
const hideAnimation = keyframes`
0% {
transform: translateX(0);
opacity: 1;
}
100% {
transform: translateX(100%);
opacity: 0;
}
`;
type PopupBaseStoryProps = { placement: string; offsetX: number; offsetY: number };

const StyledButton = styled(Button)`
margin-top: 1rem;
Expand All @@ -82,7 +59,12 @@ const OtherContent = styled.div`
right: 0;
`;

export const PopupBaseDemo: Story<PopupBaseStoryProps> = ({ position, offsetX, offsetY }) => {
const Content = styled.div`
background: ${surfaceSolid02};
padding: 1rem;
`;

export const PopupBaseDemo: Story<PopupBaseStoryProps> = ({ placement, offsetX, offsetY }) => {
const [isOpenA, setIsOpenA] = React.useState(false);
const [isOpenB, setIsOpenB] = React.useState(false);

Expand All @@ -95,28 +77,28 @@ export const PopupBaseDemo: Story<PopupBaseStoryProps> = ({ position, offsetX, o
<StyledButton text="Открыть во Frame" onClick={() => setIsOpenA(true)} />
<StyledButton text="Открыть в document" onClick={() => setIsOpenB(true)} />
</div>
<PopupBase frame={ref} isOpen={isOpenA} position={position} offset={[offsetX, offsetY]}>
<div style={{ background: 'white', padding: '1rem' }}>
<PopupBase frame={ref} isOpen={isOpenA} placement={placement} offset={[offsetX, offsetY]}>
<Content>
<Button onClick={() => setIsOpenA(false)}>Close</Button>
<>Content</>
</div>
</Content>
</PopupBase>
<OtherContent ref={ref}>
<>Frame</>
</OtherContent>
<PopupBase frame="document" isOpen={isOpenB} position={position} offset={[offsetX, offsetY]}>
<div style={{ background: 'white', padding: '1rem' }}>
<PopupBase frame="document" isOpen={isOpenB} placement={placement} offset={[offsetX, offsetY]}>
<Content>
<Button onClick={() => setIsOpenB(false)}>Close</Button>
<>Content</>
</div>
</Content>
</PopupBase>
</StyledWrapper>
</SSRProvider>
);
};

PopupBaseDemo.args = {
position: 'center',
placement: 'center',
offsetX: 0,
offsetY: 0,
};
7 changes: 2 additions & 5 deletions packages/plasma-core/api/plasma-core.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { FlattenSimpleInterpolation } from 'styled-components';
import { FunctionComponent } from 'react';
import { HTMLAttributes } from 'react';
import { InterpolationFunction } from 'styled-components';
import { Keyframes } from 'styled-components';
import { MutableRefObject } from 'react';
import { default as React_2 } from 'react';
import { ReactNode } from 'react';
Expand Down Expand Up @@ -854,14 +853,12 @@ export type PopupBasePlacement = BasicPopupBasePlacement | MixedPopupBasePlaceme
// @public (undocumented)
export interface PopupBaseProps extends React_2.HTMLAttributes<HTMLDivElement> {
children?: React_2.ReactNode;
frame: 'document' | React_2.RefObject<HTMLElement>;
hideAnimation?: Keyframes;
frame?: 'document' | React_2.RefObject<HTMLElement>;
isOpen: boolean;
// (undocumented)
offset?: [number | string, number | string];
// (undocumented)
position?: PopupBasePlacement;
showAnimation?: Keyframes;
placement?: PopupBasePlacement;
zIndex?: string;
}

Expand Down
77 changes: 25 additions & 52 deletions packages/plasma-core/src/components/PopupBase/PopupBase.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState, useContext, FC } from 'react';
import ReactDOM from 'react-dom';
import styled, { Keyframes, css } from 'styled-components';
import styled, { css } from 'styled-components';

import { useUniqId } from '../../hooks';

Expand All @@ -19,27 +19,20 @@ export interface PopupBaseProps extends React.HTMLAttributes<HTMLDivElement> {
* center - по умолчанию
* left, right, top, bottom и их комбинации
*/
position?: PopupBasePlacement;
/* Смещение отнсительно текущей позиции налево и вверх
* (x, y) - <number | string, number | string> или проценты
placement?: PopupBasePlacement;
/* Смещение отнсительно текущей позиции налево и вверх.
* (x, y) - <number | string, number | string> или проценты.
* При передаче number, то расчёт в rem.
*/
offset?: [number | string, number | string];
/**
* В каком контейнере позиционируется.
* В каком контейнере позиционируется(по умолчанию document).
*/
frame: 'document' | React.RefObject<HTMLElement>;
frame?: 'document' | React.RefObject<HTMLElement>;
/**
* Содержимое PopupBase.
*/
children?: React.ReactNode;
/**
* Анимация при появлении PopupBase.
*/
showAnimation?: Keyframes;
/**
* Анимация при скрытии PopupBase.
*/
hideAnimation?: Keyframes;
/**
* Значение z-index для PopupBase.
*/
Expand All @@ -50,33 +43,26 @@ interface HidingProps {
isHiding?: boolean;
}

const DEFAULT_Z_INDEX = 9000;
export const DEFAULT_Z_INDEX = 9000;

interface PopupBaseRootProps {
position?: PopupBasePlacement;
frame: 'document' | React.RefObject<HTMLElement>;
offset?: [number | string, number | string];
showAnimation?: Keyframes;
hideAnimation?: Keyframes;
zIndex?: string;
}
interface PopupBaseRootProps extends Omit<PopupBaseProps, 'isOpen'> {}

const PopupBaseView = styled.div`
position: relative;
max-width: 100%;
pointer-events: all;
`;

const handlePosition = (position?: PopupBasePlacement, offset?: [number | string, number | string]) => {
let x = '';
let y = '';
const handlePosition = (placement?: PopupBasePlacement, offset?: [number | string, number | string]) => {
let x = '0rem';
let y = '0rem';
if (offset) {
const [_x, _y] = offset;
x = typeof _x === 'number' ? `${_x}rem` : _x;
y = typeof _y === 'number' ? `${_y}rem` : _y;
}

if (!position || position === 'center') {
if (!placement || placement === 'center') {
return css`
left: calc(50% + ${x});
top: calc(50% - ${y});
Expand All @@ -88,34 +74,34 @@ const handlePosition = (position?: PopupBasePlacement, offset?: [number | string
let right;
let top;
let bottom;
const placements = position.split('-') as BasicPopupBasePlacement[];
const placements = placement.split('-') as BasicPopupBasePlacement[];

placements.forEach((placement: BasicPopupBasePlacement) => {
switch (placement) {
case 'left':
left = 0;
left = x;
break;
case 'right':
right = 0;
right = x;
break;
case 'top':
top = 0;
top = y;
break;
case 'bottom':
bottom = 0;
bottom = y;
break;
default:
break;
}
});

const isCenteredX = left !== 0 && right !== 0;
const isCenteredY = top !== 0 && bottom !== 0;
const isCenteredX = left === undefined && right === undefined;
const isCenteredY = top === undefined && bottom === undefined;

return css`
left: calc(${left} + ${x});
left: ${left};
right: ${right};
top: calc(${top} - ${y});
top: ${top};
bottom: ${bottom};
${isCenteredX &&
css`
Expand All @@ -139,11 +125,7 @@ const PopupBaseRoot = styled.div<HidingProps & PopupBaseRootProps>`
z-index: ${zIndex || DEFAULT_Z_INDEX};
`}
${({ position, offset }) => handlePosition(position, offset)};
${({ isHiding, showAnimation, hideAnimation }) => css`
animation: 0.4s ${isHiding ? hideAnimation : showAnimation} ease-out;
`}
${({ placement, offset }) => handlePosition(placement, offset)};
`;

/**
Expand All @@ -153,14 +135,12 @@ const PopupBaseRoot = styled.div<HidingProps & PopupBaseRootProps>`
export const PopupBase: FC<PopupBaseProps> = ({
id,
isOpen,
position,
placement,
offset,
frame = 'document',
children,
role,
zIndex,
showAnimation,
hideAnimation,
...rest
}) => {
const uniqId = useUniqId();
Expand Down Expand Up @@ -209,14 +189,7 @@ export const PopupBase: FC<PopupBaseProps> = ({
<>
{portalRef.current &&
ReactDOM.createPortal(
<PopupBaseRoot
position={position}
frame={frame}
offset={offset}
zIndex={zIndex}
showAnimation={showAnimation}
hideAnimation={hideAnimation}
>
<PopupBaseRoot placement={placement} frame={frame} offset={offset} zIndex={zIndex}>
<PopupBaseView {...rest} role={role}>
{children}
</PopupBaseView>
Expand Down
52 changes: 17 additions & 35 deletions packages/plasma-web/src/components/PopupBase/PopupBase.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import styled, { keyframes } from 'styled-components';
import styled from 'styled-components';
import { Story, Meta } from '@storybook/react';
import { surfaceSolid03 } from '@salutejs/plasma-tokens-web';
import { surfaceSolid03, surfaceSolid02 } from '@salutejs/plasma-tokens-web';

import { SSRProvider } from '../SSRProvider';
import { InSpacingDecorator } from '../../helpers';
Expand All @@ -13,7 +13,7 @@ export default {
title: 'Controls/PopupBase',
decorators: [InSpacingDecorator],
argTypes: {
position: {
placement: {
options: [
'center',
'top',
Expand All @@ -32,30 +32,7 @@ export default {
},
} as Meta;

type PopupBaseStoryProps = { position: string; offsetX: number; offsetY: number };

const showAnimation = keyframes`
0% {
transform: translateX(100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
`;
const hideAnimation = keyframes`
0% {
transform: translateX(0);
opacity: 1;
}
100% {
transform: translateX(100%);
opacity: 0;
}
`;
type PopupBaseStoryProps = { placement: string; offsetX: number; offsetY: number };

const StyledButton = styled(Button)`
margin-top: 1rem;
Expand All @@ -82,7 +59,12 @@ const OtherContent = styled.div`
right: 0;
`;

export const PopupBaseDemo: Story<PopupBaseStoryProps> = ({ position, offsetX, offsetY }) => {
const Content = styled.div`
background: ${surfaceSolid02};
padding: 1rem;
`;

export const PopupBaseDemo: Story<PopupBaseStoryProps> = ({ placement, offsetX, offsetY }) => {
const [isOpenA, setIsOpenA] = React.useState(false);
const [isOpenB, setIsOpenB] = React.useState(false);

Expand All @@ -95,28 +77,28 @@ export const PopupBaseDemo: Story<PopupBaseStoryProps> = ({ position, offsetX, o
<StyledButton text="Открыть во Frame" onClick={() => setIsOpenA(true)} />
<StyledButton text="Открыть в document" onClick={() => setIsOpenB(true)} />
</div>
<PopupBase frame={ref} isOpen={isOpenA} position={position} offset={[offsetX, offsetY]}>
<div style={{ background: 'white', padding: '1rem' }}>
<PopupBase frame={ref} isOpen={isOpenA} placement={placement} offset={[offsetX, offsetY]}>
<Content>
<Button onClick={() => setIsOpenA(false)}>Close</Button>
<>Content</>
</div>
</Content>
</PopupBase>
<OtherContent ref={ref}>
<>Frame</>
</OtherContent>
<PopupBase frame="document" isOpen={isOpenB} position={position} offset={[offsetX, offsetY]}>
<div style={{ background: 'white', padding: '1rem' }}>
<PopupBase frame="document" isOpen={isOpenB} placement={placement} offset={[offsetX, offsetY]}>
<Content>
<Button onClick={() => setIsOpenB(false)}>Close</Button>
<>Content</>
</div>
</Content>
</PopupBase>
</StyledWrapper>
</SSRProvider>
);
};

PopupBaseDemo.args = {
position: 'center',
placement: 'center',
offsetX: 0,
offsetY: 0,
};

0 comments on commit 2406189

Please sign in to comment.