@indico-data/design-system 2.45.6 → 2.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/badge/Badge.d.ts +2 -0
- package/lib/components/badge/Badge.stories.d.ts +7 -0
- package/lib/components/badge/__tests__/Badge.test.d.ts +1 -0
- package/lib/components/badge/index.d.ts +1 -0
- package/lib/components/badge/types.d.ts +7 -0
- package/lib/components/index.d.ts +2 -0
- package/lib/components/menu/Menu.d.ts +2 -1
- package/lib/components/modal/Modal.d.ts +2 -0
- package/lib/components/modal/Modal.stories.d.ts +7 -0
- package/lib/components/modal/__tests__/Modal.test.d.ts +1 -0
- package/lib/components/modal/index.d.ts +1 -0
- package/lib/components/modal/types.d.ts +15 -0
- package/lib/index.css +142 -0
- package/lib/index.d.ts +39 -49
- package/lib/index.esm.css +142 -0
- package/lib/index.esm.js +11224 -11378
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +11223 -11377
- package/lib/index.js.map +1 -1
- package/lib/legacy/components/index.d.ts +0 -1
- package/package.json +1 -1
- package/src/components/badge/Badge.mdx +36 -0
- package/src/components/badge/Badge.stories.tsx +109 -0
- package/src/components/badge/Badge.tsx +18 -0
- package/src/components/badge/__tests__/Badge.test.tsx +17 -0
- package/src/components/badge/index.ts +1 -0
- package/src/components/badge/styles/Badge.scss +61 -0
- package/src/components/badge/types.ts +8 -0
- package/src/components/card/Card.tsx +1 -1
- package/src/components/index.ts +2 -0
- package/src/components/menu/Menu.tsx +3 -2
- package/src/components/modal/Modal.mdx +111 -0
- package/src/components/modal/Modal.stories.tsx +275 -0
- package/src/components/modal/Modal.tsx +61 -0
- package/src/components/modal/__tests__/Modal.test.tsx +60 -0
- package/src/components/modal/index.ts +1 -0
- package/src/components/modal/styles/Modal.scss +100 -0
- package/src/components/modal/types.ts +15 -0
- package/src/index.ts +3 -9
- package/src/legacy/components/index.ts +0 -1
- package/src/setup/setupIcons.ts +2 -0
- package/src/styles/index.scss +2 -0
- package/lib/legacy/components/modals/ConfirmModal/ConfirmModal.d.ts +0 -17
- package/lib/legacy/components/modals/ConfirmModal/ConfirmModal.stories.d.ts +0 -44
- package/lib/legacy/components/modals/ConfirmModal/ConfirmModal.styles.d.ts +0 -1
- package/lib/legacy/components/modals/ConfirmModal/index.d.ts +0 -1
- package/lib/legacy/components/modals/ModalBase/ModalBase.d.ts +0 -26
- package/lib/legacy/components/modals/ModalBase/ModalBase.stories.d.ts +0 -9
- package/lib/legacy/components/modals/ModalBase/ModalBase.styles.d.ts +0 -4
- package/lib/legacy/components/modals/ModalBase/index.d.ts +0 -2
- package/lib/legacy/components/modals/index.d.ts +0 -2
- package/src/legacy/components/modals/ConfirmModal/ConfirmModal.stories.tsx +0 -76
- package/src/legacy/components/modals/ConfirmModal/ConfirmModal.styles.ts +0 -27
- package/src/legacy/components/modals/ConfirmModal/ConfirmModal.tsx +0 -79
- package/src/legacy/components/modals/ConfirmModal/index.ts +0 -1
- package/src/legacy/components/modals/ModalBase/ModalBase.stories.tsx +0 -45
- package/src/legacy/components/modals/ModalBase/ModalBase.styles.tsx +0 -72
- package/src/legacy/components/modals/ModalBase/ModalBase.tsx +0 -79
- package/src/legacy/components/modals/ModalBase/index.ts +0 -2
- package/src/legacy/components/modals/index.ts +0 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import ReactModal from 'react-modal';
|
|
3
|
+
import { Button } from '../button/Button';
|
|
4
|
+
import { Col, Row } from '../grid';
|
|
5
|
+
import { ModalProps } from './types';
|
|
6
|
+
|
|
7
|
+
export const Modal = ({
|
|
8
|
+
className = '',
|
|
9
|
+
children,
|
|
10
|
+
isOpen,
|
|
11
|
+
onRequestClose,
|
|
12
|
+
portalClassName,
|
|
13
|
+
overlayClassName,
|
|
14
|
+
appElement,
|
|
15
|
+
shouldCloseOnOverlayClick,
|
|
16
|
+
shouldCloseOnEsc,
|
|
17
|
+
testId,
|
|
18
|
+
contentElement,
|
|
19
|
+
overlayElement,
|
|
20
|
+
position = 'center',
|
|
21
|
+
...rest
|
|
22
|
+
}: ModalProps) => {
|
|
23
|
+
const modalClasses = classNames('modal', `modal--${position}`, className);
|
|
24
|
+
const overlayClasses = classNames('modal-overlay', overlayClassName);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<ReactModal
|
|
28
|
+
style={{}}
|
|
29
|
+
className={modalClasses}
|
|
30
|
+
overlayClassName={overlayClasses}
|
|
31
|
+
testId={testId}
|
|
32
|
+
isOpen={isOpen}
|
|
33
|
+
onRequestClose={onRequestClose}
|
|
34
|
+
portalClassName={portalClassName}
|
|
35
|
+
appElement={appElement}
|
|
36
|
+
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
|
|
37
|
+
shouldCloseOnEsc={shouldCloseOnEsc}
|
|
38
|
+
contentElement={contentElement}
|
|
39
|
+
overlayElement={overlayElement}
|
|
40
|
+
{...rest}
|
|
41
|
+
>
|
|
42
|
+
<div className="modal-content">
|
|
43
|
+
<div className="modal-header">
|
|
44
|
+
<Row nogutter>
|
|
45
|
+
<Col xs={12} className="modal-close">
|
|
46
|
+
<Button
|
|
47
|
+
className="modal-close-button"
|
|
48
|
+
onClick={onRequestClose}
|
|
49
|
+
variant="link"
|
|
50
|
+
size="md"
|
|
51
|
+
iconLeft="fa-xmark"
|
|
52
|
+
ariaLabel="Close"
|
|
53
|
+
/>
|
|
54
|
+
</Col>
|
|
55
|
+
</Row>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="modal-body">{children}</div>
|
|
58
|
+
</div>
|
|
59
|
+
</ReactModal>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { Modal } from '../Modal';
|
|
3
|
+
|
|
4
|
+
// Mock ReactModal's app element setting to avoid warnings
|
|
5
|
+
beforeAll(() => {
|
|
6
|
+
const div = document.createElement('div');
|
|
7
|
+
div.setAttribute('id', 'root');
|
|
8
|
+
document.body.appendChild(div);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe('Modal', () => {
|
|
12
|
+
const mockOnRequestClose = jest.fn();
|
|
13
|
+
|
|
14
|
+
const defaultProps = {
|
|
15
|
+
isOpen: true,
|
|
16
|
+
onRequestClose: mockOnRequestClose,
|
|
17
|
+
title: 'Test Modal',
|
|
18
|
+
ariaHideApp: false, // Disable aria hiding for tests
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('renders children content', () => {
|
|
26
|
+
render(
|
|
27
|
+
<Modal {...defaultProps}>
|
|
28
|
+
<p>Modal content</p>
|
|
29
|
+
</Modal>,
|
|
30
|
+
);
|
|
31
|
+
expect(screen.getByText('Modal content')).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('calls onRequestClose when close button is clicked', () => {
|
|
35
|
+
render(<Modal {...defaultProps} />);
|
|
36
|
+
const closeButton = screen.getByLabelText('Close');
|
|
37
|
+
fireEvent.click(closeButton);
|
|
38
|
+
expect(mockOnRequestClose).toHaveBeenCalledTimes(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('Modal positioning', () => {
|
|
42
|
+
it('applies center position class by default', () => {
|
|
43
|
+
render(<Modal {...defaultProps} />);
|
|
44
|
+
const modal = screen.getByRole('dialog');
|
|
45
|
+
expect(modal).toHaveClass('modal--center');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('applies top position class when specified', () => {
|
|
49
|
+
render(<Modal {...defaultProps} position="top" />);
|
|
50
|
+
const modal = screen.getByRole('dialog');
|
|
51
|
+
expect(modal).toHaveClass('modal--top');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('applies custom className when provided', () => {
|
|
56
|
+
render(<Modal {...defaultProps} className="custom-modal" />);
|
|
57
|
+
const modal = screen.getByRole('dialog');
|
|
58
|
+
expect(modal).toHaveClass('custom-modal');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Modal } from './Modal';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Common Variables
|
|
2
|
+
:root {
|
|
3
|
+
--pf-modal-rounded: var(--pf-rounded-lg);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// Light Theme Specific Variables
|
|
7
|
+
:root [data-theme='light'] {
|
|
8
|
+
--pf-modal-background-color: var(--pf-white-color);
|
|
9
|
+
--pf-modal-border-color: var(--pf-border-color);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Dark Theme Specific Variables
|
|
13
|
+
:root [data-theme='dark'],
|
|
14
|
+
:root {
|
|
15
|
+
--pf-modal-background-color: var(--pf-primary-color-600);
|
|
16
|
+
--pf-modal-border-color: var(--pf-border-color);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Library overrides
|
|
20
|
+
.ReactModal__Overlay {
|
|
21
|
+
position: fixed;
|
|
22
|
+
top: 0;
|
|
23
|
+
left: 0;
|
|
24
|
+
right: 0;
|
|
25
|
+
bottom: 0;
|
|
26
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
}
|
|
31
|
+
.ReactModal__Overlay {
|
|
32
|
+
opacity: 0;
|
|
33
|
+
transition: opacity 100ms ease-in-out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.ReactModal__Overlay--after-open {
|
|
37
|
+
opacity: 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ReactModal__Overlay--before-close {
|
|
41
|
+
opacity: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// New CSS
|
|
45
|
+
.modal {
|
|
46
|
+
position: absolute;
|
|
47
|
+
left: 50%;
|
|
48
|
+
transform: translateX(-50%);
|
|
49
|
+
background: var(--pf-background-color);
|
|
50
|
+
border-radius: var(--pf-modal-rounded);
|
|
51
|
+
outline: none;
|
|
52
|
+
|
|
53
|
+
&--center {
|
|
54
|
+
top: 50%;
|
|
55
|
+
transform: translate(-50%, -50%);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&--top {
|
|
59
|
+
top: 50px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.modal-content {
|
|
63
|
+
background-color: var(--pf-modal-background-color);
|
|
64
|
+
border: var(--pf-border-sm) solid var(--pf-modal-border-color);
|
|
65
|
+
border-radius: var(--pf-modal-rounded);
|
|
66
|
+
|
|
67
|
+
.modal-body {
|
|
68
|
+
padding: var(--pf-padding-8);
|
|
69
|
+
padding-top: 0;
|
|
70
|
+
|
|
71
|
+
h2 {
|
|
72
|
+
font-size: var(--pf-font-size-h1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
h1,
|
|
76
|
+
h2,
|
|
77
|
+
h3,
|
|
78
|
+
h4,
|
|
79
|
+
h5,
|
|
80
|
+
h6 {
|
|
81
|
+
margin-bottom: var(--pf-margin-4);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
p {
|
|
85
|
+
margin-bottom: var(--pf-margin-4);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// We should build a divider component for this
|
|
89
|
+
hr {
|
|
90
|
+
margin-top: var(--pf-margin-8);
|
|
91
|
+
margin-bottom: var(--pf-margin-8);
|
|
92
|
+
border: var(--pf-border-sm) solid var(--pf-border-color);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.modal-close {
|
|
97
|
+
text-align: right;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ModalProps {
|
|
2
|
+
className?: string;
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onRequestClose?: () => void;
|
|
6
|
+
portalClassName?: string;
|
|
7
|
+
overlayClassName?: string;
|
|
8
|
+
appElement?: HTMLElement;
|
|
9
|
+
shouldCloseOnOverlayClick?: boolean;
|
|
10
|
+
shouldCloseOnEsc?: boolean;
|
|
11
|
+
testId?: string;
|
|
12
|
+
contentElement?: (props: any, children: React.ReactNode) => React.ReactElement;
|
|
13
|
+
overlayElement?: (props: any, contentElement: React.ReactElement) => React.ReactElement;
|
|
14
|
+
position?: 'top' | 'center';
|
|
15
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,16 +4,8 @@ import './setup/setupIcons';
|
|
|
4
4
|
// This is so consumers of the DS can import floating ui functions/hooks/types from the DS rather than the (peer dependency) floating-ui package
|
|
5
5
|
export * from '@floating-ui/react-dom';
|
|
6
6
|
|
|
7
|
-
export {
|
|
8
|
-
BarSpinner,
|
|
9
|
-
CirclePulse,
|
|
10
|
-
CircleSpinner,
|
|
11
|
-
ConfirmModal,
|
|
12
|
-
ModalBase,
|
|
13
|
-
Tooltip,
|
|
14
|
-
} from './legacy/components';
|
|
7
|
+
export { BarSpinner, CirclePulse, CircleSpinner, Tooltip } from './legacy/components';
|
|
15
8
|
|
|
16
|
-
// New Components
|
|
17
9
|
export { Container, Row, Col } from './components/grid';
|
|
18
10
|
export { Button } from './components/button';
|
|
19
11
|
export { Icon } from './components/icons';
|
|
@@ -34,6 +26,8 @@ export { Card } from './components/card';
|
|
|
34
26
|
export { FloatUI } from './components/floatUI';
|
|
35
27
|
export { Menu } from './components/menu';
|
|
36
28
|
export { Pill } from './components/pill';
|
|
29
|
+
export { Badge } from './components/badge';
|
|
30
|
+
export { Modal } from './components/modal';
|
|
37
31
|
|
|
38
32
|
// Utilities
|
|
39
33
|
export { registerFontAwesomeIcons } from './setup/setupIcons';
|
package/src/setup/setupIcons.ts
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
faFileDownload,
|
|
23
23
|
faQuestionCircle,
|
|
24
24
|
faCopy,
|
|
25
|
+
faXmark,
|
|
25
26
|
} from '@fortawesome/free-solid-svg-icons';
|
|
26
27
|
import { indiconDefinitions } from '@/components/icons/indicons';
|
|
27
28
|
|
|
@@ -52,6 +53,7 @@ registerFontAwesomeIcons(
|
|
|
52
53
|
faFileDownload,
|
|
53
54
|
faQuestionCircle,
|
|
54
55
|
faCopy,
|
|
56
|
+
faXmark,
|
|
55
57
|
// backwards compat, don't require registration of custom indicons
|
|
56
58
|
// might want to consider doing so in the future
|
|
57
59
|
...indiconDefinitions,
|
package/src/styles/index.scss
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
@import '../components/menu/styles/Menu.scss';
|
|
22
22
|
@import '../components/floatUI/styles/FloatUI.scss';
|
|
23
23
|
@import '../components/forms/date/datePicker/styles/DatePicker.scss';
|
|
24
|
+
@import '../components/badge/styles/Badge.scss';
|
|
25
|
+
@import '../components/modal/styles/Modal.scss';
|
|
24
26
|
|
|
25
27
|
@import '../components/pill/styles/Pill.scss';
|
|
26
28
|
@import 'sheets'; // Port to an sheets component when we build it
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ModalBaseProps } from '../ModalBase';
|
|
3
|
-
import type { PermafrostComponent } from '../../../../types';
|
|
4
|
-
type Props = PermafrostComponent & Pick<ModalBaseProps, 'open'> & {
|
|
5
|
-
describedBy?: string;
|
|
6
|
-
clickOutsideHandler(e?: React.SyntheticEvent): void;
|
|
7
|
-
confirmText?: string;
|
|
8
|
-
message?: string | React.ReactNode;
|
|
9
|
-
modalNode?: string;
|
|
10
|
-
processing?: boolean;
|
|
11
|
-
rejectText?: string;
|
|
12
|
-
responseHandler(response: boolean, event: React.SyntheticEvent): void;
|
|
13
|
-
title?: string | React.ReactNode;
|
|
14
|
-
width?: number;
|
|
15
|
-
};
|
|
16
|
-
export declare function ConfirmModal(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
17
|
-
export {};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { StoryObj } from '@storybook/react';
|
|
2
|
-
import { ConfirmModal } from './ConfirmModal';
|
|
3
|
-
declare const meta: {
|
|
4
|
-
component: typeof ConfirmModal;
|
|
5
|
-
title: string;
|
|
6
|
-
args: {
|
|
7
|
-
title: string;
|
|
8
|
-
message: string;
|
|
9
|
-
confirmText: string;
|
|
10
|
-
rejectText: string;
|
|
11
|
-
};
|
|
12
|
-
argTypes: {
|
|
13
|
-
open: {
|
|
14
|
-
control: {
|
|
15
|
-
disable: true;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
className: {
|
|
19
|
-
control: {
|
|
20
|
-
disable: true;
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
describedBy: {
|
|
24
|
-
control: {
|
|
25
|
-
disable: true;
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
modalNode: {
|
|
29
|
-
control: {
|
|
30
|
-
disable: true;
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
width: {
|
|
34
|
-
control: {
|
|
35
|
-
disable: true;
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
export default meta;
|
|
41
|
-
type Story = StoryObj<typeof ConfirmModal>;
|
|
42
|
-
export declare const Base: Story;
|
|
43
|
-
export declare const Open: Story;
|
|
44
|
-
export declare const processing: Story;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const StyledConfirmModal: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ConfirmModal } from './ConfirmModal';
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { PermafrostComponent } from '../../../../types';
|
|
3
|
-
export type ModalBaseProps = PermafrostComponent & {
|
|
4
|
-
children: React.ReactNode | React.ReactNode[];
|
|
5
|
-
clickToDismiss?(): void;
|
|
6
|
-
describedBy?: string;
|
|
7
|
-
node?: string;
|
|
8
|
-
open: boolean;
|
|
9
|
-
preventEscDismiss?: boolean;
|
|
10
|
-
preventReturnFocus?: boolean;
|
|
11
|
-
maxWidth?: string;
|
|
12
|
-
} & ({
|
|
13
|
-
labelElement: string;
|
|
14
|
-
} | {
|
|
15
|
-
labelText: string;
|
|
16
|
-
});
|
|
17
|
-
/**
|
|
18
|
-
* Base modal component, powered by [react-modal](http://reactcommunity.org/react-modal/#usage)
|
|
19
|
-
*
|
|
20
|
-
* (Also see `ModalAdapter` in the styles file)
|
|
21
|
-
*
|
|
22
|
-
* Accessible element label must be included either as a string passed to `labelText`, or
|
|
23
|
-
* the id of one of the children passed to `labelElement`. If a description is available,
|
|
24
|
-
* pass that element’s id to the `describedBy` prop.
|
|
25
|
-
*/
|
|
26
|
-
export declare function ModalBase(props: ModalBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { StoryObj } from '@storybook/react';
|
|
2
|
-
import { ModalBase } from './ModalBase';
|
|
3
|
-
declare const meta: {
|
|
4
|
-
component: typeof ModalBase;
|
|
5
|
-
title: string;
|
|
6
|
-
};
|
|
7
|
-
export default meta;
|
|
8
|
-
type Story = StoryObj<typeof ModalBase>;
|
|
9
|
-
export declare const Base: Story;
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
declare function ModalAdapter(props: any): React.ReactElement;
|
|
3
|
-
export declare const StyledModalBase: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<any, never>> & string & Omit<typeof ModalAdapter, keyof React.Component<any, {}, any>>;
|
|
4
|
-
export {};
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
|
|
4
|
-
import { ConfirmModal } from './ConfirmModal';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
component: ConfirmModal,
|
|
8
|
-
title: 'legacy/Modals/ConfirmModal',
|
|
9
|
-
args: {
|
|
10
|
-
title: 'Im sorry, Dave. Im afraid I cant do that.',
|
|
11
|
-
message: 'This mission is too important for me to allow you to jeopardize it.',
|
|
12
|
-
confirmText: 'I dont know what youre talking about, Hal.',
|
|
13
|
-
rejectText: 'I dont know what youre talking about, Hal.',
|
|
14
|
-
},
|
|
15
|
-
argTypes: {
|
|
16
|
-
open: { control: { disable: true } },
|
|
17
|
-
className: { control: { disable: true } },
|
|
18
|
-
describedBy: { control: { disable: true } },
|
|
19
|
-
modalNode: { control: { disable: true } },
|
|
20
|
-
width: { control: { disable: true } },
|
|
21
|
-
},
|
|
22
|
-
} satisfies Meta<typeof ConfirmModal>;
|
|
23
|
-
|
|
24
|
-
export default meta;
|
|
25
|
-
type Story = StoryObj<typeof ConfirmModal>;
|
|
26
|
-
|
|
27
|
-
function StoryRender(props: any) {
|
|
28
|
-
const [isOpen, setIsOpen] = useState<boolean>(props.open);
|
|
29
|
-
|
|
30
|
-
const handleOpen = () => {
|
|
31
|
-
setIsOpen(true);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const handleClose = () => {
|
|
35
|
-
setIsOpen(false);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<>
|
|
40
|
-
<button type="button" onClick={handleOpen}>
|
|
41
|
-
Open the pod bay doors, HAL.
|
|
42
|
-
</button>
|
|
43
|
-
|
|
44
|
-
<ConfirmModal {...props} open={isOpen} responseHandler={handleClose} />
|
|
45
|
-
</>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const Base: Story = {
|
|
50
|
-
args: {
|
|
51
|
-
processing: false,
|
|
52
|
-
},
|
|
53
|
-
render: (args) => {
|
|
54
|
-
return <StoryRender {...args} />;
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export const Open: Story = {
|
|
59
|
-
args: {
|
|
60
|
-
open: true,
|
|
61
|
-
processing: false,
|
|
62
|
-
},
|
|
63
|
-
render: (args) => {
|
|
64
|
-
return <StoryRender {...args} />;
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export const processing: Story = {
|
|
69
|
-
args: {
|
|
70
|
-
open: true,
|
|
71
|
-
processing: true,
|
|
72
|
-
},
|
|
73
|
-
render: (args) => {
|
|
74
|
-
return <StoryRender {...args} />;
|
|
75
|
-
},
|
|
76
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import styled from 'styled-components';
|
|
2
|
-
|
|
3
|
-
export const StyledConfirmModal = styled.div`
|
|
4
|
-
padding: 20px;
|
|
5
|
-
|
|
6
|
-
.title {
|
|
7
|
-
margin: 30px 16px;
|
|
8
|
-
|
|
9
|
-
text-align: center;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.message {
|
|
13
|
-
text-align: center;
|
|
14
|
-
padding-bottom: 16px;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.actions {
|
|
18
|
-
text-align: center;
|
|
19
|
-
padding-bottom: 40px;
|
|
20
|
-
|
|
21
|
-
button {
|
|
22
|
-
min-width: 300px;
|
|
23
|
-
display: block;
|
|
24
|
-
margin: 16px auto 0;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
`;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// TODO: This component's migration was fast-tracked for Insights. Assess for potential refactor and documentation.
|
|
2
|
-
|
|
3
|
-
import React from 'react';
|
|
4
|
-
|
|
5
|
-
import { v4 as uuid } from 'uuid';
|
|
6
|
-
|
|
7
|
-
import { ModalBase } from '@/legacy/components/modals/ModalBase';
|
|
8
|
-
import { Button } from '@/components/button';
|
|
9
|
-
import { ModalBaseProps } from '../ModalBase';
|
|
10
|
-
import type { PermafrostComponent } from '../../../../types';
|
|
11
|
-
|
|
12
|
-
import { StyledConfirmModal } from './ConfirmModal.styles';
|
|
13
|
-
|
|
14
|
-
type Props = PermafrostComponent &
|
|
15
|
-
Pick<ModalBaseProps, 'open'> & {
|
|
16
|
-
describedBy?: string;
|
|
17
|
-
clickOutsideHandler(e?: React.SyntheticEvent): void;
|
|
18
|
-
confirmText?: string;
|
|
19
|
-
message?: string | React.ReactNode;
|
|
20
|
-
modalNode?: string;
|
|
21
|
-
processing?: boolean;
|
|
22
|
-
rejectText?: string;
|
|
23
|
-
responseHandler(response: boolean, event: React.SyntheticEvent): void;
|
|
24
|
-
title?: string | React.ReactNode;
|
|
25
|
-
width?: number;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export function ConfirmModal(props: Props) {
|
|
29
|
-
const id = uuid();
|
|
30
|
-
const {
|
|
31
|
-
className,
|
|
32
|
-
clickOutsideHandler,
|
|
33
|
-
confirmText,
|
|
34
|
-
describedBy,
|
|
35
|
-
message,
|
|
36
|
-
modalNode,
|
|
37
|
-
open,
|
|
38
|
-
processing,
|
|
39
|
-
rejectText,
|
|
40
|
-
responseHandler,
|
|
41
|
-
title,
|
|
42
|
-
width,
|
|
43
|
-
} = props;
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<ModalBase
|
|
47
|
-
className={className}
|
|
48
|
-
clickToDismiss={clickOutsideHandler}
|
|
49
|
-
data-cy={props['data-cy']}
|
|
50
|
-
describedBy={describedBy}
|
|
51
|
-
id={props.id}
|
|
52
|
-
labelElement={id}
|
|
53
|
-
node={modalNode}
|
|
54
|
-
open={open}
|
|
55
|
-
>
|
|
56
|
-
<StyledConfirmModal style={{ width: width || 555 }}>
|
|
57
|
-
{title && (
|
|
58
|
-
<div id={id} className="title">
|
|
59
|
-
{title || 'Please confirm'}
|
|
60
|
-
</div>
|
|
61
|
-
)}
|
|
62
|
-
|
|
63
|
-
{message && <div className="message">{message}</div>}
|
|
64
|
-
|
|
65
|
-
<Button ariaLabel="confirm" onClick={(event) => responseHandler(true, event)}>
|
|
66
|
-
{confirmText || 'Yes'}
|
|
67
|
-
</Button>
|
|
68
|
-
|
|
69
|
-
<Button
|
|
70
|
-
variant="outline"
|
|
71
|
-
ariaLabel="reject"
|
|
72
|
-
onClick={(event) => responseHandler(false, event)}
|
|
73
|
-
>
|
|
74
|
-
{rejectText || 'No'}
|
|
75
|
-
</Button>
|
|
76
|
-
</StyledConfirmModal>
|
|
77
|
-
</ModalBase>
|
|
78
|
-
);
|
|
79
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { ConfirmModal } from './ConfirmModal';
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
|
|
4
|
-
import { ModalBase } from './ModalBase';
|
|
5
|
-
|
|
6
|
-
const meta = {
|
|
7
|
-
component: ModalBase,
|
|
8
|
-
title: 'legacy/Modals/ModalBase',
|
|
9
|
-
} satisfies Meta<typeof ModalBase>;
|
|
10
|
-
|
|
11
|
-
export default meta;
|
|
12
|
-
type Story = StoryObj<typeof ModalBase>;
|
|
13
|
-
|
|
14
|
-
function StoryRender(props: any) {
|
|
15
|
-
const [isOpen, setIsOpen] = useState<boolean>(props.isOpen);
|
|
16
|
-
|
|
17
|
-
const handleOpen = () => {
|
|
18
|
-
setIsOpen(true);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const handleClose = () => {
|
|
22
|
-
setIsOpen(false);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<>
|
|
27
|
-
<button type="button" onClick={handleOpen}>
|
|
28
|
-
open modal
|
|
29
|
-
</button>
|
|
30
|
-
|
|
31
|
-
<ModalBase {...props} open={isOpen} width="300px" clickToDismiss={handleClose}>
|
|
32
|
-
There is nothing to this modal at all. It is completely up to you to style its contents.
|
|
33
|
-
</ModalBase>
|
|
34
|
-
</>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const Base: Story = {
|
|
39
|
-
args: {
|
|
40
|
-
labelText: 'my modal',
|
|
41
|
-
},
|
|
42
|
-
render: (args) => {
|
|
43
|
-
return <StoryRender {...args} />;
|
|
44
|
-
},
|
|
45
|
-
};
|