Update Toaster position

Change-Id: I474e29f277b3e2638ac758448fe20a56b5b0f3bf
This commit is contained in:
Roman Jaroš 2023-08-27 11:55:20 +02:00
parent 315756790e
commit 931979033b
9 changed files with 217 additions and 119 deletions

View file

@ -7,6 +7,7 @@ import MenuIcon from '@prokyon/components/Icons/Menu';
import RightToBracketIcon from '@prokyon/components/Icons/RightToBracket';
import Modals from '@prokyon/components/Modal/components/Modals';
import { Toasters } from '@prokyon/components/Toaster';
import { ToastersPosition } from '@prokyon/components/Toaster/components/Toasters';
import { SIZES, useMediaQuery } from '@prokyon/hooks/useMediaQuery';
import { isNilOrEmpty } from '@prokyon/utils';
@ -24,10 +25,11 @@ export type SkeletonProps = {
top?: MenuItem[];
user?: MenuItem[];
};
toasterPosition?: ToastersPosition;
};
export const Skeleton: React.FC<SkeletonProps> = (props) => {
const { children, components = {}, items } = props;
const { children, components = {}, items, toasterPosition = ToastersPosition.TopRight } = props;
const { footer } = components;
const [, setLocation] = useLocation();
@ -120,7 +122,7 @@ export const Skeleton: React.FC<SkeletonProps> = (props) => {
</div>
</div>
<Modals />
<Toasters />
<Toasters position={toasterPosition} />
</div>
);
};

View file

