@yoast/related-keyphrase-suggestions 0.1.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/build/components/CountrySelector/index.js +430 -0
- package/build/components/KeyphrasesTable/index.js +225 -0
- package/build/components/Modal/YoastIcon.js +25 -0
- package/build/components/Modal/index.js +66 -0
- package/build/css/style.css +117 -0
- package/build/elements/DifficultyBullet/index.js +104 -0
- package/build/elements/IntentBadge/index.js +57 -0
- package/build/elements/PremiumUpsell/index.js +39 -0
- package/build/elements/TableButton/index.js +86 -0
- package/build/elements/TrendGraph/TrendGraphScreenReader.js +46 -0
- package/build/elements/TrendGraph/index.js +64 -0
- package/build/elements/UserMessage/components/MaxRelatedKeyphrases.js +25 -0
- package/build/elements/UserMessage/components/RequestEmpty.js +24 -0
- package/build/elements/UserMessage/components/RequestFailed.js +24 -0
- package/build/elements/UserMessage/components/RequestLimitReached.js +40 -0
- package/build/elements/UserMessage/components/index.js +5 -0
- package/build/elements/UserMessage/index.js +46 -0
- package/build/index.js +10 -0
- package/package.json +77 -0
- package/readme.md +18 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { __, sprintf } from "@wordpress/i18n";
|
|
4
|
+
import { Link, Modal as BaseModal } from "@yoast/ui-library";
|
|
5
|
+
import { ExternalLinkIcon, ArrowNarrowRightIcon } from "@heroicons/react/outline";
|
|
6
|
+
import { YoastIcon } from "./YoastIcon";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The modal component with header and footer links.
|
|
10
|
+
*
|
|
11
|
+
* @param {boolean} isOpen Whether the modal is open.
|
|
12
|
+
* @param {Function} onClose The function to call when the modal is closed.
|
|
13
|
+
* @param {string} insightsLink The links to the insights.
|
|
14
|
+
* @param {string} learnMoreLink The link to the learn more page.
|
|
15
|
+
* @param {JSX.node?} [children=null] The content of the modal.
|
|
16
|
+
*
|
|
17
|
+
* @returns {JSX.Element} The modal component.
|
|
18
|
+
*/
|
|
19
|
+
export const Modal = ({
|
|
20
|
+
isOpen,
|
|
21
|
+
onClose,
|
|
22
|
+
insightsLink,
|
|
23
|
+
learnMoreLink,
|
|
24
|
+
children = null
|
|
25
|
+
}) => {
|
|
26
|
+
return /*#__PURE__*/React.createElement(BaseModal, {
|
|
27
|
+
onClose: onClose,
|
|
28
|
+
isOpen: isOpen
|
|
29
|
+
}, /*#__PURE__*/React.createElement(BaseModal.Panel, {
|
|
30
|
+
className: "yst-p-0 yst-max-w-2xl"
|
|
31
|
+
}, /*#__PURE__*/React.createElement(BaseModal.Container.Header, {
|
|
32
|
+
className: "yst-flex yst-gap-3 yst-p-6 yst-border-b-slate-200 yst-border-b yst-flex-row"
|
|
33
|
+
}, /*#__PURE__*/React.createElement(YoastIcon, null), /*#__PURE__*/React.createElement(BaseModal.Title, {
|
|
34
|
+
as: "h3",
|
|
35
|
+
className: "yst-text-lg yst-font-medium"
|
|
36
|
+
}, __("Related keyphrases", "wordpress-seo"))), /*#__PURE__*/React.createElement(BaseModal.Container.Content, {
|
|
37
|
+
className: "yst-related-keyphrase-modal-content yst-m-0"
|
|
38
|
+
}, children), /*#__PURE__*/React.createElement(BaseModal.Container.Footer, {
|
|
39
|
+
className: "yst-p-6 yst-border-t yst-border-t-slate-200 yst-flex yst-justify-between"
|
|
40
|
+
}, /*#__PURE__*/React.createElement(Link, {
|
|
41
|
+
href: insightsLink,
|
|
42
|
+
className: "yst-modal-footer-link",
|
|
43
|
+
target: "_blank"
|
|
44
|
+
}, sprintf(/* translators: %s expands to Semrush */
|
|
45
|
+
__("Get more insights at %s", "wordpress-seo"), "Semrush"), /*#__PURE__*/React.createElement("span", {
|
|
46
|
+
className: "yst-sr-only"
|
|
47
|
+
}, __("(Opens in a new browser tab)", "wordpress-seo")), /*#__PURE__*/React.createElement(ExternalLinkIcon, {
|
|
48
|
+
className: "yst-link-icon rtl:yst-rotate-[270deg]"
|
|
49
|
+
})), /*#__PURE__*/React.createElement(Link, {
|
|
50
|
+
href: learnMoreLink,
|
|
51
|
+
className: "yst-modal-footer-link yst-text-primary-500",
|
|
52
|
+
target: "_blank"
|
|
53
|
+
}, __("Learn more about the metrics", "wordpress-seo"), /*#__PURE__*/React.createElement("span", {
|
|
54
|
+
className: "yst-sr-only"
|
|
55
|
+
}, __("(Opens in a new browser tab)", "wordpress-seo")), /*#__PURE__*/React.createElement(ArrowNarrowRightIcon, {
|
|
56
|
+
className: "yst-link-icon rtl:yst-rotate-180"
|
|
57
|
+
})))));
|
|
58
|
+
};
|
|
59
|
+
Modal.propTypes = {
|
|
60
|
+
isOpen: PropTypes.bool.isRequired,
|
|
61
|
+
onClose: PropTypes.func.isRequired,
|
|
62
|
+
insightsLink: PropTypes.string.isRequired,
|
|
63
|
+
learnMoreLink: PropTypes.string.isRequired,
|
|
64
|
+
children: PropTypes.node
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.yst-root {
|
|
3
|
+
.yst-difficulty--very-easy {
|
|
4
|
+
@apply yst-bg-emerald-300;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.yst-difficulty--easy {
|
|
8
|
+
@apply yst-bg-emerald-600;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.yst-difficulty--possible {
|
|
12
|
+
@apply yst-bg-amber-400;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.yst-difficulty--difficult {
|
|
16
|
+
@apply yst-bg-orange-400;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.yst-difficulty--hard {
|
|
20
|
+
@apply yst-bg-red-500;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.yst-difficulty--very-hard {
|
|
24
|
+
@apply yst-bg-red-700;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}@layer components {
|
|
28
|
+
.yst-root {
|
|
29
|
+
|
|
30
|
+
.yst-intent-badge {
|
|
31
|
+
@apply yst-rounded-sm yst-w-5 yst-h-5 yst-flex yst-items-center yst-justify-center yst-font-semibold yst-text-sm yst-relative yst-uppercase;
|
|
32
|
+
|
|
33
|
+
&.yst-intent-badge--i {
|
|
34
|
+
@apply yst-text-blue-900 yst-bg-blue-200;
|
|
35
|
+
}
|
|
36
|
+
&.yst-intent-badge--n {
|
|
37
|
+
@apply yst-text-violet-900 yst-bg-violet-200;
|
|
38
|
+
}
|
|
39
|
+
&.yst-intent-badge--c {
|
|
40
|
+
@apply yst-text-amber-900 yst-bg-amber-200;
|
|
41
|
+
}
|
|
42
|
+
&.yst-intent-badge--t {
|
|
43
|
+
@apply yst-text-green-900 yst-bg-green-200;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}@layer components {
|
|
48
|
+
.yst-root {
|
|
49
|
+
|
|
50
|
+
.yst-table-button {
|
|
51
|
+
@apply yst-gap-2;
|
|
52
|
+
|
|
53
|
+
&.yst-button--secondary {
|
|
54
|
+
.yst-button-icon {
|
|
55
|
+
@apply yst-text-slate-400 yst-w-3 yst-h-3;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&.yst-button--tertiary {
|
|
60
|
+
@apply yst-text-red-500 hover:yst-text-red-700;
|
|
61
|
+
|
|
62
|
+
.yst-button-icon {
|
|
63
|
+
@apply yst-w-3.5 yst-h-3.5;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.yst-success-message {
|
|
69
|
+
@apply
|
|
70
|
+
yst-flex
|
|
71
|
+
yst-items-center
|
|
72
|
+
yst-justify-center
|
|
73
|
+
yst-gap-1
|
|
74
|
+
yst-text-slate-600
|
|
75
|
+
yst-text-xs
|
|
76
|
+
yst-px-3
|
|
77
|
+
yst-py-1
|
|
78
|
+
yst-leading-5
|
|
79
|
+
yst-transition
|
|
80
|
+
yst-duration-300
|
|
81
|
+
yst-ease-out;
|
|
82
|
+
|
|
83
|
+
.yst-success-icon {
|
|
84
|
+
@apply yst-w-4 yst-h-4;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&.yst-success-message-add {
|
|
88
|
+
.yst-success-icon {
|
|
89
|
+
@apply yst-text-green-400;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&.yst-success-message-remove {
|
|
94
|
+
.yst-success-icon {
|
|
95
|
+
@apply yst-text-red-500;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}@layer components {
|
|
102
|
+
.yst-root {
|
|
103
|
+
.yst-modal-footer-link {
|
|
104
|
+
@apply yst-flex yst-flex-row yst-gap-1 yst-items-center;
|
|
105
|
+
|
|
106
|
+
.yst-link-icon {
|
|
107
|
+
@apply yst-w-3 yst-h-3;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.yst-related-keyphrase-modal-content {
|
|
112
|
+
max-height: 60vh;
|
|
113
|
+
min-height: 350px;
|
|
114
|
+
@apply yst-p-6 yst-overflow-y-auto;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import classNames from "classnames";
|
|
4
|
+
import { __ } from "@wordpress/i18n";
|
|
5
|
+
import { TooltipContainer, TooltipTrigger, TooltipWithContext } from "@yoast/ui-library";
|
|
6
|
+
const variants = [{
|
|
7
|
+
min: 0,
|
|
8
|
+
max: 14,
|
|
9
|
+
name: "very-easy",
|
|
10
|
+
tooltip: {
|
|
11
|
+
title: __("Very easy", "wordpress-seo"),
|
|
12
|
+
description: __("Your chance to start ranking new pages.", "wordpress-seo")
|
|
13
|
+
}
|
|
14
|
+
}, {
|
|
15
|
+
min: 15,
|
|
16
|
+
max: 29,
|
|
17
|
+
name: "easy",
|
|
18
|
+
tooltip: {
|
|
19
|
+
title: __("Easy", "wordpress-seo"),
|
|
20
|
+
description: __("You will need quality content focused on the keyword’s intent.", "wordpress-seo")
|
|
21
|
+
}
|
|
22
|
+
}, {
|
|
23
|
+
min: 30,
|
|
24
|
+
max: 49,
|
|
25
|
+
name: "possible",
|
|
26
|
+
tooltip: {
|
|
27
|
+
title: __("Possible", "wordpress-seo"),
|
|
28
|
+
description: __("You will need well-structured and unique content.", "wordpress-seo")
|
|
29
|
+
}
|
|
30
|
+
}, {
|
|
31
|
+
min: 50,
|
|
32
|
+
max: 69,
|
|
33
|
+
name: "difficult",
|
|
34
|
+
tooltip: {
|
|
35
|
+
title: __("Difficult", "wordpress-seo"),
|
|
36
|
+
description: __("You will need lots of ref. domains and optimized content.", "wordpress-seo")
|
|
37
|
+
}
|
|
38
|
+
}, {
|
|
39
|
+
min: 70,
|
|
40
|
+
max: 84,
|
|
41
|
+
name: "hard",
|
|
42
|
+
tooltip: {
|
|
43
|
+
title: __("Hard", "wordpress-seo"),
|
|
44
|
+
description: __("You will need lots of high-quality ref. domains and optimized content.", "wordpress-seo")
|
|
45
|
+
}
|
|
46
|
+
}, {
|
|
47
|
+
min: 85,
|
|
48
|
+
max: 100,
|
|
49
|
+
name: "very-hard",
|
|
50
|
+
tooltip: {
|
|
51
|
+
title: __("Very hard", "wordpress-seo"),
|
|
52
|
+
description: __("It will take a lot of on-page SEO, link building, and content promotion efforts.", "wordpress-seo")
|
|
53
|
+
}
|
|
54
|
+
}];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns the variant of the difficulty.
|
|
58
|
+
*
|
|
59
|
+
* @param {number} value The difficulty index (0-100).
|
|
60
|
+
* @returns {object} The variant of the difficulty.
|
|
61
|
+
*/
|
|
62
|
+
const getVariant = value => {
|
|
63
|
+
for (const variant of variants) {
|
|
64
|
+
if (variant.min <= value && value <= variant.max) {
|
|
65
|
+
return variant;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @param {number} value The index of difficulty (0-100).
|
|
73
|
+
* @param {string} id The id of the tooltip.
|
|
74
|
+
*
|
|
75
|
+
* @returns {JSX.Element} The percentage of difficulty with a bullet with matching color.
|
|
76
|
+
*/
|
|
77
|
+
export const DifficultyBullet = ({
|
|
78
|
+
value,
|
|
79
|
+
id
|
|
80
|
+
}) => {
|
|
81
|
+
const variant = getVariant(value);
|
|
82
|
+
if (!variant) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return /*#__PURE__*/React.createElement(TooltipContainer, null, /*#__PURE__*/React.createElement(TooltipTrigger, {
|
|
86
|
+
ariaDescribedby: id,
|
|
87
|
+
className: "yst-flex yst-gap-2 yst-items-center yst-relative yst-w-10"
|
|
88
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
89
|
+
className: "yst-text-right yst-w-5"
|
|
90
|
+
}, value), /*#__PURE__*/React.createElement("div", {
|
|
91
|
+
className: classNames("yst-w-3 yst-h-3 yst-rounded-full", `yst-difficulty--${variant.name}`)
|
|
92
|
+
})), /*#__PURE__*/React.createElement(TooltipWithContext, {
|
|
93
|
+
id: id,
|
|
94
|
+
className: "yst-w-48 yst-text-xs yst-leading-4 yst-font-normal",
|
|
95
|
+
position: "left"
|
|
96
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
97
|
+
className: "yst-font-medium"
|
|
98
|
+
}, variant.tooltip.title, " "), variant.tooltip.description));
|
|
99
|
+
};
|
|
100
|
+
DifficultyBullet.propTypes = {
|
|
101
|
+
value: PropTypes.number.isRequired,
|
|
102
|
+
id: PropTypes.string.isRequired
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import classNames from "classnames";
|
|
4
|
+
import { TooltipContainer, TooltipTrigger, TooltipWithContext } from "@yoast/ui-library";
|
|
5
|
+
import { __ } from "@wordpress/i18n";
|
|
6
|
+
const variants = {
|
|
7
|
+
i: {
|
|
8
|
+
title: __("Informational", "wordpress-seo"),
|
|
9
|
+
description: __("The user wants to find an answer to a specific question.", "wordpress-seo")
|
|
10
|
+
},
|
|
11
|
+
n: {
|
|
12
|
+
title: __("Navigational", "wordpress-seo"),
|
|
13
|
+
description: __("The user wants to find a specific page or site.", "wordpress-seo")
|
|
14
|
+
},
|
|
15
|
+
c: {
|
|
16
|
+
title: __("Commercial", "wordpress-seo"),
|
|
17
|
+
description: __("The user wants to investigate brands or services.", "wordpress-seo")
|
|
18
|
+
},
|
|
19
|
+
t: {
|
|
20
|
+
title: __("Transactional", "wordpress-seo"),
|
|
21
|
+
description: __("The user wants to complete an action (conversion).", "wordpress-seo")
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The intent badge component.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} id The id of the tooltip.
|
|
29
|
+
* @param {string} value The initial of the intent, can be i,n,c or t only.
|
|
30
|
+
* @param {string} className The class name.
|
|
31
|
+
*
|
|
32
|
+
* @returns {JSX.Element} The colored initial badge.
|
|
33
|
+
*/
|
|
34
|
+
export const IntentBadge = ({
|
|
35
|
+
id,
|
|
36
|
+
value,
|
|
37
|
+
className = ""
|
|
38
|
+
}) => {
|
|
39
|
+
if (!variants[value]) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return /*#__PURE__*/React.createElement(TooltipContainer, null, /*#__PURE__*/React.createElement(TooltipTrigger, {
|
|
43
|
+
ariaDescribedby: id,
|
|
44
|
+
className: classNames("yst-intent-badge", `yst-intent-badge--${value}`, className)
|
|
45
|
+
}, value), /*#__PURE__*/React.createElement(TooltipWithContext, {
|
|
46
|
+
id: id,
|
|
47
|
+
className: "yst-w-48 yst-text-xs yst-leading-4 yst-font-normal"
|
|
48
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
49
|
+
className: "yst-font-medium"
|
|
50
|
+
}, variants[value].title, " "), variants[value].description));
|
|
51
|
+
};
|
|
52
|
+
IntentBadge.propTypes = {
|
|
53
|
+
id: PropTypes.string.isRequired,
|
|
54
|
+
value: PropTypes.oneOf(["i", "n", "c", "t"]).isRequired,
|
|
55
|
+
className: PropTypes.string
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { __, sprintf } from "@wordpress/i18n";
|
|
4
|
+
import { Button } from "@yoast/ui-library";
|
|
5
|
+
import { LockOpenIcon } from "@heroicons/react/outline";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The premium upsell component.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} url The URL to the premium page.
|
|
11
|
+
* @param {string} [className=""] The class name for the component.
|
|
12
|
+
*
|
|
13
|
+
* @returns {JSX.Element} The premium upsell component.
|
|
14
|
+
*/
|
|
15
|
+
export const PremiumUpsell = ({
|
|
16
|
+
url,
|
|
17
|
+
className = ""
|
|
18
|
+
}) => {
|
|
19
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
20
|
+
className: className
|
|
21
|
+
}, /*#__PURE__*/React.createElement("p", null, sprintf(/* translators: %s: Expands to "Yoast SEO". */
|
|
22
|
+
__("You’ll reach more people with multiple keyphrases! Want to quickly add these related keyphrases to the %s analyses for even better content optimization?", "wordpress-seo"), "Yoast SEO")), /*#__PURE__*/React.createElement(Button, {
|
|
23
|
+
variant: "upsell",
|
|
24
|
+
as: "a",
|
|
25
|
+
href: url,
|
|
26
|
+
className: "yst-mt-4 yst-gap-2",
|
|
27
|
+
target: "_blank"
|
|
28
|
+
}, /*#__PURE__*/React.createElement(LockOpenIcon, {
|
|
29
|
+
className: "yst-w-4 yst-h-4 yst-text-amber-900"
|
|
30
|
+
}), sprintf(/* translators: %s: Expands to "Yoast SEO Premium". */
|
|
31
|
+
__("Explore %s!", "wordpress-seo"), "Yoast SEO Premium"), /*#__PURE__*/React.createElement("span", {
|
|
32
|
+
className: "yst-sr-only"
|
|
33
|
+
}, __("(Opens in a new browser tab)", "wordpress-seo"))));
|
|
34
|
+
};
|
|
35
|
+
PremiumUpsell.propTypes = {
|
|
36
|
+
url: PropTypes.string.isRequired,
|
|
37
|
+
className: PropTypes.string
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import classNames from "classnames";
|
|
4
|
+
import PropTypes from "prop-types";
|
|
5
|
+
import { TrashIcon, PlusIcon, CheckIcon, XIcon } from "@heroicons/react/outline";
|
|
6
|
+
import { Button } from "@yoast/ui-library";
|
|
7
|
+
import { __ } from "@wordpress/i18n";
|
|
8
|
+
const variants = {
|
|
9
|
+
add: {
|
|
10
|
+
button: {
|
|
11
|
+
Icon: PlusIcon,
|
|
12
|
+
label: __("Add", "wordpress-seo"),
|
|
13
|
+
variant: "secondary"
|
|
14
|
+
},
|
|
15
|
+
success: {
|
|
16
|
+
Icon: CheckIcon,
|
|
17
|
+
label: __("Added!", "wordpress-seo")
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
remove: {
|
|
21
|
+
button: {
|
|
22
|
+
Icon: TrashIcon,
|
|
23
|
+
label: __("Remove", "wordpress-seo"),
|
|
24
|
+
variant: "tertiary"
|
|
25
|
+
},
|
|
26
|
+
success: {
|
|
27
|
+
Icon: XIcon,
|
|
28
|
+
label: __("Removed!", "wordpress-seo")
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The success message for the table buttons.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} [variant="add"] The variant of the success message.
|
|
37
|
+
* @param {string} className The class name.
|
|
38
|
+
*
|
|
39
|
+
* @returns {JSX.Element} The success message.
|
|
40
|
+
*/
|
|
41
|
+
const SuccessMessage = ({
|
|
42
|
+
variant = "add",
|
|
43
|
+
className = ""
|
|
44
|
+
}) => {
|
|
45
|
+
const SuccessIcon = variants[variant].success.Icon;
|
|
46
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
47
|
+
role: "alert",
|
|
48
|
+
className: classNames("yst-success-message yst-animate-appear-disappear", `yst-success-message-${variant}`, className)
|
|
49
|
+
}, /*#__PURE__*/React.createElement(SuccessIcon, {
|
|
50
|
+
className: "yst-success-icon"
|
|
51
|
+
}), variants[variant].success.label);
|
|
52
|
+
};
|
|
53
|
+
SuccessMessage.propTypes = {
|
|
54
|
+
variant: PropTypes.oneOf(["add", "remove"]),
|
|
55
|
+
className: PropTypes.string
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @param {string} variant Whether it is an add button or not.
|
|
61
|
+
* @param {string} [className=""] The class name.
|
|
62
|
+
*
|
|
63
|
+
* @returns {JSX.Element} The button.
|
|
64
|
+
*/
|
|
65
|
+
export const TableButton = /*#__PURE__*/forwardRef(({
|
|
66
|
+
variant = "add",
|
|
67
|
+
className = "",
|
|
68
|
+
...props
|
|
69
|
+
}, ref) => {
|
|
70
|
+
const ButtonIcon = variants[variant].button.Icon;
|
|
71
|
+
return /*#__PURE__*/React.createElement(Button, _extends({}, props, {
|
|
72
|
+
ref: ref,
|
|
73
|
+
variant: variants[variant].button.variant,
|
|
74
|
+
size: "small",
|
|
75
|
+
className: classNames("yst-table-button", className)
|
|
76
|
+
}), /*#__PURE__*/React.createElement(ButtonIcon, {
|
|
77
|
+
className: "yst-button-icon yst--mx-1"
|
|
78
|
+
}), variants[variant].button.label);
|
|
79
|
+
});
|
|
80
|
+
TableButton.propTypes = {
|
|
81
|
+
variant: PropTypes.oneOf(["add", "remove"]).isRequired,
|
|
82
|
+
className: PropTypes.string
|
|
83
|
+
};
|
|
84
|
+
TableButton.displayName = "TableButton";
|
|
85
|
+
TableButton.SuccessMessage = SuccessMessage;
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { __ } from "@wordpress/i18n";
|
|
4
|
+
const dataTableHeaderLabels = [__("Twelve months ago", "wordpress-seo"), __("Eleven months ago", "wordpress-seo"), __("Ten months ago", "wordpress-seo"), __("Nine months ago", "wordpress-seo"), __("Eight months ago", "wordpress-seo"), __("Seven months ago", "wordpress-seo"), __("Six months ago", "wordpress-seo"), __("Five months ago", "wordpress-seo"), __("Four months ago", "wordpress-seo"), __("Three months ago", "wordpress-seo"), __("Two months ago", "wordpress-seo"), __("Last month", "wordpress-seo")];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Adapts the chart y axis data to a more meaningful format for the alternative representation in the data table.
|
|
8
|
+
*
|
|
9
|
+
* @param {number} y The raw y axis data of the chart.
|
|
10
|
+
*
|
|
11
|
+
* @returns {number} The formatted y axis data.
|
|
12
|
+
*/
|
|
13
|
+
const mapChartDataToTableData = y => {
|
|
14
|
+
return Math.round(y * 100);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Renders a table for an accessible representation of the SVG area chart.
|
|
19
|
+
*
|
|
20
|
+
* @param {array} data Array of objects with X and Y coordinates for the SVG chart points.
|
|
21
|
+
* @param {Function} mapChartDataToTableData Function to adapt the chart points to meaningful data for the table.
|
|
22
|
+
*
|
|
23
|
+
* @returns {JSX.Element} The data table for the SVG area chart.
|
|
24
|
+
*/
|
|
25
|
+
export const TrendGraphScreenReader = ({
|
|
26
|
+
data
|
|
27
|
+
}) => {
|
|
28
|
+
if (data.length !== dataTableHeaderLabels.length) {
|
|
29
|
+
throw new Error("The number of headers and header labels don't match.");
|
|
30
|
+
}
|
|
31
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
32
|
+
className: "yst-sr-only"
|
|
33
|
+
}, /*#__PURE__*/React.createElement("table", null, /*#__PURE__*/React.createElement("caption", null, __("Keyphrase volume in the last 12 months on a scale from 0 to 100.", "wordpress-seo")), /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, dataTableHeaderLabels.map((label, index) => {
|
|
34
|
+
return /*#__PURE__*/React.createElement("th", {
|
|
35
|
+
key: index
|
|
36
|
+
}, label);
|
|
37
|
+
}))), /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, data.map((point, index) => {
|
|
38
|
+
return /*#__PURE__*/React.createElement("td", {
|
|
39
|
+
key: index
|
|
40
|
+
}, mapChartDataToTableData(point));
|
|
41
|
+
})))));
|
|
42
|
+
};
|
|
43
|
+
TrendGraphScreenReader.propTypes = {
|
|
44
|
+
data: PropTypes.arrayOf(PropTypes.number).isRequired
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=TrendGraphScreenReader.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { TrendGraphScreenReader } from "./TrendGraphScreenReader";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders a SVG area chart.
|
|
7
|
+
*
|
|
8
|
+
* @param {array} data Array of objects with X and Y coordinates for the SVG chart points.
|
|
9
|
+
*
|
|
10
|
+
* @returns {JSX.Element} The SVG area chart component.
|
|
11
|
+
*/
|
|
12
|
+
export const TrendGraph = ({
|
|
13
|
+
data
|
|
14
|
+
}) => {
|
|
15
|
+
const width = 66;
|
|
16
|
+
const height = 24;
|
|
17
|
+
const strokeWidth = 1.8;
|
|
18
|
+
if (data.length !== 12) {
|
|
19
|
+
const missingLength = 12 - data.length;
|
|
20
|
+
for (let i = 0; i < missingLength; i++) {
|
|
21
|
+
data.unshift(0);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// When all the y values are zero, make sure the maximumY value is at least 1 to avoid a division by zero later.
|
|
26
|
+
const maximumYFromData = Math.max(1, ...data.map(point => point));
|
|
27
|
+
|
|
28
|
+
// Reserve some vertical spacing to prevent the SVG stroke from being cut-off.
|
|
29
|
+
const chartHeight = height - strokeWidth;
|
|
30
|
+
const polylinePoints = data.map((point, index) => {
|
|
31
|
+
const x = index / 11 * width;
|
|
32
|
+
// Add some vertical padding to make sure the line stroke is always drawn within the SVG.
|
|
33
|
+
const y = chartHeight - point / maximumYFromData * chartHeight + strokeWidth;
|
|
34
|
+
return `${x},${y}`;
|
|
35
|
+
}).join(" ");
|
|
36
|
+
|
|
37
|
+
// Add points to close the polygon used for the area background.
|
|
38
|
+
const polygonPoints = `0,${chartHeight + strokeWidth} ` + polylinePoints + ` ${width},${chartHeight + strokeWidth}`;
|
|
39
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("svg", {
|
|
40
|
+
width: width,
|
|
41
|
+
height: height,
|
|
42
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
43
|
+
className: "yst-block",
|
|
44
|
+
role: "img",
|
|
45
|
+
"aria-hidden": "true",
|
|
46
|
+
focusable: "false"
|
|
47
|
+
}, /*#__PURE__*/React.createElement("polygon", {
|
|
48
|
+
className: "yst-fill-sky-200",
|
|
49
|
+
points: polygonPoints
|
|
50
|
+
}), /*#__PURE__*/React.createElement("polyline", {
|
|
51
|
+
fill: "none",
|
|
52
|
+
className: "yst-stroke-blue-500",
|
|
53
|
+
strokeWidth: strokeWidth,
|
|
54
|
+
strokeLinejoin: "round",
|
|
55
|
+
strokeLinecap: "round",
|
|
56
|
+
points: polylinePoints
|
|
57
|
+
})), /*#__PURE__*/React.createElement(TrendGraphScreenReader, {
|
|
58
|
+
data: data
|
|
59
|
+
}));
|
|
60
|
+
};
|
|
61
|
+
TrendGraph.propTypes = {
|
|
62
|
+
data: PropTypes.arrayOf(PropTypes.number).isRequired
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { __, sprintf } from "@wordpress/i18n";
|
|
4
|
+
import { Alert } from "@yoast/ui-library";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Display the message when reaching max related keyphrases.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} [className=""] The class name for the alert.
|
|
10
|
+
*
|
|
11
|
+
* @returns {React.Component} The alert for max related keyphrases.
|
|
12
|
+
*/
|
|
13
|
+
export const MaxRelatedKeyphrases = ({
|
|
14
|
+
className = ""
|
|
15
|
+
}) => {
|
|
16
|
+
return /*#__PURE__*/React.createElement(Alert, {
|
|
17
|
+
variant: "warning",
|
|
18
|
+
className: className
|
|
19
|
+
}, sprintf(/* translators: %s: Expands to "Yoast SEO". */
|
|
20
|
+
__("You've reached the maximum amount of 4 related keyphrases. You can change or remove related keyphrases in the %s metabox or sidebar.", "wordpress-seo"), "Yoast SEO"));
|
|
21
|
+
};
|
|
22
|
+
MaxRelatedKeyphrases.propTypes = {
|
|
23
|
+
className: PropTypes.string
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=MaxRelatedKeyphrases.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { __ } from "@wordpress/i18n";
|
|
4
|
+
import { Alert } from "@yoast/ui-library";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Display the message for a empty request.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} [className=""] The class name for the alert.
|
|
10
|
+
*
|
|
11
|
+
* @returns {React.Component} The message for a empty request.
|
|
12
|
+
*/
|
|
13
|
+
export const RequestEmpty = ({
|
|
14
|
+
className = ""
|
|
15
|
+
}) => {
|
|
16
|
+
return /*#__PURE__*/React.createElement(Alert, {
|
|
17
|
+
variant: "info",
|
|
18
|
+
className: className
|
|
19
|
+
}, __("Sorry, there's no data available for that keyphrase/country combination.", "wordpress-seo"));
|
|
20
|
+
};
|
|
21
|
+
RequestEmpty.propTypes = {
|
|
22
|
+
className: PropTypes.string
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=RequestEmpty.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { __ } from "@wordpress/i18n";
|
|
4
|
+
import { Alert } from "@yoast/ui-library";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Display the message for a failed request.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} [className=""] The class name for the alert.
|
|
10
|
+
*
|
|
11
|
+
* @returns {React.Component} The message for a failed request.
|
|
12
|
+
*/
|
|
13
|
+
export const RequestFailed = ({
|
|
14
|
+
className = ""
|
|
15
|
+
}) => {
|
|
16
|
+
return /*#__PURE__*/React.createElement(Alert, {
|
|
17
|
+
variant: "error",
|
|
18
|
+
className: className
|
|
19
|
+
}, __("We've encountered a problem trying to get related keyphrases. Please try again later.", "wordpress-seo"));
|
|
20
|
+
};
|
|
21
|
+
RequestFailed.propTypes = {
|
|
22
|
+
className: PropTypes.string
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=RequestFailed.js.map
|