@takaro/lib-components 0.4.3 → 0.4.6
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/package.json +1 -1
- package/src/components/actions/Button/Button.stories.tsx +49 -33
- package/src/components/actions/Button/__snapshots__/Button.test.tsx.snap +1 -1
- package/src/components/actions/ContextMenu/ContextMenu.stories.tsx +1 -0
- package/src/components/actions/ContextMenu/index.tsx +3 -2
- package/src/components/actions/DropdownButton/DropdownButton.stories.tsx +7 -7
- package/src/components/actions/IconButton/__snapshots__/IconButton.test.tsx.snap +1 -1
- package/src/components/data/Drawer/Drawer.stories.tsx +7 -3
- package/src/components/data/Stats/Stat.tsx +104 -25
- package/src/components/data/Stats/Stats.stories.tsx +135 -11
- package/src/components/data/Stats/context.tsx +10 -3
- package/src/components/data/Stats/index.tsx +16 -9
- package/src/components/dialogs/Dialog/Dialog.stories.tsx +8 -4
- package/src/components/feedback/Alert/Alert.stories.tsx +7 -0
- package/src/components/feedback/Alert/__snapshots__/Alert.test.tsx.snap +6 -4
- package/src/components/feedback/Alert/index.tsx +24 -14
- package/src/components/feedback/Alert/style.ts +23 -15
- package/src/components/feedback/Tooltip/Tooltip.stories.tsx +1 -1
- package/src/components/feedback/snacks/Default/default.stories.tsx +6 -5
- package/src/components/feedback/snacks/Drawer/Drawer.stories.tsx +1 -1
- package/src/components/inputs/CheckBox/CheckBox.stories.tsx +1 -1
- package/src/components/inputs/CodeField/CodeField.stories.tsx +1 -1
- package/src/components/inputs/Date/DatePicker/DatePicker.stories.tsx +6 -6
- package/src/components/inputs/FileField/FileField.stories.tsx +3 -4
- package/src/components/inputs/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/src/components/inputs/Switch/Switch.stories.tsx +1 -1
- package/src/components/inputs/TagField/TagField.stories.tsx +1 -1
- package/src/components/inputs/TextAreaField/TextAreaField.stories.tsx +3 -1
- package/src/components/inputs/TextField/TextField.stories.tsx +3 -1
- package/src/components/inputs/ValueConfirmationField/ValueConfirmationField.stories.tsx +1 -1
- package/src/components/inputs/selects/SelectField/SelectField.stories.tsx +2 -2
- package/src/components/inputs/selects/SelectQueryField/SelectQueryField.stories.tsx +3 -3
- package/src/components/navigation/Steppers/SlimStepper/Stepper.stories.tsx +14 -14
- package/src/components/navigation/Steppers/Stepper/Stepper.stories.tsx +8 -8
- package/src/components/other/ActionMenu/ActionMenu.stories.tsx +0 -4
- package/src/components/other/Empty/Empty.stories.tsx +5 -1
- package/src/components/other/PermissionsGuard/PermissionsGuard.stories.tsx +3 -2
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Meta, StoryFn } from '@storybook/react';
|
|
3
3
|
import { Stats, StatsProps } from '../../../components';
|
|
4
|
+
import { AiOutlineDollar, AiOutlineUser, AiOutlineShoppingCart, AiOutlineEye } from 'react-icons/ai';
|
|
4
5
|
|
|
5
6
|
export default {
|
|
6
7
|
title: 'Data/Stat',
|
|
7
8
|
component: Stats,
|
|
8
9
|
args: {
|
|
9
10
|
direction: 'horizontal',
|
|
10
|
-
|
|
11
|
+
grouped: false,
|
|
12
|
+
size: 'medium',
|
|
11
13
|
},
|
|
12
14
|
} as Meta<StatsProps>;
|
|
13
15
|
|
|
14
|
-
export const
|
|
16
|
+
export const HorizontalGrouped: StoryFn<StatsProps> = () => {
|
|
15
17
|
return (
|
|
16
18
|
<div style={{ width: '1000px' }}>
|
|
17
|
-
<Stats direction="horizontal"
|
|
19
|
+
<Stats direction="horizontal" grouped>
|
|
18
20
|
<Stats.Stat description="Credits" value="$0.00" />
|
|
19
21
|
<Stats.Stat description="Current month so far" value="$0.00" />
|
|
20
22
|
<Stats.Stat description="Last invoice" value="$0.00" />
|
|
@@ -23,10 +25,10 @@ export const HorizontalWithBorder: StoryFn<StatsProps> = () => {
|
|
|
23
25
|
);
|
|
24
26
|
};
|
|
25
27
|
|
|
26
|
-
export const
|
|
28
|
+
export const HorizontalSeparated: StoryFn<StatsProps> = () => {
|
|
27
29
|
return (
|
|
28
30
|
<div style={{ width: '1000px' }}>
|
|
29
|
-
<Stats direction="horizontal"
|
|
31
|
+
<Stats direction="horizontal" grouped={false}>
|
|
30
32
|
<Stats.Stat description="Credits" value="$0.00" />
|
|
31
33
|
<Stats.Stat description="Current month so far" value="$0.00" />
|
|
32
34
|
<Stats.Stat description="Last invoice" value="$0.00" />
|
|
@@ -35,10 +37,10 @@ export const HorizontalWithoutBorder: StoryFn<StatsProps> = () => {
|
|
|
35
37
|
);
|
|
36
38
|
};
|
|
37
39
|
|
|
38
|
-
export const
|
|
40
|
+
export const VerticalGrouped: StoryFn<StatsProps> = () => {
|
|
39
41
|
return (
|
|
40
42
|
<div style={{ width: '300px' }}>
|
|
41
|
-
<Stats direction="vertical"
|
|
43
|
+
<Stats direction="vertical" grouped>
|
|
42
44
|
<Stats.Stat description="Credits" value="$0.00" />
|
|
43
45
|
<Stats.Stat description="Current month so far" value="$0.00" />
|
|
44
46
|
<Stats.Stat description="Last invoice" value="$0.00" />
|
|
@@ -47,10 +49,10 @@ export const VerticalWithBorder: StoryFn<StatsProps> = () => {
|
|
|
47
49
|
);
|
|
48
50
|
};
|
|
49
51
|
|
|
50
|
-
export const
|
|
52
|
+
export const VerticalSeparated: StoryFn<StatsProps> = () => {
|
|
51
53
|
return (
|
|
52
54
|
<div style={{ width: '300px' }}>
|
|
53
|
-
<Stats direction="vertical"
|
|
55
|
+
<Stats direction="vertical" grouped={false}>
|
|
54
56
|
<Stats.Stat description="Credits" value="$0.00" />
|
|
55
57
|
<Stats.Stat description="Current month so far" value="$0.00" />
|
|
56
58
|
<Stats.Stat description="Last invoice" value="$0.00" />
|
|
@@ -59,10 +61,10 @@ export const VerticalWithoutBorder: StoryFn<StatsProps> = () => {
|
|
|
59
61
|
);
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
export const
|
|
64
|
+
export const LoadingState: StoryFn<StatsProps> = (args) => {
|
|
63
65
|
return (
|
|
64
66
|
<div style={{ width: '700px' }}>
|
|
65
|
-
<Stats direction={args.direction}
|
|
67
|
+
<Stats direction={args.direction} grouped={args.grouped}>
|
|
66
68
|
<Stats.Stat isLoading description="Credits" value="$0.00" />
|
|
67
69
|
<Stats.Stat description="Current month so far" value="$0.00" />
|
|
68
70
|
<Stats.Stat description="Last invoice" value="$0.00" />
|
|
@@ -70,3 +72,125 @@ export const LoadingWithoutBorder: StoryFn<StatsProps> = (args) => {
|
|
|
70
72
|
</div>
|
|
71
73
|
);
|
|
72
74
|
};
|
|
75
|
+
|
|
76
|
+
export const WithIcons: StoryFn<StatsProps> = () => {
|
|
77
|
+
return (
|
|
78
|
+
<div style={{ width: '1000px' }}>
|
|
79
|
+
<Stats direction="horizontal" grouped>
|
|
80
|
+
<Stats.Stat description="Revenue" value="$12,345" icon={<AiOutlineDollar />} />
|
|
81
|
+
<Stats.Stat description="Active Users" value={1234} icon={<AiOutlineUser />} />
|
|
82
|
+
<Stats.Stat description="Total Orders" value="567" icon={<AiOutlineShoppingCart />} />
|
|
83
|
+
</Stats>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const WithTrends: StoryFn<StatsProps> = () => {
|
|
89
|
+
return (
|
|
90
|
+
<div style={{ width: '1000px' }}>
|
|
91
|
+
<Stats direction="horizontal" grouped>
|
|
92
|
+
<Stats.Stat
|
|
93
|
+
description="Revenue"
|
|
94
|
+
value="$12,345"
|
|
95
|
+
icon={<AiOutlineDollar />}
|
|
96
|
+
trend={{ direction: 'up', value: '+12.5%' }}
|
|
97
|
+
/>
|
|
98
|
+
<Stats.Stat
|
|
99
|
+
description="Active Users"
|
|
100
|
+
value={1234}
|
|
101
|
+
icon={<AiOutlineUser />}
|
|
102
|
+
trend={{ direction: 'down', value: '-5.2%' }}
|
|
103
|
+
/>
|
|
104
|
+
<Stats.Stat
|
|
105
|
+
description="Page Views"
|
|
106
|
+
value="45.2K"
|
|
107
|
+
icon={<AiOutlineEye />}
|
|
108
|
+
trend={{ direction: 'up', value: '+8%' }}
|
|
109
|
+
/>
|
|
110
|
+
</Stats>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const SizeVariants: StoryFn<StatsProps> = () => {
|
|
116
|
+
return (
|
|
117
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
|
|
118
|
+
<div>
|
|
119
|
+
<h3>Small</h3>
|
|
120
|
+
<Stats direction="horizontal" grouped size="small">
|
|
121
|
+
<Stats.Stat description="Revenue" value="$12,345" icon={<AiOutlineDollar />} />
|
|
122
|
+
<Stats.Stat description="Users" value="1,234" icon={<AiOutlineUser />} />
|
|
123
|
+
</Stats>
|
|
124
|
+
</div>
|
|
125
|
+
<div>
|
|
126
|
+
<h3>Medium (Default)</h3>
|
|
127
|
+
<Stats direction="horizontal" grouped size="medium">
|
|
128
|
+
<Stats.Stat description="Revenue" value="$12,345" icon={<AiOutlineDollar />} />
|
|
129
|
+
<Stats.Stat description="Users" value="1,234" icon={<AiOutlineUser />} />
|
|
130
|
+
</Stats>
|
|
131
|
+
</div>
|
|
132
|
+
<div>
|
|
133
|
+
<h3>Large</h3>
|
|
134
|
+
<Stats direction="horizontal" grouped size="large">
|
|
135
|
+
<Stats.Stat description="Revenue" value="$12,345" icon={<AiOutlineDollar />} />
|
|
136
|
+
<Stats.Stat description="Users" value="1,234" icon={<AiOutlineUser />} />
|
|
137
|
+
</Stats>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const AllFeatures: StoryFn<StatsProps> = () => {
|
|
144
|
+
return (
|
|
145
|
+
<div style={{ width: '1000px' }}>
|
|
146
|
+
<Stats direction="horizontal" grouped size="medium">
|
|
147
|
+
<Stats.Stat
|
|
148
|
+
description="Total Revenue"
|
|
149
|
+
value="$45,231"
|
|
150
|
+
icon={<AiOutlineDollar />}
|
|
151
|
+
trend={{ direction: 'up', value: '+20.1%' }}
|
|
152
|
+
/>
|
|
153
|
+
<Stats.Stat
|
|
154
|
+
description="Active Users"
|
|
155
|
+
value="2,345"
|
|
156
|
+
icon={<AiOutlineUser />}
|
|
157
|
+
trend={{ direction: 'up', value: '+12%' }}
|
|
158
|
+
/>
|
|
159
|
+
<Stats.Stat
|
|
160
|
+
description="Orders"
|
|
161
|
+
value="892"
|
|
162
|
+
icon={<AiOutlineShoppingCart />}
|
|
163
|
+
trend={{ direction: 'down', value: '-3.5%' }}
|
|
164
|
+
/>
|
|
165
|
+
<Stats.Stat description="Page Views" value="123.4K" icon={<AiOutlineEye />} />
|
|
166
|
+
</Stats>
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const VerticalWithAllFeatures: StoryFn<StatsProps> = () => {
|
|
172
|
+
return (
|
|
173
|
+
<div style={{ width: '350px' }}>
|
|
174
|
+
<Stats direction="vertical" grouped size="medium">
|
|
175
|
+
<Stats.Stat
|
|
176
|
+
description="Total Revenue"
|
|
177
|
+
value="$45,231"
|
|
178
|
+
icon={<AiOutlineDollar />}
|
|
179
|
+
trend={{ direction: 'up', value: '+20.1%' }}
|
|
180
|
+
/>
|
|
181
|
+
<Stats.Stat
|
|
182
|
+
description="Active Users"
|
|
183
|
+
value="2,345"
|
|
184
|
+
icon={<AiOutlineUser />}
|
|
185
|
+
trend={{ direction: 'up', value: '+12%' }}
|
|
186
|
+
/>
|
|
187
|
+
<Stats.Stat
|
|
188
|
+
description="Total Orders"
|
|
189
|
+
value="892"
|
|
190
|
+
icon={<AiOutlineShoppingCart />}
|
|
191
|
+
trend={{ direction: 'down', value: '-3.5%' }}
|
|
192
|
+
/>
|
|
193
|
+
</Stats>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { createContext } from 'react';
|
|
2
2
|
|
|
3
3
|
export type Direction = 'horizontal' | 'vertical';
|
|
4
|
+
export type Size = 'small' | 'medium' | 'large';
|
|
4
5
|
|
|
5
6
|
interface StatsContextValue {
|
|
6
|
-
|
|
7
|
+
grouped: boolean;
|
|
7
8
|
direction: Direction;
|
|
8
|
-
|
|
9
|
+
size: Size;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
const defaultValue: StatsContextValue = {
|
|
13
|
+
grouped: false,
|
|
14
|
+
direction: 'vertical',
|
|
15
|
+
size: 'medium',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const StatContext = createContext<StatsContextValue>(defaultValue);
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import { FC, PropsWithChildren, Children, isValidElement } from 'react';
|
|
2
2
|
import { styled } from '../../../styled';
|
|
3
3
|
import { Stat } from './Stat';
|
|
4
|
-
import { StatContext, Direction } from './context';
|
|
4
|
+
import { StatContext, Direction, Size } from './context';
|
|
5
5
|
|
|
6
|
-
export const Container = styled.dl<{ direction: Direction;
|
|
6
|
+
export const Container = styled.dl<{ direction: Direction; grouped: boolean; count: number }>`
|
|
7
7
|
display: grid;
|
|
8
8
|
${({ direction, count }) => {
|
|
9
9
|
return direction === 'horizontal'
|
|
10
10
|
? `grid-template-columns: repeat(${count},1fr)`
|
|
11
11
|
: `grid-template-rows: repeat(${count},1fr)`;
|
|
12
12
|
}};
|
|
13
|
-
border: ${({
|
|
13
|
+
border: ${({ grouped, theme }) => (grouped ? `1px solid ${theme.colors.secondary}` : 'none')};
|
|
14
14
|
border-radius: ${({ theme }) => theme.borderRadius.medium};
|
|
15
|
-
gap: ${({ theme, direction }) =>
|
|
16
|
-
|
|
15
|
+
gap: ${({ theme, direction, grouped }) => {
|
|
16
|
+
if (grouped) return 0;
|
|
17
|
+
return direction === 'vertical' ? `${theme.spacing['2']} 0` : `0 ${theme.spacing['2']}`;
|
|
18
|
+
}};
|
|
17
19
|
`;
|
|
18
20
|
|
|
19
21
|
export interface StatsProps {
|
|
20
22
|
direction?: Direction;
|
|
21
|
-
|
|
23
|
+
grouped: boolean;
|
|
24
|
+
size?: Size;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
interface SubComponents {
|
|
@@ -27,7 +30,8 @@ interface SubComponents {
|
|
|
27
30
|
|
|
28
31
|
export const Stats: FC<PropsWithChildren<StatsProps>> & SubComponents = ({
|
|
29
32
|
direction = 'vertical',
|
|
30
|
-
|
|
33
|
+
grouped,
|
|
34
|
+
size = 'medium',
|
|
31
35
|
children,
|
|
32
36
|
}) => {
|
|
33
37
|
// throw error if child is not a Stat component
|
|
@@ -41,10 +45,13 @@ export const Stats: FC<PropsWithChildren<StatsProps>> & SubComponents = ({
|
|
|
41
45
|
});
|
|
42
46
|
|
|
43
47
|
return (
|
|
44
|
-
<Container direction={direction}
|
|
45
|
-
<StatContext.Provider value={{
|
|
48
|
+
<Container direction={direction} grouped={grouped} count={Children.count(children)}>
|
|
49
|
+
<StatContext.Provider value={{ grouped, direction, size }}>{children}</StatContext.Provider>
|
|
46
50
|
</Container>
|
|
47
51
|
);
|
|
48
52
|
};
|
|
49
53
|
|
|
50
54
|
Stats.Stat = Stat;
|
|
55
|
+
|
|
56
|
+
export type { Direction, Size } from './context';
|
|
57
|
+
export type { TrendConfig } from './Stat';
|
|
@@ -26,7 +26,7 @@ export const Default: StoryFn = () => {
|
|
|
26
26
|
|
|
27
27
|
return (
|
|
28
28
|
<>
|
|
29
|
-
<Button onClick={() => setOpen(true)}
|
|
29
|
+
<Button onClick={() => setOpen(true)}>Open dialog</Button>
|
|
30
30
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
31
31
|
<Dialog.Content>
|
|
32
32
|
<Dialog.Heading>New Module</Dialog.Heading>
|
|
@@ -35,7 +35,9 @@ export const Default: StoryFn = () => {
|
|
|
35
35
|
<p>Modules are what makes Takaro great.</p>
|
|
36
36
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
37
37
|
<TextField label="Module name" name="moduleName" placeholder="cute kittens" control={control} />
|
|
38
|
-
<Button
|
|
38
|
+
<Button type="submit" fullWidth>
|
|
39
|
+
Create module
|
|
40
|
+
</Button>
|
|
39
41
|
</form>
|
|
40
42
|
</Dialog.Body>
|
|
41
43
|
</Dialog.Content>
|
|
@@ -54,7 +56,7 @@ export const SingleActionDialog: StoryFn = () => {
|
|
|
54
56
|
|
|
55
57
|
return (
|
|
56
58
|
<>
|
|
57
|
-
<Button onClick={() => setOpen(true)}
|
|
59
|
+
<Button onClick={() => setOpen(true)}>Open dialog</Button>
|
|
58
60
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
59
61
|
<Dialog.Content>
|
|
60
62
|
<Dialog.Heading>New Module</Dialog.Heading>
|
|
@@ -64,7 +66,9 @@ export const SingleActionDialog: StoryFn = () => {
|
|
|
64
66
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
|
|
65
67
|
dolore magna aliqua.
|
|
66
68
|
</p>
|
|
67
|
-
<Button onClick={handleAction} size="large" fullWidth
|
|
69
|
+
<Button onClick={handleAction} size="large" fullWidth>
|
|
70
|
+
Go back to dashboard
|
|
71
|
+
</Button>
|
|
68
72
|
</Dialog.Body>
|
|
69
73
|
</Dialog.Content>
|
|
70
74
|
</Dialog>
|
|
@@ -13,6 +13,13 @@ export default {
|
|
|
13
13
|
|
|
14
14
|
export const Default: StoryFn<AlertProps> = (args) => <Alert {...args} />;
|
|
15
15
|
|
|
16
|
+
export const TitleOnly: StoryObj<AlertProps> = {
|
|
17
|
+
args: {
|
|
18
|
+
title: 'Important Notice',
|
|
19
|
+
variant: 'info',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
16
23
|
export const WithList: StoryObj<AlertProps> = {
|
|
17
24
|
args: {
|
|
18
25
|
title: 'There were errors with your submission',
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
exports[`Should render <Alert/> 1`] = `
|
|
4
4
|
<div>
|
|
5
5
|
<div
|
|
6
|
-
|
|
6
|
+
aria-atomic="true"
|
|
7
|
+
aria-live="polite"
|
|
8
|
+
class="sc-aXZVg efcfNn"
|
|
7
9
|
role="status"
|
|
8
10
|
style="opacity: 0; will-change: opacity;"
|
|
9
11
|
>
|
|
10
12
|
<div
|
|
11
|
-
class="sc-gEvEer
|
|
13
|
+
class="sc-gEvEer ciCPPR"
|
|
12
14
|
>
|
|
13
15
|
<div
|
|
14
|
-
class="sc-eqUAAy
|
|
16
|
+
class="sc-eqUAAy hqcNUj"
|
|
15
17
|
>
|
|
16
18
|
<svg
|
|
17
19
|
fill="currentColor"
|
|
@@ -34,7 +36,7 @@ exports[`Should render <Alert/> 1`] = `
|
|
|
34
36
|
Alert text
|
|
35
37
|
</p>
|
|
36
38
|
<div
|
|
37
|
-
class="sc-fqkvVR
|
|
39
|
+
class="sc-fqkvVR huFkoW action"
|
|
38
40
|
/>
|
|
39
41
|
</div>
|
|
40
42
|
</div>
|
|
@@ -27,12 +27,16 @@ export interface AlertProps {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
|
|
30
|
-
{ variant, title, text, dismiss = false, elevation =
|
|
30
|
+
{ variant, title, text, dismiss = false, elevation = 2, action },
|
|
31
31
|
ref,
|
|
32
32
|
) {
|
|
33
33
|
const [visible, setVisible] = useState(true);
|
|
34
|
-
|
|
35
|
-
const
|
|
34
|
+
const hasTitle = !!title;
|
|
35
|
+
const hasText = !!text;
|
|
36
|
+
const hasContent = hasTitle || hasText;
|
|
37
|
+
// Use center alignment when we have only one content line (title OR text, not both)
|
|
38
|
+
// Use start alignment when we have multiple lines (title AND text, or text as an array)
|
|
39
|
+
const useStartAlignment = (hasTitle && hasText) || Array.isArray(text);
|
|
36
40
|
|
|
37
41
|
const handleExecute = (e: MouseEvent<HTMLButtonElement>) => {
|
|
38
42
|
e.preventDefault();
|
|
@@ -66,10 +70,19 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
|
|
|
66
70
|
if (typeof text === 'string') {
|
|
67
71
|
return <p>{text}</p>;
|
|
68
72
|
} else if (Array.isArray(text)) {
|
|
69
|
-
return <ul>{text?.map((message) => <li key={
|
|
73
|
+
return <ul>{text?.map((message, index) => <li key={index}>{message}</li>)}</ul>;
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
// Determine ARIA role based on variant
|
|
78
|
+
const getAriaRole = () => {
|
|
79
|
+
return variant === 'error' || variant === 'warning' ? 'alert' : 'status';
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getAriaLive = () => {
|
|
83
|
+
return variant === 'error' || variant === 'warning' ? 'assertive' : 'polite';
|
|
84
|
+
};
|
|
85
|
+
|
|
73
86
|
return (
|
|
74
87
|
<AnimatePresence>
|
|
75
88
|
{visible && (
|
|
@@ -82,25 +95,22 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(
|
|
|
82
95
|
$elevation={elevation}
|
|
83
96
|
transition={{ duration: 0.2 }}
|
|
84
97
|
ref={ref}
|
|
85
|
-
role=
|
|
98
|
+
role={getAriaRole()}
|
|
99
|
+
aria-live={getAriaLive()}
|
|
100
|
+
aria-atomic="true"
|
|
86
101
|
>
|
|
87
|
-
<Grid>
|
|
102
|
+
<Grid $useStartAlignment={useStartAlignment}>
|
|
88
103
|
<IconContainer variant={variant}>{getIcon()}</IconContainer>
|
|
89
104
|
{title && <h2>{title}</h2>}
|
|
90
105
|
{renderText()}
|
|
91
|
-
<ButtonContainer
|
|
92
|
-
hasTitle={hasTitle}
|
|
93
|
-
show={dismiss || action ? true : false}
|
|
94
|
-
variant={variant}
|
|
95
|
-
className="action"
|
|
96
|
-
>
|
|
106
|
+
<ButtonContainer hasContent={hasContent} show={!!(dismiss || action)} variant={variant} className="action">
|
|
97
107
|
{action && (
|
|
98
|
-
<Button size="
|
|
108
|
+
<Button size="small" variant="outline" onClick={handleExecute} color={variant}>
|
|
99
109
|
{action.text}
|
|
100
110
|
</Button>
|
|
101
111
|
)}
|
|
102
112
|
{dismiss && (
|
|
103
|
-
<Button size="
|
|
113
|
+
<Button size="small" color="white" variant="outline" onClick={handleDismiss}>
|
|
104
114
|
Dismiss
|
|
105
115
|
</Button>
|
|
106
116
|
)}
|
|
@@ -12,33 +12,38 @@ export const Container = styled(motion.div)<{
|
|
|
12
12
|
$elevation: Elevation;
|
|
13
13
|
}>`
|
|
14
14
|
width: 100%;
|
|
15
|
-
padding: ${({ theme }) =>
|
|
16
|
-
`${theme.spacing['0_75']} ${theme.spacing['0_75']} ${theme.spacing['0_75']} ${theme.spacing['0']}`};
|
|
15
|
+
padding: ${({ theme }) => theme.spacing['0_75']};
|
|
17
16
|
border-radius: ${({ theme }) => theme.borderRadius.large};
|
|
18
17
|
box-shadow: ${({ theme, $elevation }) => theme.elevation[$elevation]};
|
|
19
18
|
margin: ${({ theme }) => `${theme.spacing['1_5']} auto`};
|
|
20
19
|
h2 {
|
|
21
|
-
font-size:
|
|
22
|
-
display: flex;
|
|
23
|
-
align-items: center;
|
|
20
|
+
font-size: ${({ theme }) => theme.fontSize.mediumLarge};
|
|
24
21
|
font-weight: 700;
|
|
25
|
-
|
|
22
|
+
margin: 0;
|
|
23
|
+
text-align: left;
|
|
26
24
|
}
|
|
27
25
|
p {
|
|
28
|
-
margin-top: ${({ theme, $hasTitle }) => ($hasTitle ? theme.spacing['
|
|
26
|
+
margin-top: ${({ theme, $hasTitle }) => ($hasTitle ? theme.spacing['0_25'] : theme.spacing[0])};
|
|
29
27
|
margin-bottom: 0;
|
|
30
28
|
hyphens: auto;
|
|
29
|
+
text-align: left;
|
|
30
|
+
font-size: ${({ theme }) => theme.fontSize.medium};
|
|
31
31
|
}
|
|
32
|
-
p,
|
|
33
32
|
li {
|
|
34
|
-
font-size:
|
|
33
|
+
font-size: ${({ theme }) => theme.fontSize.medium};
|
|
34
|
+
text-align: left;
|
|
35
35
|
}
|
|
36
36
|
ul {
|
|
37
37
|
margin-left: ${({ theme }) => theme.spacing['1_5']};
|
|
38
|
+
margin-top: ${({ theme, $hasTitle }) => ($hasTitle ? theme.spacing['0_25'] : theme.spacing[0])};
|
|
39
|
+
margin-bottom: 0;
|
|
38
40
|
li {
|
|
39
41
|
list-style-type: disc;
|
|
40
42
|
margin-top: ${({ theme }) => theme.spacing['0_5']};
|
|
41
43
|
margin-bottom: ${({ theme }) => theme.spacing['0_5']};
|
|
44
|
+
&::marker {
|
|
45
|
+
font-size: ${({ theme }) => theme.fontSize.medium};
|
|
46
|
+
}
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
/* set background color equal to provided type */
|
|
@@ -59,12 +64,14 @@ export const Container = styled(motion.div)<{
|
|
|
59
64
|
}}
|
|
60
65
|
`;
|
|
61
66
|
|
|
62
|
-
export const Grid = styled.div
|
|
67
|
+
export const Grid = styled.div<{ $useStartAlignment: boolean }>`
|
|
63
68
|
display: grid;
|
|
64
69
|
grid-template-columns: 40px 1fr;
|
|
65
|
-
align-items: center;
|
|
70
|
+
align-items: ${({ $useStartAlignment }) => ($useStartAlignment ? 'start' : 'center')};
|
|
71
|
+
gap: ${({ theme }) => theme.spacing['0_5']};
|
|
66
72
|
|
|
67
73
|
p,
|
|
74
|
+
ul,
|
|
68
75
|
.action {
|
|
69
76
|
grid-column: 2;
|
|
70
77
|
}
|
|
@@ -75,17 +82,18 @@ export const IconContainer = styled.div<{ variant: AlertVariants }>`
|
|
|
75
82
|
align-items: center;
|
|
76
83
|
justify-content: center;
|
|
77
84
|
svg {
|
|
78
|
-
fill:
|
|
85
|
+
fill: white;
|
|
79
86
|
}
|
|
80
87
|
`;
|
|
81
88
|
|
|
82
89
|
export const ButtonContainer = styled.div<{
|
|
83
90
|
show: boolean;
|
|
84
91
|
variant: AlertVariants;
|
|
85
|
-
|
|
92
|
+
hasContent: boolean;
|
|
86
93
|
}>`
|
|
87
94
|
display: ${({ show }): string => (show ? 'flex' : 'none')};
|
|
88
95
|
align-items: center;
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
flex-wrap: wrap;
|
|
97
|
+
gap: ${({ theme }) => theme.spacing['0_5']};
|
|
98
|
+
margin-top: ${({ theme, hasContent }): string => (hasContent ? theme.spacing['1'] : theme.spacing[0])};
|
|
91
99
|
`;
|
|
@@ -63,7 +63,7 @@ export const Controlled: StoryFn<TooltipProps & ExtraTooltipStoryProps> = () =>
|
|
|
63
63
|
<Tooltip.Trigger asChild>I am the trigger</Tooltip.Trigger>
|
|
64
64
|
<Tooltip.Content>controlled tooltip</Tooltip.Content>
|
|
65
65
|
</Tooltip>
|
|
66
|
-
<Button onClick={() => setOpen(true)}
|
|
66
|
+
<Button onClick={() => setOpen(true)}>open tooltip on, I am the trigger</Button>
|
|
67
67
|
</>
|
|
68
68
|
);
|
|
69
69
|
};
|
|
@@ -38,7 +38,7 @@ export const Default: StoryFn<DefaultSnackProps> = (args) => {
|
|
|
38
38
|
|
|
39
39
|
return (
|
|
40
40
|
<Wrapper>
|
|
41
|
-
<Button onClick={handleOnClick}
|
|
41
|
+
<Button onClick={handleOnClick}>show snack</Button>
|
|
42
42
|
</Wrapper>
|
|
43
43
|
);
|
|
44
44
|
};
|
|
@@ -51,22 +51,23 @@ export const Buttons: StoryFn<DefaultSnackProps> = (args) => {
|
|
|
51
51
|
title: args.title,
|
|
52
52
|
type: args.type,
|
|
53
53
|
key: 'software-update',
|
|
54
|
-
button1: <Button
|
|
54
|
+
button1: <Button>Update</Button>,
|
|
55
55
|
button2: (
|
|
56
56
|
<Button
|
|
57
57
|
onClick={() => {
|
|
58
58
|
closeSnackbar('software-update');
|
|
59
59
|
}}
|
|
60
|
-
text="Not now"
|
|
61
60
|
variant="outline"
|
|
62
|
-
|
|
61
|
+
>
|
|
62
|
+
Not now
|
|
63
|
+
</Button>
|
|
63
64
|
),
|
|
64
65
|
});
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
return (
|
|
68
69
|
<Wrapper>
|
|
69
|
-
<Button onClick={handleOnClick}
|
|
70
|
+
<Button onClick={handleOnClick}>show snack</Button>
|
|
70
71
|
</Wrapper>
|
|
71
72
|
);
|
|
72
73
|
};
|
|
@@ -43,7 +43,7 @@ export const OnSubmit: StoryFn<CheckBoxProps & { defaultValue: boolean }> = (arg
|
|
|
43
43
|
<>
|
|
44
44
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
45
45
|
<CheckBox {...args} control={control} />
|
|
46
|
-
<Button type="submit"
|
|
46
|
+
<Button type="submit">submit</Button>
|
|
47
47
|
</form>
|
|
48
48
|
<pre>value: {result ? 'true' : 'false'}</pre>
|
|
49
49
|
<p>NOTE: defaultValue will only be set on initial load. Limitation of react-hook-form.</p>
|
|
@@ -74,7 +74,7 @@ export const OnDateSubmit: StoryFn<DatePickerProps> = (args) => {
|
|
|
74
74
|
allowFutureDates={args.allowFutureDates}
|
|
75
75
|
allowPastDates={args.allowPastDates}
|
|
76
76
|
/>
|
|
77
|
-
<Button type="submit"
|
|
77
|
+
<Button type="submit">Submit form</Button>
|
|
78
78
|
</form>
|
|
79
79
|
<p>result: {result}</p>
|
|
80
80
|
</Wrapper>
|
|
@@ -110,7 +110,7 @@ export const CustomDateFilter: StoryFn<DatePickerProps> = (args) => {
|
|
|
110
110
|
popOverPlacement={args.popOverPlacement}
|
|
111
111
|
customDateFilter={(date) => date.weekday == 6 || date.weekday == 7}
|
|
112
112
|
/>
|
|
113
|
-
<Button type="submit"
|
|
113
|
+
<Button type="submit">Submit form</Button>
|
|
114
114
|
</form>
|
|
115
115
|
<p>result: {result}</p>
|
|
116
116
|
</Wrapper>
|
|
@@ -148,7 +148,7 @@ export const OnDateAndTimeSubmit: StoryFn<DatePickerProps> = (args) => {
|
|
|
148
148
|
allowPastDates={args.allowPastDates}
|
|
149
149
|
allowFutureDates={args.allowFutureDates}
|
|
150
150
|
/>
|
|
151
|
-
<Button type="submit"
|
|
151
|
+
<Button type="submit">Submit form</Button>
|
|
152
152
|
</form>
|
|
153
153
|
<p>result: {result}</p>
|
|
154
154
|
</Wrapper>
|
|
@@ -186,7 +186,7 @@ export const OnTimeSubmit: StoryFn<DatePickerProps> = (args) => {
|
|
|
186
186
|
allowPastDates={args.allowPastDates}
|
|
187
187
|
allowFutureDates={args.allowFutureDates}
|
|
188
188
|
/>
|
|
189
|
-
<Button type="submit"
|
|
189
|
+
<Button type="submit">Submit form</Button>
|
|
190
190
|
</form>
|
|
191
191
|
<p>result: {result}</p>
|
|
192
192
|
</Wrapper>
|
|
@@ -225,7 +225,7 @@ export const RelativeSubmit: StoryFn<DatePickerProps> = (args) => {
|
|
|
225
225
|
allowPastDates={args.allowPastDates}
|
|
226
226
|
allowFutureDates={args.allowFutureDates}
|
|
227
227
|
/>
|
|
228
|
-
<Button type="submit"
|
|
228
|
+
<Button type="submit">Submit form</Button>
|
|
229
229
|
</form>
|
|
230
230
|
<p>result: {result}</p>
|
|
231
231
|
</Wrapper>
|
|
@@ -259,7 +259,7 @@ export const AbsoluteSubmit = () => {
|
|
|
259
259
|
allowPastDates={false}
|
|
260
260
|
format={DateTime.TIME_SIMPLE}
|
|
261
261
|
/>
|
|
262
|
-
<Button type="submit"
|
|
262
|
+
<Button type="submit">Submit form</Button>
|
|
263
263
|
</form>
|
|
264
264
|
<p>result: {result}</p>
|
|
265
265
|
</StrictMode>
|