@khanacademy/wonder-blocks-link 4.0.8 → 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,30 @@
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
+
13
+ ## 4.1.0
14
+
15
+ ### Minor Changes
16
+
17
+ - ba1a0362: add title prop to link
18
+ - b1ea80f0: Adds external icon to link when `target='_blank'`
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [3c400719]
23
+ - Updated dependencies [a6164ed0]
24
+ - @khanacademy/wonder-blocks-core@5.1.0
25
+ - @khanacademy/wonder-blocks-clickable@3.0.9
26
+ - @khanacademy/wonder-blocks-icon@2.0.9
27
+
3
28
  ## 4.0.8
4
29
 
5
30
  ### Patch 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.
@@ -115,6 +116,20 @@ export type SharedProps = AriaProps & {
115
116
  * navigation.
116
117
  */
117
118
  beforeNav?: () => Promise<unknown>;
119
+ /**
120
+ * An optional title attribute.
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;
118
133
  };
119
134
  type DefaultProps = {
120
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
  ...{|
@@ -141,6 +142,23 @@ export type SharedProps = {|
141
142
  * navigation.
142
143
  */
143
144
  beforeNav?: () => Promise<mixed>,
145
+
146
+ /**
147
+ * An optional title attribute.
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,
144
162
  |},
145
163
  |};
146
164
  declare type DefaultProps = {|
package/dist/es/index.js CHANGED
@@ -5,6 +5,8 @@ import { StyleSheet } from 'aphrodite';
5
5
  import { Link as Link$1 } from 'react-router-dom';
6
6
  import { addStyle } from '@khanacademy/wonder-blocks-core';
7
7
  import Color, { mix, fade } from '@khanacademy/wonder-blocks-color';
8
+ import Icon from '@khanacademy/wonder-blocks-icon';
9
+ import Spacing from '@khanacademy/wonder-blocks-spacing';
8
10
 
9
11
  function _objectDestructuringEmpty(obj) {
10
12
  if (obj == null) throw new TypeError("Cannot destructure " + obj);
@@ -38,7 +40,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
38
40
  return target;
39
41
  }
40
42
 
41
- const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting"];
43
+ const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"];
42
44
  const StyledAnchor = addStyle("a");
43
45
  const StyledLink = addStyle(Link$1);
44
46
  class LinkCore extends React.Component {
@@ -56,33 +58,75 @@ class LinkCore extends React.Component {
56
58
  visitable,
57
59
  pressed,
58
60
  style,
59
- testId
61
+ testId,
62
+ target,
63
+ startIcon,
64
+ endIcon
60
65
  } = _this$props,
61
66
  restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
62
67
  const linkStyles = _generateStyles(inline, kind, light, visitable);
63
68
  const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting;
64
- 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];
65
70
  const commonProps = _extends({
66
71
  "data-test-id": testId,
67
- style: [defaultStyles, style]
72
+ style: [defaultStyles, style],
73
+ target
68
74
  }, restProps);
75
+ const externalIconPath = {
76
+ small: "M14 6.5C14 6.63261 13.9473 6.75979 13.8536 6.85355C13.7598 6.94732 13.6326 7 13.5 7C13.3674 7 13.2402 6.94732 13.1464 6.85355C13.0527 6.75979 13 6.63261 13 6.5V3.7075L8.85437 7.85375C8.76055 7.94757 8.63331 8.00028 8.50062 8.00028C8.36794 8.00028 8.2407 7.94757 8.14688 7.85375C8.05306 7.75993 8.00035 7.63268 8.00035 7.5C8.00035 7.36732 8.05306 7.24007 8.14688 7.14625L12.2925 3H9.5C9.36739 3 9.24021 2.94732 9.14645 2.85355C9.05268 2.75979 9 2.63261 9 2.5C9 2.36739 9.05268 2.24021 9.14645 2.14645C9.24021 2.05268 9.36739 2 9.5 2H13.5C13.6326 2 13.7598 2.05268 13.8536 2.14645C13.9473 2.24021 14 2.36739 14 2.5V6.5ZM11.5 8C11.3674 8 11.2402 8.05268 11.1464 8.14645C11.0527 8.24021 11 8.36739 11 8.5V13H3V5H7.5C7.63261 5 7.75979 4.94732 7.85355 4.85355C7.94732 4.75979 8 4.63261 8 4.5C8 4.36739 7.94732 4.24021 7.85355 4.14645C7.75979 4.05268 7.63261 4 7.5 4H3C2.73478 4 2.48043 4.10536 2.29289 4.29289C2.10536 4.48043 2 4.73478 2 5V13C2 13.2652 2.10536 13.5196 2.29289 13.7071C2.48043 13.8946 2.73478 14 3 14H11C11.2652 14 11.5196 13.8946 11.7071 13.7071C11.8946 13.5196 12 13.2652 12 13V8.5C12 8.36739 11.9473 8.24021 11.8536 8.14645C11.7598 8.05268 11.6326 8 11.5 8Z"
77
+ };
78
+ const externalIcon = React.createElement(Icon, {
79
+ icon: externalIconPath,
80
+ size: "small",
81
+ style: iconStyles.endIcon,
82
+ testId: "external-icon"
83
+ });
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);
69
101
  return router && !skipClientNav && isClientSideUrl(href) ? React.createElement(StyledLink, _extends({}, commonProps, {
70
102
  to: href
71
- }), children) : React.createElement(StyledAnchor, _extends({}, commonProps, {
103
+ }), linkContent) : React.createElement(StyledAnchor, _extends({}, commonProps, {
72
104
  href: href
73
- }), children);
105
+ }), linkContent);
74
106
  }
75
107
  render() {
76
108
  return React.createElement(__RouterContext.Consumer, null, router => this.renderInner(router));
77
109
  }
78
110
  }
79
111
  const styles = {};
112
+ const iconStyles = StyleSheet.create({
113
+ startIcon: {
114
+ marginInlineEnd: Spacing.xxxSmall_4,
115
+ verticalAlign: "middle"
116
+ },
117
+ endIcon: {
118
+ marginInlineStart: Spacing.xxxSmall_4,
119
+ verticalAlign: "middle"
120
+ }
121
+ });
80
122
  const sharedStyles = StyleSheet.create({
81
123
  shared: {
82
124
  cursor: "pointer",
83
125
  textDecoration: "none",
84
126
  outline: "none",
85
- display: "inline-flex"
127
+ verticalAlign: "bottom",
128
+ textUnderlineOffset: "3px",
129
+ alignItems: "center"
86
130
  }
87
131
  });
88
132
  const _generateStyles = (inline, kind, light, visitable) => {
@@ -137,11 +181,13 @@ const _generateStyles = (inline, kind, light, visitable) => {
137
181
  textDecoration: "underline currentcolor solid",
138
182
  color: defaultTextColor
139
183
  }, defaultVisited),
140
- focus: _extends({
141
- color: defaultTextColor,
142
- outline: `1px solid ${light ? white : blue}`,
143
- borderRadius: 3
144
- }, defaultVisited),
184
+ focus: {
185
+ ":focus-visible": _extends({
186
+ color: defaultTextColor,
187
+ outline: `1px solid ${light ? white : blue}`,
188
+ borderRadius: 3
189
+ }, defaultVisited)
190
+ },
145
191
  active: _extends({
146
192
  color: activeColor,
147
193
  textDecoration: "underline currentcolor solid"
package/dist/index.js CHANGED
@@ -7,6 +7,8 @@ var aphrodite = require('aphrodite');
7
7
  var reactRouterDom = require('react-router-dom');
8
8
  var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
9
9
  var Color = require('@khanacademy/wonder-blocks-color');
10
+ var Icon = require('@khanacademy/wonder-blocks-icon');
11
+ var Spacing = require('@khanacademy/wonder-blocks-spacing');
10
12
 
11
13
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
14
 
@@ -30,6 +32,8 @@ function _interopNamespace(e) {
30
32
 
31
33
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
32
34
  var Color__default = /*#__PURE__*/_interopDefaultLegacy(Color);
35
+ var Icon__default = /*#__PURE__*/_interopDefaultLegacy(Icon);
36
+ var Spacing__default = /*#__PURE__*/_interopDefaultLegacy(Spacing);
33
37
 
34
38
  function _objectDestructuringEmpty(obj) {
35
39
  if (obj == null) throw new TypeError("Cannot destructure " + obj);
@@ -63,7 +67,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
63
67
  return target;
64
68
  }
65
69
 
66
- const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting"];
70
+ const _excluded$1 = ["children", "skipClientNav", "focused", "hovered", "href", "inline", "kind", "light", "visitable", "pressed", "style", "testId", "waiting", "target", "startIcon", "endIcon"];
67
71
  const StyledAnchor = wonderBlocksCore.addStyle("a");
68
72
  const StyledLink = wonderBlocksCore.addStyle(reactRouterDom.Link);
69
73
  class LinkCore extends React__namespace.Component {
@@ -81,33 +85,75 @@ class LinkCore extends React__namespace.Component {
81
85
  visitable,
82
86
  pressed,
83
87
  style,
84
- testId
88
+ testId,
89
+ target,
90
+ startIcon,
91
+ endIcon
85
92
  } = _this$props,
86
93
  restProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
87
94
  const linkStyles = _generateStyles(inline, kind, light, visitable);
88
95
  const restingStyles = inline ? linkStyles.restingInline : linkStyles.resting;
89
- 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];
90
97
  const commonProps = _extends({
91
98
  "data-test-id": testId,
92
- style: [defaultStyles, style]
99
+ style: [defaultStyles, style],
100
+ target
93
101
  }, restProps);
102
+ const externalIconPath = {
103
+ small: "M14 6.5C14 6.63261 13.9473 6.75979 13.8536 6.85355C13.7598 6.94732 13.6326 7 13.5 7C13.3674 7 13.2402 6.94732 13.1464 6.85355C13.0527 6.75979 13 6.63261 13 6.5V3.7075L8.85437 7.85375C8.76055 7.94757 8.63331 8.00028 8.50062 8.00028C8.36794 8.00028 8.2407 7.94757 8.14688 7.85375C8.05306 7.75993 8.00035 7.63268 8.00035 7.5C8.00035 7.36732 8.05306 7.24007 8.14688 7.14625L12.2925 3H9.5C9.36739 3 9.24021 2.94732 9.14645 2.85355C9.05268 2.75979 9 2.63261 9 2.5C9 2.36739 9.05268 2.24021 9.14645 2.14645C9.24021 2.05268 9.36739 2 9.5 2H13.5C13.6326 2 13.7598 2.05268 13.8536 2.14645C13.9473 2.24021 14 2.36739 14 2.5V6.5ZM11.5 8C11.3674 8 11.2402 8.05268 11.1464 8.14645C11.0527 8.24021 11 8.36739 11 8.5V13H3V5H7.5C7.63261 5 7.75979 4.94732 7.85355 4.85355C7.94732 4.75979 8 4.63261 8 4.5C8 4.36739 7.94732 4.24021 7.85355 4.14645C7.75979 4.05268 7.63261 4 7.5 4H3C2.73478 4 2.48043 4.10536 2.29289 4.29289C2.10536 4.48043 2 4.73478 2 5V13C2 13.2652 2.10536 13.5196 2.29289 13.7071C2.48043 13.8946 2.73478 14 3 14H11C11.2652 14 11.5196 13.8946 11.7071 13.7071C11.8946 13.5196 12 13.2652 12 13V8.5C12 8.36739 11.9473 8.24021 11.8536 8.14645C11.7598 8.05268 11.6326 8 11.5 8Z"
104
+ };
105
+ const externalIcon = React__namespace.createElement(Icon__default["default"], {
106
+ icon: externalIconPath,
107
+ size: "small",
108
+ style: iconStyles.endIcon,
109
+ testId: "external-icon"
110
+ });
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);
94
128
  return router && !skipClientNav && wonderBlocksClickable.isClientSideUrl(href) ? React__namespace.createElement(StyledLink, _extends({}, commonProps, {
95
129
  to: href
96
- }), children) : React__namespace.createElement(StyledAnchor, _extends({}, commonProps, {
130
+ }), linkContent) : React__namespace.createElement(StyledAnchor, _extends({}, commonProps, {
97
131
  href: href
98
- }), children);
132
+ }), linkContent);
99
133
  }
