@automattic/vip-design-system 2.4.2 → 2.4.4
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/system/Button/Button.js +3 -0
- package/build/system/Dropdown/DropdownItem.d.ts +1 -0
- package/build/system/Dropdown/DropdownItem.js +2 -1
- package/build/system/LinkExternal/LinkExternal.d.ts +11 -0
- package/build/system/LinkExternal/LinkExternal.js +48 -0
- package/build/system/LinkExternal/LinkExternal.stories.d.ts +17 -0
- package/build/system/LinkExternal/LinkExternal.stories.js +16 -0
- package/build/system/LinkExternal/LinkExternal.test.d.ts +1 -0
- package/build/system/LinkExternal/LinkExternal.test.js +49 -0
- package/build/system/MobileMenu/MobileMenu.js +6 -5
- package/build/system/index.d.ts +2 -1
- package/build/system/index.js +2 -0
- package/build/system/theme/index.d.ts +30 -40
- package/build/system/theme/index.js +13 -18
- package/package.json +2 -1
- package/src/system/Button/Button.tsx +3 -0
- package/src/system/Dropdown/DropdownItem.js +2 -1
- package/src/system/LinkExternal/LinkExternal.stories.tsx +17 -0
- package/src/system/LinkExternal/LinkExternal.test.tsx +47 -0
- package/src/system/LinkExternal/LinkExternal.tsx +50 -0
- package/src/system/MobileMenu/MobileMenu.tsx +11 -5
- package/src/system/index.js +2 -0
- package/src/system/theme/index.js +13 -18
|
@@ -52,6 +52,9 @@ var Button = exports.Button = /*#__PURE__*/(0, _react.forwardRef)(function (_ref
|
|
|
52
52
|
cursor: 'not-allowed',
|
|
53
53
|
pointerEvents: 'none'
|
|
54
54
|
},
|
|
55
|
+
'&:hover, &:focus': {
|
|
56
|
+
textDecoration: 'none'
|
|
57
|
+
},
|
|
55
58
|
flexGrow: Boolean(grow) === true ? '1' : undefined,
|
|
56
59
|
width: Boolean(full) === true ? '100%' : undefined
|
|
57
60
|
}, sx)
|
|
@@ -25,6 +25,7 @@ export const styles = {
|
|
|
25
25
|
py: 1,
|
|
26
26
|
'&:hover, &:focus': {
|
|
27
27
|
backgroundColor: 'hover',
|
|
28
|
+
textDecoration: 'none',
|
|
28
29
|
},
|
|
29
30
|
|
|
30
31
|
'&[data-disabled]': {
|
|
@@ -34,7 +35,7 @@ export const styles = {
|
|
|
34
35
|
|
|
35
36
|
'&[data-highlighted]': {
|
|
36
37
|
backgroundColor: 'hover',
|
|
37
|
-
color: '
|
|
38
|
+
color: 'link',
|
|
38
39
|
},
|
|
39
40
|
};
|
|
40
41
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
type Props = {
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
screenReaderText?: string | number;
|
|
5
|
+
href: string;
|
|
6
|
+
showExternalIcon?: boolean;
|
|
7
|
+
defaultScreenReaderText?: boolean;
|
|
8
|
+
newTab?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare const LinkExternal: React.FC<Props>;
|
|
11
|
+
export default LinkExternal;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports["default"] = exports.LinkExternal = void 0;
|
|
5
|
+
var _i18nCalypso = require("i18n-calypso");
|
|
6
|
+
var _Link = require("../Link");
|
|
7
|
+
var _ScreenReaderText = _interopRequireDefault(require("../ScreenReaderText"));
|
|
8
|
+
var _jsxRuntime = require("theme-ui/jsx-runtime");
|
|
9
|
+
var _excluded = ["children", "screenReaderText", "href", "showExternalIcon", "newTab"];
|
|
10
|
+
/**
|
|
11
|
+
* External dependencies
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Internal dependencies
|
|
15
|
+
*/
|
|
16
|
+
// Screen reader announcements
|
|
17
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
18
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
19
|
+
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
20
|
+
var DEFAULT_EXTERNAL_LINK_TEXT = (0, _i18nCalypso.translate)(', external link'); // reads as: link, <link text>, external link
|
|
21
|
+
var NEW_TAB_TEXT = (0, _i18nCalypso.translate)(', opens in a new tab'); // reads as: link, <link text>, external link, opens in a new tab
|
|
22
|
+
|
|
23
|
+
var LinkExternal = exports.LinkExternal = function LinkExternal(_ref) {
|
|
24
|
+
var _ref$children = _ref.children,
|
|
25
|
+
children = _ref$children === void 0 ? null : _ref$children,
|
|
26
|
+
_ref$screenReaderText = _ref.screenReaderText,
|
|
27
|
+
screenReaderText = _ref$screenReaderText === void 0 ? '' : _ref$screenReaderText,
|
|
28
|
+
href = _ref.href,
|
|
29
|
+
_ref$showExternalIcon = _ref.showExternalIcon,
|
|
30
|
+
showExternalIcon = _ref$showExternalIcon === void 0 ? true : _ref$showExternalIcon,
|
|
31
|
+
_ref$newTab = _ref.newTab,
|
|
32
|
+
newTab = _ref$newTab === void 0 ? false : _ref$newTab,
|
|
33
|
+
rest = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
34
|
+
return (0, _jsxRuntime.jsxs)(_Link.Link, _extends({
|
|
35
|
+
as: "a",
|
|
36
|
+
target: newTab ? '_blank' : '_self',
|
|
37
|
+
rel: newTab ? 'noopener noreferrer' : '',
|
|
38
|
+
href: href
|
|
39
|
+
}, rest, {
|
|
40
|
+
children: [children, (0, _jsxRuntime.jsxs)(_ScreenReaderText["default"], {
|
|
41
|
+
children: [screenReaderText, DEFAULT_EXTERNAL_LINK_TEXT, newTab ? NEW_TAB_TEXT : '']
|
|
42
|
+
}), showExternalIcon && (0, _jsxRuntime.jsx)("span", {
|
|
43
|
+
"aria-hidden": "true",
|
|
44
|
+
children: "\xA0\u2197"
|
|
45
|
+
})]
|
|
46
|
+
}));
|
|
47
|
+
};
|
|
48
|
+
var _default = exports["default"] = LinkExternal;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import LinkExternal from './LinkExternal';
|
|
3
|
+
import type { StoryObj } from '@storybook/react';
|
|
4
|
+
declare const _default: {
|
|
5
|
+
title: string;
|
|
6
|
+
component: import("react").FC<{
|
|
7
|
+
children?: import("react").ReactNode;
|
|
8
|
+
screenReaderText?: string | number | undefined;
|
|
9
|
+
href: string;
|
|
10
|
+
showExternalIcon?: boolean | undefined;
|
|
11
|
+
defaultScreenReaderText?: boolean | undefined;
|
|
12
|
+
newTab?: boolean | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
export default _default;
|
|
16
|
+
type Story = StoryObj<typeof LinkExternal>;
|
|
17
|
+
export declare const Default: Story;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports["default"] = exports.Default = void 0;
|
|
5
|
+
var _LinkExternal = _interopRequireDefault(require("./LinkExternal"));
|
|
6
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
7
|
+
var _default = exports["default"] = {
|
|
8
|
+
title: 'Navigation/LinkExternal',
|
|
9
|
+
component: _LinkExternal["default"]
|
|
10
|
+
};
|
|
11
|
+
var Default = exports.Default = {
|
|
12
|
+
args: {
|
|
13
|
+
children: 'View on GitHub',
|
|
14
|
+
href: 'https://github.com/Automattic/vip-design-system'
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("@testing-library/jest-dom");
|
|
4
|
+
var _react = require("@testing-library/react");
|
|
5
|
+
var _LinkExternal = _interopRequireDefault(require("./LinkExternal"));
|
|
6
|
+
var _jsxRuntime = require("theme-ui/jsx-runtime");
|
|
7
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
8
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
var props = {
|
|
12
|
+
children: 'View on Github',
|
|
13
|
+
href: 'https://github.com/Automattic/vip-design-system'
|
|
14
|
+
};
|
|
15
|
+
describe('<LinkExternal />', function () {
|
|
16
|
+
it('should render correctly', function () {
|
|
17
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_LinkExternal["default"], _extends({}, props, {
|
|
18
|
+
children: "View on Github"
|
|
19
|
+
})));
|
|
20
|
+
var link = _react.screen.getByRole('link');
|
|
21
|
+
expect(link).toHaveTextContent(/view on github/i);
|
|
22
|
+
expect(link).toHaveTextContent(/external link/i);
|
|
23
|
+
expect(link).toHaveAttribute('target', '_self');
|
|
24
|
+
expect(link).toHaveAttribute('rel', '');
|
|
25
|
+
});
|
|
26
|
+
it('should open in new tab when newTab is true', function () {
|
|
27
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_LinkExternal["default"], _extends({}, props, {
|
|
28
|
+
newTab: true
|
|
29
|
+
})));
|
|
30
|
+
var link = _react.screen.getByRole('link');
|
|
31
|
+
expect(link).toHaveTextContent(/opens in a new tab/i);
|
|
32
|
+
expect(link).toHaveAttribute('target', '_blank');
|
|
33
|
+
expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
|
34
|
+
});
|
|
35
|
+
it('should contain additional screenreader text when added', function () {
|
|
36
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_LinkExternal["default"], _extends({}, props, {
|
|
37
|
+
screenReaderText: "VIP Design System"
|
|
38
|
+
})));
|
|
39
|
+
expect(_react.screen.getByRole('link', {
|
|
40
|
+
name: /vip design system/i
|
|
41
|
+
})).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
it('should hide icon when showExternalIcon is false', function () {
|
|
44
|
+
(0, _react.render)((0, _jsxRuntime.jsx)(_LinkExternal["default"], _extends({}, props, {
|
|
45
|
+
showExternalIcon: false
|
|
46
|
+
})));
|
|
47
|
+
expect(_react.screen.queryByText('↗')).not.toBeInTheDocument();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -44,16 +44,17 @@ var MobileMenu = exports.MobileMenu = /*#__PURE__*/(0, _react.forwardRef)(functi
|
|
|
44
44
|
children: (0, _jsxRuntime.jsx)(_Logo.Logo, {})
|
|
45
45
|
}), (0, _jsxRuntime.jsx)("div", {
|
|
46
46
|
sx: {
|
|
47
|
-
|
|
48
|
-
overflowY: 'auto',
|
|
49
|
-
height: 'calc(100vh - 64px)',
|
|
47
|
+
height: '100vh',
|
|
50
48
|
display: 'flex',
|
|
51
49
|
flex: 1
|
|
52
50
|
},
|
|
53
51
|
children: (0, _jsxRuntime.jsxs)(_index.Flex, {
|
|
54
52
|
sx: {
|
|
55
53
|
width: '100%',
|
|
56
|
-
flexDirection: 'column'
|
|
54
|
+
flexDirection: 'column',
|
|
55
|
+
height: 'calc(100vh - 64px)',
|
|
56
|
+
overflowX: 'hidden',
|
|
57
|
+
overflowY: 'auto'
|
|
57
58
|
},
|
|
58
59
|
children: [toolbarItems && (0, _jsxRuntime.jsx)(_index.Nav.PrimaryInverse, {
|
|
59
60
|
label: "Main Links",
|
|
@@ -63,7 +64,7 @@ var MobileMenu = exports.MobileMenu = /*#__PURE__*/(0, _react.forwardRef)(functi
|
|
|
63
64
|
sx: {
|
|
64
65
|
alignSelf: 'stretch',
|
|
65
66
|
backgroundColor: 'layer.1',
|
|
66
|
-
|
|
67
|
+
height: '100%',
|
|
67
68
|
gap: 4,
|
|
68
69
|
width: '100%',
|
|
69
70
|
a: {
|
package/build/system/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ import { TableRow } from './Table';
|
|
|
38
38
|
import { TableCell } from './Table';
|
|
39
39
|
import { Tooltip } from './Tooltip';
|
|
40
40
|
import { Link } from './Link';
|
|
41
|
+
import LinkExternal from './LinkExternal/LinkExternal';
|
|
41
42
|
import { Radio } from './Form';
|
|
42
43
|
import { RadioBoxGroup } from './Form';
|
|
43
44
|
import { Textarea } from './Form';
|
|
@@ -56,4 +57,4 @@ import { Validation } from './Form';
|
|
|
56
57
|
import { Wizard } from './Wizard';
|
|
57
58
|
import { WizardStep } from './Wizard';
|
|
58
59
|
import theme from './theme';
|
|
59
|
-
export { Accordion, Avatar, Badge, Box, Breadcrumbs, Button, ButtonSubmit, ButtonVariant, Card, Checkbox, Code, Dialog, NewDialog, Form, Drawer, Dropdown, DialogButton, DialogMenu, DialogMenuItem, DialogDivider, DialogContent, DialogTrigger, ConfirmationDialog, MobileMenu, MobileMenuTrigger, MobileMenuWrapper, NewConfirmationDialog, Grid, Flex, Notice, OptionRow, Heading, Input, Label, Spinner, Table, TableRow, TableCell, Tooltip, Link, Radio, RadioBoxGroup, Textarea, Progress, Text, Tabs, Nav, NavItem, TabsTrigger, TabsContent, TabsList, Toggle, ToggleRow, Toolbar, Validation, Wizard, WizardStep, theme };
|
|
60
|
+
export { Accordion, Avatar, Badge, Box, Breadcrumbs, Button, ButtonSubmit, ButtonVariant, Card, Checkbox, Code, Dialog, NewDialog, Form, Drawer, Dropdown, DialogButton, DialogMenu, DialogMenuItem, DialogDivider, DialogContent, DialogTrigger, ConfirmationDialog, MobileMenu, MobileMenuTrigger, MobileMenuWrapper, NewConfirmationDialog, Grid, Flex, Notice, OptionRow, Heading, Input, Label, Spinner, Table, TableRow, TableCell, Tooltip, Link, LinkExternal, Radio, RadioBoxGroup, Textarea, Progress, Text, Tabs, Nav, NavItem, TabsTrigger, TabsContent, TabsList, Toggle, ToggleRow, Toolbar, Validation, Wizard, WizardStep, theme };
|
package/build/system/index.js
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { Grid } from './Grid';
|
|
37
37
|
import { Heading } from './Heading';
|
|
38
38
|
import { Link } from './Link';
|
|
39
|
+
import LinkExternal from './LinkExternal/LinkExternal';
|
|
39
40
|
import { MobileMenuWrapper, MobileMenuTrigger, MobileMenu } from './MobileMenu/MobileMenu';
|
|
40
41
|
import { Nav } from './Nav/Nav';
|
|
41
42
|
import { NavItem } from './Nav/NavItem';
|
|
@@ -95,6 +96,7 @@ export {
|
|
|
95
96
|
TableCell,
|
|
96
97
|
Tooltip,
|
|
97
98
|
Link,
|
|
99
|
+
LinkExternal,
|
|
98
100
|
Radio,
|
|
99
101
|
RadioBoxGroup,
|
|
100
102
|
Textarea,
|
|
@@ -72,9 +72,10 @@ declare namespace _default {
|
|
|
72
72
|
fontWeight: string;
|
|
73
73
|
boxShadow: string;
|
|
74
74
|
borderRadius: number;
|
|
75
|
-
'&:hover
|
|
75
|
+
'&:hover': {
|
|
76
76
|
backgroundColor: string;
|
|
77
77
|
color: string;
|
|
78
|
+
textDecoration: string;
|
|
78
79
|
};
|
|
79
80
|
verticalAlign: string;
|
|
80
81
|
alignItems: string;
|
|
@@ -86,16 +87,13 @@ declare namespace _default {
|
|
|
86
87
|
fill: string;
|
|
87
88
|
};
|
|
88
89
|
};
|
|
89
|
-
'&:hover': {
|
|
90
|
-
textDecoration: string;
|
|
91
|
-
};
|
|
92
90
|
};
|
|
93
91
|
export { primary_1 as primary };
|
|
94
92
|
let secondary_1: {
|
|
95
93
|
variant: string;
|
|
96
94
|
color: string;
|
|
97
95
|
bg: string;
|
|
98
|
-
'&:hover
|
|
96
|
+
'&:hover': {
|
|
99
97
|
backgroundColor: string;
|
|
100
98
|
color: string;
|
|
101
99
|
};
|
|
@@ -107,7 +105,7 @@ declare namespace _default {
|
|
|
107
105
|
bg: string;
|
|
108
106
|
border: string;
|
|
109
107
|
borderColor: string;
|
|
110
|
-
'&:hover
|
|
108
|
+
'&:hover': {
|
|
111
109
|
backgroundColor: string;
|
|
112
110
|
color: string;
|
|
113
111
|
border: string;
|
|
@@ -120,7 +118,7 @@ declare namespace _default {
|
|
|
120
118
|
bg: string;
|
|
121
119
|
border: string;
|
|
122
120
|
borderColor: string;
|
|
123
|
-
'&:hover
|
|
121
|
+
'&:hover': {
|
|
124
122
|
backgroundColor: string;
|
|
125
123
|
color: string;
|
|
126
124
|
border: string;
|
|
@@ -133,7 +131,7 @@ declare namespace _default {
|
|
|
133
131
|
bg: string;
|
|
134
132
|
border: string;
|
|
135
133
|
borderColor: string;
|
|
136
|
-
'&:hover
|
|
134
|
+
'&:hover': {
|
|
137
135
|
backgroundColor: string;
|
|
138
136
|
color: string;
|
|
139
137
|
border: string;
|
|
@@ -146,7 +144,7 @@ declare namespace _default {
|
|
|
146
144
|
bg: string;
|
|
147
145
|
border: string;
|
|
148
146
|
borderColor: string;
|
|
149
|
-
'&:hover
|
|
147
|
+
'&:hover': {
|
|
150
148
|
backgroundColor: string;
|
|
151
149
|
color: string;
|
|
152
150
|
border: string;
|
|
@@ -174,7 +172,7 @@ declare namespace _default {
|
|
|
174
172
|
variant: string;
|
|
175
173
|
color: string;
|
|
176
174
|
padding: number;
|
|
177
|
-
'&:hover
|
|
175
|
+
'&:hover': {
|
|
178
176
|
backgroundColor: string;
|
|
179
177
|
};
|
|
180
178
|
};
|
|
@@ -187,17 +185,14 @@ declare namespace _default {
|
|
|
187
185
|
};
|
|
188
186
|
'&:hover': {
|
|
189
187
|
color: string;
|
|
188
|
+
textDecorationLine: string;
|
|
189
|
+
textDecorationThickness: string;
|
|
190
190
|
};
|
|
191
191
|
'&:active': {
|
|
192
192
|
color: string;
|
|
193
193
|
};
|
|
194
194
|
textDecorationThickness: string;
|
|
195
195
|
textUnderlineOffset: string;
|
|
196
|
-
'&:hover, &:focus': {
|
|
197
|
-
color: string;
|
|
198
|
-
textDecorationLine: string;
|
|
199
|
-
textDecorationThickness: string;
|
|
200
|
-
};
|
|
201
196
|
};
|
|
202
197
|
'button-primary': {
|
|
203
198
|
variant: string;
|
|
@@ -313,37 +308,32 @@ declare namespace _default {
|
|
|
313
308
|
};
|
|
314
309
|
};
|
|
315
310
|
export namespace styles {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
export let a: {
|
|
311
|
+
let root: {
|
|
312
|
+
fontFamily: string;
|
|
313
|
+
lineHeight: string;
|
|
314
|
+
fontWeight: string;
|
|
315
|
+
color: string;
|
|
316
|
+
backgroundColor: string;
|
|
317
|
+
'-webkit-font-smoothing': string;
|
|
318
|
+
'-moz-osx-font-smoothing': string;
|
|
319
|
+
a: {
|
|
326
320
|
'&:hover': {
|
|
327
321
|
textDecorationLine: string;
|
|
328
322
|
textDecorationThickness: string;
|
|
329
323
|
textUnderlineOffset: string;
|
|
330
324
|
};
|
|
331
325
|
};
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
export { color_2 as color };
|
|
344
|
-
}
|
|
345
|
-
export { p_2 as p };
|
|
346
|
-
}
|
|
326
|
+
svg: {
|
|
327
|
+
fill: string;
|
|
328
|
+
display: string;
|
|
329
|
+
};
|
|
330
|
+
pre: {
|
|
331
|
+
fontFamily: string;
|
|
332
|
+
};
|
|
333
|
+
p: {
|
|
334
|
+
color: string;
|
|
335
|
+
};
|
|
336
|
+
};
|
|
347
337
|
}
|
|
348
338
|
}
|
|
349
339
|
export default _default;
|
|
@@ -283,9 +283,10 @@ export default {
|
|
|
283
283
|
fontWeight: 'medium',
|
|
284
284
|
boxShadow: 'none',
|
|
285
285
|
borderRadius: 1,
|
|
286
|
-
'&:hover
|
|
286
|
+
'&:hover': {
|
|
287
287
|
backgroundColor: 'button.primary.background.hover',
|
|
288
288
|
color: 'button.primary.label.hover',
|
|
289
|
+
textDecoration: 'none',
|
|
289
290
|
},
|
|
290
291
|
verticalAlign: 'middle',
|
|
291
292
|
alignItems: 'center',
|
|
@@ -297,9 +298,6 @@ export default {
|
|
|
297
298
|
fill: 'inherit',
|
|
298
299
|
},
|
|
299
300
|
},
|
|
300
|
-
'&:hover': {
|
|
301
|
-
textDecoration: 'none',
|
|
302
|
-
},
|
|
303
301
|
},
|
|
304
302
|
|
|
305
303
|
secondary: {
|
|
@@ -307,7 +305,7 @@ export default {
|
|
|
307
305
|
color: 'button.secondary.label.default',
|
|
308
306
|
bg: 'button.secondary.background.default',
|
|
309
307
|
|
|
310
|
-
'&:hover
|
|
308
|
+
'&:hover': {
|
|
311
309
|
backgroundColor: 'button.secondary.background.hover',
|
|
312
310
|
color: 'button.secondary.label.hover',
|
|
313
311
|
},
|
|
@@ -320,7 +318,7 @@ export default {
|
|
|
320
318
|
border: '1px solid',
|
|
321
319
|
borderColor: 'button.tertiary.border.default',
|
|
322
320
|
|
|
323
|
-
'&:hover
|
|
321
|
+
'&:hover': {
|
|
324
322
|
backgroundColor: 'button.tertiary.background.hover',
|
|
325
323
|
color: 'button.tertiary.label.hover',
|
|
326
324
|
border: '1px solid',
|
|
@@ -335,7 +333,7 @@ export default {
|
|
|
335
333
|
border: '1px solid',
|
|
336
334
|
borderColor: 'transparent',
|
|
337
335
|
|
|
338
|
-
'&:hover
|
|
336
|
+
'&:hover': {
|
|
339
337
|
backgroundColor: 'button.display.background.hover',
|
|
340
338
|
color: 'button.display.label.hover',
|
|
341
339
|
border: '1px solid',
|
|
@@ -350,7 +348,7 @@ export default {
|
|
|
350
348
|
border: '1px solid',
|
|
351
349
|
borderColor: 'transparent',
|
|
352
350
|
|
|
353
|
-
'&:hover
|
|
351
|
+
'&:hover': {
|
|
354
352
|
backgroundColor: 'button.ghost.background.hover',
|
|
355
353
|
color: 'button.ghost.label.hover',
|
|
356
354
|
border: '1px solid',
|
|
@@ -365,7 +363,7 @@ export default {
|
|
|
365
363
|
border: '1px solid',
|
|
366
364
|
borderColor: 'transparent',
|
|
367
365
|
|
|
368
|
-
'&:hover
|
|
366
|
+
'&:hover': {
|
|
369
367
|
backgroundColor: 'button.danger.primary.background.hover',
|
|
370
368
|
color: 'button.danger.primary.label.hover',
|
|
371
369
|
border: '1px solid',
|
|
@@ -396,7 +394,7 @@ export default {
|
|
|
396
394
|
color: 'text',
|
|
397
395
|
padding: 1,
|
|
398
396
|
|
|
399
|
-
'&:hover
|
|
397
|
+
'&:hover': {
|
|
400
398
|
backgroundColor: 'borders.2',
|
|
401
399
|
},
|
|
402
400
|
},
|
|
@@ -409,7 +407,9 @@ export default {
|
|
|
409
407
|
color: 'links.visited',
|
|
410
408
|
},
|
|
411
409
|
'&:hover': {
|
|
412
|
-
color: 'hover',
|
|
410
|
+
color: 'links.hover',
|
|
411
|
+
textDecorationLine: 'underline',
|
|
412
|
+
textDecorationThickness: '0.125rem',
|
|
413
413
|
},
|
|
414
414
|
'&:active': {
|
|
415
415
|
color: 'links.active',
|
|
@@ -417,12 +417,6 @@ export default {
|
|
|
417
417
|
|
|
418
418
|
textDecorationThickness: '0.125rem',
|
|
419
419
|
textUnderlineOffset: '0.250rem',
|
|
420
|
-
|
|
421
|
-
'&:hover, &:focus': {
|
|
422
|
-
color: 'links.hover',
|
|
423
|
-
textDecorationLine: 'underline',
|
|
424
|
-
textDecorationThickness: '0.125rem',
|
|
425
|
-
},
|
|
426
420
|
},
|
|
427
421
|
'button-primary': {
|
|
428
422
|
variant: 'buttons.primary',
|
|
@@ -532,7 +526,8 @@ export default {
|
|
|
532
526
|
fontWeight: 'body',
|
|
533
527
|
color: 'text',
|
|
534
528
|
backgroundColor: 'backgrounds.primary',
|
|
535
|
-
|
|
529
|
+
'-webkit-font-smoothing': 'antialiased',
|
|
530
|
+
'-moz-osx-font-smoothing': 'grayscale',
|
|
536
531
|
a: {
|
|
537
532
|
'&:hover': {
|
|
538
533
|
textDecorationLine: 'underline',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automattic/vip-design-system",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.4",
|
|
4
4
|
"main": "build/system/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build-storybook": "storybook build",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"accessible-autocomplete": "^2.0.4",
|
|
44
44
|
"classnames": "^2.3.1",
|
|
45
45
|
"framer-motion": "^3.9.1",
|
|
46
|
+
"i18n-calypso": "^7.0.0",
|
|
46
47
|
"react-icons": "^4.7.0"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
@@ -54,6 +54,9 @@ const Button = forwardRef< HTMLButtonElement, ButtonProps >(
|
|
|
54
54
|
cursor: 'not-allowed',
|
|
55
55
|
pointerEvents: 'none',
|
|
56
56
|
},
|
|
57
|
+
'&:hover, &:focus': {
|
|
58
|
+
textDecoration: 'none',
|
|
59
|
+
},
|
|
57
60
|
flexGrow: Boolean( grow ) === true ? '1' : undefined,
|
|
58
61
|
width: Boolean( full ) === true ? '100%' : undefined,
|
|
59
62
|
...sx,
|
|
@@ -25,6 +25,7 @@ export const styles = {
|
|
|
25
25
|
py: 1,
|
|
26
26
|
'&:hover, &:focus': {
|
|
27
27
|
backgroundColor: 'hover',
|
|
28
|
+
textDecoration: 'none',
|
|
28
29
|
},
|
|
29
30
|
|
|
30
31
|
'&[data-disabled]': {
|
|
@@ -34,7 +35,7 @@ export const styles = {
|
|
|
34
35
|
|
|
35
36
|
'&[data-highlighted]': {
|
|
36
37
|
backgroundColor: 'hover',
|
|
37
|
-
color: '
|
|
38
|
+
color: 'link',
|
|
38
39
|
},
|
|
39
40
|
};
|
|
40
41
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import LinkExternal from './LinkExternal';
|
|
2
|
+
|
|
3
|
+
import type { StoryObj } from '@storybook/react';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Navigation/LinkExternal',
|
|
7
|
+
component: LinkExternal,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type Story = StoryObj< typeof LinkExternal >;
|
|
11
|
+
|
|
12
|
+
export const Default: Story = {
|
|
13
|
+
args: {
|
|
14
|
+
children: 'View on GitHub',
|
|
15
|
+
href: 'https://github.com/Automattic/vip-design-system',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Internal dependencies
|
|
6
|
+
*/
|
|
7
|
+
import LinkExternal from './LinkExternal';
|
|
8
|
+
|
|
9
|
+
const props = {
|
|
10
|
+
children: 'View on Github',
|
|
11
|
+
href: 'https://github.com/Automattic/vip-design-system',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe( '<LinkExternal />', () => {
|
|
15
|
+
it( 'should render correctly', () => {
|
|
16
|
+
render( <LinkExternal { ...props }>View on Github</LinkExternal> );
|
|
17
|
+
|
|
18
|
+
const link = screen.getByRole( 'link' );
|
|
19
|
+
|
|
20
|
+
expect( link ).toHaveTextContent( /view on github/i );
|
|
21
|
+
expect( link ).toHaveTextContent( /external link/i );
|
|
22
|
+
expect( link ).toHaveAttribute( 'target', '_self' );
|
|
23
|
+
expect( link ).toHaveAttribute( 'rel', '' );
|
|
24
|
+
} );
|
|
25
|
+
|
|
26
|
+
it( 'should open in new tab when newTab is true', () => {
|
|
27
|
+
render( <LinkExternal { ...props } newTab /> );
|
|
28
|
+
|
|
29
|
+
const link = screen.getByRole( 'link' );
|
|
30
|
+
|
|
31
|
+
expect( link ).toHaveTextContent( /opens in a new tab/i );
|
|
32
|
+
expect( link ).toHaveAttribute( 'target', '_blank' );
|
|
33
|
+
expect( link ).toHaveAttribute( 'rel', 'noopener noreferrer' );
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
it( 'should contain additional screenreader text when added', () => {
|
|
37
|
+
render( <LinkExternal { ...props } screenReaderText="VIP Design System" /> );
|
|
38
|
+
|
|
39
|
+
expect( screen.getByRole( 'link', { name: /vip design system/i } ) ).toBeInTheDocument();
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
it( 'should hide icon when showExternalIcon is false', () => {
|
|
43
|
+
render( <LinkExternal { ...props } showExternalIcon={ false } /> );
|
|
44
|
+
|
|
45
|
+
expect( screen.queryByText( '↗' ) ).not.toBeInTheDocument();
|
|
46
|
+
} );
|
|
47
|
+
} );
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { translate } from 'i18n-calypso';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { Link } from '../Link';
|
|
10
|
+
import ScreenReaderText from '../ScreenReaderText';
|
|
11
|
+
|
|
12
|
+
// Screen reader announcements
|
|
13
|
+
const DEFAULT_EXTERNAL_LINK_TEXT = translate( ', external link' ); // reads as: link, <link text>, external link
|
|
14
|
+
const NEW_TAB_TEXT = translate( ', opens in a new tab' ); // reads as: link, <link text>, external link, opens in a new tab
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
screenReaderText?: string | number;
|
|
19
|
+
href: string;
|
|
20
|
+
showExternalIcon?: boolean;
|
|
21
|
+
defaultScreenReaderText?: boolean;
|
|
22
|
+
newTab?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const LinkExternal: React.FC< Props > = ( {
|
|
26
|
+
children = null,
|
|
27
|
+
screenReaderText = '',
|
|
28
|
+
href,
|
|
29
|
+
showExternalIcon = true,
|
|
30
|
+
newTab = false,
|
|
31
|
+
...rest
|
|
32
|
+
} ) => (
|
|
33
|
+
<Link
|
|
34
|
+
as="a"
|
|
35
|
+
target={ newTab ? '_blank' : '_self' }
|
|
36
|
+
rel={ newTab ? 'noopener noreferrer' : '' }
|
|
37
|
+
href={ href }
|
|
38
|
+
{ ...rest }
|
|
39
|
+
>
|
|
40
|
+
{ children }
|
|
41
|
+
<ScreenReaderText>
|
|
42
|
+
{ screenReaderText }
|
|
43
|
+
{ DEFAULT_EXTERNAL_LINK_TEXT }
|
|
44
|
+
{ newTab ? NEW_TAB_TEXT : '' }
|
|
45
|
+
</ScreenReaderText>
|
|
46
|
+
{ showExternalIcon && <span aria-hidden="true"> ↗</span> }
|
|
47
|
+
</Link>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
export default LinkExternal;
|
|
@@ -44,14 +44,20 @@ export const MobileMenu = forwardRef< HTMLDivElement, MobileMenuProps >(
|
|
|
44
44
|
|
|
45
45
|
<div
|
|
46
46
|
sx={ {
|
|
47
|
-
|
|
48
|
-
overflowY: 'auto',
|
|
49
|
-
height: 'calc(100vh - 64px)',
|
|
47
|
+
height: '100vh',
|
|
50
48
|
display: 'flex',
|
|
51
49
|
flex: 1,
|
|
52
50
|
} }
|
|
53
51
|
>
|
|
54
|
-
<Flex
|
|
52
|
+
<Flex
|
|
53
|
+
sx={ {
|
|
54
|
+
width: '100%',
|
|
55
|
+
flexDirection: 'column',
|
|
56
|
+
height: 'calc(100vh - 64px)',
|
|
57
|
+
overflowX: 'hidden',
|
|
58
|
+
overflowY: 'auto',
|
|
59
|
+
} }
|
|
60
|
+
>
|
|
55
61
|
{ toolbarItems && (
|
|
56
62
|
<Nav.PrimaryInverse label="Main Links" orientation="vertical">
|
|
57
63
|
{ toolbarItems }
|
|
@@ -62,7 +68,7 @@ export const MobileMenu = forwardRef< HTMLDivElement, MobileMenuProps >(
|
|
|
62
68
|
sx={ {
|
|
63
69
|
alignSelf: 'stretch',
|
|
64
70
|
backgroundColor: 'layer.1',
|
|
65
|
-
|
|
71
|
+
height: '100%',
|
|
66
72
|
gap: 4,
|
|
67
73
|
width: '100%',
|
|
68
74
|
a: {
|
package/src/system/index.js
CHANGED
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
import { Grid } from './Grid';
|
|
37
37
|
import { Heading } from './Heading';
|
|
38
38
|
import { Link } from './Link';
|
|
39
|
+
import LinkExternal from './LinkExternal/LinkExternal';
|
|
39
40
|
import { MobileMenuWrapper, MobileMenuTrigger, MobileMenu } from './MobileMenu/MobileMenu';
|
|
40
41
|
import { Nav } from './Nav/Nav';
|
|
41
42
|
import { NavItem } from './Nav/NavItem';
|
|
@@ -95,6 +96,7 @@ export {
|
|
|
95
96
|
TableCell,
|
|
96
97
|
Tooltip,
|
|
97
98
|
Link,
|
|
99
|
+
LinkExternal,
|
|
98
100
|
Radio,
|
|
99
101
|
RadioBoxGroup,
|
|
100
102
|
Textarea,
|
|
@@ -283,9 +283,10 @@ export default {
|
|
|
283
283
|
fontWeight: 'medium',
|
|
284
284
|
boxShadow: 'none',
|
|
285
285
|
borderRadius: 1,
|
|
286
|
-
'&:hover
|
|
286
|
+
'&:hover': {
|
|
287
287
|
backgroundColor: 'button.primary.background.hover',
|
|
288
288
|
color: 'button.primary.label.hover',
|
|
289
|
+
textDecoration: 'none',
|
|
289
290
|
},
|
|
290
291
|
verticalAlign: 'middle',
|
|
291
292
|
alignItems: 'center',
|
|
@@ -297,9 +298,6 @@ export default {
|
|
|
297
298
|
fill: 'inherit',
|
|
298
299
|
},
|
|
299
300
|
},
|
|
300
|
-
'&:hover': {
|
|
301
|
-
textDecoration: 'none',
|
|
302
|
-
},
|
|
303
301
|
},
|
|
304
302
|
|
|
305
303
|
secondary: {
|
|
@@ -307,7 +305,7 @@ export default {
|
|
|
307
305
|
color: 'button.secondary.label.default',
|
|
308
306
|
bg: 'button.secondary.background.default',
|
|
309
307
|
|
|
310
|
-
'&:hover
|
|
308
|
+
'&:hover': {
|
|
311
309
|
backgroundColor: 'button.secondary.background.hover',
|
|
312
310
|
color: 'button.secondary.label.hover',
|
|
313
311
|
},
|
|
@@ -320,7 +318,7 @@ export default {
|
|
|
320
318
|
border: '1px solid',
|
|
321
319
|
borderColor: 'button.tertiary.border.default',
|
|
322
320
|
|
|
323
|
-
'&:hover
|
|
321
|
+
'&:hover': {
|
|
324
322
|
backgroundColor: 'button.tertiary.background.hover',
|
|
325
323
|
color: 'button.tertiary.label.hover',
|
|
326
324
|
border: '1px solid',
|
|
@@ -335,7 +333,7 @@ export default {
|
|
|
335
333
|
border: '1px solid',
|
|
336
334
|
borderColor: 'transparent',
|
|
337
335
|
|
|
338
|
-
'&:hover
|
|
336
|
+
'&:hover': {
|
|
339
337
|
backgroundColor: 'button.display.background.hover',
|
|
340
338
|
color: 'button.display.label.hover',
|
|
341
339
|
border: '1px solid',
|
|
@@ -350,7 +348,7 @@ export default {
|
|
|
350
348
|
border: '1px solid',
|
|
351
349
|
borderColor: 'transparent',
|
|
352
350
|
|
|
353
|
-
'&:hover
|
|
351
|
+
'&:hover': {
|
|
354
352
|
backgroundColor: 'button.ghost.background.hover',
|
|
355
353
|
color: 'button.ghost.label.hover',
|
|
356
354
|
border: '1px solid',
|
|
@@ -365,7 +363,7 @@ export default {
|
|
|
365
363
|
border: '1px solid',
|
|
366
364
|
borderColor: 'transparent',
|
|
367
365
|
|
|
368
|
-
'&:hover
|
|
366
|
+
'&:hover': {
|
|
369
367
|
backgroundColor: 'button.danger.primary.background.hover',
|
|
370
368
|
color: 'button.danger.primary.label.hover',
|
|
371
369
|
border: '1px solid',
|
|
@@ -396,7 +394,7 @@ export default {
|
|
|
396
394
|
color: 'text',
|
|
397
395
|
padding: 1,
|
|
398
396
|
|
|
399
|
-
'&:hover
|
|
397
|
+
'&:hover': {
|
|
400
398
|
backgroundColor: 'borders.2',
|
|
401
399
|
},
|
|
402
400
|
},
|
|
@@ -409,7 +407,9 @@ export default {
|
|
|
409
407
|
color: 'links.visited',
|
|
410
408
|
},
|
|
411
409
|
'&:hover': {
|
|
412
|
-
color: 'hover',
|
|
410
|
+
color: 'links.hover',
|
|
411
|
+
textDecorationLine: 'underline',
|
|
412
|
+
textDecorationThickness: '0.125rem',
|
|
413
413
|
},
|
|
414
414
|
'&:active': {
|
|
415
415
|
color: 'links.active',
|
|
@@ -417,12 +417,6 @@ export default {
|
|
|
417
417
|
|
|
418
418
|
textDecorationThickness: '0.125rem',
|
|
419
419
|
textUnderlineOffset: '0.250rem',
|
|
420
|
-
|
|
421
|
-
'&:hover, &:focus': {
|
|
422
|
-
color: 'links.hover',
|
|
423
|
-
textDecorationLine: 'underline',
|
|
424
|
-
textDecorationThickness: '0.125rem',
|
|
425
|
-
},
|
|
426
420
|
},
|
|
427
421
|
'button-primary': {
|
|
428
422
|
variant: 'buttons.primary',
|
|
@@ -532,7 +526,8 @@ export default {
|
|
|
532
526
|
fontWeight: 'body',
|
|
533
527
|
color: 'text',
|
|
534
528
|
backgroundColor: 'backgrounds.primary',
|
|
535
|
-
|
|
529
|
+
'-webkit-font-smoothing': 'antialiased',
|
|
530
|
+
'-moz-osx-font-smoothing': 'grayscale',
|
|
536
531
|
a: {
|
|
537
532
|
'&:hover': {
|
|
538
533
|
textDecorationLine: 'underline',
|