@automattic/jetpack-components 0.39.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/.gitattributes +8 -0
- package/CHANGELOG.md +747 -0
- package/LICENSE.txt +357 -0
- package/README.md +11 -0
- package/SECURITY.md +38 -0
- package/components/action-button/index.jsx +70 -0
- package/components/action-button/stories/index.stories.jsx +38 -0
- package/components/action-button/style.module.scss +11 -0
- package/components/action-button/test/component.jsx +16 -0
- package/components/action-popover/index.tsx +105 -0
- package/components/action-popover/stories/index.stories.jsx +115 -0
- package/components/action-popover/stories/styles.module.scss +7 -0
- package/components/action-popover/styles.module.scss +49 -0
- package/components/action-popover/types.ts +20 -0
- package/components/admin-page/index.tsx +58 -0
- package/components/admin-page/stories/index.stories.tsx +35 -0
- package/components/admin-page/stories/style.module.scss +13 -0
- package/components/admin-page/style.module.scss +11 -0
- package/components/admin-page/types.ts +41 -0
- package/components/admin-section/basic/index.tsx +15 -0
- package/components/admin-section/basic/style.module.scss +3 -0
- package/components/admin-section/hero/index.tsx +15 -0
- package/components/admin-section/hero/style.module.scss +3 -0
- package/components/admin-section/stories/index.stories.tsx +60 -0
- package/components/admin-section/types.ts +6 -0
- package/components/alert/index.tsx +61 -0
- package/components/alert/stories/index.stories.jsx +24 -0
- package/components/alert/style.module.scss +43 -0
- package/components/automattic-byline-logo/README.md +16 -0
- package/components/automattic-byline-logo/index.tsx +38 -0
- package/components/automattic-byline-logo/stories/index.stories.tsx +20 -0
- package/components/automattic-byline-logo/test/component.tsx +28 -0
- package/components/automattic-byline-logo/types.ts +18 -0
- package/components/boost-score-bar/index.tsx +103 -0
- package/components/boost-score-bar/stories/index.stories.tsx +39 -0
- package/components/boost-score-bar/style.scss +184 -0
- package/components/boost-score-bar/test/component.tsx +102 -0
- package/components/boost-score-bar/types.ts +9 -0
- package/components/button/index.tsx +84 -0
- package/components/button/stories/index.mdx +90 -0
- package/components/button/stories/index.stories.tsx +400 -0
- package/components/button/stories/style.module.scss +20 -0
- package/components/button/style.module.scss +212 -0
- package/components/button/types.ts +21 -0
- package/components/contextual-upgrade-trigger/README.md +81 -0
- package/components/contextual-upgrade-trigger/index.tsx +44 -0
- package/components/contextual-upgrade-trigger/stories/index.stories.tsx +25 -0
- package/components/contextual-upgrade-trigger/style.module.scss +75 -0
- package/components/contextual-upgrade-trigger/types.ts +9 -0
- package/components/decorative-card/index.tsx +44 -0
- package/components/decorative-card/stories/index.stories.tsx +18 -0
- package/components/decorative-card/style.scss +116 -0
- package/components/decorative-card/types.ts +16 -0
- package/components/dialog/index.tsx +69 -0
- package/components/dialog/stories/boost.png +0 -0
- package/components/dialog/stories/declaration.d.ts +1 -0
- package/components/dialog/stories/index.stories.tsx +118 -0
- package/components/dialog/stories/js-components.components.dialog.mdx +62 -0
- package/components/dialog/stories/js-components.components.dialog.stories.js +37 -0
- package/components/dialog/stories/style.module.scss +21 -0
- package/components/dialog/style.module.scss +30 -0
- package/components/donut-meter/index.tsx +147 -0
- package/components/donut-meter/stories/index.stories.tsx +51 -0
- package/components/donut-meter/style.scss +11 -0
- package/components/donut-meter/test/component.tsx +24 -0
- package/components/gridicon/index.tsx +298 -0
- package/components/gridicon/stories/index.stories.tsx +18 -0
- package/components/gridicon/style.scss +16 -0
- package/components/gridicon/types.ts +48 -0
- package/components/icon-tooltip/index.tsx +96 -0
- package/components/icon-tooltip/stories/index.stories.tsx +108 -0
- package/components/icon-tooltip/stories/style.scss +36 -0
- package/components/icon-tooltip/style.scss +121 -0
- package/components/icon-tooltip/test/component.tsx +15 -0
- package/components/icon-tooltip/types.ts +76 -0
- package/components/icons/README.md +98 -0
- package/components/icons/index.tsx +369 -0
- package/components/icons/stories/index.stories.tsx +65 -0
- package/components/icons/stories/style.module.scss +33 -0
- package/components/icons/style.module.scss +40 -0
- package/components/icons/types.ts +38 -0
- package/components/indeterminate-progress-bar/index.tsx +28 -0
- package/components/indeterminate-progress-bar/stories/index.stories.tsx +14 -0
- package/components/indeterminate-progress-bar/style.module.scss +34 -0
- package/components/indeterminate-progress-bar/types.ts +6 -0
- package/components/jetpack-footer/README.md +21 -0
- package/components/jetpack-footer/index.tsx +94 -0
- package/components/jetpack-footer/stories/index.stories.tsx +40 -0
- package/components/jetpack-footer/style.scss +116 -0
- package/components/jetpack-footer/test/component.tsx +45 -0
- package/components/jetpack-footer/types.ts +36 -0
- package/components/jetpack-logo/README.md +20 -0
- package/components/jetpack-logo/index.tsx +46 -0
- package/components/jetpack-logo/stories/index.stories.tsx +20 -0
- package/components/jetpack-logo/test/component.tsx +16 -0
- package/components/jetpack-logo/types.ts +7 -0
- package/components/jetpack-search-logo/README.md +20 -0
- package/components/jetpack-search-logo/index.tsx +93 -0
- package/components/jetpack-search-logo/stories/index.stories.tsx +21 -0
- package/components/jetpack-search-logo/test/component.tsx +16 -0
- package/components/jetpack-search-logo/types.ts +7 -0
- package/components/jetpack-vaultpress-backup-logo/README.md +19 -0
- package/components/jetpack-vaultpress-backup-logo/index.tsx +113 -0
- package/components/jetpack-vaultpress-backup-logo/stories/index.stories.tsx +20 -0
- package/components/jetpack-vaultpress-backup-logo/test/component.tsx +18 -0
- package/components/jetpack-vaultpress-backup-logo/types.ts +6 -0
- package/components/jetpack-videopress-logo/README.md +19 -0
- package/components/jetpack-videopress-logo/index.tsx +93 -0
- package/components/jetpack-videopress-logo/stories/index.stories.tsx +20 -0
- package/components/jetpack-videopress-logo/test/component.tsx +16 -0
- package/components/jetpack-videopress-logo/types.tsx +6 -0
- package/components/layout/README.md +9 -0
- package/components/layout/breakpoints.module.scss +20 -0
- package/components/layout/col/README.md +81 -0
- package/components/layout/col/index.tsx +49 -0
- package/components/layout/col/style.module.scss +28 -0
- package/components/layout/container/README.md +77 -0
- package/components/layout/container/index.tsx +42 -0
- package/components/layout/container/style.module.scss +35 -0
- package/components/layout/stories/index.stories.tsx +145 -0
- package/components/layout/stories/styles.module.scss +22 -0
- package/components/layout/types.ts +55 -0
- package/components/layout/use-breakpoint-match/README.md +43 -0
- package/components/layout/use-breakpoint-match/declaration.d.ts +9 -0
- package/components/layout/use-breakpoint-match/index.ts +79 -0
- package/components/loading-placeholder/README.md +22 -0
- package/components/loading-placeholder/index.tsx +23 -0
- package/components/loading-placeholder/stories/index.stories.tsx +78 -0
- package/components/loading-placeholder/style.module.scss +18 -0
- package/components/notice/index.tsx +98 -0
- package/components/notice/stories/index.stories.jsx +90 -0
- package/components/notice/style.module.scss +107 -0
- package/components/number-format/README.md +25 -0
- package/components/number-format/index.ts +16 -0
- package/components/pricing-card/index.tsx +127 -0
- package/components/pricing-card/stories/index.stories.tsx +55 -0
- package/components/pricing-card/style.scss +112 -0
- package/components/pricing-card/test/component.tsx +89 -0
- package/components/pricing-card/types.ts +52 -0
- package/components/pricing-slider/index.tsx +53 -0
- package/components/pricing-slider/stories/index.stories.tsx +44 -0
- package/components/pricing-slider/style.scss +55 -0
- package/components/pricing-slider/test/component.tsx +14 -0
- package/components/pricing-slider/types.ts +58 -0
- package/components/pricing-table/index.tsx +200 -0
- package/components/pricing-table/stories/index.stories.tsx +74 -0
- package/components/pricing-table/styles.module.scss +160 -0
- package/components/pricing-table/test/component.tsx +41 -0
- package/components/pricing-table/types.ts +84 -0
- package/components/product-offer/icons-card.tsx +47 -0
- package/components/product-offer/index.tsx +115 -0
- package/components/product-offer/product-offer-header.tsx +23 -0
- package/components/product-offer/stories/index.stories.tsx +104 -0
- package/components/product-offer/style.module.scss +93 -0
- package/components/product-offer/types.ts +125 -0
- package/components/product-price/index.tsx +90 -0
- package/components/product-price/price.tsx +35 -0
- package/components/product-price/stories/index.stories.tsx +33 -0
- package/components/product-price/style.module.scss +69 -0
- package/components/product-price/test/component.tsx +26 -0
- package/components/product-price/types.ts +73 -0
- package/components/qr-code/Readme.md +5 -0
- package/components/qr-code/index.tsx +78 -0
- package/components/qr-code/stories/index.stories.tsx +32 -0
- package/components/record-meter-bar/index.tsx +135 -0
- package/components/record-meter-bar/stories/index.stories.tsx +39 -0
- package/components/record-meter-bar/style.scss +38 -0
- package/components/record-meter-bar/test/component.tsx +52 -0
- package/components/spinner/README.md +28 -0
- package/components/spinner/index.jsx +45 -0
- package/components/spinner/stories/index.stories.jsx +20 -0
- package/components/spinner/style.scss +31 -0
- package/components/spinner/test/component.jsx +17 -0
- package/components/split-button/index.tsx +39 -0
- package/components/split-button/stories/index.stories.tsx +35 -0
- package/components/split-button/style.module.scss +21 -0
- package/components/split-button/types.ts +14 -0
- package/components/stat-card/index.tsx +49 -0
- package/components/stat-card/stories/index.mdx +35 -0
- package/components/stat-card/stories/index.stories.tsx +41 -0
- package/components/stat-card/style.module.scss +49 -0
- package/components/stat-card/test/component.tsx +24 -0
- package/components/stat-card/types.ts +28 -0
- package/components/status/README.md +42 -0
- package/components/status/index.tsx +40 -0
- package/components/status/stories/index.stories.tsx +44 -0
- package/components/status/style.module.scss +72 -0
- package/components/terms-of-service/index.tsx +63 -0
- package/components/terms-of-service/styles.scss +10 -0
- package/components/terms-of-service/test/index.test.jsx +52 -0
- package/components/terms-of-service/types.ts +30 -0
- package/components/testimonials/index.tsx +58 -0
- package/components/testimonials/style.scss +127 -0
- package/components/testimonials/test/component.tsx +103 -0
- package/components/testimonials/testimonial.tsx +47 -0
- package/components/testimonials/types.ts +17 -0
- package/components/text/constants.ts +30 -0
- package/components/text/index.tsx +91 -0
- package/components/text/stories/headings.index.stories.tsx +80 -0
- package/components/text/stories/index.mdx +195 -0
- package/components/text/stories/index.stories.tsx +69 -0
- package/components/text/stories/style.module.scss +64 -0
- package/components/text/stories/title.index.stories.tsx +34 -0
- package/components/text/style.module.scss +125 -0
- package/components/text/types.ts +53 -0
- package/components/theme-provider/Readme.md +49 -0
- package/components/theme-provider/globals.module.scss +6 -0
- package/components/theme-provider/index.tsx +151 -0
- package/components/theme-provider/stories/index.stories.tsx +164 -0
- package/components/theme-provider/stories/style.module.scss +79 -0
- package/components/theme-provider/types.ts +25 -0
- package/components/toggle-control/README.md +5 -0
- package/components/toggle-control/index.tsx +67 -0
- package/components/toggle-control/stories/index.stories.tsx +83 -0
- package/components/toggle-control/styles.module.scss +41 -0
- package/components/zendesk-chat/README.md +26 -0
- package/components/zendesk-chat/constants.ts +2 -0
- package/components/zendesk-chat/index.tsx +22 -0
- package/components/zendesk-chat/stories/index.stories.tsx +15 -0
- package/components/zendesk-chat/test/component.tsx +16 -0
- package/components/zendesk-chat/types.ts +3 -0
- package/index.ts +69 -0
- package/lib/locale/index.ts +48 -0
- package/lib/locale/test/index.ts +21 -0
- package/package.json +80 -0
- package/tools/get-product-checkout-url/Readme.md +32 -0
- package/tools/get-product-checkout-url/index.ts +31 -0
- package/tools/jp-redirect/README.md +61 -0
- package/tools/jp-redirect/index.ts +62 -0
- package/tools/jp-redirect/test/index.tsx +89 -0
- package/tools/jp-redirect/types.ts +49 -0
- package/tools/pricing-utils/README.md +16 -0
- package/tools/pricing-utils/index.ts +11 -0
- package/tools/pricing-utils/test/index.ts +39 -0
- package/tools/pricing-utils/types.ts +12 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import AutomatticBylineLogo from '../index';
|
|
3
|
+
|
|
4
|
+
describe( 'AutomatticBylineLogo', () => {
|
|
5
|
+
const testProps = {
|
|
6
|
+
className: 'sample-classname',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
describe( 'Render the AutomatticBylineLogo component', () => {
|
|
10
|
+
it( 'validate the class name', () => {
|
|
11
|
+
const { container } = render( <AutomatticBylineLogo { ...testProps } /> );
|
|
12
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
13
|
+
expect( container.firstChild ).toHaveClass( 'sample-classname' );
|
|
14
|
+
} );
|
|
15
|
+
|
|
16
|
+
it( 'renders the default title', () => {
|
|
17
|
+
render( <AutomatticBylineLogo /> );
|
|
18
|
+
|
|
19
|
+
expect( screen.getByText( 'An Automattic Airline' ) ).toBeInTheDocument();
|
|
20
|
+
} );
|
|
21
|
+
|
|
22
|
+
it( 'renders the given title', () => {
|
|
23
|
+
render( <AutomatticBylineLogo title="An A8C Airline" /> );
|
|
24
|
+
|
|
25
|
+
expect( screen.getByText( 'An A8C Airline' ) ).toBeInTheDocument();
|
|
26
|
+
} );
|
|
27
|
+
} );
|
|
28
|
+
} );
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface AutomatticBylineLogoProps extends React.SVGProps< SVGSVGElement > {
|
|
4
|
+
/**
|
|
5
|
+
* Title for SVG.
|
|
6
|
+
*/
|
|
7
|
+
title?: string;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Height for SVG.
|
|
11
|
+
*/
|
|
12
|
+
height?: number;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Additional className for the a wrapper. `jp-automattic-byline-logo` always included
|
|
16
|
+
*/
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { __ } from '@wordpress/i18n';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import Gridicon from '../gridicon';
|
|
4
|
+
import type { BoostScoreBarProps } from './types';
|
|
5
|
+
import type { FunctionComponent } from 'react';
|
|
6
|
+
|
|
7
|
+
import './style.scss';
|
|
8
|
+
|
|
9
|
+
export const BoostScoreBar: FunctionComponent< BoostScoreBarProps > = ( {
|
|
10
|
+
score,
|
|
11
|
+
isLoading,
|
|
12
|
+
showPrevScores,
|
|
13
|
+
active,
|
|
14
|
+
prevScore = 0,
|
|
15
|
+
scoreBarType,
|
|
16
|
+
noBoostScoreTooltip,
|
|
17
|
+
} ) => {
|
|
18
|
+
if ( ! active ) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const prevScoreOffset = ( prevScore / score ) * 100;
|
|
23
|
+
const desktopIconLabel = __( 'Desktop score', 'jetpack' );
|
|
24
|
+
const mobileIconLabel = __( 'Mobile score', 'jetpack' );
|
|
25
|
+
|
|
26
|
+
const getIcon = () => {
|
|
27
|
+
if ( scoreBarType === 'desktop' ) {
|
|
28
|
+
return <Gridicon icon="computer" size={ 24 } />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <Gridicon icon="phone" size={ 24 } />;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const getFillColor = () => {
|
|
35
|
+
// This shows the loading color unless a score already exists.
|
|
36
|
+
// In that case, shows the color based on the current score while refreshing.
|
|
37
|
+
if ( isLoading && ! score ) {
|
|
38
|
+
return 'fill-loading';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ( score > 70 ) {
|
|
42
|
+
return 'fill-good';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if ( score > 50 ) {
|
|
46
|
+
return 'fill-mediocre';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return 'fill-bad';
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className={ classNames( 'jb-score-bar', `jb-score-bar--${ scoreBarType }` ) }>
|
|
54
|
+
<div className="jb-score-bar__label">
|
|
55
|
+
{ getIcon() }
|
|
56
|
+
<div>{ scoreBarType === 'desktop' ? desktopIconLabel : mobileIconLabel }</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div className="jb-score-bar__bounds">
|
|
60
|
+
<div
|
|
61
|
+
className={ classNames( 'jb-score-bar__filler', getFillColor() ) }
|
|
62
|
+
style={ { width: `${ score }%` } }
|
|
63
|
+
>
|
|
64
|
+
{ isLoading ? (
|
|
65
|
+
<div className="jb-score-bar__loading">
|
|
66
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 128 128">
|
|
67
|
+
<g>
|
|
68
|
+
<path d="M64 0a7 7 0 11-7 7 7 7 0 017-7zm29.86 12.2a2.8 2.8 0 11-3.83 1.02 2.8 2.8 0 013.83-1.02zm22.16 21.68a3.15 3.15 0 11-4.3-1.15 3.15 3.15 0 014.3 1.15zm.87 60.53a4.2 4.2 0 11-1.57-5.7 4.2 4.2 0 011.54 5.73zm7.8-30.5a3.85 3.85 0 11-3.85-3.85 3.85 3.85 0 013.85 3.84zm-30 53.2a4.55 4.55 0 111.66-6.23 4.55 4.55 0 01-1.67 6.22zM64 125.9a4.9 4.9 0 114.9-4.9 4.9 4.9 0 01-4.9 4.9zm-31.06-8.22a5.25 5.25 0 117.17-1.93 5.25 5.25 0 01-7.14 1.93zM9.9 95.1a5.6 5.6 0 117.65 2.06A5.6 5.6 0 019.9 95.1zM1.18 63.9a5.95 5.95 0 115.95 5.94 5.95 5.95 0 01-5.96-5.94zm8.1-31.6a6.3 6.3 0 112.32 8.6 6.3 6.3 0 01-2.3-8.6zM32.25 8.87a6.65 6.65 0 11-2.44 9.1 6.65 6.65 0 012.46-9.1z" />
|
|
69
|
+
<animateTransform
|
|
70
|
+
attributeName="transform"
|
|
71
|
+
type="rotate"
|
|
72
|
+
values="0 64 64;30 64 64;60 64 64;90 64 64;120 64 64;150 64 64;180 64 64;210 64 64;240 64 64;270 64 64;300 64 64;330 64 64"
|
|
73
|
+
calcMode="discrete"
|
|
74
|
+
dur="1080ms"
|
|
75
|
+
repeatCount="indefinite"
|
|
76
|
+
/>
|
|
77
|
+
</g>
|
|
78
|
+
</svg>
|
|
79
|
+
</div>
|
|
80
|
+
) : (
|
|
81
|
+
<div className="jb-score-bar__score">{ score }</div>
|
|
82
|
+
) }
|
|
83
|
+
|
|
84
|
+
{ showPrevScores && prevScore && prevScore < score && (
|
|
85
|
+
<div
|
|
86
|
+
className="jb-score-bar__no_boost_score"
|
|
87
|
+
style={ { left: `min(${ prevScoreOffset }%, calc( 100% - var(--clearance-space))` } }
|
|
88
|
+
>
|
|
89
|
+
{ prevScore }
|
|
90
|
+
{ noBoostScoreTooltip && (
|
|
91
|
+
<div role="tooltip" className="jb-score-bar__no_boost_score_tooltip">
|
|
92
|
+
{ noBoostScoreTooltip }
|
|
93
|
+
</div>
|
|
94
|
+
) }
|
|
95
|
+
</div>
|
|
96
|
+
) }
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default BoostScoreBar;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import BoostScoreBar from '../index';
|
|
2
|
+
import type { Meta } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
const meta: Meta< typeof BoostScoreBar > = {
|
|
5
|
+
title: 'JS Packages/Components/Boost Score Bar',
|
|
6
|
+
component: BoostScoreBar,
|
|
7
|
+
argTypes: {
|
|
8
|
+
score: { control: 'range', min: 0, max: 100, defaultValue: 80 },
|
|
9
|
+
prevScore: { control: 'range', min: 0, max: 100 },
|
|
10
|
+
isLoading: { control: 'boolean' },
|
|
11
|
+
showPrevScores: { control: 'boolean' },
|
|
12
|
+
active: { control: 'boolean' },
|
|
13
|
+
scoreBarType: { control: 'radio', options: [ 'desktop', 'mobile' ] },
|
|
14
|
+
noBoostScoreTooltip: { control: 'text' },
|
|
15
|
+
},
|
|
16
|
+
decorators: [
|
|
17
|
+
Story => (
|
|
18
|
+
<div style={ { width: '80%', maxWidth: '1320px', margin: '200px auto', fontSize: '16px' } }>
|
|
19
|
+
<Story />
|
|
20
|
+
</div>
|
|
21
|
+
),
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const defaultValues = {
|
|
26
|
+
score: 80,
|
|
27
|
+
prevScore: 70,
|
|
28
|
+
isLoading: false,
|
|
29
|
+
showPrevScores: true,
|
|
30
|
+
active: true,
|
|
31
|
+
scoreBarType: 'desktop',
|
|
32
|
+
noBoostScoreTooltip: 'No boost score',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default meta;
|
|
36
|
+
|
|
37
|
+
const Template = args => <BoostScoreBar { ...args } />;
|
|
38
|
+
export const _default = Template.bind( {} );
|
|
39
|
+
_default.args = defaultValues;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
@use "sass:math";
|
|
2
|
+
|
|
3
|
+
$bar_height: 42px;
|
|
4
|
+
$label_z_index: 50;
|
|
5
|
+
$score_pointer_size: 6px;
|
|
6
|
+
$no_boost_score_size: 28px;
|
|
7
|
+
|
|
8
|
+
%score-pill {
|
|
9
|
+
background-color: #fff;
|
|
10
|
+
border-radius: $bar_height;
|
|
11
|
+
height: $bar_height;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
border: 2px solid transparent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.jb-score-bar {
|
|
18
|
+
width: 100%;
|
|
19
|
+
display: flex;
|
|
20
|
+
color: var(--jp-gray-70);
|
|
21
|
+
|
|
22
|
+
&--mobile { // .jb-score-bar--mobile
|
|
23
|
+
margin-bottom: 1.5rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@media (max-width: 767px) {
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
&__label {
|
|
29
|
+
background-color: transparent;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
&__loading {
|
|
35
|
+
@extend %score-pill;
|
|
36
|
+
width: $bar_height;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&__label {
|
|
43
|
+
@extend %score-pill;
|
|
44
|
+
display: grid;
|
|
45
|
+
grid-template-columns: 24px 1fr;
|
|
46
|
+
grid-column-gap: 10px;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
position: relative;
|
|
49
|
+
font-size: 14px;
|
|
50
|
+
position: relative;
|
|
51
|
+
|
|
52
|
+
@media (min-width: 768px) {
|
|
53
|
+
padding-left: 15px;
|
|
54
|
+
padding-right: 15px;
|
|
55
|
+
width: 200px;
|
|
56
|
+
z-index: $label_z_index;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&__score {
|
|
61
|
+
@extend %score-pill;
|
|
62
|
+
border-radius: 100%;
|
|
63
|
+
font-weight: 700;
|
|
64
|
+
width: $bar_height;
|
|
65
|
+
justify-content: center;
|
|
66
|
+
position: absolute;
|
|
67
|
+
right: -1px;
|
|
68
|
+
height: $bar_height;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&__bounds {
|
|
72
|
+
background-color: #f1f1f1;
|
|
73
|
+
border-radius: math.div($bar-height, 2);
|
|
74
|
+
display: flex;
|
|
75
|
+
height: $bar_height;
|
|
76
|
+
width: 100%;
|
|
77
|
+
max-width: 100%;
|
|
78
|
+
position: relative;
|
|
79
|
+
z-index: $label_z_index - 10;
|
|
80
|
+
@media (min-width: 768px) {
|
|
81
|
+
width: calc(100% + #{math.div($bar-height, 2)});
|
|
82
|
+
margin-left: math.div(-$bar_height, 2) ;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&__filler {
|
|
87
|
+
display: flex;
|
|
88
|
+
min-width: 1px + $bar_height * 2;
|
|
89
|
+
justify-content: flex-end;
|
|
90
|
+
border-radius: 0 $bar_height $bar_height 0;
|
|
91
|
+
transition: width 300ms ease-in-out;
|
|
92
|
+
will-change: width;
|
|
93
|
+
width: 0;
|
|
94
|
+
position: relative;
|
|
95
|
+
@media (max-width: 767px) {
|
|
96
|
+
min-width: $bar_height + 1px;
|
|
97
|
+
border-radius: inherit;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&__no_boost_score {
|
|
102
|
+
|
|
103
|
+
--clearance-space: #{$bar_height + $no_boost_score_size + 4px};
|
|
104
|
+
|
|
105
|
+
position: absolute;
|
|
106
|
+
background: #fff;
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
padding: 3px;
|
|
109
|
+
top: $score_pointer_size;
|
|
110
|
+
width: $no_boost_score_size;
|
|
111
|
+
height: $no_boost_score_size;
|
|
112
|
+
line-height: 1.625;
|
|
113
|
+
font-size: 0.7em;
|
|
114
|
+
text-align: center;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
z-index: 2;
|
|
117
|
+
border: 2px solid transparent;
|
|
118
|
+
background-clip: padding-box;
|
|
119
|
+
|
|
120
|
+
&:hover {
|
|
121
|
+
border: 2px solid rgba(255, 255, 255, 0.5);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&::after {
|
|
125
|
+
content: " ";
|
|
126
|
+
width: 0;
|
|
127
|
+
height: 0;
|
|
128
|
+
border-left: $score_pointer_size solid transparent;
|
|
129
|
+
border-right: $score_pointer_size solid transparent;
|
|
130
|
+
border-bottom: $score_pointer_size solid #fff;
|
|
131
|
+
|
|
132
|
+
position: absolute;
|
|
133
|
+
top: $bar_height - $score_pointer_size * 2 - 2px;
|
|
134
|
+
left: $score_pointer_size;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&__no_boost_score_tooltip {
|
|
139
|
+
box-shadow: 0 0 20px 0 rgb(170 170 170 / 28%);
|
|
140
|
+
position: absolute;
|
|
141
|
+
top: -62px;
|
|
142
|
+
left: -10em;
|
|
143
|
+
width: 20em;
|
|
144
|
+
background: #FFF;
|
|
145
|
+
padding: 16px;
|
|
146
|
+
border-radius: 4px;
|
|
147
|
+
margin: 0 16px;
|
|
148
|
+
display: none;
|
|
149
|
+
|
|
150
|
+
&::after {
|
|
151
|
+
content: " ";
|
|
152
|
+
width: 0;
|
|
153
|
+
height: 0;
|
|
154
|
+
border-left: $score_pointer_size solid transparent;
|
|
155
|
+
border-right: $score_pointer_size solid transparent;
|
|
156
|
+
border-top: $score_pointer_size solid #fff;
|
|
157
|
+
|
|
158
|
+
position: absolute;
|
|
159
|
+
bottom: -$score_pointer_size;
|
|
160
|
+
left: 10em;
|
|
161
|
+
margin: 0 -10px
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
&__no_boost_score:hover &__no_boost_score_tooltip {
|
|
166
|
+
display: block;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.fill-loading {
|
|
170
|
+
background-color: var(--jp-white);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.fill-good {
|
|
174
|
+
background-color: var(--jp-green);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.fill-mediocre {
|
|
178
|
+
background-color: var(--jp-orange-20);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.fill-bad {
|
|
182
|
+
background-color: var(--jp-red-50);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* eslint-disable testing-library/no-container */
|
|
2
|
+
/* eslint-disable testing-library/no-node-access */
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import BoostScoreBar from '..';
|
|
5
|
+
import type { BoostScoreBarProps } from '../types';
|
|
6
|
+
|
|
7
|
+
describe( 'BoostScrollBar', () => {
|
|
8
|
+
const defaultProps: BoostScoreBarProps = {
|
|
9
|
+
score: 80,
|
|
10
|
+
prevScore: 60,
|
|
11
|
+
scoreBarType: 'desktop',
|
|
12
|
+
active: true,
|
|
13
|
+
showPrevScores: true,
|
|
14
|
+
isLoading: false,
|
|
15
|
+
noBoostScoreTooltip: 'Test tooltip text',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
it( 'renders the boost scroll bar when active is true', () => {
|
|
19
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } /> );
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
22
|
+
expect( container.firstChild ).toHaveAttribute( 'class', 'jb-score-bar jb-score-bar--desktop' );
|
|
23
|
+
} );
|
|
24
|
+
|
|
25
|
+
it( 'does not render the boost scroll bar when active is false', () => {
|
|
26
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } active={ false } /> );
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line testing-library/no-node-access
|
|
29
|
+
expect( container ).toBeEmptyDOMElement();
|
|
30
|
+
} );
|
|
31
|
+
|
|
32
|
+
it( 'does not render the tooltip when noBoostScoreTooltip is not provided', () => {
|
|
33
|
+
render( <BoostScoreBar { ...defaultProps } noBoostScoreTooltip={ undefined } /> );
|
|
34
|
+
|
|
35
|
+
expect( screen.queryByRole( 'tooltip' ) ).not.toBeInTheDocument();
|
|
36
|
+
} );
|
|
37
|
+
|
|
38
|
+
it( 'renders the tooltip with the correct text when noBoostScoreTooltip is provided', () => {
|
|
39
|
+
render( <BoostScoreBar { ...defaultProps } /> );
|
|
40
|
+
|
|
41
|
+
expect( screen.getByRole( 'tooltip' ) ).toHaveTextContent( 'Test tooltip text' );
|
|
42
|
+
} );
|
|
43
|
+
|
|
44
|
+
it( 'displays loading spinner when isLoading is true', () => {
|
|
45
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } isLoading={ true } /> );
|
|
46
|
+
|
|
47
|
+
expect( container.querySelector( '.jb-score-bar__loading' ) ).toBeInTheDocument();
|
|
48
|
+
} );
|
|
49
|
+
|
|
50
|
+
it( 'does not display loading spinner when isLoading is false', () => {
|
|
51
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } /> );
|
|
52
|
+
|
|
53
|
+
expect( container.querySelector( '.jb-score-bar__loading' ) ).not.toBeInTheDocument();
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
it( 'renders mobile icon and text when scoreBarType is mobile', () => {
|
|
57
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } scoreBarType="mobile" /> );
|
|
58
|
+
|
|
59
|
+
expect( screen.getByText( 'Mobile score' ) ).toBeInTheDocument();
|
|
60
|
+
expect( container.querySelector( '.gridicons-phone' ) ).toBeInTheDocument();
|
|
61
|
+
} );
|
|
62
|
+
|
|
63
|
+
it( 'renders desktop icon and text when scoreBarType is desktop', () => {
|
|
64
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } /> );
|
|
65
|
+
|
|
66
|
+
expect( screen.getByText( 'Desktop score' ) ).toBeInTheDocument();
|
|
67
|
+
expect( container.querySelector( '.gridicons-computer' ) ).toBeInTheDocument();
|
|
68
|
+
} );
|
|
69
|
+
|
|
70
|
+
it( 'renders previous scores when showPrevScores is true', () => {
|
|
71
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } /> );
|
|
72
|
+
|
|
73
|
+
const previousScoreContainer = container.querySelector( '.jb-score-bar__no_boost_score' );
|
|
74
|
+
|
|
75
|
+
expect( previousScoreContainer ).toBeInTheDocument();
|
|
76
|
+
expect( previousScoreContainer ).toHaveTextContent( '60' );
|
|
77
|
+
} );
|
|
78
|
+
|
|
79
|
+
it( 'does not render previous scores when showPrevScores is false', () => {
|
|
80
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } showPrevScores={ false } /> );
|
|
81
|
+
|
|
82
|
+
expect( container.querySelector( '.jb-score-bar__no_boost_score' ) ).not.toBeInTheDocument();
|
|
83
|
+
} );
|
|
84
|
+
|
|
85
|
+
it( 'renders the correct score bar class when score is < 50', () => {
|
|
86
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } score={ 40 } /> );
|
|
87
|
+
|
|
88
|
+
expect( container.querySelector( '.fill-bad' ) ).toBeInTheDocument();
|
|
89
|
+
} );
|
|
90
|
+
|
|
91
|
+
it( 'renders the correct score bar class when score is >= 50 and < 71', () => {
|
|
92
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } score={ 60 } /> );
|
|
93
|
+
|
|
94
|
+
expect( container.querySelector( '.fill-mediocre' ) ).toBeInTheDocument();
|
|
95
|
+
} );
|
|
96
|
+
|
|
97
|
+
it( 'renders the correct score bar class when score is > 70', () => {
|
|
98
|
+
const { container } = render( <BoostScoreBar { ...defaultProps } /> );
|
|
99
|
+
|
|
100
|
+
expect( container.querySelector( '.fill-good' ) ).toBeInTheDocument();
|
|
101
|
+
} );
|
|
102
|
+
} );
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Button as WPButton, Spinner } from '@wordpress/components';
|
|
5
|
+
import { Icon, external } from '@wordpress/icons';
|
|
6
|
+
import classNames from 'classnames';
|
|
7
|
+
import React, { forwardRef } from 'react';
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import styles from './style.module.scss';
|
|
12
|
+
import type { ButtonProps } from './types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Button component
|
|
16
|
+
*
|
|
17
|
+
* @param {ButtonProps} props - Component Props
|
|
18
|
+
* @returns {React.ReactNode} Rendered button
|
|
19
|
+
*/
|
|
20
|
+
const Button = forwardRef< HTMLInputElement, ButtonProps >( ( props, ref ) => {
|
|
21
|
+
const {
|
|
22
|
+
children,
|
|
23
|
+
variant = 'primary',
|
|
24
|
+
size = 'normal',
|
|
25
|
+
weight = 'bold',
|
|
26
|
+
icon,
|
|
27
|
+
iconSize,
|
|
28
|
+
disabled,
|
|
29
|
+
isDestructive,
|
|
30
|
+
isLoading,
|
|
31
|
+
isExternalLink,
|
|
32
|
+
className: propsClassName,
|
|
33
|
+
text,
|
|
34
|
+
fullWidth,
|
|
35
|
+
...componentProps
|
|
36
|
+
} = props;
|
|
37
|
+
|
|
38
|
+
const className = classNames( styles.button, propsClassName, {
|
|
39
|
+
[ styles.normal ]: size === 'normal',
|
|
40
|
+
[ styles.small ]: size === 'small',
|
|
41
|
+
[ styles.icon ]: Boolean( icon ),
|
|
42
|
+
[ styles.loading ]: isLoading,
|
|
43
|
+
[ styles.regular ]: weight === 'regular',
|
|
44
|
+
[ styles[ 'full-width' ] ]: fullWidth,
|
|
45
|
+
[ styles[ 'is-icon-button' ] ]: Boolean( icon ) && ! children,
|
|
46
|
+
} );
|
|
47
|
+
|
|
48
|
+
componentProps.ref = ref;
|
|
49
|
+
|
|
50
|
+
const externalIconSize = size === 'normal' ? 20 : 16;
|
|
51
|
+
const externalIcon = isExternalLink && (
|
|
52
|
+
<Icon size={ externalIconSize } icon={ external } className={ styles[ 'external-icon' ] } />
|
|
53
|
+
);
|
|
54
|
+
const externalTarget = isExternalLink ? '_blank' : undefined;
|
|
55
|
+
|
|
56
|
+
// ref https://github.com/WordPress/gutenberg/pull/44198
|
|
57
|
+
const hasChildren =
|
|
58
|
+
children?.[ 0 ] &&
|
|
59
|
+
children[ 0 ] !== null &&
|
|
60
|
+
// Tooltip should not considered as a child
|
|
61
|
+
children?.[ 0 ]?.props?.className !== 'components-tooltip';
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<WPButton
|
|
65
|
+
target={ externalTarget }
|
|
66
|
+
variant={ variant }
|
|
67
|
+
className={ classNames( className, { 'has-text': !! icon && hasChildren } ) }
|
|
68
|
+
icon={ ! isExternalLink ? icon : undefined }
|
|
69
|
+
iconSize={ iconSize }
|
|
70
|
+
disabled={ disabled }
|
|
71
|
+
aria-disabled={ disabled }
|
|
72
|
+
isDestructive={ isDestructive }
|
|
73
|
+
text={ text }
|
|
74
|
+
{ ...componentProps }
|
|
75
|
+
>
|
|
76
|
+
{ isLoading && <Spinner /> }
|
|
77
|
+
<span>{ children }</span>
|
|
78
|
+
{ externalIcon }
|
|
79
|
+
</WPButton>
|
|
80
|
+
);
|
|
81
|
+
} );
|
|
82
|
+
Button.displayName = 'Button';
|
|
83
|
+
|
|
84
|
+
export default Button;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Meta, Story, Canvas } from '@storybook/addon-docs';
|
|
2
|
+
import Button from '../index';
|
|
3
|
+
import * as ButtonStories from './index.stories';
|
|
4
|
+
|
|
5
|
+
<Meta of={ButtonStories} />
|
|
6
|
+
|
|
7
|
+
# Button
|
|
8
|
+
This is a component to create buttons and links across Jetpack.
|
|
9
|
+
|
|
10
|
+
## Props
|
|
11
|
+
|
|
12
|
+
Below is the current available props for `Button`.
|
|
13
|
+
|
|
14
|
+
### variant
|
|
15
|
+
|
|
16
|
+
It accepts 4 variant types: `primary`, `secondary`, `link`, `external-link`.
|
|
17
|
+
|
|
18
|
+
<Canvas withSource="open">
|
|
19
|
+
<Story id="js-packages-components-button--button-primary" />
|
|
20
|
+
<Story id="js-packages-components-button--button-secondary" />
|
|
21
|
+
<Story id="js-packages-components-button--button-link" />
|
|
22
|
+
<Story id="js-packages-components-button--button-external-link" />
|
|
23
|
+
</Canvas>
|
|
24
|
+
|
|
25
|
+
### size
|
|
26
|
+
|
|
27
|
+
It accepts 2 size types: `normal` and `small`.
|
|
28
|
+
|
|
29
|
+
<Canvas>
|
|
30
|
+
<Story id="js-packages-components-button--button-primary" />
|
|
31
|
+
<Button size="small">Jetpack Button</Button>
|
|
32
|
+
</Canvas>
|
|
33
|
+
|
|
34
|
+
### weight
|
|
35
|
+
|
|
36
|
+
It accepts 2 weight types: `bold` and `regular`. `bold` as default.
|
|
37
|
+
|
|
38
|
+
### icon
|
|
39
|
+
|
|
40
|
+
It accepts an SVG, Component or string.
|
|
41
|
+
|
|
42
|
+
You could use the ones from [@wordpress/icons](https://github.com/WordPress/gutenberg/blob/trunk/packages/icons/src/index.js).
|
|
43
|
+
|
|
44
|
+
<Canvas withSource="open">
|
|
45
|
+
<Story id="js-packages-components-button--icon" />
|
|
46
|
+
</Canvas>
|
|
47
|
+
|
|
48
|
+
### iconSize
|
|
49
|
+
|
|
50
|
+
It defines the size of the icon, it needs to be a number.
|
|
51
|
+
|
|
52
|
+
### disabled
|
|
53
|
+
|
|
54
|
+
Disables the button removing cursor-pointer effect.
|
|
55
|
+
|
|
56
|
+
<Canvas withSource="open">
|
|
57
|
+
<Story id="js-packages-components-button--disabled" />
|
|
58
|
+
</Canvas>
|
|
59
|
+
|
|
60
|
+
### isDestructive
|
|
61
|
+
|
|
62
|
+
Set button on destructive state, which changes the color to red.
|
|
63
|
+
|
|
64
|
+
<Canvas withSource="open">
|
|
65
|
+
<Story id="js-packages-components-button--destructive" />
|
|
66
|
+
</Canvas>
|
|
67
|
+
|
|
68
|
+
### isLoading
|
|
69
|
+
|
|
70
|
+
Set button on loading state, which applies a centered spinner.
|
|
71
|
+
|
|
72
|
+
<Canvas withSource="open">
|
|
73
|
+
<Story id="js-packages-components-button--loading" />
|
|
74
|
+
</Canvas>
|
|
75
|
+
|
|
76
|
+
### text
|
|
77
|
+
|
|
78
|
+
It applies a text before children, it could be used together or on its own.
|
|
79
|
+
|
|
80
|
+
<Canvas>
|
|
81
|
+
<Button text="My Text">My Children</Button>
|
|
82
|
+
</Canvas>
|
|
83
|
+
|
|
84
|
+
### fullWidth
|
|
85
|
+
|
|
86
|
+
Stretches the button to take up the full width of the container.
|
|
87
|
+
|
|
88
|
+
<Canvas withSource="open">
|
|
89
|
+
<Story id="js-packages-components-button--full-width" />
|
|
90
|
+
</Canvas>
|