@transferwise/components 0.0.0-experimental-88c518c → 0.0.0-experimental-656d955
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/build/index.esm.js +37 -52
- package/build/index.esm.js.map +1 -1
- package/build/index.js +37 -52
- package/build/index.js.map +1 -1
- package/build/main.css +1 -1
- package/build/styles/main.css +1 -1
- package/build/styles/stepper/Stepper.css +1 -1
- package/build/styles/tooltip/Tooltip.css +1 -1
- package/build/types/tooltip/Tooltip.d.ts +2 -1
- package/build/types/tooltip/Tooltip.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/main.css +1 -1
- package/src/stepper/Stepper.css +1 -1
- package/src/stepper/Stepper.less +1 -1
- package/src/tooltip/Tooltip.css +1 -1
- package/src/tooltip/Tooltip.less +13 -0
- package/src/tooltip/Tooltip.spec.tsx +97 -29
- package/src/tooltip/Tooltip.tsx +24 -31
- package/src/tooltip/__snapshots__/Tooltip.spec.tsx.snap +31 -0
package/src/stepper/Stepper.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.tw-stepper{padding-bottom:24px;width:100%}@media only screen and (max-width:575px){.tw-stepper{padding-bottom:0}}.tw-stepper__step{list-style-type:none;position:absolute;top:0}.tw-stepper__step--active .tw-stepper__step-label{color:#37517e;color:var(--color-content-primary);cursor:default}.tw-stepper__step--clickable .tw-stepper__step-label{border-radius:2px;color:#0097c7;color:var(--color-content-accent);line-height:0;transition:color .15s ease-in-out}.np-theme-personal .tw-stepper__step--clickable .tw-stepper__step-label{color:#5d7079;color:var(--color-content-secondary);top:0}.tw-stepper__step--has-tooltip{cursor:pointer}@media screen and (min-width:576px) and (max-width:991px){.tw-stepper__step:first-child .tooltip-inner{transform:translateX(calc(50% - 32px))}.tw-stepper__step:last-child .tooltip-inner{transform:translateX(calc(-50% + 32px))}}.tw-stepper__step-label{color:#5d7079;color:var(--color-content-secondary);position:absolute;top:0;transform:translateX(-50%);transition:color .6s ease-in-out;white-space:nowrap}[dir=rtl] .tw-stepper__step-label{transform:translateX(50%)}.tw-stepper .tooltip{top:24px!important;white-space:nowrap}.tw-stepper .tooltip .tooltip-inner{max-width:100%}.tw-stepper .tw-tooltip-container{display:block}.tw-stepper-steps{padding:0;position:relative}[dir=rtl] .tw-stepper-steps{padding:0}.progress-bar{-webkit-backface-visibility:hidden;background-color:var(--color-interactive-primary);border-bottom-left-radius:1px;border-top-left-radius:1px;float:left;height:100%;transition:width .6s ease-in-out;will-change:width}[dir=rtl] .progress-bar{float:right}.progress-bar:after{border-radius:4px;content:"";float:right;height:8px;margin-right:-4px;margin-top:-3px;width:8px}[dir=rtl] .progress-bar:after{float:left;margin-left:-4px;margin-right:0}.btn-unstyled{background:none;border:none;display:block;margin:0;padding:0}
|
|
1
|
+
.tw-stepper{padding-bottom:24px;width:100%}@media only screen and (max-width:575px){.tw-stepper{padding-bottom:0}}.tw-stepper__step{list-style-type:none;position:absolute;top:0}.tw-stepper__step--active .tw-stepper__step-label{color:#37517e;color:var(--color-content-primary);cursor:default}.tw-stepper__step--clickable .tw-stepper__step-label{border-radius:2px;color:#0097c7;color:var(--color-content-accent);line-height:0;transition:color .15s ease-in-out}.np-theme-personal .tw-stepper__step--clickable .tw-stepper__step-label{color:#5d7079;color:var(--color-content-secondary);top:0}.tw-stepper__step--has-tooltip{cursor:pointer}@media screen and (min-width:576px) and (max-width:991px){.tw-stepper__step:first-child .tooltip-inner{transform:translateX(calc(50% - 32px))}.tw-stepper__step:last-child .tooltip-inner{transform:translateX(calc(-50% + 32px))}}.tw-stepper__step-label{color:#5d7079;color:var(--color-content-secondary);position:absolute;top:0;transform:translateX(-50%);transition:color .6s ease-in-out;white-space:nowrap}[dir=rtl] .tw-stepper__step-label{transform:translateX(50%)}.tw-stepper .tooltip{top:24px!important;white-space:nowrap}.tw-stepper .tooltip .tooltip-inner{max-width:100%}.tw-stepper .tw-tooltip-container{display:inline-block}.tw-stepper-steps{padding:0;position:relative}[dir=rtl] .tw-stepper-steps{padding:0}.progress-bar{-webkit-backface-visibility:hidden;background-color:var(--color-interactive-primary);border-bottom-left-radius:1px;border-top-left-radius:1px;float:left;height:100%;transition:width .6s ease-in-out;will-change:width}[dir=rtl] .progress-bar{float:right}.progress-bar:after{border-radius:4px;content:"";float:right;height:8px;margin-right:-4px;margin-top:-3px;width:8px}[dir=rtl] .progress-bar:after{float:left;margin-left:-4px;margin-right:0}.btn-unstyled{background:none;border:none;display:block;margin:0;padding:0}
|
package/src/stepper/Stepper.less
CHANGED
package/src/tooltip/Tooltip.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.tw-tooltip-container{display:inline-block}.tw-tooltip-container .tooltip{-webkit-user-select:none;-moz-user-select:none;user-select:none;visibility:visible}.tw-tooltip-container .tooltip:not(.in){animation:tw-tooltip-disappear;animation-delay:.15s;animation-duration:0s;animation-fill-mode:both;pointer-events:none}@keyframes tw-tooltip-disappear{0%{visibility:visible}to{visibility:hidden}}.np-tooltip{z-index:1070}.np-panel[data-popper-placement^=right]>.np-panel__content.tooltip-inner .np-panel__arrow{left:-7px}.np-panel[data-popper-placement^=left]>.np-panel__content.tooltip-inner .np-panel__arrow{right:-7px}
|
|
1
|
+
.tw-tooltip-container{display:inline-block}.tw-tooltip-container .tooltip{-webkit-user-select:none;-moz-user-select:none;user-select:none;visibility:visible}.tw-tooltip-container .tooltip:not(.in){animation:tw-tooltip-disappear;animation-delay:.15s;animation-duration:0s;animation-fill-mode:both;pointer-events:none}@keyframes tw-tooltip-disappear{0%{visibility:visible}to{visibility:hidden}}.np-tooltip{z-index:1070}.np-tooltip,.np-tooltip .tooltip-inner{visibility:hidden}.np-tooltip--open,.np-tooltip--open .tooltip-inner{visibility:initial}.np-panel[data-popper-placement^=right]>.np-panel__content.tooltip-inner .np-panel__arrow{left:-7px}.np-panel[data-popper-placement^=left]>.np-panel__content.tooltip-inner .np-panel__arrow{right:-7px}
|
package/src/tooltip/Tooltip.less
CHANGED
|
@@ -34,6 +34,19 @@
|
|
|
34
34
|
|
|
35
35
|
.np-tooltip {
|
|
36
36
|
z-index: @zindex-tooltip;
|
|
37
|
+
visibility: hidden;
|
|
38
|
+
|
|
39
|
+
.tooltip-inner {
|
|
40
|
+
visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&--open {
|
|
44
|
+
visibility: initial;
|
|
45
|
+
|
|
46
|
+
.tooltip-inner {
|
|
47
|
+
visibility: initial;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
37
50
|
}
|
|
38
51
|
|
|
39
52
|
.np-panel[data-popper-placement^="right"] > .np-panel__content.tooltip-inner {
|
|
@@ -1,48 +1,116 @@
|
|
|
1
|
-
import { render, screen
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import React from 'react';
|
|
2
4
|
|
|
3
5
|
import Tooltip from '.';
|
|
4
6
|
|
|
5
|
-
describe('Tooltip', () => {
|
|
6
|
-
|
|
7
|
+
describe('Tooltip Component', () => {
|
|
8
|
+
it('renders an empty list when no items are passed', () => {
|
|
9
|
+
expect(
|
|
10
|
+
render(
|
|
11
|
+
<Tooltip label="Test Tooltip">
|
|
12
|
+
<span>Hover me</span>
|
|
13
|
+
</Tooltip>,
|
|
14
|
+
).container,
|
|
15
|
+
).toMatchSnapshot();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('initially is hidden (test with toBeInTheDocument)', () => {
|
|
19
|
+
render(
|
|
20
|
+
<Tooltip label="Test Tooltip">
|
|
21
|
+
<span>Hover me</span>
|
|
22
|
+
</Tooltip>,
|
|
23
|
+
);
|
|
24
|
+
const tooltip = screen.getByRole('tooltip', { hidden: true });
|
|
25
|
+
expect(tooltip).toBeInTheDocument();
|
|
26
|
+
expect(tooltip).toHaveAttribute('aria-hidden', 'true');
|
|
27
|
+
});
|
|
7
28
|
|
|
8
|
-
it('
|
|
9
|
-
render(
|
|
29
|
+
it('should render the tooltip label when closed', () => {
|
|
30
|
+
render(
|
|
31
|
+
<Tooltip label="Test Tooltip">
|
|
32
|
+
<span>Hover me</span>
|
|
33
|
+
</Tooltip>,
|
|
34
|
+
);
|
|
35
|
+
const triggerElement = screen.getByText('Hover me');
|
|
36
|
+
const tooltip = screen.getByRole('tooltip', { hidden: true });
|
|
37
|
+
expect(tooltip).toHaveAttribute('aria-hidden', 'true');
|
|
10
38
|
|
|
11
|
-
|
|
39
|
+
userEvent.hover(triggerElement);
|
|
40
|
+
expect(tooltip).toHaveAttribute('aria-hidden', 'false');
|
|
12
41
|
});
|
|
13
42
|
|
|
14
|
-
it('
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
43
|
+
it('should display the tooltip on mouse hover', () => {
|
|
44
|
+
render(
|
|
45
|
+
<Tooltip label="Test Tooltip">
|
|
46
|
+
<span>Hover over me!</span>
|
|
47
|
+
</Tooltip>,
|
|
48
|
+
);
|
|
49
|
+
const triggerElement = screen.getByText('Hover over me!');
|
|
18
50
|
|
|
19
|
-
userEvent.hover(
|
|
20
|
-
|
|
51
|
+
userEvent.hover(triggerElement);
|
|
52
|
+
|
|
53
|
+
const tooltipElement = screen.queryByText('Test Tooltip');
|
|
54
|
+
expect(tooltipElement).toBeVisible();
|
|
21
55
|
});
|
|
22
56
|
|
|
23
|
-
it('
|
|
24
|
-
|
|
25
|
-
|
|
57
|
+
it('should hide the tooltip on mouse out', () => {
|
|
58
|
+
render(
|
|
59
|
+
<Tooltip label="Test Tooltip">
|
|
60
|
+
<span>Hover me</span>
|
|
61
|
+
</Tooltip>,
|
|
62
|
+
);
|
|
63
|
+
const triggerElement = screen.getByText('Hover me');
|
|
64
|
+
|
|
65
|
+
userEvent.hover(triggerElement);
|
|
66
|
+
let tooltipElement = screen.getByText('Test Tooltip');
|
|
67
|
+
expect(tooltipElement).toBeVisible();
|
|
26
68
|
|
|
27
|
-
userEvent.
|
|
28
|
-
|
|
29
|
-
|
|
69
|
+
userEvent.unhover(triggerElement);
|
|
70
|
+
tooltipElement = screen.getByRole('tooltip', { hidden: true });
|
|
71
|
+
expect(tooltipElement).toHaveAttribute('aria-hidden', 'true');
|
|
30
72
|
});
|
|
31
73
|
|
|
32
|
-
it('
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
74
|
+
it('should display the tooltip on focus', () => {
|
|
75
|
+
render(
|
|
76
|
+
<Tooltip label="Test Tooltip">
|
|
77
|
+
<span>Focus me</span>
|
|
78
|
+
</Tooltip>,
|
|
79
|
+
);
|
|
80
|
+
const triggerElement = screen.getByText('Focus me');
|
|
81
|
+
|
|
82
|
+
userEvent.tab();
|
|
83
|
+
const tooltipElement = screen.getByText('Test Tooltip');
|
|
84
|
+
expect(tooltipElement).toBeVisible();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should hide the tooltip on blur', () => {
|
|
88
|
+
render(
|
|
89
|
+
<Tooltip label="Test Tooltip">
|
|
90
|
+
<span>Focus me</span>
|
|
91
|
+
</Tooltip>,
|
|
92
|
+
);
|
|
93
|
+
const triggerElement = screen.getByText('Focus me');
|
|
94
|
+
|
|
95
|
+
userEvent.tab();
|
|
96
|
+
let tooltipElement = screen.getByRole('tooltip', { hidden: true });
|
|
97
|
+
expect(tooltipElement).toBeVisible();
|
|
36
98
|
|
|
37
|
-
|
|
38
|
-
|
|
99
|
+
userEvent.tab({ shift: true }); // Blur the element
|
|
100
|
+
tooltipElement = screen.getByRole('tooltip', { hidden: true });
|
|
101
|
+
expect(tooltipElement).toHaveAttribute('aria-hidden', 'true');
|
|
39
102
|
});
|
|
40
103
|
|
|
41
|
-
it('
|
|
42
|
-
|
|
43
|
-
|
|
104
|
+
it('should display the tooltip when the "children" prop is a React element', () => {
|
|
105
|
+
render(
|
|
106
|
+
<Tooltip label="Test Tooltip">
|
|
107
|
+
<button type="button">Click me</button>
|
|
108
|
+
</Tooltip>,
|
|
109
|
+
);
|
|
110
|
+
const triggerElement = screen.getByText('Click me');
|
|
44
111
|
|
|
45
|
-
|
|
46
|
-
|
|
112
|
+
userEvent.hover(triggerElement);
|
|
113
|
+
const tooltipElement = screen.getByRole('tooltip', { hidden: true });
|
|
114
|
+
expect(tooltipElement).toBeVisible();
|
|
47
115
|
});
|
|
48
116
|
});
|
package/src/tooltip/Tooltip.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
import { useId } from '@radix-ui/react-id';
|
|
2
3
|
import classNames from 'classnames';
|
|
3
4
|
import {
|
|
4
5
|
cloneElement,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
type Props = PropsWithChildren<{
|
|
23
24
|
position?: PositionTop | PositionRight | PositionBottom | PositionLeft;
|
|
24
25
|
label: ReactNode;
|
|
26
|
+
id?: string;
|
|
25
27
|
}> &
|
|
26
28
|
CommonProps;
|
|
27
29
|
|
|
@@ -29,6 +31,7 @@ const Tooltip = ({
|
|
|
29
31
|
position = Position.TOP,
|
|
30
32
|
children = undefined,
|
|
31
33
|
label,
|
|
34
|
+
id,
|
|
32
35
|
className,
|
|
33
36
|
}: Props): ReactElement => {
|
|
34
37
|
const [open, setOpen] = useState(false);
|
|
@@ -36,6 +39,8 @@ const Tooltip = ({
|
|
|
36
39
|
const [arrowElement, setArrowElement] = useState(null);
|
|
37
40
|
const [popperElement, setPopperElement] = useState(null);
|
|
38
41
|
|
|
42
|
+
const fallbackId = useId();
|
|
43
|
+
const tooltipId = id ?? fallbackId;
|
|
39
44
|
const modifiers = [];
|
|
40
45
|
|
|
41
46
|
modifiers.push({
|
|
@@ -71,46 +76,34 @@ const Tooltip = ({
|
|
|
71
76
|
|
|
72
77
|
return (
|
|
73
78
|
<>
|
|
74
|
-
<span
|
|
79
|
+
<span
|
|
80
|
+
ref={anchorReference}
|
|
81
|
+
className="tw-tooltip-container"
|
|
82
|
+
onMouseOver={() => setOpen(true)}
|
|
83
|
+
onFocus={() => setOpen(true)}
|
|
84
|
+
onMouseOut={() => setOpen(false)}
|
|
85
|
+
onBlur={() => setOpen(false)}
|
|
86
|
+
>
|
|
75
87
|
{children
|
|
76
88
|
? cloneElement(children as ReactElement, {
|
|
77
|
-
|
|
78
|
-
onMouseOver: () => {
|
|
79
|
-
if ((children as ReactElement)?.props?.onMouseOver) {
|
|
80
|
-
(children as ReactElement)?.props?.onMouseOver();
|
|
81
|
-
}
|
|
82
|
-
setOpen(true);
|
|
83
|
-
},
|
|
84
|
-
onFocus: () => {
|
|
85
|
-
if ((children as ReactElement)?.props?.onFocus) {
|
|
86
|
-
(children as ReactElement).props.onFocus();
|
|
87
|
-
}
|
|
88
|
-
setOpen(true);
|
|
89
|
-
},
|
|
90
|
-
onMouseOut: () => {
|
|
91
|
-
if ((children as ReactElement)?.props?.onMouseOver) {
|
|
92
|
-
(children as ReactElement).props.onMouseOver();
|
|
93
|
-
}
|
|
94
|
-
setOpen(false);
|
|
95
|
-
},
|
|
96
|
-
onBlur: () => {
|
|
97
|
-
if ((children as ReactElement)?.props?.onBlur) {
|
|
98
|
-
(children as ReactElement).props.onBlur();
|
|
99
|
-
}
|
|
100
|
-
setOpen(false);
|
|
101
|
-
},
|
|
102
|
-
/* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */
|
|
89
|
+
'aria-describedby': `${tooltipId}-tooltip`,
|
|
103
90
|
})
|
|
104
91
|
: null}
|
|
105
|
-
</span>
|
|
106
|
-
{open ? (
|
|
107
92
|
<div
|
|
108
93
|
// @ts-expect-error
|
|
109
94
|
ref={setPopperElement}
|
|
110
|
-
className={classNames(
|
|
95
|
+
className={classNames(
|
|
96
|
+
'np-tooltip',
|
|
97
|
+
'np-panel',
|
|
98
|
+
open ? `np-panel--open np-tooltip--open` : null,
|
|
99
|
+
className,
|
|
100
|
+
)}
|
|
111
101
|
// eslint-disable-next-line react/forbid-dom-props
|
|
112
102
|
style={{ ...styles.popper }}
|
|
113
103
|
{...attributes.popper}
|
|
104
|
+
aria-hidden={!open}
|
|
105
|
+
role="tooltip"
|
|
106
|
+
id={`${tooltipId}-tooltip`}
|
|
114
107
|
>
|
|
115
108
|
<div className="np-panel__content tooltip-inner">
|
|
116
109
|
{label}
|
|
@@ -123,7 +116,7 @@ const Tooltip = ({
|
|
|
123
116
|
/>
|
|
124
117
|
</div>
|
|
125
118
|
</div>
|
|
126
|
-
|
|
119
|
+
</span>
|
|
127
120
|
</>
|
|
128
121
|
);
|
|
129
122
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`Tooltip Component renders an empty list when no items are passed 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<span
|
|
6
|
+
class="tw-tooltip-container"
|
|
7
|
+
>
|
|
8
|
+
<span
|
|
9
|
+
aria-describedby="radix-0-tooltip"
|
|
10
|
+
>
|
|
11
|
+
Hover me
|
|
12
|
+
</span>
|
|
13
|
+
<div
|
|
14
|
+
aria-hidden="true"
|
|
15
|
+
class="np-tooltip np-panel"
|
|
16
|
+
id="radix-0-tooltip"
|
|
17
|
+
role="tooltip"
|
|
18
|
+
style="position: absolute; left: 0px; top: 0px;"
|
|
19
|
+
>
|
|
20
|
+
<div
|
|
21
|
+
class="np-panel__content tooltip-inner"
|
|
22
|
+
>
|
|
23
|
+
Test Tooltip
|
|
24
|
+
<div
|
|
25
|
+
class="np-panel__arrow"
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</span>
|
|
30
|
+
</div>
|
|
31
|
+
`;
|