@khanacademy/wonder-blocks-link 4.1.0 → 4.2.0

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @khanacademy/wonder-blocks-link
2
2
 
3
+ ## 4.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ef08a547: Adds start and end icon props to link
8
+
9
+ ### Patch Changes
10
+
11
+ - 3686db61: Stop showing a focus outline on the first link when revisiting a tab
12
+
3
13
  ## 4.1.0
4
14
 
5
15
  ### 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,7 +40,7 @@ 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
46
  class LinkCore extends React.Component {
@@ -59,12 +59,14 @@ class LinkCore extends React.Component {
59
59
  pressed,
60
60
  style,
61
61
  testId,
62
- target
62
+ target,
63
+ startIcon,
64
+ endIcon
63
65
  } = _this$props,
64
66
  restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
65
67
  const linkStyles = _generateStyles(inline, kind, light, visitable);
66
68
  const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting;
67
- const defaultStyles = [sharedStyles.shared, !(hovered || focused || pressed) && restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus];
69
+ const defaultStyles = [sharedStyles.shared, restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus];
68
70
  const commonProps = _extends({
69
71
  "data-test-id": testId,
70
72
  style: [defaultStyles, style],
@@ -76,10 +78,26 @@ class LinkCore extends React.Component {
76
78
  const externalIcon = React.createElement(Icon, {
77
79
  icon: externalIconPath,
78
80
  size: "small",
79
- style: iconStyles.icon,
81
+ style: iconStyles.endIcon,
80
82
  testId: "external-icon"
81
83
  });
82
- const linkContent = React.createElement(React.Fragment, null, children, target === "_blank" && externalIcon);
84
+ const linkContent = React.createElement(React.Fragment, null, startIcon && React.createElement(Icon, {
85
+ icon: startIcon,
86
+ size: "small",
87
+ style: iconStyles.startIcon,
88
+ testId: "start-icon",
89
+ "aria-hidden": "true"
90
+ }), React.createElement("span", {
91
+ style: {
92
+ verticalAlign: "middle"
93
+ }
94
+ }, children), endIcon ? React.createElement(Icon, {
95
+ icon: endIcon,
96
+ size: "small",
97
+ style: iconStyles.endIcon,
98
+ testId: "end-icon",
99
+ "aria-hidden": "true"
100
+ }) : target === "_blank" && externalIcon);
83
101
  return router && !skipClientNav && isClientSideUrl(href) ? React.createElement(StyledLink, _extends({}, commonProps, {
84
102
  to: href
85
103
  }), linkContent) : React.createElement(StyledAnchor, _extends({}, commonProps, {
@@ -92,8 +110,13 @@ class LinkCore extends React.Component {
92
110
  }
93
111
  const styles = {};
94
112
  const iconStyles = StyleSheet.create({
95
- icon: {
96
- marginLeft: Spacing.xxxSmall_4
113
+ startIcon: {
114
+ marginInlineEnd: Spacing.xxxSmall_4,
115
+ verticalAlign: "middle"
116
+ },
117
+ endIcon: {
118
+ marginInlineStart: Spacing.xxxSmall_4,
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
- display: "inline-flex",
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: _extends({
161
- color: defaultTextColor,
162
- outline: `1px solid ${light ? white : blue}`,
163
- borderRadius: 3
164
- }, defaultVisited),
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,7 +67,7 @@ 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
73
  class LinkCore extends React__namespace.Component {
@@ -86,12 +86,14 @@ class LinkCore extends React__namespace.Component {
86
86
  pressed,
87
87
  style,
88
88
  testId,
89
- target
89
+ target,
90
+ startIcon,
91
+ endIcon
90
92
  } = _this$props,
91
93
  restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
92
94
  const linkStyles = _generateStyles(inline, kind, light, visitable);
93
95
  const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting;
94
- const defaultStyles = [sharedStyles.shared, !(hovered || focused || pressed) && restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus];
96
+ const defaultStyles = [sharedStyles.shared, restingStyles, pressed && linkStyles.active, !pressed && hovered && linkStyles.hover, !pressed && focused && linkStyles.focus];
95
97
  const commonProps = _extends({
96
98
  "data-test-id": testId,
97
99
  style: [defaultStyles, style],
@@ -103,10 +105,26 @@ class LinkCore extends React__namespace.Component {
103
105
  const externalIcon = React__namespace.createElement(Icon__default["default"], {
104
106
  icon: externalIconPath,
105
107
  size: "small",
106
- style: iconStyles.icon,
108
+ style: iconStyles.endIcon,
107
109
  testId: "external-icon"
108
110
  });
109
- const linkContent = React__namespace.createElement(React__namespace.Fragment, null, children, target === "_blank" && externalIcon);
111
+ const linkContent = React__namespace.createElement(React__namespace.Fragment, null, startIcon && React__namespace.createElement(Icon__default["default"], {
112
+ icon: startIcon,
113
+ size: "small",
114
+ style: iconStyles.startIcon,
115
+ testId: "start-icon",
116
+ "aria-hidden": "true"
117
+ }), React__namespace.createElement("span", {
118
+ style: {
119
+ verticalAlign: "middle"
120
+ }
121
+ }, children), endIcon ? React__namespace.createElement(Icon__default["default"], {
122
+ icon: endIcon,
123
+ size: "small",
124
+ style: iconStyles.endIcon,
125
+ testId: "end-icon",
126
+ "aria-hidden": "true"
127
+ }) : target === "_blank" && externalIcon);
110
128
  return router && !skipClientNav && wonderBlocksClickable.isClientSideUrl(href) ? React__namespace.createElement(StyledLink, _extends({}, commonProps, {
111
129
  to: href
112
130
  }), linkContent) : React__namespace.createElement(StyledAnchor, _extends({}, commonProps, {
@@ -119,8 +137,13 @@ class LinkCore extends React__namespace.Component {
119
137
  }
120
138
  const styles = {};
121
139
  const iconStyles = aphrodite.StyleSheet.create({
122
- icon: {
123
- marginLeft: Spacing__default["default"].xxxSmall_4
140
+ startIcon: {
141
+ marginInlineEnd: Spacing__default["default"].xxxSmall_4,
142
+ verticalAlign: "middle"
143
+ },
144
+ endIcon: {
145
+ marginInlineStart: Spacing__default["default"].xxxSmall_4,
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
- display: "inline-flex",
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: _extends({
188
- color: defaultTextColor,
189
- outline: `1px solid ${light ? white : blue}`,
190
- borderRadius: 3
191
- }, defaultVisited),
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.0",
3
+ "version": "4.2.0",
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",