@khanacademy/wonder-blocks-link 3.8.8 → 3.8.9
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 +7 -0
- package/dist/index.js +2 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +1 -1
- package/src/components/__docs__/link.argtypes.js +143 -0
- package/src/components/__docs__/link.stories.js +197 -0
- package/src/components/link.js +2 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -283,7 +283,8 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|
|
283
283
|
* `LinkCore` is a stateless component which displays the different states
|
|
284
284
|
* the `Link` can take.
|
|
285
285
|
*
|
|
286
|
-
*
|
|
286
|
+
* ### Usage
|
|
287
|
+
*
|
|
287
288
|
* ```jsx
|
|
288
289
|
* <Link
|
|
289
290
|
* href="https://khanacademy.org/"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-link",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.9",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@babel/runtime": "^7.18.6",
|
|
19
19
|
"@khanacademy/wonder-blocks-clickable": "^2.3.0",
|
|
20
|
-
"@khanacademy/wonder-blocks-color": "^1.
|
|
20
|
+
"@khanacademy/wonder-blocks-color": "^1.2.0",
|
|
21
21
|
"@khanacademy/wonder-blocks-core": "^4.3.2"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
children: {
|
|
5
|
+
control: {type: "text"},
|
|
6
|
+
description:
|
|
7
|
+
"Text to appear on the link. It can be a plain text or Typography element.",
|
|
8
|
+
table: {type: {summary: "string | React.Element<Typography>"}},
|
|
9
|
+
type: {required: true},
|
|
10
|
+
},
|
|
11
|
+
href: {
|
|
12
|
+
control: {type: "text"},
|
|
13
|
+
description: "URL to navigate to.",
|
|
14
|
+
table: {type: {summary: "string"}},
|
|
15
|
+
type: {required: true},
|
|
16
|
+
},
|
|
17
|
+
id: {
|
|
18
|
+
control: {type: "text"},
|
|
19
|
+
description: "An optional id attribute.",
|
|
20
|
+
table: {type: {summary: "string"}},
|
|
21
|
+
type: {required: false},
|
|
22
|
+
},
|
|
23
|
+
kind: {
|
|
24
|
+
control: {type: "select"},
|
|
25
|
+
description:
|
|
26
|
+
"Kind of Link. Note: Secondary light Links are not supported.",
|
|
27
|
+
options: ["primary", "secondary"],
|
|
28
|
+
table: {
|
|
29
|
+
type: {summary: `"primary" | "secondary"`},
|
|
30
|
+
},
|
|
31
|
+
type: {required: false},
|
|
32
|
+
},
|
|
33
|
+
light: {
|
|
34
|
+
control: {type: "boolean"},
|
|
35
|
+
description: "Whether the button is on a dark/colored background.",
|
|
36
|
+
table: {
|
|
37
|
+
type: {summary: "boolean"},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
visitable: {
|
|
41
|
+
control: {type: "boolean"},
|
|
42
|
+
description:
|
|
43
|
+
"Whether the link should change color once it's visited. Secondary or primary (light) links are not allowed to be visitable.",
|
|
44
|
+
table: {
|
|
45
|
+
type: {summary: "boolean"},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
rel: {
|
|
49
|
+
control: {type: "text"},
|
|
50
|
+
description: `Specifies the type of relationship between the current
|
|
51
|
+
document and the linked document. Should only be used when
|
|
52
|
+
\`href\` is specified. This defaults to "noopener noreferrer"
|
|
53
|
+
when \`target="_blank"\`, but can be overridden by setting this
|
|
54
|
+
prop to something else.`,
|
|
55
|
+
table: {
|
|
56
|
+
type: {summary: "string"},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
tabIndex: {
|
|
60
|
+
control: {type: "number"},
|
|
61
|
+
description: "Set the tabindex attribute on the rendered element.",
|
|
62
|
+
table: {
|
|
63
|
+
defaultValue: {summary: 0},
|
|
64
|
+
type: {summary: "number"},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
testId: {
|
|
68
|
+
control: {type: "text"},
|
|
69
|
+
description: "Test ID used for e2e testing.",
|
|
70
|
+
table: {
|
|
71
|
+
type: {summary: "string"},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
style: {
|
|
76
|
+
control: {type: "object"},
|
|
77
|
+
description: "custom styles.",
|
|
78
|
+
table: {type: {summary: "StyleType"}},
|
|
79
|
+
},
|
|
80
|
+
className: {
|
|
81
|
+
control: {type: "text"},
|
|
82
|
+
description: "Adds CSS classes to the Link.",
|
|
83
|
+
table: {type: {summary: "string"}},
|
|
84
|
+
},
|
|
85
|
+
beforeNav: {
|
|
86
|
+
description: `Run async code before navigating to the URL passed to
|
|
87
|
+
\`href\`. If the promise returned rejects then navigation will not
|
|
88
|
+
occur. If both safeWithNav and beforeNav are provided, beforeNav
|
|
89
|
+
will be run first and safeWithNav will only be run if beforeNav
|
|
90
|
+
does not reject.`,
|
|
91
|
+
table: {
|
|
92
|
+
category: "Navigation",
|
|
93
|
+
type: {summary: "() => Promise<mixed>"},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
safeWithNav: {
|
|
97
|
+
description: `Run async code in the background while client-side
|
|
98
|
+
navigating. If the browser does a full page load navigation, the
|
|
99
|
+
callback promise must be settled before the navigation will occur.
|
|
100
|
+
Errors are ignored so that navigation is guaranteed to succeed.`,
|
|
101
|
+
table: {
|
|
102
|
+
category: "Navigation",
|
|
103
|
+
type: {summary: "() => Promise<mixed>"},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
skipClientNav: {
|
|
107
|
+
control: {type: "boolean"},
|
|
108
|
+
description: `Whether to avoid using client-side navigation.
|
|
109
|
+
If the URL passed to href is local to the client-side, e.g.
|
|
110
|
+
/math/algebra/eval-exprs, then it tries to use react-router-dom's
|
|
111
|
+
Link component which handles the client-side navigation. You can set
|
|
112
|
+
\`skipClientNav\` to true avoid using client-side nav entirely.`,
|
|
113
|
+
table: {
|
|
114
|
+
category: "Navigation",
|
|
115
|
+
type: {summary: "boolean"},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
onClick: {
|
|
119
|
+
description: `Function to call when button is clicked.
|
|
120
|
+
This should NOT be used to redirect to a different URL or to
|
|
121
|
+
prevent navigation via e.preventDefault(). The event passed to this
|
|
122
|
+
handler will have its preventDefault() and stopPropagation() methods
|
|
123
|
+
stubbed out.`,
|
|
124
|
+
table: {
|
|
125
|
+
category: "Events",
|
|
126
|
+
type: {summary: "(e: SyntheticEvent<>) => mixed"},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
onKeyDown: {
|
|
130
|
+
description: `Respond to raw "keydown" event.`,
|
|
131
|
+
table: {
|
|
132
|
+
category: "Events",
|
|
133
|
+
type: {summary: "(e: SyntheticKeyboardEvent<>) => mixed"},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
onKeyUp: {
|
|
137
|
+
description: `Respond to raw "keyup" event.`,
|
|
138
|
+
table: {
|
|
139
|
+
category: "Events",
|
|
140
|
+
type: {summary: "(e: SyntheticKeyboardEvent<>) => mixed"},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import {StyleSheet} from "aphrodite";
|
|
4
|
+
import {MemoryRouter, Route, Switch} from "react-router-dom";
|
|
5
|
+
|
|
6
|
+
import Color from "@khanacademy/wonder-blocks-color";
|
|
7
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
8
|
+
import Link from "@khanacademy/wonder-blocks-link";
|
|
9
|
+
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
10
|
+
import {
|
|
11
|
+
Body,
|
|
12
|
+
HeadingSmall,
|
|
13
|
+
LabelLarge,
|
|
14
|
+
} from "@khanacademy/wonder-blocks-typography";
|
|
15
|
+
import type {StoryComponentType} from "@storybook/react";
|
|
16
|
+
|
|
17
|
+
import LinkArgTypes from "./link.argtypes.js";
|
|
18
|
+
import ComponentInfo from "../../../../../.storybook/components/component-info.js";
|
|
19
|
+
import {name, version} from "../../../package.json";
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
title: "Link",
|
|
23
|
+
component: Link,
|
|
24
|
+
parameters: {
|
|
25
|
+
componentSubtitle: ((
|
|
26
|
+
<ComponentInfo name={name} version={version} />
|
|
27
|
+
): any),
|
|
28
|
+
},
|
|
29
|
+
argTypes: LinkArgTypes,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Default: StoryComponentType = (args) => (
|
|
33
|
+
<Link target="_blank" {...args} />
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
Default.args = {
|
|
37
|
+
href: "/",
|
|
38
|
+
children: "Hello, world!",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Basic: StoryComponentType = () => (
|
|
42
|
+
<Link href="#">Hello, world!</Link>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
Basic.parameters = {
|
|
46
|
+
docs: {
|
|
47
|
+
storyDescription: `Minimal link usage.
|
|
48
|
+
This links to the top of the page.`,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const Variants: StoryComponentType = () => (
|
|
53
|
+
<Body>
|
|
54
|
+
I am a <Link href="#nonexistent-link">Primary Link</Link>.{" "}
|
|
55
|
+
<span style={{color: Color.offBlack64}}>
|
|
56
|
+
My friend the{" "}
|
|
57
|
+
<Link href="#secondary-nonexistent-link" kind="secondary">
|
|
58
|
+
Secondary Link
|
|
59
|
+
</Link>{" "}
|
|
60
|
+
is used here with a lighter text.
|
|
61
|
+
</span>{" "}
|
|
62
|
+
We also have a{" "}
|
|
63
|
+
<Link href="#" visitable={true}>
|
|
64
|
+
Visitable Primary Link
|
|
65
|
+
</Link>{" "}
|
|
66
|
+
friend.
|
|
67
|
+
</Body>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
Variants.parameters = {
|
|
71
|
+
docs: {
|
|
72
|
+
storyDescription: `Primary links are blue, secondary links are black,
|
|
73
|
+
and visitable links turn purple after they've been clicked on.`,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const LightVariants: StoryComponentType = () => (
|
|
78
|
+
<Body style={styles.darkBackground}>
|
|
79
|
+
I am a{" "}
|
|
80
|
+
<Link href="#dark-link" light={true}>
|
|
81
|
+
Primary Link
|
|
82
|
+
</Link>{" "}
|
|
83
|
+
used on a dark background. My friend the Secondary Link is not supported
|
|
84
|
+
on this dark background.
|
|
85
|
+
</Body>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
LightVariants.parameters = {
|
|
89
|
+
docs: {
|
|
90
|
+
storyDescription: `Links are white on a dark background when the
|
|
91
|
+
\`light\` prop is true. Secondary \`light\` links are not supported.
|
|
92
|
+
Links also cannot be \`visitable\` if they're \`light\`. If
|
|
93
|
+
a link has \`light\` set to \`true\` and you try to set \`kind\`
|
|
94
|
+
to \`"secondary"\` or \`visitable\` to \`true\`, it will throw
|
|
95
|
+
an error.`,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const WithTypography: StoryComponentType = () => (
|
|
100
|
+
<Link href="#nonexistent-link" id="typography-link">
|
|
101
|
+
<HeadingSmall>Heading inside a Link element</HeadingSmall>
|
|
102
|
+
</Link>
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
WithTypography.parameters = {
|
|
106
|
+
docs: {
|
|
107
|
+
storyDescription: `Wonder Blocks Typography elements can also be used
|
|
108
|
+
inside Links instead of plain text. Here, we have a \`Link\`
|
|
109
|
+
containing a \`HeadingSmall\`.`,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const WithStyle: StoryComponentType = () => (
|
|
114
|
+
<Link href="#" style={styles.pinkLink}>
|
|
115
|
+
This link has a style.
|
|
116
|
+
</Link>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
WithStyle.parameters = {
|
|
120
|
+
docs: {
|
|
121
|
+
storyDescription: `Link can take a \`style\` prop. Here, the
|
|
122
|
+
Link has been given a style in which the \`color\` field has
|
|
123
|
+
been set to \`Colors.pink\`.`,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export const Navigation: StoryComponentType = () => (
|
|
128
|
+
<MemoryRouter>
|
|
129
|
+
<View>
|
|
130
|
+
<View style={styles.row}>
|
|
131
|
+
<Link
|
|
132
|
+
href="/foo"
|
|
133
|
+
style={styles.heading}
|
|
134
|
+
onClick={() => {
|
|
135
|
+
// eslint-disable-next-line no-console
|
|
136
|
+
console.log("I'm still on the same page!");
|
|
137
|
+
}}
|
|
138
|
+
>
|
|
139
|
+
<LabelLarge>Uses Client-side Nav</LabelLarge>
|
|
140
|
+
</Link>
|
|
141
|
+
<Link
|
|
142
|
+
href="/iframe.html?id=link--default&viewMode=story"
|
|
143
|
+
style={styles.heading}
|
|
144
|
+
skipClientNav
|
|
145
|
+
>
|
|
146
|
+
<LabelLarge>Avoids Client-side Nav</LabelLarge>
|
|
147
|
+
</Link>
|
|
148
|
+
</View>
|
|
149
|
+
<View style={styles.navigation}>
|
|
150
|
+
<Switch>
|
|
151
|
+
<Route path="/foo">
|
|
152
|
+
<View id="foo">
|
|
153
|
+
The first link does client-side navigation here.
|
|
154
|
+
</View>
|
|
155
|
+
</Route>
|
|
156
|
+
<Route path="*">See navigation changes here</Route>
|
|
157
|
+
</Switch>
|
|
158
|
+
</View>
|
|
159
|
+
</View>
|
|
160
|
+
</MemoryRouter>
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
Navigation.parameters = {
|
|
164
|
+
docs: {
|
|
165
|
+
storyDescription: `If you want to navigate to an external URL
|
|
166
|
+
and/or reload the window, make sure to use \`href\` and
|
|
167
|
+
\`skipClientNav={true}\`, as shown in this example.
|
|
168
|
+
**For navigation callbacks:** The \`onClick\`, \`beforeNav\`, and
|
|
169
|
+
\`safeWithNav\` props can be used to run callbacks when navigating
|
|
170
|
+
to the new URL. Which prop to use depends on the use case. See the
|
|
171
|
+
[Button documentation](/story/button-navigation-callbacks--before-nav-callbacks&viewMode=docs)
|
|
172
|
+
for details.`,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const styles = StyleSheet.create({
|
|
177
|
+
darkBackground: {
|
|
178
|
+
backgroundColor: Color.darkBlue,
|
|
179
|
+
color: Color.white64,
|
|
180
|
+
padding: 10,
|
|
181
|
+
},
|
|
182
|
+
heading: {
|
|
183
|
+
marginRight: Spacing.large_24,
|
|
184
|
+
},
|
|
185
|
+
navigation: {
|
|
186
|
+
border: `1px dashed ${Color.lightBlue}`,
|
|
187
|
+
marginTop: Spacing.large_24,
|
|
188
|
+
padding: Spacing.large_24,
|
|
189
|
+
},
|
|
190
|
+
pinkLink: {
|
|
191
|
+
color: Color.pink,
|
|
192
|
+
},
|
|
193
|
+
row: {
|
|
194
|
+
flexDirection: "row",
|
|
195
|
+
alignItems: "center",
|
|
196
|
+
},
|
|
197
|
+
});
|
package/src/components/link.js
CHANGED