@hyphen/hyphen-components 6.12.0 → 6.14.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/dist/components/Alert/Alert.d.ts +3 -12
- package/dist/components/Alert/Alert.stories.d.ts +8 -4
- package/dist/components/Badge/Badge.stories.d.ts +5 -5
- package/dist/components/Button/Button.stories.d.ts +13 -13
- package/dist/hyphen-components.cjs.development.js +36 -29
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +1 -1
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +37 -30
- package/dist/hyphen-components.esm.js.map +1 -1
- package/package.json +3 -3
- package/src/components/Alert/Alert.constants.ts +0 -1
- package/src/components/Alert/Alert.stories.tsx +102 -47
- package/src/components/Alert/Alert.test.tsx +2 -66
- package/src/components/Alert/Alert.tsx +78 -65
- package/src/components/Badge/Badge.stories.tsx +69 -22
- package/src/components/Button/Button.stories.tsx +265 -127
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyphen/hyphen-components",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.14.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "@hyphen"
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
88
|
"@babel/core": "^7.27.4",
|
|
89
|
-
"@chromatic-com/storybook": "^4.1.
|
|
89
|
+
"@chromatic-com/storybook": "^4.1.3",
|
|
90
90
|
"@semantic-release/commit-analyzer": "^11.1.0",
|
|
91
91
|
"@size-limit/preset-small-lib": "^11.2.0",
|
|
92
92
|
"@storybook/addon-a11y": "^9.1.3",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"@types/react-modal": "^3.16.3",
|
|
106
106
|
"autoprefixer": "^10.4.20",
|
|
107
107
|
"babel-loader": "^9.1.3",
|
|
108
|
-
"chromatic": "^13.
|
|
108
|
+
"chromatic": "^13.3.4",
|
|
109
109
|
"clean-webpack-plugin": "^4.0.0",
|
|
110
110
|
"cross-env": "^7.0.3",
|
|
111
111
|
"css-loader": "^6.11.0",
|
|
@@ -1,30 +1,96 @@
|
|
|
1
1
|
import { Alert } from './Alert';
|
|
2
2
|
import { AlertVariant } from './Alert.types';
|
|
3
3
|
import { Button } from '../Button/Button';
|
|
4
|
+
import { ALERT_VARIANTS } from './Alert.constants';
|
|
4
5
|
|
|
5
|
-
import type { Meta } from '@storybook/react-vite';
|
|
6
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
6
7
|
import React from 'react';
|
|
7
8
|
import { useState } from 'react';
|
|
8
9
|
|
|
9
10
|
const meta: Meta<typeof Alert> = {
|
|
10
11
|
title: 'Components/Alert',
|
|
11
12
|
component: Alert,
|
|
13
|
+
argTypes: {
|
|
14
|
+
variant: {
|
|
15
|
+
control: 'select',
|
|
16
|
+
options: ALERT_VARIANTS,
|
|
17
|
+
description: 'The type/color of the alert to show',
|
|
18
|
+
},
|
|
19
|
+
title: {
|
|
20
|
+
control: 'text',
|
|
21
|
+
description: 'The title for the alert',
|
|
22
|
+
},
|
|
23
|
+
message: {
|
|
24
|
+
control: 'text',
|
|
25
|
+
description:
|
|
26
|
+
'The text message to be rendered in the alert (deprecated, use children instead)',
|
|
27
|
+
},
|
|
28
|
+
hasIcon: {
|
|
29
|
+
control: 'boolean',
|
|
30
|
+
description:
|
|
31
|
+
'Whether the alert has an icon that corresponds to its variant',
|
|
32
|
+
},
|
|
33
|
+
isCompact: {
|
|
34
|
+
control: 'boolean',
|
|
35
|
+
description: 'Renders a version of the alert with smaller padding',
|
|
36
|
+
},
|
|
37
|
+
className: {
|
|
38
|
+
control: 'text',
|
|
39
|
+
description: 'Custom class to apply to the alert',
|
|
40
|
+
},
|
|
41
|
+
onClose: {
|
|
42
|
+
action: 'closed',
|
|
43
|
+
description: 'Callback when alert is closed',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
args: {
|
|
47
|
+
variant: 'default',
|
|
48
|
+
hasIcon: false,
|
|
49
|
+
isCompact: false,
|
|
50
|
+
},
|
|
12
51
|
};
|
|
13
52
|
|
|
14
53
|
export default meta;
|
|
54
|
+
type Story = StoryObj<typeof Alert>;
|
|
15
55
|
|
|
16
|
-
export const Overview =
|
|
17
|
-
|
|
18
|
-
title
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
56
|
+
export const Overview: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
title: 'Contact Created',
|
|
59
|
+
variant: 'success',
|
|
60
|
+
hasIcon: true,
|
|
61
|
+
children: 'The contact was saved on December 3, 2020 at 6:10pm PDT',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const Compact: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
title: 'Contact Created',
|
|
68
|
+
variant: 'success',
|
|
69
|
+
hasIcon: true,
|
|
70
|
+
isCompact: true,
|
|
71
|
+
children: 'The contact was saved on December 3, 2020 at 6:10pm PDT',
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const WithCustomContent: Story = {
|
|
76
|
+
args: {
|
|
77
|
+
title: 'Custom Content',
|
|
78
|
+
variant: 'info',
|
|
79
|
+
hasIcon: true,
|
|
80
|
+
},
|
|
81
|
+
render: (args) => (
|
|
82
|
+
<Alert {...args}>
|
|
83
|
+
<p>
|
|
84
|
+
This alert uses <strong>children</strong> for custom content. You can
|
|
85
|
+
include any JSX content here, including <a href="/#">links</a>,{' '}
|
|
86
|
+
<code>code snippets</code>, and more.
|
|
87
|
+
</p>
|
|
88
|
+
</Alert>
|
|
89
|
+
),
|
|
90
|
+
};
|
|
25
91
|
|
|
26
|
-
export const Variants =
|
|
27
|
-
(
|
|
92
|
+
export const Variants: Story = {
|
|
93
|
+
render: () => {
|
|
28
94
|
const variants: AlertVariant[] = [
|
|
29
95
|
'default',
|
|
30
96
|
'info',
|
|
@@ -41,62 +107,51 @@ export const Variants = () =>
|
|
|
41
107
|
<>
|
|
42
108
|
{variants.map((variant: AlertVariant) => (
|
|
43
109
|
<Alert
|
|
44
|
-
message={message(variant)}
|
|
45
110
|
key={variant}
|
|
46
111
|
title={variant.charAt(0).toUpperCase() + variant.slice(1)}
|
|
47
112
|
variant={variant}
|
|
48
113
|
hasIcon
|
|
49
114
|
className="m-bottom-md"
|
|
50
|
-
|
|
115
|
+
>
|
|
116
|
+
{message(variant)}
|
|
117
|
+
</Alert>
|
|
51
118
|
))}
|
|
52
119
|
</>
|
|
53
120
|
);
|
|
54
|
-
}
|
|
121
|
+
},
|
|
122
|
+
parameters: {
|
|
123
|
+
controls: { disable: true },
|
|
124
|
+
},
|
|
125
|
+
};
|
|
55
126
|
|
|
56
|
-
export const
|
|
57
|
-
const [
|
|
58
|
-
const [isAlertThreeShowing, setAlertThreeShowing] = useState(true);
|
|
127
|
+
export const ClosableAlert = () => {
|
|
128
|
+
const [isAlertShowing, setIsAlertShowing] = useState(true);
|
|
59
129
|
|
|
60
130
|
return (
|
|
61
131
|
<>
|
|
62
|
-
|
|
63
|
-
title="Won't Close"
|
|
64
|
-
message="Closable, but with no onClose callback so nothing happens when clicked."
|
|
65
|
-
variant="warning"
|
|
66
|
-
isClosable
|
|
67
|
-
className="m-bottom-md"
|
|
68
|
-
/>
|
|
69
|
-
{isAlertTwoShowing ? (
|
|
132
|
+
{isAlertShowing ? (
|
|
70
133
|
<Alert
|
|
71
134
|
title="Closable"
|
|
72
|
-
message="This one works!"
|
|
73
135
|
variant="info"
|
|
74
|
-
|
|
75
|
-
onClose={() => setAlertTwoShowing(false)}
|
|
136
|
+
onClose={() => setIsAlertShowing(false)}
|
|
76
137
|
className="m-bottom-md"
|
|
77
|
-
|
|
138
|
+
>
|
|
139
|
+
Try closing me.
|
|
140
|
+
</Alert>
|
|
78
141
|
) : (
|
|
79
142
|
<div className="m-bottom-md">
|
|
80
|
-
<Button onClick={() =>
|
|
81
|
-
Give me the
|
|
82
|
-
</Button>
|
|
83
|
-
</div>
|
|
84
|
-
)}
|
|
85
|
-
{isAlertThreeShowing ? (
|
|
86
|
-
<Alert
|
|
87
|
-
message="With custom close text!"
|
|
88
|
-
variant="info"
|
|
89
|
-
isClosable
|
|
90
|
-
onClose={() => setAlertThreeShowing(false)}
|
|
91
|
-
closeText="Close me!"
|
|
92
|
-
/>
|
|
93
|
-
) : (
|
|
94
|
-
<div className="m-bottom-md">
|
|
95
|
-
<Button onClick={() => setAlertThreeShowing(true)} size="sm">
|
|
96
|
-
Give me the third alert back!
|
|
143
|
+
<Button onClick={() => setIsAlertShowing(true)} size="sm">
|
|
144
|
+
Give me the alert back!
|
|
97
145
|
</Button>
|
|
98
146
|
</div>
|
|
99
147
|
)}
|
|
100
148
|
</>
|
|
101
149
|
);
|
|
102
150
|
};
|
|
151
|
+
|
|
152
|
+
export const Closable: Story = {
|
|
153
|
+
render: () => ClosableAlert(),
|
|
154
|
+
parameters: {
|
|
155
|
+
controls: { disable: true },
|
|
156
|
+
},
|
|
157
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
-
import { render, screen
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import { Alert } from './Alert';
|
|
4
4
|
import { ALERT_VARIANTS } from './Alert.constants';
|
|
5
5
|
|
|
@@ -111,77 +111,13 @@ describe('Alert', () => {
|
|
|
111
111
|
});
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
describe('Closable Alert', () => {
|
|
115
|
-
test('It renders a close icon if `isClosable` prop is passed', () => {
|
|
116
|
-
const message = 'I am closable!';
|
|
117
|
-
const { rerender } = render(<Alert message={message} />);
|
|
118
|
-
|
|
119
|
-
const noCloseButton = screen.queryByTestId('alert-close-icon-test-id');
|
|
120
|
-
expect(noCloseButton).not.toBeInTheDocument();
|
|
121
|
-
|
|
122
|
-
rerender(<Alert message={message} isClosable />);
|
|
123
|
-
const closeButton = screen.queryByTestId('alert-close-icon-test-id');
|
|
124
|
-
expect(closeButton).toBeInTheDocument();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('It renders with custom close text if closeText prop is passed', () => {
|
|
128
|
-
const message = 'I am closable too!';
|
|
129
|
-
render(<Alert message={message} isClosable closeText="Close me!" />);
|
|
130
|
-
|
|
131
|
-
const closeButton = screen.queryByText('Close me!');
|
|
132
|
-
expect(closeButton).toBeInTheDocument();
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test('It fires a callback if onClose prop is passed', () => {
|
|
136
|
-
const message = 'I am closable too!';
|
|
137
|
-
const mockOnClose = jest.fn();
|
|
138
|
-
|
|
139
|
-
const { rerender } = render(
|
|
140
|
-
<Alert message={message} isClosable onClose={mockOnClose} />
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const closeButton = screen.queryByTestId('alert-close-icon-test-id');
|
|
144
|
-
if (closeButton) fireEvent.click(closeButton);
|
|
145
|
-
expect(mockOnClose).toBeCalledTimes(1);
|
|
146
|
-
mockOnClose.mockReset();
|
|
147
|
-
|
|
148
|
-
rerender(
|
|
149
|
-
<Alert
|
|
150
|
-
message={message}
|
|
151
|
-
isClosable
|
|
152
|
-
onClose={mockOnClose}
|
|
153
|
-
closeText="close"
|
|
154
|
-
/>
|
|
155
|
-
);
|
|
156
|
-
const closeButtonSpan = screen.getByText('close');
|
|
157
|
-
if (closeButtonSpan) {
|
|
158
|
-
fireEvent.click(closeButtonSpan); // 1
|
|
159
|
-
fireEvent.keyUp(closeButtonSpan, { keyCode: 13 }); // 2
|
|
160
|
-
fireEvent.keyUp(closeButtonSpan, { keyCode: 13 }); // 3
|
|
161
|
-
fireEvent.keyUp(closeButtonSpan, { keyCode: 30 }); // No-op
|
|
162
|
-
fireEvent.keyUp(closeButtonSpan, { keyCode: 30 }); // No-op
|
|
163
|
-
}
|
|
164
|
-
expect(mockOnClose).toBeCalledTimes(3);
|
|
165
|
-
mockOnClose.mockReset();
|
|
166
|
-
|
|
167
|
-
rerender(<Alert message={message} isClosable closeText="close" />);
|
|
168
|
-
const closeButtonNotClickable = screen.getByText('close');
|
|
169
|
-
if (closeButtonNotClickable) {
|
|
170
|
-
fireEvent.click(closeButtonSpan); // No-op
|
|
171
|
-
fireEvent.keyUp(closeButtonSpan, { keyCode: 13 }); // No-op
|
|
172
|
-
fireEvent.keyUp(closeButtonSpan, { keyCode: 30 }); // No-op
|
|
173
|
-
}
|
|
174
|
-
expect(mockOnClose).toBeCalledTimes(0);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
114
|
describe('Compact', () => {
|
|
179
115
|
test('It renders with the compact class when isCompact prop is true', () => {
|
|
180
116
|
const message = 'Hello world!';
|
|
181
117
|
render(<Alert message={message} isCompact />);
|
|
182
118
|
|
|
183
119
|
const alert = screen.getByRole('alert');
|
|
184
|
-
expect(alert).toHaveClass('p-
|
|
120
|
+
expect(alert).toHaveClass('p-md');
|
|
185
121
|
});
|
|
186
122
|
});
|
|
187
123
|
});
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
FC,
|
|
3
|
+
ReactNode,
|
|
4
|
+
MouseEvent,
|
|
5
|
+
KeyboardEvent,
|
|
6
|
+
useCallback,
|
|
7
|
+
useMemo,
|
|
8
|
+
memo,
|
|
9
|
+
} from 'react';
|
|
2
10
|
import classNames from 'classnames';
|
|
3
11
|
import { Box } from '../Box/Box';
|
|
4
12
|
import { Icon } from '../Icon/Icon';
|
|
@@ -11,25 +19,16 @@ export interface AlertProps {
|
|
|
11
19
|
* Custom class to apply to the alert.
|
|
12
20
|
*/
|
|
13
21
|
className?: string;
|
|
14
|
-
/**
|
|
15
|
-
* Custom text to use as a close button.
|
|
16
|
-
*/
|
|
17
|
-
closeText?: string;
|
|
18
22
|
/**
|
|
19
23
|
* Whether the alert as an icon that corresponds to its variant (Success, warning, etc.).
|
|
20
24
|
*/
|
|
21
25
|
hasIcon?: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Whether the alert can be closed by the user. If `true` it will render
|
|
24
|
-
* the 'close' icon on the right hand side of the alert.
|
|
25
|
-
*/
|
|
26
|
-
isClosable?: boolean;
|
|
27
26
|
/**
|
|
28
27
|
* Renders a version of the alert with smaller padding.
|
|
29
28
|
*/
|
|
30
29
|
isCompact?: boolean;
|
|
31
30
|
/**
|
|
32
|
-
* The text message or ReactNode to be rendered in the alert.
|
|
31
|
+
* @deprecated Use children instead. The text message or ReactNode to be rendered in the alert.
|
|
33
32
|
*/
|
|
34
33
|
message?: string | ReactNode;
|
|
35
34
|
/**
|
|
@@ -56,12 +55,12 @@ export interface AlertProps {
|
|
|
56
55
|
*/
|
|
57
56
|
[x: string]: any; // eslint-disable-line
|
|
58
57
|
}
|
|
59
|
-
|
|
58
|
+
|
|
59
|
+
const AlertComponent: FC<AlertProps> = ({
|
|
60
|
+
children,
|
|
60
61
|
className = '',
|
|
61
|
-
closeText = '',
|
|
62
62
|
hasIcon = false,
|
|
63
63
|
isCompact = false,
|
|
64
|
-
isClosable = false,
|
|
65
64
|
message = '',
|
|
66
65
|
onClose = undefined,
|
|
67
66
|
render = undefined,
|
|
@@ -69,29 +68,44 @@ export const Alert: FC<AlertProps> = ({
|
|
|
69
68
|
variant = 'default',
|
|
70
69
|
...restProps
|
|
71
70
|
}) => {
|
|
72
|
-
const handleClose = (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
onClose(event);
|
|
78
|
-
};
|
|
71
|
+
const handleClose = useCallback(
|
|
72
|
+
(
|
|
73
|
+
event: MouseEvent<HTMLOrSVGElement> | KeyboardEvent<HTMLSpanElement>
|
|
74
|
+
): void => {
|
|
75
|
+
if (!onClose) return;
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
name={ALERT_ICONS_MAP[variant].icon}
|
|
84
|
-
data-testid={`alert-icon-${variant}-test-id`}
|
|
85
|
-
/>
|
|
86
|
-
</Box>
|
|
77
|
+
onClose(event);
|
|
78
|
+
},
|
|
79
|
+
[onClose]
|
|
87
80
|
);
|
|
88
81
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
event: KeyboardEvent<HTMLSpanElement>
|
|
92
|
-
): void => {
|
|
82
|
+
const handleCloseKeyPress = useCallback(
|
|
83
|
+
(event: KeyboardEvent<HTMLSpanElement>): void => {
|
|
93
84
|
if (event.keyCode === 13) handleClose(event);
|
|
94
|
-
}
|
|
85
|
+
},
|
|
86
|
+
[handleClose]
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const alertContainerClasses = useMemo(
|
|
90
|
+
() => classNames(styles[`alert__${variant}`], styles.alert, className),
|
|
91
|
+
[variant, className]
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const alertIcon = useMemo(() => {
|
|
95
|
+
if (!hasIcon) return null;
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<Box fontSize="md" className={styles[`alert__icon__${variant}`]}>
|
|
99
|
+
<Icon
|
|
100
|
+
name={ALERT_ICONS_MAP[variant].icon}
|
|
101
|
+
data-testid={`alert-icon-${variant}-test-id`}
|
|
102
|
+
/>
|
|
103
|
+
</Box>
|
|
104
|
+
);
|
|
105
|
+
}, [hasIcon, variant]);
|
|
106
|
+
|
|
107
|
+
const closeIcon = useMemo(() => {
|
|
108
|
+
if (!onClose) return null;
|
|
95
109
|
|
|
96
110
|
return (
|
|
97
111
|
<Box
|
|
@@ -105,19 +119,35 @@ export const Alert: FC<AlertProps> = ({
|
|
|
105
119
|
onKeyUp={handleCloseKeyPress}
|
|
106
120
|
aria-label="dismiss"
|
|
107
121
|
>
|
|
108
|
-
|
|
109
|
-
<Icon name="remove" data-testid="alert-close-icon-test-id" />
|
|
110
|
-
)}
|
|
122
|
+
<Icon name="remove" data-testid="alert-close-icon-test-id" />
|
|
111
123
|
</button>
|
|
112
124
|
</Box>
|
|
113
125
|
);
|
|
114
|
-
};
|
|
126
|
+
}, [onClose, handleClose, handleCloseKeyPress]);
|
|
115
127
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
const content = useMemo(() => {
|
|
129
|
+
if (render) {
|
|
130
|
+
return render();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<Box display="block" childGap={message && title ? '2xs' : undefined}>
|
|
135
|
+
{title && (
|
|
136
|
+
<Box
|
|
137
|
+
as="h4"
|
|
138
|
+
fontSize="sm"
|
|
139
|
+
fontWeight="semibold"
|
|
140
|
+
className={styles['alert-heading']}
|
|
141
|
+
>
|
|
142
|
+
{title}
|
|
143
|
+
</Box>
|
|
144
|
+
)}
|
|
145
|
+
{children ??
|
|
146
|
+
(message &&
|
|
147
|
+
(typeof message === 'string' ? <p>{message}</p> : message))}
|
|
148
|
+
</Box>
|
|
149
|
+
);
|
|
150
|
+
}, [render, message, title, children]);
|
|
121
151
|
|
|
122
152
|
return (
|
|
123
153
|
<Box
|
|
@@ -125,34 +155,17 @@ export const Alert: FC<AlertProps> = ({
|
|
|
125
155
|
gap="md"
|
|
126
156
|
className={alertContainerClasses}
|
|
127
157
|
direction="row"
|
|
128
|
-
padding={isCompact ? '
|
|
158
|
+
padding={isCompact ? 'md' : '2xl'}
|
|
129
159
|
radius="md"
|
|
130
160
|
role="alert"
|
|
131
161
|
fontSize="sm"
|
|
132
162
|
{...restProps}
|
|
133
163
|
>
|
|
134
|
-
{
|
|
135
|
-
<div>
|
|
136
|
-
|
|
137
|
-
render()
|
|
138
|
-
) : (
|
|
139
|
-
<Box display="block" childGap={message && title ? '2xs' : undefined}>
|
|
140
|
-
{title && (
|
|
141
|
-
<Box
|
|
142
|
-
as="h4"
|
|
143
|
-
fontSize="sm"
|
|
144
|
-
fontWeight="semibold"
|
|
145
|
-
className={styles['alert-heading']}
|
|
146
|
-
>
|
|
147
|
-
{title}
|
|
148
|
-
</Box>
|
|
149
|
-
)}
|
|
150
|
-
{message &&
|
|
151
|
-
(typeof message === 'string' ? <p>{message}</p> : message)}
|
|
152
|
-
</Box>
|
|
153
|
-
)}
|
|
154
|
-
</div>
|
|
155
|
-
{isClosable && renderCloseIcon()}
|
|
164
|
+
{alertIcon}
|
|
165
|
+
<div>{content}</div>
|
|
166
|
+
{closeIcon}
|
|
156
167
|
</Box>
|
|
157
168
|
);
|
|
158
169
|
};
|
|
170
|
+
|
|
171
|
+
export const Alert = memo(AlertComponent);
|
|
@@ -1,42 +1,86 @@
|
|
|
1
|
-
import { Meta } from '@storybook/react-vite';
|
|
2
1
|
import { Badge, BadgeVariant } from './Badge';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { Box } from '../Box/Box';
|
|
4
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
5
|
+
|
|
6
|
+
const BADGE_VARIANTS: BadgeVariant[] = [
|
|
7
|
+
'light-grey',
|
|
8
|
+
'dark-grey',
|
|
9
|
+
'inverse',
|
|
10
|
+
'purple',
|
|
11
|
+
'blue',
|
|
12
|
+
'green',
|
|
13
|
+
'yellow',
|
|
14
|
+
'red',
|
|
15
|
+
'hyphen',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const BADGE_SIZES = ['sm', 'md', 'lg'];
|
|
5
19
|
|
|
6
20
|
const meta: Meta<typeof Badge> = {
|
|
7
21
|
title: 'Components/Badge',
|
|
8
22
|
component: Badge,
|
|
23
|
+
argTypes: {
|
|
24
|
+
variant: {
|
|
25
|
+
control: 'select',
|
|
26
|
+
options: BADGE_VARIANTS,
|
|
27
|
+
description: 'The type/color of the badge to show',
|
|
28
|
+
},
|
|
29
|
+
size: {
|
|
30
|
+
control: 'select',
|
|
31
|
+
options: BADGE_SIZES,
|
|
32
|
+
description: 'The size of the badge',
|
|
33
|
+
},
|
|
34
|
+
message: {
|
|
35
|
+
control: 'text',
|
|
36
|
+
description:
|
|
37
|
+
'The text message to be rendered in the badge (deprecated, use children instead)',
|
|
38
|
+
},
|
|
39
|
+
className: {
|
|
40
|
+
control: 'text',
|
|
41
|
+
description: 'Custom class to apply to the badge',
|
|
42
|
+
},
|
|
43
|
+
children: {
|
|
44
|
+
control: 'text',
|
|
45
|
+
description: 'Badge content (preferred over message)',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
args: {
|
|
49
|
+
variant: 'light-grey',
|
|
50
|
+
size: 'md',
|
|
51
|
+
message: '',
|
|
52
|
+
className: '',
|
|
53
|
+
children: undefined,
|
|
54
|
+
},
|
|
9
55
|
};
|
|
10
56
|
|
|
11
57
|
export default meta;
|
|
12
58
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export const
|
|
16
|
-
|
|
17
|
-
'
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'yellow',
|
|
24
|
-
'red',
|
|
25
|
-
'hyphen',
|
|
26
|
-
] as BadgeVariant[];
|
|
27
|
-
return (
|
|
59
|
+
type Story = StoryObj<typeof Badge>;
|
|
60
|
+
|
|
61
|
+
export const Overview: Story = {
|
|
62
|
+
args: {
|
|
63
|
+
message: 'Hello world!',
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const Variants: Story = {
|
|
68
|
+
render: () => (
|
|
28
69
|
<Box direction="row" gap="sm">
|
|
29
|
-
{
|
|
70
|
+
{BADGE_VARIANTS.map((variant) => (
|
|
30
71
|
<Badge variant={variant} key={variant}>
|
|
31
72
|
{variant}
|
|
32
73
|
</Badge>
|
|
33
74
|
))}
|
|
34
75
|
</Box>
|
|
35
|
-
)
|
|
76
|
+
),
|
|
77
|
+
parameters: {
|
|
78
|
+
controls: { disable: true },
|
|
79
|
+
},
|
|
36
80
|
};
|
|
37
81
|
|
|
38
|
-
export const Sizes =
|
|
39
|
-
|
|
82
|
+
export const Sizes: Story = {
|
|
83
|
+
render: () => (
|
|
40
84
|
<Box direction="column" alignItems="flex-start" gap="md">
|
|
41
85
|
<Badge size="sm" message="Small" />
|
|
42
86
|
<Badge size="md" message="Medium" />
|
|
@@ -51,5 +95,8 @@ export const Sizes = () => (
|
|
|
51
95
|
Responsive
|
|
52
96
|
</Badge>
|
|
53
97
|
</Box>
|
|
54
|
-
|
|
55
|
-
|
|
98
|
+
),
|
|
99
|
+
parameters: {
|
|
100
|
+
controls: { disable: true },
|
|
101
|
+
},
|
|
102
|
+
};
|