100
134
  render() {
101
135
  return React__namespace.createElement(reactRouter.__RouterContext.Consumer, null, router => this.renderInner(router));
102
136
  }
103
137
  }
104
138
  const styles = {};
139
+ const iconStyles = aphrodite.StyleSheet.create({
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"
147
+ }
148
+ });
105
149
  const sharedStyles = aphrodite.StyleSheet.create({
106
150
  shared: {
107
151
  cursor: "pointer",
108
152
  textDecoration: "none",
109
153
  outline: "none",
110
- display: "inline-flex"
154
+ verticalAlign: "bottom",
155
+ textUnderlineOffset: "3px",
156
+ alignItems: "center"
111
157
  }
112
158
  });
113
159
  const _generateStyles = (inline, kind, light, visitable) => {
@@ -162,11 +208,13 @@ const _generateStyles = (inline, kind, light, visitable) => {
162
208
  textDecoration: "underline currentcolor solid",
163
209
  color: defaultTextColor
164
210
  }, defaultVisited),
165
- focus: _extends({
166
- color: defaultTextColor,
167
- outline: `1px solid ${light ? white : blue}`,
168
- borderRadius: 3
169
- }, defaultVisited),
211
+ focus: {
212
+ ":focus-visible": _extends({
213
+ color: defaultTextColor,
214
+ outline: `1px solid ${light ? white : blue}`,
215
+ borderRadius: 3
216
+ }, defaultVisited)
217
+ },
170
218
  active: _extends({
171
219
  color: activeColor,
172
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.0.8",
3
+ "version": "4.2.0",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,9 +16,11 @@
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "@babel/runtime": "^7.18.6",
19
- "@khanacademy/wonder-blocks-clickable": "^3.0.8",
19
+ "@khanacademy/wonder-blocks-clickable": "^3.0.9",
20
20
  "@khanacademy/wonder-blocks-color": "^2.0.1",
21
- "@khanacademy/wonder-blocks-core": "^5.0.4"
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
24
  },
23
25
  "peerDependencies": {
24
26
  "aphrodite": "^1.2.5",