Update Toaster position
Change-Id: I474e29f277b3e2638ac758448fe20a56b5b0f3bf
This commit is contained in:
parent
315756790e
commit
931979033b
9 changed files with 217 additions and 119 deletions
|
@ -7,6 +7,7 @@ import MenuIcon from '@prokyon/components/Icons/Menu';
|
||||||
import RightToBracketIcon from '@prokyon/components/Icons/RightToBracket';
|
import RightToBracketIcon from '@prokyon/components/Icons/RightToBracket';
|
||||||
import Modals from '@prokyon/components/Modal/components/Modals';
|
import Modals from '@prokyon/components/Modal/components/Modals';
|
||||||
import { Toasters } from '@prokyon/components/Toaster';
|
import { Toasters } from '@prokyon/components/Toaster';
|
||||||
|
import { ToastersPosition } from '@prokyon/components/Toaster/components/Toasters';
|
||||||
import { SIZES, useMediaQuery } from '@prokyon/hooks/useMediaQuery';
|
import { SIZES, useMediaQuery } from '@prokyon/hooks/useMediaQuery';
|
||||||
import { isNilOrEmpty } from '@prokyon/utils';
|
import { isNilOrEmpty } from '@prokyon/utils';
|
||||||
|
|
||||||
|
@ -24,10 +25,11 @@ export type SkeletonProps = {
|
||||||
top?: MenuItem[];
|
top?: MenuItem[];
|
||||||
user?: MenuItem[];
|
user?: MenuItem[];
|
||||||
};
|
};
|
||||||
|
toasterPosition?: ToastersPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Skeleton: React.FC<SkeletonProps> = (props) => {
|
export const Skeleton: React.FC<SkeletonProps> = (props) => {
|
||||||
const { children, components = {}, items } = props;
|
const { children, components = {}, items, toasterPosition = ToastersPosition.TopRight } = props;
|
||||||
const { footer } = components;
|
const { footer } = components;
|
||||||
|
|
||||||
const [, setLocation] = useLocation();
|
const [, setLocation] = useLocation();
|
||||||
|
@ -120,7 +122,7 @@ export const Skeleton: React.FC<SkeletonProps> = (props) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Modals />
|
<Modals />
|
||||||
<Toasters />
|
<Toasters position={toasterPosition} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,21 +7,21 @@ import Message from '../../Message';
|
||||||
import { useToaster } from '../hooks';
|
import { useToaster } from '../hooks';
|
||||||
|
|
||||||
export enum ToastersPosition {
|
export enum ToastersPosition {
|
||||||
topLeft,
|
BottomCenter = 'bottomCenter',
|
||||||
topCenter,
|
BottomLeft = 'bottomLeft',
|
||||||
topRight,
|
BottomRight = 'bottomRight',
|
||||||
rightCenter,
|
LeftCenter = 'leftCenter',
|
||||||
bottomRight,
|
RightCenter = 'rightCenter',
|
||||||
bottomCenter,
|
TopCenter = 'topCenter',
|
||||||
bottomLeft,
|
TopLeft = 'topLeft',
|
||||||
leftCenter,
|
TopRight = 'topRight',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToastersProps = {
|
export type ToastersProps = {
|
||||||
position: ToastersPosition;
|
position: ToastersPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Toasters({ position = ToastersPosition.topRight }) {
|
export function Toasters({ position }) {
|
||||||
const { toasters } = useToaster();
|
const { toasters } = useToaster();
|
||||||
|
|
||||||
if (isNilOrEmpty(toasters)) {
|
if (isNilOrEmpty(toasters)) {
|
||||||
|
@ -31,14 +31,14 @@ export function Toasters({ position = ToastersPosition.topRight }) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx('toasters', {
|
className={clsx('toasters', {
|
||||||
'toasters--topLeft': ToastersPosition.topLeft === position,
|
'toasters--topLeft': ToastersPosition.TopLeft === position,
|
||||||
'toasters--topCenter': ToastersPosition.topCenter === position,
|
'toasters--topCenter': ToastersPosition.TopCenter === position,
|
||||||
'toasters--topRight': ToastersPosition.topRight === position,
|
'toasters--topRight': ToastersPosition.TopRight === position,
|
||||||
'toasters--rightCenter': ToastersPosition.rightCenter === position,
|
'toasters--rightCenter': ToastersPosition.RightCenter === position,
|
||||||
'toasters--bottomRight': ToastersPosition.bottomRight === position,
|
'toasters--bottomRight': ToastersPosition.BottomRight === position,
|
||||||
'toasters--bottomCenter': ToastersPosition.bottomCenter === position,
|
'toasters--bottomCenter': ToastersPosition.BottomCenter === position,
|
||||||
'toasters--bottomLeft': ToastersPosition.bottomLeft === position,
|
'toasters--bottomLeft': ToastersPosition.BottomLeft === position,
|
||||||
'toasters--leftCenter': ToastersPosition.leftCenter === position,
|
'toasters--leftCenter': ToastersPosition.LeftCenter === position,
|
||||||
})}>
|
})}>
|
||||||
{Object.keys(toasters).map((toasterId) => {
|
{Object.keys(toasters).map((toasterId) => {
|
||||||
const toaster = toasters[toasterId];
|
const toaster = toasters[toasterId];
|
||||||
|
|
|
@ -18,7 +18,7 @@ type ToasterContextType = {
|
||||||
toasters: Record<ToasterId, Toaster>;
|
toasters: Record<ToasterId, Toaster>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DefaultTimeout = 6000;
|
const DefaultTimeout = 60000;
|
||||||
const timeouts: { [key: ToasterId]: any } = [];
|
const timeouts: { [key: ToasterId]: any } = [];
|
||||||
|
|
||||||
export const ToasterContext = createContext<ToasterContextType>({
|
export const ToasterContext = createContext<ToasterContextType>({
|
||||||
|
|
|
@ -8,35 +8,39 @@ const toaster = (theme) => ({
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
'&--topLeft': {
|
'&--topLeft': {
|
||||||
top: '3rem',
|
top: '3rem',
|
||||||
right: '3rem',
|
left: '3rem',
|
||||||
},
|
},
|
||||||
'&--topCenter': {
|
'&--topCenter': {
|
||||||
top: '3rem',
|
top: '3rem',
|
||||||
right: '3rem',
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, 0%)',
|
||||||
},
|
},
|
||||||
'&--topRight': {
|
'&--topRight': {
|
||||||
top: '3rem',
|
top: '3rem',
|
||||||
right: '3rem',
|
right: '3rem',
|
||||||
},
|
},
|
||||||
'&--rightCenter': {
|
'&--rightCenter': {
|
||||||
top: '3rem',
|
top: '50%',
|
||||||
|
transform: 'translate(0%, -50%)',
|
||||||
right: '3rem',
|
right: '3rem',
|
||||||
},
|
},
|
||||||
'&--bottomRight': {
|
'&--bottomRight': {
|
||||||
top: '3rem',
|
bottom: '3rem',
|
||||||
right: '3rem',
|
right: '3rem',
|
||||||
},
|
},
|
||||||
'&--bottomCenter': {
|
'&--bottomCenter': {
|
||||||
top: '3rem',
|
bottom: '3rem',
|
||||||
right: '3rem',
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, 0%)',
|
||||||
},
|
},
|
||||||
'&--bottomLeft': {
|
'&--bottomLeft': {
|
||||||
top: '3rem',
|
bottom: '3rem',
|
||||||
right: '3rem',
|
left: '3rem',
|
||||||
},
|
},
|
||||||
'&--leftCenter': {
|
'&--leftCenter': {
|
||||||
top: '3rem',
|
top: '50%',
|
||||||
right: '3rem',
|
transform: 'translate(0%, -50%)',
|
||||||
|
left: '3rem',
|
||||||
},
|
},
|
||||||
[`@media (max-width: ${theme('screens.sm-m.max')})`]: {
|
[`@media (max-width: ${theme('screens.sm-m.max')})`]: {
|
||||||
left: '2rem',
|
left: '2rem',
|
||||||
|
|
|
@ -42,76 +42,76 @@ All icons are from [reactsvgicons.com](https://reactsvgicons.com/).
|
||||||
<IconItem name="AngleLeft">
|
<IconItem name="AngleLeft">
|
||||||
<AngleLeft />
|
<AngleLeft />
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="ExclamationCircle">
|
|
||||||
<ExclamationCircle />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="RightToBracket">
|
|
||||||
<RightToBracket />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="AngleRight">
|
<IconItem name="AngleRight">
|
||||||
<AngleRight />
|
<AngleRight />
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="ExclamationTriangle">
|
|
||||||
<ExclamationTriangle />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="Settings">
|
|
||||||
<Settings />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="BuildingStore">
|
<IconItem name="BuildingStore">
|
||||||
<BuildingStore />
|
<BuildingStore />
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="External">
|
|
||||||
<External />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="Square">
|
|
||||||
<Square />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="CheckCircle">
|
<IconItem name="CheckCircle">
|
||||||
<CheckCircle />
|
<CheckCircle />
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="File">
|
|
||||||
<File />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="Today">
|
|
||||||
<Today />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="CheckSquare">
|
<IconItem name="CheckSquare">
|
||||||
<CheckSquare />
|
<CheckSquare />
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="Folder">
|
<IconItem name="Circle">
|
||||||
<Folder />
|
<Circle />
|
||||||
</IconItem>
|
|
||||||
<IconItem name="Trash">
|
|
||||||
<Trash />
|
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="CircleFill">
|
<IconItem name="CircleFill">
|
||||||
<CircleFill />
|
<CircleFill />
|
||||||
</IconItem>
|
</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">
|
<IconItem name="Cross">
|
||||||
<Cross />
|
<Cross />
|
||||||
</IconItem>
|
</IconItem>
|
||||||
<IconItem name="Menu">
|
|
||||||
<Menu />
|
|
||||||
</IconItem>
|
|
||||||
<IconItem name="Dashboard">
|
<IconItem name="Dashboard">
|
||||||
<Dashboard />
|
<Dashboard />
|
||||||
</IconItem>
|
</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">
|
<IconItem name="RightFromBracket">
|
||||||
<RightFromBracket />
|
<RightFromBracket />
|
||||||
</IconItem>
|
</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>
|
</IconGallery>
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { ModalWrapper, openModal as openOutsideReactModal } from '@prokyon/compo
|
||||||
import { useModal } from '@prokyon/components/Modal/hooks';
|
import { useModal } from '@prokyon/components/Modal/hooks';
|
||||||
import { TextField } from '@prokyon/components/TextField';
|
import { TextField } from '@prokyon/components/TextField';
|
||||||
|
|
||||||
type Story = StoryObj<typeof AddModalButton>;
|
type Story = StoryObj<typeof Modals>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Modals,
|
component: Modals,
|
||||||
|
|
|
@ -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>
|
|
44
stories/components/Toasters.mdx
Normal file
44
stories/components/Toasters.mdx
Normal 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 />
|
89
stories/components/Toasters.stories.tsx
Normal file
89
stories/components/Toasters.stories.tsx
Normal 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} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue