@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.
Files changed (235) hide show
  1. package/.gitattributes +8 -0
  2. package/CHANGELOG.md +747 -0
  3. package/LICENSE.txt +357 -0
  4. package/README.md +11 -0
  5. package/SECURITY.md +38 -0
  6. package/components/action-button/index.jsx +70 -0
  7. package/components/action-button/stories/index.stories.jsx +38 -0
  8. package/components/action-button/style.module.scss +11 -0
  9. package/components/action-button/test/component.jsx +16 -0
  10. package/components/action-popover/index.tsx +105 -0
  11. package/components/action-popover/stories/index.stories.jsx +115 -0
  12. package/components/action-popover/stories/styles.module.scss +7 -0
  13. package/components/action-popover/styles.module.scss +49 -0
  14. package/components/action-popover/types.ts +20 -0
  15. package/components/admin-page/index.tsx +58 -0
  16. package/components/admin-page/stories/index.stories.tsx +35 -0
  17. package/components/admin-page/stories/style.module.scss +13 -0
  18. package/components/admin-page/style.module.scss +11 -0
  19. package/components/admin-page/types.ts +41 -0
  20. package/components/admin-section/basic/index.tsx +15 -0
  21. package/components/admin-section/basic/style.module.scss +3 -0
  22. package/components/admin-section/hero/index.tsx +15 -0
  23. package/components/admin-section/hero/style.module.scss +3 -0
  24. package/components/admin-section/stories/index.stories.tsx +60 -0
  25. package/components/admin-section/types.ts +6 -0
  26. package/components/alert/index.tsx +61 -0
  27. package/components/alert/stories/index.stories.jsx +24 -0
  28. package/components/alert/style.module.scss +43 -0
  29. package/components/automattic-byline-logo/README.md +16 -0
  30. package/components/automattic-byline-logo/index.tsx +38 -0
  31. package/components/automattic-byline-logo/stories/index.stories.tsx +20 -0
  32. package/components/automattic-byline-logo/test/component.tsx +28 -0
  33. package/components/automattic-byline-logo/types.ts +18 -0
  34. package/components/boost-score-bar/index.tsx +103 -0
  35. package/components/boost-score-bar/stories/index.stories.tsx +39 -0
  36. package/components/boost-score-bar/style.scss +184 -0
  37. package/components/boost-score-bar/test/component.tsx +102 -0
  38. package/components/boost-score-bar/types.ts +9 -0
  39. package/components/button/index.tsx +84 -0
  40. package/components/button/stories/index.mdx +90 -0
  41. package/components/button/stories/index.stories.tsx +400 -0
  42. package/components/button/stories/style.module.scss +20 -0
  43. package/components/button/style.module.scss +212 -0
  44. package/components/button/types.ts +21 -0
  45. package/components/contextual-upgrade-trigger/README.md +81 -0
  46. package/components/contextual-upgrade-trigger/index.tsx +44 -0
  47. package/components/contextual-upgrade-trigger/stories/index.stories.tsx +25 -0
  48. package/components/contextual-upgrade-trigger/style.module.scss +75 -0
  49. package/components/contextual-upgrade-trigger/types.ts +9 -0
  50. package/components/decorative-card/index.tsx +44 -0
  51. package/components/decorative-card/stories/index.stories.tsx +18 -0
  52. package/components/decorative-card/style.scss +116 -0
  53. package/components/decorative-card/types.ts +16 -0
  54. package/components/dialog/index.tsx +69 -0
  55. package/components/dialog/stories/boost.png +0 -0
  56. package/components/dialog/stories/declaration.d.ts +1 -0
  57. package/components/dialog/stories/index.stories.tsx +118 -0
  58. package/components/dialog/stories/js-components.components.dialog.mdx +62 -0
  59. package/components/dialog/stories/js-components.components.dialog.stories.js +37 -0
  60. package/components/dialog/stories/style.module.scss +21 -0
  61. package/components/dialog/style.module.scss +30 -0
  62. package/components/donut-meter/index.tsx +147 -0
  63. package/components/donut-meter/stories/index.stories.tsx +51 -0
  64. package/components/donut-meter/style.scss +11 -0
  65. package/components/donut-meter/test/component.tsx +24 -0
  66. package/components/gridicon/index.tsx +298 -0
  67. package/components/gridicon/stories/index.stories.tsx +18 -0
  68. package/components/gridicon/style.scss +16 -0
  69. package/components/gridicon/types.ts +48 -0
  70. package/components/icon-tooltip/index.tsx +96 -0
  71. package/components/icon-tooltip/stories/index.stories.tsx +108 -0
  72. package/components/icon-tooltip/stories/style.scss +36 -0
  73. package/components/icon-tooltip/style.scss +121 -0
  74. package/components/icon-tooltip/test/component.tsx +15 -0
  75. package/components/icon-tooltip/types.ts +76 -0
  76. package/components/icons/README.md +98 -0
  77. package/components/icons/index.tsx +369 -0
  78. package/components/icons/stories/index.stories.tsx +65 -0
  79. package/components/icons/stories/style.module.scss +33 -0
  80. package/components/icons/style.module.scss +40 -0
  81. package/components/icons/types.ts +38 -0
  82. package/components/indeterminate-progress-bar/index.tsx +28 -0
  83. package/components/indeterminate-progress-bar/stories/index.stories.tsx +14 -0
  84. package/components/indeterminate-progress-bar/style.module.scss +34 -0
  85. package/components/indeterminate-progress-bar/types.ts +6 -0
  86. package/components/jetpack-footer/README.md +21 -0
  87. package/components/jetpack-footer/index.tsx +94 -0
  88. package/components/jetpack-footer/stories/index.stories.tsx +40 -0
  89. package/components/jetpack-footer/style.scss +116 -0
  90. package/components/jetpack-footer/test/component.tsx +45 -0
  91. package/components/jetpack-footer/types.ts +36 -0
  92. package/components/jetpack-logo/README.md +20 -0
  93. package/components/jetpack-logo/index.tsx +46 -0
  94. package/components/jetpack-logo/stories/index.stories.tsx +20 -0
  95. package/components/jetpack-logo/test/component.tsx +16 -0
  96. package/components/jetpack-logo/types.ts +7 -0
  97. package/components/jetpack-search-logo/README.md +20 -0
  98. package/components/jetpack-search-logo/index.tsx +93 -0
  99. package/components/jetpack-search-logo/stories/index.stories.tsx +21 -0
  100. package/components/jetpack-search-logo/test/component.tsx +16 -0
  101. package/components/jetpack-search-logo/types.ts +7 -0
  102. package/components/jetpack-vaultpress-backup-logo/README.md +19 -0
  103. package/components/jetpack-vaultpress-backup-logo/index.tsx +113 -0
  104. package/components/jetpack-vaultpress-backup-logo/stories/index.stories.tsx +20 -0
  105. package/components/jetpack-vaultpress-backup-logo/test/component.tsx +18 -0
  106. package/components/jetpack-vaultpress-backup-logo/types.ts +6 -0
  107. package/components/jetpack-videopress-logo/README.md +19 -0
  108. package/components/jetpack-videopress-logo/index.tsx +93 -0
  109. package/components/jetpack-videopress-logo/stories/index.stories.tsx +20 -0
  110. package/components/jetpack-videopress-logo/test/component.tsx +16 -0
  111. package/components/jetpack-videopress-logo/types.tsx +6 -0
  112. package/components/layout/README.md +9 -0
  113. package/components/layout/breakpoints.module.scss +20 -0
  114. package/components/layout/col/README.md +81 -0
  115. package/components/layout/col/index.tsx +49 -0
  116. package/components/layout/col/style.module.scss +28 -0
  117. package/components/layout/container/README.md +77 -0
  118. package/components/layout/container/index.tsx +42 -0
  119. package/components/layout/container/style.module.scss +35 -0
  120. package/components/layout/stories/index.stories.tsx +145 -0
  121. package/components/layout/stories/styles.module.scss +22 -0
  122. package/components/layout/types.ts +55 -0
  123. package/components/layout/use-breakpoint-match/README.md +43 -0
  124. package/components/layout/use-breakpoint-match/declaration.d.ts +9 -0
  125. package/components/layout/use-breakpoint-match/index.ts +79 -0
  126. package/components/loading-placeholder/README.md +22 -0
  127. package/components/loading-placeholder/index.tsx +23 -0
  128. package/components/loading-placeholder/stories/index.stories.tsx +78 -0
  129. package/components/loading-placeholder/style.module.scss +18 -0
  130. package/components/notice/index.tsx +98 -0
  131. package/components/notice/stories/index.stories.jsx +90 -0
  132. package/components/notice/style.module.scss +107 -0
  133. package/components/number-format/README.md +25 -0
  134. package/components/number-format/index.ts +16 -0
  135. package/components/pricing-card/index.tsx +127 -0
  136. package/components/pricing-card/stories/index.stories.tsx +55 -0
  137. package/components/pricing-card/style.scss +112 -0
  138. package/components/pricing-card/test/component.tsx +89 -0
  139. package/components/pricing-card/types.ts +52 -0
  140. package/components/pricing-slider/index.tsx +53 -0
  141. package/components/pricing-slider/stories/index.stories.tsx +44 -0
  142. package/components/pricing-slider/style.scss +55 -0
  143. package/components/pricing-slider/test/component.tsx +14 -0
  144. package/components/pricing-slider/types.ts +58 -0
  145. package/components/pricing-table/index.tsx +200 -0
  146. package/components/pricing-table/stories/index.stories.tsx +74 -0
  147. package/components/pricing-table/styles.module.scss +160 -0
  148. package/components/pricing-table/test/component.tsx +41 -0
  149. package/components/pricing-table/types.ts +84 -0
  150. package/components/product-offer/icons-card.tsx +47 -0
  151. package/components/product-offer/index.tsx +115 -0
  152. package/components/product-offer/product-offer-header.tsx +23 -0
  153. package/components/product-offer/stories/index.stories.tsx +104 -0
  154. package/components/product-offer/style.module.scss +93 -0
  155. package/components/product-offer/types.ts +125 -0
  156. package/components/product-price/index.tsx +90 -0
  157. package/components/product-price/price.tsx +35 -0
  158. package/components/product-price/stories/index.stories.tsx +33 -0
  159. package/components/product-price/style.module.scss +69 -0
  160. package/components/product-price/test/component.tsx +26 -0
  161. package/components/product-price/types.ts +73 -0
  162. package/components/qr-code/Readme.md +5 -0
  163. package/components/qr-code/index.tsx +78 -0
  164. package/components/qr-code/stories/index.stories.tsx +32 -0
  165. package/components/record-meter-bar/index.tsx +135 -0
  166. package/components/record-meter-bar/stories/index.stories.tsx +39 -0
  167. package/components/record-meter-bar/style.scss +38 -0
  168. package/components/record-meter-bar/test/component.tsx +52 -0
  169. package/components/spinner/README.md +28 -0
  170. package/components/spinner/index.jsx +45 -0
  171. package/components/spinner/stories/index.stories.jsx +20 -0
  172. package/components/spinner/style.scss +31 -0
  173. package/components/spinner/test/component.jsx +17 -0
  174. package/components/split-button/index.tsx +39 -0
  175. package/components/split-button/stories/index.stories.tsx +35 -0
  176. package/components/split-button/style.module.scss +21 -0
  177. package/components/split-button/types.ts +14 -0
  178. package/components/stat-card/index.tsx +49 -0
  179. package/components/stat-card/stories/index.mdx +35 -0
  180. package/components/stat-card/stories/index.stories.tsx +41 -0
  181. package/components/stat-card/style.module.scss +49 -0
  182. package/components/stat-card/test/component.tsx +24 -0
  183. package/components/stat-card/types.ts +28 -0
  184. package/components/status/README.md +42 -0
  185. package/components/status/index.tsx +40 -0
  186. package/components/status/stories/index.stories.tsx +44 -0
  187. package/components/status/style.module.scss +72 -0
  188. package/components/terms-of-service/index.tsx +63 -0
  189. package/components/terms-of-service/styles.scss +10 -0
  190. package/components/terms-of-service/test/index.test.jsx +52 -0
  191. package/components/terms-of-service/types.ts +30 -0
  192. package/components/testimonials/index.tsx +58 -0
  193. package/components/testimonials/style.scss +127 -0
  194. package/components/testimonials/test/component.tsx +103 -0
  195. package/components/testimonials/testimonial.tsx +47 -0
  196. package/components/testimonials/types.ts +17 -0
  197. package/components/text/constants.ts +30 -0
  198. package/components/text/index.tsx +91 -0
  199. package/components/text/stories/headings.index.stories.tsx +80 -0
  200. package/components/text/stories/index.mdx +195 -0
  201. package/components/text/stories/index.stories.tsx +69 -0
  202. package/components/text/stories/style.module.scss +64 -0
  203. package/components/text/stories/title.index.stories.tsx +34 -0
  204. package/components/text/style.module.scss +125 -0
  205. package/components/text/types.ts +53 -0
  206. package/components/theme-provider/Readme.md +49 -0
  207. package/components/theme-provider/globals.module.scss +6 -0
  208. package/components/theme-provider/index.tsx +151 -0
  209. package/components/theme-provider/stories/index.stories.tsx +164 -0
  210. package/components/theme-provider/stories/style.module.scss +79 -0
  211. package/components/theme-provider/types.ts +25 -0
  212. package/components/toggle-control/README.md +5 -0
  213. package/components/toggle-control/index.tsx +67 -0
  214. package/components/toggle-control/stories/index.stories.tsx +83 -0
  215. package/components/toggle-control/styles.module.scss +41 -0
  216. package/components/zendesk-chat/README.md +26 -0
  217. package/components/zendesk-chat/constants.ts +2 -0
  218. package/components/zendesk-chat/index.tsx +22 -0
  219. package/components/zendesk-chat/stories/index.stories.tsx +15 -0
  220. package/components/zendesk-chat/test/component.tsx +16 -0
  221. package/components/zendesk-chat/types.ts +3 -0
  222. package/index.ts +69 -0
  223. package/lib/locale/index.ts +48 -0
  224. package/lib/locale/test/index.ts +21 -0
  225. package/package.json +80 -0
  226. package/tools/get-product-checkout-url/Readme.md +32 -0
  227. package/tools/get-product-checkout-url/index.ts +31 -0
  228. package/tools/jp-redirect/README.md +61 -0
  229. package/tools/jp-redirect/index.ts +62 -0
  230. package/tools/jp-redirect/test/index.tsx +89 -0
  231. package/tools/jp-redirect/types.ts +49 -0
  232. package/tools/pricing-utils/README.md +16 -0
  233. package/tools/pricing-utils/index.ts +11 -0
  234. package/tools/pricing-utils/test/index.ts +39 -0
  235. package/tools/pricing-utils/types.ts +12 -0
@@ -0,0 +1,20 @@
1
+ /* eslint-disable react/react-in-jsx-scope */
2
+ import React from 'react';
3
+ import Spinner from '../index.jsx';
4
+
5
+ export default {
6
+ title: 'JS Packages/Components/Spinner',
7
+ component: Spinner,
8
+ argTypes: {
9
+ color: { control: 'color' },
10
+ },
11
+ parameters: {
12
+ backgrounds: {
13
+ default: 'dark',
14
+ },
15
+ },
16
+ };
17
+
18
+ const Template = args => <Spinner { ...args } />;
19
+
20
+ export const _default = Template.bind( {} );
@@ -0,0 +1,31 @@
1
+ @keyframes rotate-spinner {
2
+ 100% {
3
+ transform: rotate( 360deg );
4
+ }
5
+ }
6
+
7
+ .jp-components-spinner {
8
+ display: flex;
9
+ align-items: center;
10
+ }
11
+
12
+ .jp-components-spinner__outer, .jp-components-spinner__inner {
13
+ margin: auto;
14
+ box-sizing: border-box;
15
+ border: 0.1em solid transparent;
16
+ border-radius: 50%;
17
+ animation: 3s linear infinite;
18
+ animation-name: rotate-spinner;
19
+ }
20
+
21
+ .jp-components-spinner__outer {
22
+ border-top-color: white;
23
+ }
24
+
25
+ .jp-components-spinner__inner {
26
+ width: 100%;
27
+ height: 100%;
28
+ border-top-color: white;
29
+ border-right-color: white;
30
+ opacity: 0.4;
31
+ }
@@ -0,0 +1,17 @@
1
+ import { render } from '@testing-library/react';
2
+ import Spinner from '../index';
3
+
4
+ describe( 'Spinner', () => {
5
+ const testProps = {
6
+ className: 'sample-classname',
7
+ };
8
+
9
+ describe( 'Render the Spinner component', () => {
10
+ const { container } = render( <Spinner { ...testProps } /> );
11
+
12
+ it( 'validate the class name', () => {
13
+ // eslint-disable-next-line testing-library/no-node-access
14
+ expect( container.firstChild ).toHaveClass( 'sample-classname' );
15
+ } );
16
+ } );
17
+ } );
@@ -0,0 +1,39 @@
1
+ import { ButtonGroup, Button, DropdownMenu } from '@wordpress/components';
2
+ import styles from './style.module.scss';
3
+ import { SplitButtonProps } from './types';
4
+ import type React from 'react';
5
+
6
+ const DownIcon = () => (
7
+ <svg width="15" height="9" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="10 9 4 7">
8
+ <path
9
+ fillRule="evenodd"
10
+ clipRule="evenodd"
11
+ d="m18.004 10.555-6.005 5.459-6.004-5.459 1.009-1.11 4.995 4.542 4.996-4.542 1.009 1.11Z"
12
+ />
13
+ </svg>
14
+ );
15
+
16
+ const SplitButton: React.FC< SplitButtonProps > = ( {
17
+ variant,
18
+ controls,
19
+ popoverProps,
20
+ toggleProps,
21
+ label,
22
+ ...buttonProps
23
+ } ) => {
24
+ return (
25
+ <ButtonGroup className={ styles[ 'split-button' ] }>
26
+ <Button variant={ variant } { ...buttonProps } className={ styles.button } />
27
+ <DropdownMenu
28
+ toggleProps={ { variant, className: styles.button, ...toggleProps } }
29
+ popoverProps={ { noArrow: false, ...popoverProps } }
30
+ icon={ <DownIcon /> }
31
+ disableOpenOnArrowDown={ true }
32
+ controls={ controls }
33
+ label={ label }
34
+ />
35
+ </ButtonGroup>
36
+ );
37
+ };
38
+
39
+ export default SplitButton;
@@ -0,0 +1,35 @@
1
+ import SplitButton from '../index';
2
+ import type { ComponentStory, ComponentMeta } from '@storybook/react';
3
+
4
+ export default {
5
+ title: 'JS Packages/Components/Split Button',
6
+ component: SplitButton,
7
+ argTypes: {
8
+ variant: { type: 'select', options: [ undefined, 'secondary', 'primary', 'tertiary', 'link' ] },
9
+ },
10
+ args: {
11
+ controls: [
12
+ {
13
+ title: 'Add to cart',
14
+ icon: null,
15
+ onClick: () => null,
16
+ },
17
+ {
18
+ title: 'Add to wishlist',
19
+ icon: null,
20
+ onClick: () => null,
21
+ },
22
+ ],
23
+ },
24
+ parameters: {
25
+ backgrounds: {
26
+ default: 'dark',
27
+ },
28
+ },
29
+ } as ComponentMeta< typeof SplitButton >;
30
+
31
+ const Template: ComponentStory< typeof SplitButton > = args => (
32
+ <SplitButton { ...args }>Buy now!</SplitButton>
33
+ );
34
+
35
+ export const _default = Template.bind( {} );
@@ -0,0 +1,21 @@
1
+ .split-button {
2
+ --actions-size: 28px;
3
+ display: flex;
4
+ height: var(--actions-size);
5
+ border-radius: var(--jp-border-radius);
6
+
7
+ & > .button:first-child {
8
+ border-radius: var(--jp-border-radius) 0 0 var(--jp-border-radius);
9
+ }
10
+
11
+ & > :global(.components-dropdown) > .button {
12
+ border-radius: 0 var(--jp-border-radius) var(--jp-border-radius) 0;
13
+ }
14
+ }
15
+
16
+ .button {
17
+ font-size: var(--font-body-extra-small);
18
+ border-radius: var(--jp-border-radius);
19
+ height: var(--actions-size);
20
+ line-height: var(--actions-size);
21
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { Button, DropdownMenu } from '@wordpress/components';
5
+
6
+ type AllowedDropdownMenuProps = Pick<
7
+ React.ComponentProps< typeof DropdownMenu >,
8
+ 'controls' | 'popoverProps' | 'toggleProps' | 'label'
9
+ >;
10
+
11
+ export type SplitButtonProps = Omit< React.ComponentProps< typeof Button >, 'controls' > &
12
+ AllowedDropdownMenuProps &
13
+ // make `controls` prop required
14
+ Required< Pick< AllowedDropdownMenuProps, 'controls' > >;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { Tooltip } from '@wordpress/components';
5
+ import classnames from 'classnames';
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import numberFormat from '../number-format';
10
+ import Text from '../text';
11
+ import styles from './style.module.scss';
12
+ import { StatCardProps } from './types';
13
+ import type React from 'react';
14
+
15
+ /**
16
+ * StatCard component
17
+ *
18
+ * @param {StatCardProps} props - Component props.
19
+ * @returns {React.ReactNode} - StatCard react component.
20
+ */
21
+ const StatCard = ( { className, icon, label, value, variant = 'square' }: StatCardProps ) => {
22
+ const formattedValue = numberFormat( value );
23
+ const compactValue = numberFormat( value, {
24
+ notation: 'compact',
25
+ compactDisplay: 'short',
26
+ } );
27
+
28
+ return (
29
+ <div className={ classnames( className, styles.wrapper, styles[ variant ] ) }>
30
+ <div className={ classnames( styles.icon ) }>{ icon }</div>
31
+ <div className={ classnames( styles.info ) }>
32
+ <Text className={ styles.label }>{ label }</Text>
33
+ { variant === 'square' ? (
34
+ <Tooltip text={ formattedValue } position="top center">
35
+ <Text variant="headline-small" className={ classnames( styles.value ) }>
36
+ { compactValue }
37
+ </Text>
38
+ </Tooltip>
39
+ ) : (
40
+ <Text variant="title-medium-semi-bold" className={ classnames( styles.value ) }>
41
+ { formattedValue }
42
+ </Text>
43
+ ) }
44
+ </div>
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default StatCard;
@@ -0,0 +1,35 @@
1
+ import { Meta, Story, Canvas } from '@storybook/addon-docs';
2
+ import StatCard from '../index';
3
+ import * as StatCardStories from './index.stories';
4
+
5
+ <Meta of={StatCardStories} />
6
+
7
+ # StatCard
8
+
9
+ Component that shows a stat value.
10
+
11
+ ## API
12
+
13
+ ### icon
14
+
15
+ - type: `JSX.Element`
16
+
17
+ ### label
18
+
19
+ - type: `string`
20
+
21
+ ### value
22
+
23
+ - type: `number`
24
+
25
+ ### variant
26
+
27
+ - type: `string`
28
+ - default: `"square"`
29
+
30
+ It accepts 2 values: `square` and `horizontal`.
31
+
32
+ <Canvas withSource="open">
33
+ <Story id="js-packages-components-stat-card--default" />
34
+ <Story id="js-packages-components-stat-card--horizontal" />
35
+ </Canvas>
@@ -0,0 +1,41 @@
1
+ import { Icon, postList } from '@wordpress/icons';
2
+ import StatCard from '..';
3
+ import type { ComponentStory, ComponentMeta } from '@storybook/react';
4
+
5
+ export default {
6
+ title: 'JS Packages/Components/Stat Card',
7
+ component: StatCard,
8
+ argTypes: {
9
+ variant: {
10
+ control: { type: 'radio' },
11
+ options: [ 'square', 'horizontal' ],
12
+ },
13
+ label: {
14
+ control: { type: 'text' },
15
+ },
16
+ value: {
17
+ control: { type: 'number' },
18
+ },
19
+ icon: {
20
+ table: {
21
+ disable: true,
22
+ },
23
+ },
24
+ },
25
+ } as ComponentMeta< typeof StatCard >;
26
+
27
+ const defaultArgs = {
28
+ icon: <Icon icon={ postList } color="green" />,
29
+ label: 'Posted this month',
30
+ value: 1806,
31
+ };
32
+
33
+ const Template: ComponentStory< typeof StatCard > = args => {
34
+ return <StatCard { ...args } />;
35
+ };
36
+
37
+ export const _default = Template.bind( {} );
38
+ _default.args = defaultArgs;
39
+
40
+ export const Horizontal = Template.bind( {} );
41
+ Horizontal.args = { ...defaultArgs, variant: 'horizontal' };
@@ -0,0 +1,49 @@
1
+ .wrapper {
2
+ background-color: var( --jp-white );
3
+ box-shadow: 0px 4px 40px rgba(0, 0, 0, 0.08);
4
+ border-radius: calc( var( --jp-border-radius ) * 2 ); // 8px;
5
+ display: flex;
6
+
7
+ &.horizontal {
8
+ align-items: center;
9
+ padding: calc( var( --spacing-base ) * 2 ); // 16px;
10
+ width: 358px;
11
+
12
+ .info {
13
+ display: flex;
14
+ align-items: center;
15
+ width: 100%;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .label {
20
+ margin: 0 calc( var( --spacing-base ) * 2 ); // 16px;
21
+ flex-grow: 1;
22
+ }
23
+ }
24
+
25
+ &.square {
26
+ --square-stat-vertical-spacing: calc( var( --spacing-base ) * 2 ); // 16px;
27
+ --square-stat-horizontal-spacing: calc( var( --spacing-base ) * 3 ); // 24px;
28
+ flex-direction: column;
29
+ justify-content: space-between;
30
+ height: 168px;
31
+ width: 168px;
32
+ padding: var( --square-stat-vertical-spacing ) var( --square-stat-horizontal-spacing );
33
+
34
+ .label {
35
+ margin-bottom: calc( var( --spacing-base ) / 2 ); // 4px;
36
+ }
37
+ }
38
+
39
+ .value {
40
+ overflow: hidden;
41
+ text-overflow: ellipsis;
42
+ }
43
+
44
+ .icon {
45
+ display: flex;
46
+ color: var( --jp-green-40 );
47
+ fill: var( --jp-green-40 );
48
+ }
49
+ }
@@ -0,0 +1,24 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import StatCard from '../index';
3
+
4
+ describe( 'StatCard', () => {
5
+ const testProps = {
6
+ icon: <div></div>,
7
+ label: 'Label',
8
+ value: 1806,
9
+ };
10
+
11
+ describe( 'when using the square variant', () => {
12
+ it( 'renders the compact value', () => {
13
+ render( <StatCard { ...testProps } variant="square" /> );
14
+ expect( screen.getByText( '1.8K' ) ).toBeInTheDocument();
15
+ } );
16
+ } );
17
+
18
+ describe( 'when using the horizontal variant', () => {
19
+ it( 'renders the full value', () => {
20
+ render( <StatCard { ...testProps } variant="horizontal" /> );
21
+ expect( screen.getByText( '1,806' ) ).toBeInTheDocument();
22
+ } );
23
+ } );
24
+ } );
@@ -0,0 +1,28 @@
1
+ export type StatCardProps = {
2
+ /**
3
+ * Custom className to be inserted.
4
+ */
5
+ className?: string;
6
+
7
+ /**
8
+ * The stat card icon.
9
+ */
10
+ icon: JSX.Element;
11
+
12
+ /**
13
+ * The stat label.
14
+ */
15
+ label: string;
16
+
17
+ /**
18
+ * The stat value.
19
+ */
20
+ value: number;
21
+
22
+ /**
23
+ * The component variant.
24
+ *
25
+ * @default 'square'
26
+ */
27
+ variant?: 'square' | 'horizontal';
28
+ };
@@ -0,0 +1,42 @@
1
+ = Status
2
+
3
+ A simple component to display a status indicator.
4
+
5
+ ## Usage
6
+
7
+ ```jsx
8
+ import { Status } from '@automattic/jetpack-components';
9
+
10
+ function MyComponent() {
11
+ return (
12
+ <>
13
+ { /* Default status is "inactive". */}
14
+ <Status />
15
+
16
+ { /* You can also pass a status prop to display a different status. */}
17
+ <Status status="active" />
18
+
19
+ { /* You can also pass a label prop to display a label beside the status indicator. */}
20
+ <Status status="error" label="Connection Error" />
21
+ </>
22
+ );
23
+ }
24
+ ```
25
+
26
+ ## Props
27
+
28
+ ### status
29
+
30
+ Optional. The status to display. It can be one of the following:
31
+
32
+ - `active`
33
+ - `inactive`
34
+ - `error`
35
+
36
+ Defaults to `inactive`.
37
+
38
+ ### label
39
+
40
+ Optional. The label to display beside the status indicator.
41
+
42
+ If none is provided, the name of the status will be used by default (i.e. "Active"). Pass an empty string to hide the label.
@@ -0,0 +1,40 @@
1
+ import { __ } from '@wordpress/i18n';
2
+ import classNames from 'classnames';
3
+ import Text from '../text';
4
+ import styles from './style.module.scss';
5
+
6
+ interface StatusProps {
7
+ status?: 'active' | 'error' | 'inactive' | 'action' | 'initializing';
8
+ label?: string;
9
+ className?: string;
10
+ }
11
+
12
+ const Status = ( { className, label, status = 'inactive' }: StatusProps ): JSX.Element => {
13
+ const defaultLabels: Record< string, string > = {
14
+ active: __( 'Active', 'jetpack' ),
15
+ error: __( 'Error', 'jetpack' ),
16
+ action: __( 'Action needed', 'jetpack' ),
17
+ inactive: __( 'Inactive', 'jetpack' ),
18
+ initializing: __( 'Setting up', 'jetpack' ),
19
+ };
20
+
21
+ return (
22
+ <Text
23
+ variant="body-extra-small"
24
+ className={ classNames(
25
+ styles.status,
26
+ {
27
+ [ styles[ `is-${ status }` ] ]: status,
28
+ },
29
+ className
30
+ ) }
31
+ >
32
+ <span className={ styles.status__indicator } />
33
+ <span className={ styles.status__label }>
34
+ { label || label === '' ? label : defaultLabels[ status ] }
35
+ </span>
36
+ </Text>
37
+ );
38
+ };
39
+
40
+ export default Status;
@@ -0,0 +1,44 @@
1
+ import Status from '..';
2
+
3
+ export default {
4
+ title: 'JS Packages/Components/Status',
5
+ component: Status,
6
+ parameters: {
7
+ layout: 'centered',
8
+ },
9
+ };
10
+
11
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
+ export const Active = args => {
13
+ return <Status status="active" />;
14
+ };
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
17
+ export const Error = args => {
18
+ return <Status status="error" />;
19
+ };
20
+
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ export const ActionNeeded = args => {
23
+ return <Status status="action" />;
24
+ };
25
+
26
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
27
+ export const Initializing = args => {
28
+ return <Status status="initializing" />;
29
+ };
30
+
31
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
32
+ export const Inactive = args => {
33
+ return <Status status="inactive" />;
34
+ };
35
+
36
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
37
+ export const CustomLabel = args => {
38
+ return <Status label="Code is poetry" />;
39
+ };
40
+
41
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
42
+ export const NoLabel = args => {
43
+ return <Status status="active" label="" />;
44
+ };
@@ -0,0 +1,72 @@
1
+ .status {
2
+ --spacing-base: 8px;
3
+ --wp-admin-border-width-focus: 1.5px;
4
+
5
+ align-items: center;
6
+ display: flex;
7
+ white-space: nowrap;
8
+
9
+ &__indicator {
10
+ background-color: var( --jp-gray-50 );
11
+ border-radius: 50%;
12
+ flex-shrink: 0;
13
+ height: 0.666em;
14
+ width: 0.666em;
15
+ }
16
+
17
+ &__label {
18
+ font-weight: 600;
19
+ line-height: 1.666;
20
+ margin-left: calc( var( --spacing-base ) / 2 ); // 4px
21
+ }
22
+
23
+ &.is-active {
24
+ span, a {
25
+ color: var(--jp-green-50);
26
+ }
27
+
28
+ .status__indicator {
29
+ background-color: var( --jp-green-50 );
30
+ }
31
+ }
32
+
33
+ &.is-inactive {
34
+ span, a {
35
+ color: var(--jp-gray-50);
36
+ }
37
+
38
+ .status__indicator {
39
+ background-color: var( --jp-gray-50 );
40
+ }
41
+ }
42
+
43
+ &.is-error {
44
+ span, a {
45
+ color: var(--jp-red-50);
46
+ }
47
+
48
+ .status__indicator {
49
+ background-color: var( --jp-red-50 );
50
+ }
51
+ }
52
+
53
+ &.is-action {
54
+ span, a {
55
+ color: var(--jp-yellow-30);
56
+ }
57
+
58
+ .status__indicator {
59
+ background-color: var( --jp-yellow-30 );
60
+ }
61
+ }
62
+
63
+ &.is-initializing {
64
+ span, a {
65
+ color: var(--jp-blue-40);
66
+ }
67
+
68
+ .status__indicator {
69
+ background-color: var( --jp-blue-40 );
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,63 @@
1
+ import { createInterpolateElement } from '@wordpress/element';
2
+ import { __, sprintf } from '@wordpress/i18n';
3
+ import classNames from 'classnames';
4
+ import { getRedirectUrl } from '../../../components';
5
+ import Text from '../text';
6
+ import type { TermsOfServiceProps } from './types';
7
+ import './styles.scss';
8
+
9
+ const TermsOfService: React.FC< TermsOfServiceProps > = ( {
10
+ className,
11
+ multipleButtons,
12
+ agreeButtonLabel,
13
+ } ) => (
14
+ <Text className={ classNames( className, 'terms-of-service' ) }>
15
+ { multipleButtons ? (
16
+ <MultipleButtonsText />
17
+ ) : (
18
+ <SingleButtonText agreeButtonLabel={ agreeButtonLabel } />
19
+ ) }
20
+ </Text>
21
+ );
22
+
23
+ const MultipleButtonsText = () =>
24
+ createInterpolateElement(
25
+ __(
26
+ 'By clicking the buttons above, you agree to our <tosLink>Terms of Service</tosLink> and to <shareDetailsLink>share details</shareDetailsLink> with WordPress.com.',
27
+ 'jetpack'
28
+ ),
29
+ {
30
+ tosLink: <Link slug="wpcom-tos" />,
31
+ shareDetailsLink: <Link slug="jetpack-support-what-data-does-jetpack-sync" />,
32
+ }
33
+ );
34
+
35
+ const SingleButtonText = ( { agreeButtonLabel } ) =>
36
+ createInterpolateElement(
37
+ sprintf(
38
+ /* translators: %s is a button label */
39
+ __(
40
+ 'By clicking the <strong>%s</strong> button, you agree to our <tosLink>Terms of Service</tosLink> and to <shareDetailsLink>share details</shareDetailsLink> with WordPress.com.',
41
+ 'jetpack'
42
+ ),
43
+ agreeButtonLabel
44
+ ),
45
+ {
46
+ strong: <strong />,
47
+ tosLink: <Link slug="wpcom-tos" />,
48
+ shareDetailsLink: <Link slug="jetpack-support-what-data-does-jetpack-sync" />,
49
+ }
50
+ );
51
+
52
+ const Link: React.FC< { slug: string; children?: React.ReactNode } > = ( { slug, children } ) => (
53
+ <a
54
+ className="terms-of-service__link"
55
+ href={ getRedirectUrl( slug ) }
56
+ rel="noopener noreferrer"
57
+ target="_blank"
58
+ >
59
+ { children }
60
+ </a>
61
+ );
62
+
63
+ export default TermsOfService;
@@ -0,0 +1,10 @@
1
+ .terms-of-service {
2
+ font-size: var(--font-body);
3
+ color: var(--jp-black);
4
+
5
+ .terms-of-service__link {
6
+ color: var(--jp-green-50);
7
+ white-space: nowrap;
8
+ text-decoration: underline;
9
+ }
10
+ }