@scm-manager/ui-components 2.30.2-20220115-150339 → 2.30.2-20220118-082340
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 +5 -5
- package/src/Help.tsx +3 -2
- package/src/OverviewPageActions.tsx +4 -1
- package/src/Tag.tsx +6 -3
- package/src/Tooltip.stories.tsx +11 -0
- package/src/Tooltip.tsx +166 -24
- package/src/__snapshots__/storyshots.test.ts.snap +3974 -3363
- package/src/forms/Radio.tsx +5 -5
- package/src/forms/Select.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scm-manager/ui-components",
|
|
3
|
-
"version": "2.30.2-
|
|
3
|
+
"version": "2.30.2-20220118-082340",
|
|
4
4
|
"description": "UI Components for SCM-Manager and its plugins",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"files": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@scm-manager/jest-preset": "^2.13.0",
|
|
26
26
|
"@scm-manager/prettier-config": "^2.10.1",
|
|
27
27
|
"@scm-manager/tsconfig": "^2.12.0",
|
|
28
|
-
"@scm-manager/ui-tests": "^2.30.2-
|
|
28
|
+
"@scm-manager/ui-tests": "^2.30.2-20220118-082340",
|
|
29
29
|
"@storybook/addon-actions": "^6.3.12",
|
|
30
30
|
"@storybook/addon-storyshots": "^6.3.12",
|
|
31
31
|
"@storybook/builder-webpack5": "^6.3.12",
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@headlessui/react": "^1.4.3",
|
|
69
|
-
"@scm-manager/ui-api": "^2.30.2-
|
|
70
|
-
"@scm-manager/ui-extensions": "^2.30.2-
|
|
71
|
-
"@scm-manager/ui-types": "^2.30.2-
|
|
69
|
+
"@scm-manager/ui-api": "^2.30.2-20220118-082340",
|
|
70
|
+
"@scm-manager/ui-extensions": "^2.30.2-20220118-082340",
|
|
71
|
+
"@scm-manager/ui-types": "^2.30.2-20220118-082340",
|
|
72
72
|
"classnames": "^2.2.6",
|
|
73
73
|
"date-fns": "^2.4.1",
|
|
74
74
|
"deepmerge": "^4.2.2",
|
package/src/Help.tsx
CHANGED
|
@@ -40,16 +40,17 @@ const AbsolutePositionTooltip = styled(Tooltip)`
|
|
|
40
40
|
|
|
41
41
|
const Help: FC<Props> = ({ message, multiline, className, id }) => (
|
|
42
42
|
<AbsolutePositionTooltip
|
|
43
|
-
className={classNames("is-inline-block", "pl-1",
|
|
43
|
+
className={classNames("is-inline-block", "pl-1", className)}
|
|
44
44
|
message={message}
|
|
45
45
|
id={id}
|
|
46
|
+
multiline={multiline}
|
|
46
47
|
>
|
|
47
48
|
<HelpIcon />
|
|
48
49
|
</AbsolutePositionTooltip>
|
|
49
50
|
);
|
|
50
51
|
|
|
51
52
|
Help.defaultProps = {
|
|
52
|
-
multiline: true
|
|
53
|
+
multiline: true
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
export default Help;
|
|
@@ -37,6 +37,7 @@ type Props = {
|
|
|
37
37
|
label?: string;
|
|
38
38
|
testId?: string;
|
|
39
39
|
searchPlaceholder?: string;
|
|
40
|
+
groupAriaLabelledby?: string;
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
const createAbsoluteLink = (url: string) => {
|
|
@@ -52,7 +53,8 @@ const OverviewPageActions: FC<Props> = ({
|
|
|
52
53
|
groupSelected,
|
|
53
54
|
label,
|
|
54
55
|
testId,
|
|
55
|
-
searchPlaceholder
|
|
56
|
+
searchPlaceholder,
|
|
57
|
+
groupAriaLabelledby
|
|
56
58
|
}) => {
|
|
57
59
|
const history = useHistory();
|
|
58
60
|
const location = useLocation();
|
|
@@ -62,6 +64,7 @@ const OverviewPageActions: FC<Props> = ({
|
|
|
62
64
|
const groupSelector = groups && (
|
|
63
65
|
<div className="column is-flex">
|
|
64
66
|
<Select
|
|
67
|
+
ariaLabelledby={groupAriaLabelledby}
|
|
65
68
|
className="is-fullwidth"
|
|
66
69
|
options={groups.map(g => ({ value: g, label: g }))}
|
|
67
70
|
value={currentGroup}
|
package/src/Tag.tsx
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import React, { FC } from "react";
|
|
25
25
|
import classNames from "classnames";
|
|
26
26
|
import { Color, Size } from "./styleConstants";
|
|
27
|
+
import { useTranslation } from "react-i18next";
|
|
27
28
|
|
|
28
29
|
type Props = {
|
|
29
30
|
className?: string;
|
|
@@ -51,8 +52,10 @@ const Tag: FC<Props> = ({
|
|
|
51
52
|
title,
|
|
52
53
|
onClick,
|
|
53
54
|
onRemove,
|
|
54
|
-
children
|
|
55
|
+
children
|
|
55
56
|
}) => {
|
|
57
|
+
const [t] = useTranslation("commons");
|
|
58
|
+
|
|
56
59
|
let showIcon = null;
|
|
57
60
|
if (icon) {
|
|
58
61
|
showIcon = (
|
|
@@ -64,7 +67,7 @@ const Tag: FC<Props> = ({
|
|
|
64
67
|
}
|
|
65
68
|
let showDelete = null;
|
|
66
69
|
if (onRemove) {
|
|
67
|
-
showDelete = <button className="tag is-delete" onClick={onRemove} />;
|
|
70
|
+
showDelete = <button className="tag is-delete" onClick={onRemove} aria-label={t("tag.delete")} />;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
return (
|
|
@@ -78,7 +81,7 @@ const Tag: FC<Props> = ({
|
|
|
78
81
|
{
|
|
79
82
|
"is-outlined": outlined,
|
|
80
83
|
"is-rounded": rounded,
|
|
81
|
-
"is-clickable": onClick
|
|
84
|
+
"is-clickable": onClick
|
|
82
85
|
},
|
|
83
86
|
size === "small" && smallClassNames
|
|
84
87
|
)}
|
package/src/Tooltip.stories.tsx
CHANGED
|
@@ -94,4 +94,15 @@ storiesOf("Tooltip", module)
|
|
|
94
94
|
</Spacing>
|
|
95
95
|
))}
|
|
96
96
|
</Wrapper>
|
|
97
|
+
))
|
|
98
|
+
.add("Styled", () => (
|
|
99
|
+
<Wrapper>
|
|
100
|
+
{positions.map((position) => (
|
|
101
|
+
<Spacing>
|
|
102
|
+
<Tooltip message={message} location={position} className={"has-text-warning"}>
|
|
103
|
+
<Button label={position} color="info" />{" "}
|
|
104
|
+
</Tooltip>
|
|
105
|
+
</Spacing>
|
|
106
|
+
))}
|
|
107
|
+
</Wrapper>
|
|
97
108
|
));
|
package/src/Tooltip.tsx
CHANGED
|
@@ -21,12 +21,128 @@
|
|
|
21
21
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
|
-
import React, { ReactNode } from "react";
|
|
24
|
+
import React, { FC, ReactNode, useEffect, useState } from "react";
|
|
25
|
+
import styled from "styled-components";
|
|
26
|
+
import classNames from "classnames";
|
|
27
|
+
|
|
28
|
+
// See for css reference: https://github.com/Wikiki/bulma-tooltip/blob/master/src/sass/index.sass
|
|
29
|
+
|
|
30
|
+
const TooltipWrapper = styled.div`
|
|
31
|
+
position: relative;
|
|
32
|
+
display: inline-block;
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const ArrowBase = styled.span`
|
|
36
|
+
z-index: 1020;
|
|
37
|
+
position: absolute;
|
|
38
|
+
width: 0;
|
|
39
|
+
height: 0;
|
|
40
|
+
border-style: solid;
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
const ArrowTop = styled(ArrowBase)`
|
|
44
|
+
top: 0;
|
|
45
|
+
right: auto;
|
|
46
|
+
bottom: auto;
|
|
47
|
+
left: 50%;
|
|
48
|
+
margin-top: -5px;
|
|
49
|
+
margin-right: auto;
|
|
50
|
+
margin-bottom: auto;
|
|
51
|
+
margin-left: -5px;
|
|
52
|
+
border-width: 5px 5px 0 5px;
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const ArrowRight = styled(ArrowBase)`
|
|
56
|
+
top: auto;
|
|
57
|
+
right: 0;
|
|
58
|
+
bottom: 50%;
|
|
59
|
+
left: auto;
|
|
60
|
+
margin-top: auto;
|
|
61
|
+
margin-right: -5px;
|
|
62
|
+
margin-bottom: -5px;
|
|
63
|
+
margin-left: auto;
|
|
64
|
+
border-width: 5px 5px 5px 0;
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
const ArrowLeft = styled(ArrowBase)`
|
|
68
|
+
top: auto;
|
|
69
|
+
right: auto;
|
|
70
|
+
bottom: 50%;
|
|
71
|
+
left: 0;
|
|
72
|
+
margin-top: auto;
|
|
73
|
+
margin-right: auto;
|
|
74
|
+
margin-bottom: -5px;
|
|
75
|
+
margin-left: -5px;
|
|
76
|
+
border-width: 5px 0 5px 5px;
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const ArrowBottom = styled(ArrowBase)`
|
|
80
|
+
top: auto;
|
|
81
|
+
right: auto;
|
|
82
|
+
bottom: 0;
|
|
83
|
+
left: 50%;
|
|
84
|
+
margin-top: auto;
|
|
85
|
+
margin-right: auto;
|
|
86
|
+
margin-bottom: -5px;
|
|
87
|
+
margin-left: -5px;
|
|
88
|
+
border-width: 0 5px 5px 5px;
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const Arrow = {
|
|
92
|
+
bottom: ArrowBottom,
|
|
93
|
+
left: ArrowLeft,
|
|
94
|
+
right: ArrowRight,
|
|
95
|
+
top: ArrowTop
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const TooltipContainerBase = styled.div<{ multiline?: boolean }>`
|
|
99
|
+
z-index: 1020;
|
|
100
|
+
position: absolute;
|
|
101
|
+
padding: 0.5rem 1rem;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
hyphens: auto;
|
|
104
|
+
text-overflow: ${({ multiline }) => (multiline ? "clip" : "ellipsis")};
|
|
105
|
+
white-space: ${({ multiline }) => (multiline ? "normal" : "pre")};
|
|
106
|
+
max-width: ${({ multiline }) => (multiline ? "15rem" : "auto")};
|
|
107
|
+
width: ${({ multiline }) => (multiline ? "15rem" : "auto")};
|
|
108
|
+
word-break: ${({ multiline }) => (multiline ? "keep-all" : "unset")};
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
const TooltipContainerTop = styled(TooltipContainerBase)`
|
|
112
|
+
left: 50%;
|
|
113
|
+
bottom: calc(100% + 5px);
|
|
114
|
+
transform: translateX(-50%);
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
const TooltipContainerBottom = styled(TooltipContainerBase)`
|
|
118
|
+
left: 50%;
|
|
119
|
+
top: calc(100% + 5px);
|
|
120
|
+
transform: translateX(-50%);
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const TooltipContainerLeft = styled(TooltipContainerBase)`
|
|
124
|
+
right: calc(100% + 5px);
|
|
125
|
+
top: 50%;
|
|
126
|
+
transform: translateY(-50%);
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
const TooltipContainerRight = styled(TooltipContainerBase)`
|
|
130
|
+
left: calc(100% + 5px);
|
|
131
|
+
top: 50%;
|
|
132
|
+
transform: translateY(-50%);
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
const Container = {
|
|
136
|
+
bottom: TooltipContainerBottom,
|
|
137
|
+
left: TooltipContainerLeft,
|
|
138
|
+
right: TooltipContainerRight,
|
|
139
|
+
top: TooltipContainerTop
|
|
140
|
+
};
|
|
25
141
|
|
|
26
142
|
type Props = {
|
|
27
143
|
message: string;
|
|
28
144
|
className?: string;
|
|
29
|
-
location
|
|
145
|
+
location?: TooltipLocation;
|
|
30
146
|
multiline?: boolean;
|
|
31
147
|
children: ReactNode;
|
|
32
148
|
id?: string;
|
|
@@ -34,27 +150,53 @@ type Props = {
|
|
|
34
150
|
|
|
35
151
|
export type TooltipLocation = "bottom" | "right" | "top" | "left";
|
|
36
152
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
153
|
+
const Tooltip: FC<Props> = ({ className, message, location = "right", multiline, children, id }) => {
|
|
154
|
+
const [open, setOpen] = useState(false);
|
|
155
|
+
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
const listener = (event: KeyboardEvent) => {
|
|
158
|
+
if (event.key === "Escape") {
|
|
159
|
+
setOpen(false);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
window.addEventListener("keydown", listener);
|
|
163
|
+
return () => window.removeEventListener("keydown", listener);
|
|
164
|
+
}, []);
|
|
165
|
+
|
|
166
|
+
const LocationContainer = Container[location];
|
|
167
|
+
const LocationArrow = Arrow[location];
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<TooltipWrapper
|
|
171
|
+
onMouseEnter={() => setOpen(true)}
|
|
172
|
+
onMouseLeave={() => setOpen(false)}
|
|
173
|
+
onClick={() => setOpen(false)}
|
|
174
|
+
>
|
|
175
|
+
{open ? (
|
|
176
|
+
<>
|
|
177
|
+
<LocationArrow className={`tooltip-arrow-${location}-border-color`} />
|
|
178
|
+
<LocationContainer
|
|
179
|
+
className={classNames(
|
|
180
|
+
"is-size-7",
|
|
181
|
+
"is-family-primary",
|
|
182
|
+
"has-rounded-border",
|
|
183
|
+
"has-text-white",
|
|
184
|
+
"has-background-grey-dark",
|
|
185
|
+
"has-text-weight-semibold",
|
|
186
|
+
className
|
|
187
|
+
)}
|
|
188
|
+
multiline={multiline}
|
|
189
|
+
aria-live="polite"
|
|
190
|
+
id={id}
|
|
191
|
+
role="tooltip"
|
|
192
|
+
>
|
|
193
|
+
{message}
|
|
194
|
+
</LocationContainer>
|
|
195
|
+
</>
|
|
196
|
+
) : null}
|
|
197
|
+
{children}
|
|
198
|
+
</TooltipWrapper>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
59
201
|
|
|
60
202
|
export default Tooltip;
|