@khanacademy/wonder-blocks-link 4.1.0 → 4.2.1
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/CHANGELOG.md +16 -0
- package/dist/components/link.d.ts +11 -0
- package/dist/components/link.js.flow +13 -0
- package/dist/es/index.js +40 -14
- package/dist/index.js +40 -14
- package/package.json +3 -3
- package/src/__tests__/__snapshots__/custom-snapshot.test.tsx.snap +910 -176
- package/src/components/__tests__/link.test.tsx +90 -62
- package/src/components/link-core.tsx +54 -12
- package/src/components/link.tsx +11 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-link
|
|
2
2
|
|
|
3
|
+
## 4.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6a026e35: Fix link style
|
|
8
|
+
|
|
9
|
+
## 4.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- ef08a547: Adds start and end icon props to link
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 3686db61: Stop showing a focus outline on the first link when revisiting a tab
|
|
18
|
+
|
|
3
19
|
## 4.1.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
3
|
import type { Typography } from "@khanacademy/wonder-blocks-typography";
|
|
4
|
+
import type { IconAsset } from "@khanacademy/wonder-blocks-icon";
|
|
4
5
|
export type SharedProps = AriaProps & {
|
|
5
6
|
/**
|
|
6
7
|
* Text to appear on the link. It can be a plain text or a Typography element.
|
|
@@ -119,6 +120,16 @@ export type SharedProps = AriaProps & {
|
|
|
119
120
|
* An optional title attribute.
|
|
120
121
|
*/
|
|
121
122
|
title?: string;
|
|
123
|
+
/**
|
|
124
|
+
* An optional icon displayed before the link label.
|
|
125
|
+
*/
|
|
126
|
+
startIcon?: IconAsset;
|
|
127
|
+
/**
|
|
128
|
+
* An optional icon displayed after the link label.
|
|
129
|
+
* If `target="_blank"` and `endIcon` is passed in, `endIcon` will override
|
|
130
|
+
* the default `externalIcon`.
|
|
131
|
+
*/
|
|
132
|
+
endIcon?: IconAsset;
|
|
122
133
|
};
|
|
123
134
|
type DefaultProps = {
|
|
124
135
|
inline: SharedProps["inline"];
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import type { AriaProps, StyleType } from "@khanacademy/wonder-blocks-core";
|
|
9
9
|
import type { Typography } from "@khanacademy/wonder-blocks-typography";
|
|
10
|
+
import type { IconAsset } from "@khanacademy/wonder-blocks-icon";
|
|
10
11
|
export type SharedProps = {|
|
|
11
12
|
...AriaProps,
|
|
12
13
|
...{|
|
|
@@ -146,6 +147,18 @@ export type SharedProps = {|
|
|
|
146
147
|
* An optional title attribute.
|
|
147
148
|
*/
|
|
148
149
|
title?: string,
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* An optional icon displayed before the link label.
|
|
153
|
+
*/
|
|
154
|
+
startIcon?: IconAsset,
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* An optional icon displayed after the link label.
|
|
158
|
+
* If `target="_blank"` and `endIcon` is passed in, `endIcon` will override
|
|
159
|
+
* the default `externalIcon`.
|
|
160
|
+
*/
|
|
161
|
+
endIcon?: IconAsset,
|
|
149
162
|
|},
|
|
150
163
|
|};
|
|
151
164
|
declare type DefaultProps = {|
|
package/dist/es/index.js
CHANGED
|
@@ -40,9 +40,10 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
40
40
|
return target;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target"];
|
|
43
|
+
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"];
|
|
44
44
|
const StyledAnchor = addStyle("a");
|
|
45
45
|
const StyledLink = addStyle(Link$1);
|
|
46
|
+
const StyledSpan = addStyle("span");
|
|
46
47
|
class LinkCore extends React.Component {
|
|
47
48
|
renderInner(router) {
|
|
48
49
|
const _this$props = this.props,
|
|
@@ -59,12 +60,14 @@ class LinkCore extends React.Component {
|
|
|
59
60
|
pressed,
|
|
60
61
|
style,
|
|
61
62
|
testId,
|
|
62
|
-
target
|
|
63
|
+
target,
|
|
64
|
+
startIcon,
|
|
65
|
+
endIcon
|
|
63
66
|
} = _this$props,
|
|
64
67
|
restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
|
|
65
68
|
const linkStyles = _generateStyles(inline, kind, light, visitable);
|
|
66
69
|
const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting;
|
|
67
|
-
const defaultStyles = [sharedStyles.shared,
|
|
70
|
+
const defaultStyles = [sharedStyles.shared, restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus];
|
|
68
71
|
const commonProps = _extends({
|
|
69
72
|
"data-test-id": testId,
|
|
70
73
|
style: [defaultStyles, style],
|
|
@@ -76,10 +79,24 @@ class LinkCore extends React.Component {
|
|
|
76
79
|
const externalIcon = React.createElement(Icon, {
|
|
77
80
|
icon: externalIconPath,
|
|
78
81
|
size: "small",
|
|
79
|
-
style:
|
|
82
|
+
style: [linkContentStyles.endIcon, linkContentStyles.centered],
|
|
80
83
|
testId: "external-icon"
|
|
81
84
|
});
|
|
82
|
-
const linkContent = React.createElement(React.Fragment, null,
|
|
85
|
+
const linkContent = React.createElement(React.Fragment, null, startIcon && React.createElement(Icon, {
|
|
86
|
+
icon: startIcon,
|
|
87
|
+
size: "small",
|
|
88
|
+
style: [linkContentStyles.startIcon, linkContentStyles.centered],
|
|
89
|
+
testId: "start-icon",
|
|
90
|
+
"aria-hidden": "true"
|
|
91
|
+
}), React.createElement(StyledSpan, {
|
|
92
|
+
style: linkContentStyles.centered
|
|
93
|
+
}, children), endIcon ? React.createElement(Icon, {
|
|
94
|
+
icon: endIcon,
|
|
95
|
+
size: "small",
|
|
96
|
+
style: [linkContentStyles.endIcon, linkContentStyles.centered],
|
|
97
|
+
testId: "end-icon",
|
|
98
|
+
"aria-hidden": "true"
|
|
99
|
+
}) : target === "_blank" && externalIcon);
|
|
83
100
|
return router && !skipClientNav && isClientSideUrl(href) ? React.createElement(StyledLink, _extends({}, commonProps, {
|
|
84
101
|
to: href
|
|
85
102
|
}), linkContent) : React.createElement(StyledAnchor, _extends({}, commonProps, {
|
|
@@ -91,9 +108,15 @@ class LinkCore extends React.Component {
|
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
const styles = {};
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
111
|
+
const linkContentStyles = StyleSheet.create({
|
|
112
|
+
startIcon: {
|
|
113
|
+
marginInlineEnd: Spacing.xxxSmall_4
|
|
114
|
+
},
|
|
115
|
+
endIcon: {
|
|
116
|
+
marginInlineStart: Spacing.xxxSmall_4
|
|
117
|
+
},
|
|
118
|
+
centered: {
|
|
119
|
+
verticalAlign: "middle"
|
|
97
120
|
}
|
|
98
121
|
});
|
|
99
122
|
const sharedStyles = StyleSheet.create({
|
|
@@ -101,7 +124,8 @@ const sharedStyles = StyleSheet.create({
|
|
|
101
124
|
cursor: "pointer",
|
|
102
125
|
textDecoration: "none",
|
|
103
126
|
outline: "none",
|
|
104
|
-
|
|
127
|
+
verticalAlign: "bottom",
|
|
128
|
+
textUnderlineOffset: "3px",
|
|
105
129
|
alignItems: "center"
|
|
106
130
|
}
|
|
107
131
|
});
|
|
@@ -157,11 +181,13 @@ const _generateStyles = (inline, kind, light, visitable) => {
|
|
|
157
181
|
textDecoration: "underline currentcolor solid",
|
|
158
182
|
color: defaultTextColor
|
|
159
183
|
}, defaultVisited),
|
|
160
|
-
focus:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
184
|
+
focus: {
|
|
185
|
+
":focus-visible": _extends({
|
|
186
|
+
color: defaultTextColor,
|
|
187
|
+
outline: `1px solid ${light ? white : blue}`,
|
|
188
|
+
borderRadius: 3
|
|
189
|
+
}, defaultVisited)
|
|
190
|
+
},
|
|
165
191
|
active: _extends({
|
|
166
192
|
color: activeColor,
|
|
167
193
|
textDecoration: "underline currentcolor solid"
|
package/dist/index.js
CHANGED
|
@@ -67,9 +67,10 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
67
67
|
return target;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target"];
|
|
70
|
+
const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"];
|
|
71
71
|
const StyledAnchor = wonderBlocksCore.addStyle("a");
|
|
72
72
|
const StyledLink = wonderBlocksCore.addStyle(reactRouterDom.Link);
|
|
73
|
+
const StyledSpan = wonderBlocksCore.addStyle("span");
|
|
73
74
|
class LinkCore extends React__namespace.Component {
|
|
74
75
|
renderInner(router) {
|
|
75
76
|
const _this$props = this.props,
|
|
@@ -86,12 +87,14 @@ class LinkCore extends React__namespace.Component {
|
|
|
86
87
|
pressed,
|
|
87
88
|
style,
|
|
88
89
|
testId,
|
|
89
|
-
target
|
|
90
|
+
target,
|
|
91
|
+
startIcon,
|
|
92
|
+
endIcon
|
|
90
93
|
} = _this$props,
|
|
91
94
|
restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
|
|
92
95
|
const linkStyles = _generateStyles(inline, kind, light, visitable);
|
|
93
96
|
const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting;
|
|
94
|
-
const defaultStyles = [sharedStyles.shared,
|
|
97
|
+
const defaultStyles = [sharedStyles.shared, restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus];
|
|
95
98
|
const commonProps = _extends({
|
|
96
99
|
"data-test-id": testId,
|
|
97
100
|
style: [defaultStyles, style],
|
|
@@ -103,10 +106,24 @@ class LinkCore extends React__namespace.Component {
|
|
|
103
106
|
const externalIcon = React__namespace.createElement(Icon__default["default"], {
|
|
104
107
|
icon: externalIconPath,
|
|
105
108
|
size: "small",
|
|
106
|
-
style:
|
|
109
|
+
style: [linkContentStyles.endIcon, linkContentStyles.centered],
|
|
107
110
|
testId: "external-icon"
|
|
108
111
|
});
|
|
109
|
-
const linkContent = React__namespace.createElement(React__namespace.Fragment, null,
|
|
112
|
+
const linkContent = React__namespace.createElement(React__namespace.Fragment, null, startIcon && React__namespace.createElement(Icon__default["default"], {
|
|
113
|
+
icon: startIcon,
|
|
114
|
+
size: "small",
|
|
115
|
+
style: [linkContentStyles.startIcon, linkContentStyles.centered],
|
|
116
|
+
testId: "start-icon",
|
|
117
|
+
"aria-hidden": "true"
|
|
118
|
+
}), React__namespace.createElement(StyledSpan, {
|
|
119
|
+
style: linkContentStyles.centered
|
|
120
|
+
}, children), endIcon ? React__namespace.createElement(Icon__default["default"], {
|
|
121
|
+
icon: endIcon,
|
|
122
|
+
size: "small",
|
|
123
|
+
style: [linkContentStyles.endIcon, linkContentStyles.centered],
|
|
124
|
+
testId: "end-icon",
|
|
125
|
+
"aria-hidden": "true"
|
|
126
|
+
}) : target === "_blank" && externalIcon);
|
|
110
127
|
return router && !skipClientNav && wonderBlocksClickable.isClientSideUrl(href) ? React__namespace.createElement(StyledLink, _extends({}, commonProps, {
|
|
111
128
|
to: href
|
|
112
129
|
}), linkContent) : React__namespace.createElement(StyledAnchor, _extends({}, commonProps, {
|
|
@@ -118,9 +135,15 @@ class LinkCore extends React__namespace.Component {
|
|
|
118
135
|
}
|
|
119
136
|
}
|
|
120
137
|
const styles = {};
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
138
|
+
const linkContentStyles = aphrodite.StyleSheet.create({
|
|
139
|
+
startIcon: {
|
|
140
|
+
marginInlineEnd: Spacing__default["default"].xxxSmall_4
|
|
141
|
+
},
|
|
142
|
+
endIcon: {
|
|
143
|
+
marginInlineStart: Spacing__default["default"].xxxSmall_4
|
|
144
|
+
},
|
|
145
|
+
centered: {
|
|
146
|
+
verticalAlign: "middle"
|
|
124
147
|
}
|
|
125
148
|
});
|
|
126
149
|
const sharedStyles = aphrodite.StyleSheet.create({
|
|
@@ -128,7 +151,8 @@ const sharedStyles = aphrodite.StyleSheet.create({
|
|
|
128
151
|
cursor: "pointer",
|
|
129
152
|
textDecoration: "none",
|
|
130
153
|
outline: "none",
|
|
131
|
-
|
|
154
|
+
verticalAlign: "bottom",
|
|
155
|
+
textUnderlineOffset: "3px",
|
|
132
156
|
alignItems: "center"
|
|
133
157
|
}
|
|
134
158
|
});
|
|
@@ -184,11 +208,13 @@ const _generateStyles = (inline, kind, light, visitable) => {
|
|
|
184
208
|
textDecoration: "underline currentcolor solid",
|
|
185
209
|
color: defaultTextColor
|
|
186
210
|
}, defaultVisited),
|
|
187
|
-
focus:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
211
|
+
focus: {
|
|
212
|
+
":focus-visible": _extends({
|
|
213
|
+
color: defaultTextColor,
|
|
214
|
+
outline: `1px solid ${light ? white : blue}`,
|
|
215
|
+
borderRadius: 3
|
|
216
|
+
}, defaultVisited)
|
|
217
|
+
},
|
|
192
218
|
active: _extends({
|
|
193
219
|
color: activeColor,
|
|
194
220
|
textDecoration: "underline currentcolor solid"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-link",
|
|
3
|
-
"version": "4.1
|
|
3
|
+
"version": "4.2.1",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"@khanacademy/wonder-blocks-clickable": "^3.0.9",
|
|
20
20
|
"@khanacademy/wonder-blocks-color": "^2.0.1",
|
|
21
21
|
"@khanacademy/wonder-blocks-core": "^5.1.0",
|
|
22
|
-
"@khanacademy/wonder-blocks-icon": "2.0.9",
|
|
23
|
-
"@khanacademy/wonder-blocks-spacing": "4.0.1"
|
|
22
|
+
"@khanacademy/wonder-blocks-icon": "^2.0.9",
|
|
23
|
+
"@khanacademy/wonder-blocks-spacing": "^4.0.1"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"aphrodite": "^1.2.5",
|