@ -7,21 +7,21 @@ import Message from '../../Message';
import { useToaster } from '../hooks';
export enum ToastersPosition {
topLeft,
topCenter,
topRight,
rightCenter,
bottomRight,
bottomCenter,
bottomLeft,
leftCenter,
BottomCenter = 'bottomCenter',
BottomLeft = 'bottomLeft',
BottomRight = 'bottomRight',
LeftCenter = 'leftCenter',
RightCenter = 'rightCenter',
TopCenter = 'topCenter',
TopLeft = 'topLeft',
TopRight = 'topRight',
}
export type ToastersProps = {
position: ToastersPosition;
};
export function Toasters({ position = ToastersPosition.topRight }) {
export function Toasters({ position }) {
const { toasters } = useToaster();
if (isNilOrEmpty(toasters)) {
@ -31,14 +31,14 @@ export function Toasters({ position = ToastersPosition.topRight }) {
return (
<div
className={clsx('toasters', {
'toasters--topLeft': ToastersPosition.topLeft === position,
'toasters--topCenter': ToastersPosition.topCenter === position,
'toasters--topRight': ToastersPosition.topRight === position,
'toasters--rightCenter': ToastersPosition.rightCenter === position,
'toasters--bottomRight': ToastersPosition.bottomRight === position,
'toasters--bottomCenter': ToastersPosition.bottomCenter === position,
'toasters--bottomLeft': ToastersPosition.bottomLeft === position,
'toasters--leftCenter': ToastersPosition.leftCenter === position,
'toasters--topLeft': ToastersPosition.TopLeft === position,
'toasters--topCenter': ToastersPosition.TopCenter === position,
'toasters--topRight': ToastersPosition.TopRight === position,
'toasters--rightCenter': ToastersPosition.RightCenter === position,
'toasters--bottomRight': ToastersPosition.BottomRight === position,
'toasters--bottomCenter': ToastersPosition.BottomCenter === position,
'toasters--bottomLeft': ToastersPosition.BottomLeft === position,
'toasters--leftCenter': ToastersPosition.LeftCenter === position,
})}>
{Object.keys(toasters).map((toasterId) => {
const toaster = toasters[toasterId];

View file

@ -18,7 +18,7 @@ type ToasterContextType = {
toasters: Record<ToasterId, Toaster>;
};
const DefaultTimeout = 6000;
const DefaultTimeout = 60000;
const timeouts: { [key: ToasterId]: any } = [];
export const ToasterContext = createContext<ToasterContextType>({

View file

@ -8,35 +8,39 @@ const toaster = (theme) => ({
zIndex: 10,
'&--topLeft': {
top: '3rem',
right: '3rem',
left: '3rem',
},
'&--topCenter': {
top: '3rem',
right: '3rem',
left: '50%',
transform: 'translate(-50%, 0%)',
},
'&--topRight': {
top: '3rem',
right: '3rem',
},
'&--rightCenter': {
top: '3rem',
top: '50%',
transform: 'translate(0%, -50%)',
right: '3rem',
},
'&--bottomRight': {
top: '3rem',
bottom: '3rem',
right: '3rem',
},
'&--bottomCenter': {
top: '3rem',
right: '3rem',
bottom: '3rem',
left: '50%',
transform: 'translate(-50%, 0%)',
},
'&--bottomLeft': {
top: '3rem',
right: '3rem',
bottom: '3rem',
left: '3rem',
},
'&--leftCenter': {
top: '3rem',
right: '3rem',
top: '50%',
transform: 'translate(0%, -50%)',
left: '3rem',
},
[`@media (max-width: ${theme('screens.sm-m.max')})`]: {
left: '2rem',

View file

@ -42,76 +42,76 @@ All icons are from [reactsvgicons.com](https://reactsvgicons.com/).
<IconItem name="AngleLeft">
<AngleLeft />
</IconItem>
<IconItem name="ExclamationCircle">
<ExclamationCircle />
</IconItem>
<IconItem name="RightToBracket">
<RightToBracket />
</IconItem>
<IconItem name="AngleRight">
<AngleRight />
</IconItem>
<IconItem name="ExclamationTriangle">
<ExclamationTriangle />
</IconItem>
<IconItem name="Settings">
<Settings />
</IconItem>
<IconItem name="BuildingStore">
<BuildingStore />
</IconItem>
<IconItem name="External">
<External />
</IconItem>
<IconItem name="Square">
<Square />
</IconItem>
<IconItem name="CheckCircle">
<CheckCircle />
</IconItem>
<IconItem name="File">
<File />
</IconItem>
<IconItem name="Today">
<Today />
</IconItem>
<IconItem name="CheckSquare">
<CheckSquare />
</IconItem>
<IconItem name="Folder">
<Folder />
</IconItem>
<IconItem name="Trash">
<Trash />
<IconItem name="Circle">
<Circle />
</IconItem>
<IconItem name="CircleFill">
<CircleFill />
</IconItem>
<IconItem name="HappyMessage">
<HappyMessage />
</IconItem>
<IconItem name="UserTie">
<UserTie />
</IconItem>
<IconItem name="Circle">
<Circle />
</IconItem>
<IconItem name="InfoCircle">
<InfoCircle />
</IconItem>
<IconItem name="User">
<User />
</IconItem>
<IconItem name="Cross">
<Cross />
</IconItem>
<IconItem name="Menu">
<Menu />
</IconItem>
<IconItem name="Dashboard">
<Dashboard />
</IconItem>
<IconItem name="ExclamationCircle">
<ExclamationCircle />
</IconItem>
<IconItem name="ExclamationTriangle">
<ExclamationTriangle />
</IconItem>
<IconItem name="External">
<External />
</IconItem>
<IconItem name="File">
<File />
</IconItem>
<IconItem name="Folder">
<Folder />
</IconItem>
<IconItem name="HappyMessage">
<HappyMessage />
</IconItem>
<IconItem name="InfoCircle">
<InfoCircle />
</IconItem>
<IconItem name="Menu">
<Menu />
</IconItem>
<IconItem name="RightFromBracket">
<RightFromBracket />
</IconItem>
<IconItem name="RightToBracket">
<RightToBracket />
</IconItem>
<IconItem name="Settings">
<Settings />
</IconItem>
<IconItem name="Square">
<Square />
</IconItem>
<IconItem name="Today">
<Today />
</IconItem>
<IconItem name="Trash">
<Trash />
</IconItem>
<IconItem name="User">
<User />
</IconItem>
<IconItem name="UserTie">
<UserTie />
</IconItem>
</IconGallery>

View file

@ -9,7 +9,7 @@ import { ModalWrapper, openModal as openOutsideReactModal } from '@prokyon/compo
import { useModal } from '@prokyon/components/Modal/hooks';
import { TextField } from '@prokyon/components/TextField';
type Story = StoryObj<typeof AddModalButton>;
type Story = StoryObj<typeof Modals>;
export default {
component: Modals,

View file

@ -1,41 +0,0 @@
import { Title, Unstyled } from '@storybook/blocks';
import { Button } from '@prokyon/components/Button';
import { Toasters } from '@prokyon/components/Toaster';
import { showToaster, ToasterWrapper } from '@prokyon/components/Toaster/context';
import { StatusEnum } from '@prokyon/types/common';
<Title>Toaster</Title>
`import Toaster sfrom '@prokyon/components/Toaster/components/Toasters';`
```tsx
import { useToaster } from '@prokyon/components/Toaster/hooks';
const { showToaster } = useToaster();
showToaster({ id: 'id', status: STATUS.none, message: 'message', title: 'title' });
```
Or you can call outside of React component `showToaster` from `@prokyon/components/Toaster/context`.
## Example
<Unstyled>
<ToasterWrapper>
<Button
label="Open Toaster"
status={StatusEnum.info}
onClick={() => {
showToaster({
id: 'none',
title: 'Show toaster',
label: 'Show toaster',
message: 'Toaster message.',
status: StatusEnum.info,
});
}}
/>
<Toasters />
</ToasterWrapper>
</Unstyled>

View file

@ -0,0 +1,44 @@
import { Canvas, Meta } from '@storybook/blocks';
import * as ToastersStories from './Toasters.stories';
<Meta of={ToastersStories} />
# Toasters
## Before start
### In root application use
```tsx
import { Toasters } from '@prokyon/components/Toaster';
import { ToasterWrapper } from '@prokyon/components/Toaster/context';
return (
<ToasterWrapper>
...
<Toasters />
</ToasterWrapper>
);
```
## Use hook `useToaster()`
```tsx
import { useToaster } from '@prokyon/components/Toaster/hooks';
const { showToaster } = useToaster();
showToaster({ id: 'id', status: STATUS.none, message: 'message', title: 'title' });
```
<Canvas of={ToastersStories.Hook} withToolbar />
## Use function `showToaster()`
```tsx
import { showToaster } from '@prokyon/components/Toaster/context';
showToaster({ id: 'id', status: STATUS.none, message: 'message', title: 'title' });
```
<Canvas of={ToastersStories.OutsideReact} withToolbar />

View file

@ -0,0 +1,89 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { Button } from '@prokyon/components/Button';
import { Toasters } from '@prokyon/components/Toaster';
import { ToastersPosition } from '@prokyon/components/Toaster/components/Toasters';
import { showToaster, ToasterWrapper } from '@prokyon/components/Toaster/context';
import { useToaster } from '@prokyon/components/Toaster/hooks';
import { StatusEnum } from '@prokyon/types/common';
type Story = StoryObj<typeof Toasters>;
export default {
component: Toasters,
argTypes: {
position: {
options: [
ToastersPosition.TopLeft,
ToastersPosition.TopCenter,
ToastersPosition.TopRight,
ToastersPosition.RightCenter,
ToastersPosition.BottomLeft,
ToastersPosition.BottomCenter,
ToastersPosition.BottomRight,
ToastersPosition.LeftCenter,
],
control: { type: 'radio' },
},
},
decorators: [
(Story) => (
<div className="h-80">
<ToasterWrapper>
<Story />
</ToasterWrapper>
</div>
),
],
} as Meta;
export const Hook: Story = {
name: 'Hook',
render: (args) => {
const Comp = () => {
const { showToaster } = useToaster();
return (
<Button
label="Open Toaster message"
onClick={() =>
showToaster({
id: 'toaster1',
title: 'Title',
message: 'Message',
status: StatusEnum.info,
})
}
/>
);
};
return (
<>
<Comp />
<Toasters {...args} />
</>
);
},
};
export const OutsideReact: Story = {
name: 'Function',
render: (args) => {
return (
<>
<Button
label="Open Toaster message"
onClick={() =>
showToaster({
id: 'toaster2',
title: 'Title',
message: 'Message',
status: StatusEnum.success,
})
}
/>
<Toasters {...args} />
</>
);
},
};