Update Modal documentation in storybook
Change-Id: I4b64feffccaae46b32d5619cec4cc9551ff9e7ed
This commit is contained in:
parent
3a9b0872e4
commit
315756790e
11 changed files with 286 additions and 132 deletions
|
@ -1,7 +1,3 @@
|
|||
# Prokyon
|
||||
|
||||
Framework for react app.
|
||||
|
||||
## Release and deploy
|
||||
|
||||
- use Jenkins parametrized pipeline
|
||||
Suite of React components
|
||||
|
|
|
@ -3,28 +3,20 @@ import clsx from 'clsx';
|
|||
|
||||
import { DirectionEnum } from '@prokyon/types/common';
|
||||
|
||||
import { Title, TitleSizeEnum } from './Title';
|
||||
|
||||
export type SectionProps = {
|
||||
Title: FC;
|
||||
children: any;
|
||||
margin?: Partial<Record<DirectionEnum, number>>;
|
||||
title?: string;
|
||||
titleMargin?: Partial<Record<DirectionEnum, number>>;
|
||||
titleSize?: TitleSizeEnum;
|
||||
space?: Partial<Record<DirectionEnum, number>>;
|
||||
};
|
||||
|
||||
const Section: FC<SectionProps> = ({ title, children, titleSize, margin, titleMargin }) => {
|
||||
const margins: string[] = [];
|
||||
for (const direct in margin) {
|
||||
margins.push(`m${direct}-${margin[direct]}`);
|
||||
const Section: FC<SectionProps> = ({ Title, children, space = { [DirectionEnum.bottom]: 4 } }) => {
|
||||
const spaces: string[] = [];
|
||||
for (const direct in space) {
|
||||
spaces.push(`m${direct}-${space[direct]}`);
|
||||
}
|
||||
return (
|
||||
<div className={clsx(margins)}>
|
||||
{title && (
|
||||
<Title size={titleSize} margin={titleMargin}>
|
||||
{title}
|
||||
</Title>
|
||||
)}
|
||||
<div className={clsx(spaces)}>
|
||||
{Title && <Title />}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,11 +1,27 @@
|
|||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import { isNilOrEmpty } from '@prokyon/utils';
|
||||
|
||||
import Message from '../../Message';
|
||||
import { useToaster } from '../hooks';
|
||||
|
||||
export function Toasters() {
|
||||
export enum ToastersPosition {
|
||||
topLeft,
|
||||
topCenter,
|
||||
topRight,
|
||||
rightCenter,
|
||||
bottomRight,
|
||||
bottomCenter,
|
||||
bottomLeft,
|
||||
leftCenter,
|
||||
}
|
||||
|
||||
export type ToastersProps = {
|
||||
position: ToastersPosition;
|
||||
};
|
||||
|
||||
export function Toasters({ position = ToastersPosition.topRight }) {
|
||||
const { toasters } = useToaster();
|
||||
|
||||
if (isNilOrEmpty(toasters)) {
|
||||
|
@ -13,7 +29,17 @@ export function Toasters() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="fixed top-4 right-6 sm-m:left-6 w-80 sm-m:w-auto z-10">
|
||||
<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,
|
||||
})}>
|
||||
{Object.keys(toasters).map((toasterId) => {
|
||||
const toaster = toasters[toasterId];
|
||||
return (
|
||||
|
|
|
@ -16,8 +16,10 @@ const buildState = (theme, color, bg) => {
|
|||
'& > div:nth-of-type(2)': {
|
||||
width: '100%',
|
||||
border: `1px solid ${color}`,
|
||||
backgroundColor: bg,
|
||||
backgroundColor: 'white',
|
||||
borderLeft: 'none',
|
||||
paddingLeft: theme('spacing.5'),
|
||||
paddingRight: theme('spacing.5'),
|
||||
borderRadius: `0 ${theme('borderRadius.md')} ${theme('borderRadius.md')} 0`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
@ -32,7 +34,7 @@ const message = (theme) => ({
|
|||
color: theme('colors.black'),
|
||||
borderRadius: theme('borderRadius.md'),
|
||||
backgroundColor: 'white',
|
||||
'&--none': buildState(theme, theme('colors.gray.500'), theme('colors.gray.50')),
|
||||
'&--none': buildState(theme, theme('colors.gray.400'), theme('colors.gray.200')),
|
||||
'&--info': buildState(theme, theme('colors.info.300'), theme('colors.info.50')),
|
||||
'&--success': buildState(theme, theme('colors.success.300'), theme('colors.success.50')),
|
||||
'&--warning': buildState(theme, theme('colors.warning.300'), theme('colors.warning.50')),
|
||||
|
|
|
@ -60,7 +60,7 @@ const skeleton = (theme) => ({
|
|||
borderRadius: theme('borderRadius.sm'),
|
||||
position: 'relative',
|
||||
paddingTop: '2.5rem',
|
||||
margin: '0 .125rem',
|
||||
margin: '.125rem',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
|
|
52
packages/styles/src/components/toaster.js
Normal file
52
packages/styles/src/components/toaster.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
const buildState = ({ theme, color, backgroundColor, borderColor }) => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const toaster = (theme) => ({
|
||||
'.toasters': {
|
||||
position: 'fixed',
|
||||
zIndex: 10,
|
||||
'&--topLeft': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--topCenter': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--topRight': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--rightCenter': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--bottomRight': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--bottomCenter': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--bottomLeft': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
'&--leftCenter': {
|
||||
top: '3rem',
|
||||
right: '3rem',
|
||||
},
|
||||
[`@media (max-width: ${theme('screens.sm-m.max')})`]: {
|
||||
left: '2rem',
|
||||
with: 'auto',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = ({ addComponents, theme }) => {
|
||||
addComponents(toaster(theme));
|
||||
};
|
||||
|
||||
module.exports.toaster = toaster;
|
|
@ -44,6 +44,7 @@ module.exports = {
|
|||
plugin(require('./components/modal')),
|
||||
plugin(require('./components/calendar')),
|
||||
plugin(require('./components/human')),
|
||||
plugin(require('./components/toaster')),
|
||||
function ({ addVariant }) {
|
||||
addVariant('child', '& > *');
|
||||
},
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
import React from 'react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { Modals } from '@prokyon/components/Modal';
|
||||
import { AddModalButton } from '@prokyon/components/Modal/components/AddModalButton';
|
||||
import { ModalWrapper } from '@prokyon/components/Modal/context';
|
||||
import { TextField } from '@prokyon/components/TextField';
|
||||
|
||||
type Story = StoryObj<typeof AddModalButton>;
|
||||
|
||||
export default {
|
||||
component: AddModalButton,
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"`import { AddModalButton } from '@prokyon/components/Modal/components/AddModalButton';`",
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<ModalWrapper>
|
||||
<Story />
|
||||
<Modals />
|
||||
</ModalWrapper>
|
||||
),
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
export const Default: Story = {
|
||||
name: 'Default',
|
||||
args: {
|
||||
id: 'default',
|
||||
title: 'Open modal 1',
|
||||
modalTitle: 'Default modal',
|
||||
Component: () => <div>Hi there</div>,
|
||||
},
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
name: 'Small',
|
||||
args: {
|
||||
id: 'small',
|
||||
title: 'Open modal',
|
||||
modalTitle: 'Small modal',
|
||||
Component: () => (
|
||||
<div>
|
||||
<TextField name="search" label="Search" />
|
||||
</div>
|
||||
),
|
||||
style: {
|
||||
width: 250,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const ModalWindow = () => <div>Hi there, again</div>;
|
||||
|
||||
export const Multiple: Story = {
|
||||
name: 'Multiple',
|
||||
args: {
|
||||
id: 'multiple',
|
||||
title: 'Open modal',
|
||||
modalTitle: 'First modal',
|
||||
Component: () => (
|
||||
<div>
|
||||
Hello
|
||||
<AddModalButton
|
||||
Component={ModalWindow}
|
||||
title="Open next modal"
|
||||
modalTitle="Second modal"
|
||||
id="secondModal"
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export const WithCloseCallback: Story = {
|
||||
args: {
|
||||
id: 'withCloseCallback',
|
||||
title: 'Open modal',
|
||||
modalTitle: 'Modal',
|
||||
Component: () => <div>Hello</div>,
|
||||
props: {
|
||||
onClose: () => console.info('Close callback called.'),
|
||||
},
|
||||
},
|
||||
};
|
|
@ -1,8 +1,38 @@
|
|||
import { Title } from '@storybook/blocks';
|
||||
import { Canvas, Meta } from '@storybook/blocks';
|
||||
|
||||
<Title>Modals</Title>
|
||||
import * as ModalStories from './Modals.stories';
|
||||
|
||||
`import Modals from '@prokyon/components/Modal/components/Modals';`
|
||||
<Meta of={ModalStories} />
|
||||
|
||||
# Modals
|
||||
|
||||
## Before start
|
||||
|
||||
### In root application use
|
||||
|
||||
```tsx
|
||||
import Modals from '@prokyon/components/Modal/components/Modals';
|
||||
import { ModalWrapper } from '@prokyon/components/Modal/context';
|
||||
|
||||
return (
|
||||
<ModalWrapper>
|
||||
...
|
||||
<Modals />
|
||||
</ModalWrapper>
|
||||
);
|
||||
```
|
||||
|
||||
## Use `AddModalButton`
|
||||
|
||||
```tsx
|
||||
import { AddModalButton } from '@prokyon/components/Modal/components/AddModalButton';
|
||||
|
||||
return <AddModalButton />;
|
||||
```
|
||||
|
||||
<Canvas of={ModalStories.Default} withToolbar />
|
||||
|
||||
## Use hook `useModal()`
|
||||
|
||||
```tsx
|
||||
import { useModal } from '@prokyon/components/Modal/hooks';
|
||||
|
@ -27,10 +57,16 @@ const { openModal } = useModal();
|
|||
openModal('modal1');
|
||||
```
|
||||
|
||||
Or, call `openModal` function outside of React component.
|
||||
<Canvas of={ModalStories.Hook} withToolbar />
|
||||
|
||||
## Use function `openModal()`
|
||||
|
||||
Outside of React component.
|
||||
|
||||
```ts
|
||||
import { openModal } from '@prokyon/components/Modal/context';
|
||||
|
||||
openModal('modal1');
|
||||
```
|
||||
|
||||
<Canvas of={ModalStories.OutsideReact} withToolbar />
|
||||
|
|
136
stories/components/Modals.stories.tsx
Normal file
136
stories/components/Modals.stories.tsx
Normal file
|
@ -0,0 +1,136 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { Button } from '@prokyon/components/Button';
|
||||
import { Modals } from '@prokyon/components/Modal';
|
||||
import { AddModalButton } from '@prokyon/components/Modal/components/AddModalButton';
|
||||
import { ModalWrapper, openModal as openOutsideReactModal } from '@prokyon/components/Modal/context';
|
||||
import { useModal } from '@prokyon/components/Modal/hooks';
|
||||
import { TextField } from '@prokyon/components/TextField';
|
||||
|
||||
type Story = StoryObj<typeof AddModalButton>;
|
||||
|
||||
export default {
|
||||
component: Modals,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div className="h-80">
|
||||
<ModalWrapper>
|
||||
<Story />
|
||||
<Modals />
|
||||
</ModalWrapper>
|
||||
</div>
|
||||
),
|
||||
],
|
||||
} as Meta;
|
||||
|
||||
export const Default: Story = {
|
||||
name: 'Default',
|
||||
render: () => {
|
||||
return (
|
||||
<AddModalButton
|
||||
id="default"
|
||||
title="Open modal"
|
||||
modalTitle="Default modal"
|
||||
Component={() => <div>Hi there</div>}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Hook: Story = {
|
||||
name: 'Hook',
|
||||
render: () => {
|
||||
const Comp = () => {
|
||||
const { registerModal, openModal } = useModal();
|
||||
useEffect(() => {
|
||||
registerModal({
|
||||
Component: () => <div>Hi there</div>,
|
||||
id: 'modal2',
|
||||
title: 'Modal Title',
|
||||
});
|
||||
}, []);
|
||||
return <Button label="Open Modal" onClick={() => openModal('modal2')} />;
|
||||
};
|
||||
return <Comp />;
|
||||
},
|
||||
};
|
||||
|
||||
export const OutsideReact: Story = {
|
||||
name: 'Function',
|
||||
render: () => {
|
||||
return (
|
||||
<Button
|
||||
label="Open Modal"
|
||||
onClick={() =>
|
||||
openOutsideReactModal({
|
||||
Component: () => <div>Hi there</div>,
|
||||
id: 'modal3',
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
name: 'Small',
|
||||
render: () => {
|
||||
return (
|
||||
<AddModalButton
|
||||
id="small"
|
||||
title="Open modal"
|
||||
modalTitle="Small modal"
|
||||
Component={() => (
|
||||
<div>
|
||||
<TextField name="search" label="Search" />
|
||||
</div>
|
||||
)}
|
||||
style={{
|
||||
width: 250,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Multiple: Story = {
|
||||
name: 'Multiple',
|
||||
render: () => {
|
||||
return (
|
||||
<AddModalButton
|
||||
id="multiple"
|
||||
title="Open modal"
|
||||
modalTitle="First modal"
|
||||
Component={() => (
|
||||
<div>
|
||||
Hello
|
||||
<AddModalButton
|
||||
Component={() => <div>Hi there, again</div>}
|
||||
title="Open next modal"
|
||||
modalTitle="Second modal"
|
||||
id="secondModal"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const WithCloseCallback: Story = {
|
||||
render: () => {
|
||||
return (
|
||||
<AddModalButton
|
||||
id="withCloseCallback"
|
||||
title="Open modal"
|
||||
modalTitle="Modal"
|
||||
Component={() => <div>Hello</div>}
|
||||
props={{
|
||||
onClose: () => action('Close callback called.'),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
import React from 'react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import Section from '@prokyon/components/Section';
|
||||
import { TitleSizeEnum } from '@prokyon/components/Title';
|
||||
import { Title, TitleSizeEnum } from '@prokyon/components/Title';
|
||||
import { DirectionEnum } from '@prokyon/types/common';
|
||||
|
||||
type Story = StoryObj<typeof Section>;
|
||||
|
@ -20,34 +21,37 @@ export default {
|
|||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
title: 'Section',
|
||||
Title: () => <Title>Section</Title>,
|
||||
children: 'Content',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithoutTitle: Story = {
|
||||
args: {
|
||||
children: 'Content',
|
||||
},
|
||||
};
|
||||
|
||||
export const Medium: Story = {
|
||||
args: {
|
||||
title: 'Section',
|
||||
Title: () => <Title size={TitleSizeEnum.md}>Section</Title>,
|
||||
children: 'content',
|
||||
titleSize: TitleSizeEnum.md,
|
||||
margin: { [DirectionEnum.y]: 2 },
|
||||
space: { [DirectionEnum.y]: 2 },
|
||||
},
|
||||
};
|
||||
|
||||
export const Large: Story = {
|
||||
args: {
|
||||
title: 'Section',
|
||||
Title: () => <Title size={TitleSizeEnum.lg}>Section</Title>,
|
||||
children: 'content',
|
||||
titleSize: TitleSizeEnum.lg,
|
||||
margin: { [DirectionEnum.y]: 2, [DirectionEnum.top]: 3 },
|
||||
space: { [DirectionEnum.y]: 2, [DirectionEnum.top]: 3 },
|
||||
},
|
||||
};
|
||||
|
||||
export const ExtraLarge: Story = {
|
||||
args: {
|
||||
title: 'Section',
|
||||
Title: () => <Title size={TitleSizeEnum.xl}>Section</Title>,
|
||||
children: 'content',
|
||||
titleSize: TitleSizeEnum.xl,
|
||||
margin: { [DirectionEnum.y]: 2, [DirectionEnum.top]: 4 },
|
||||
space: { [DirectionEnum.y]: 2, [DirectionEnum.top]: 4 },
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue