@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,42 @@
1
+ import classNames from 'classnames';
2
+ import { useMemo } from 'react';
3
+ import { ContainerProps } from '../types';
4
+ import styles from './style.module.scss';
5
+ import type React from 'react';
6
+
7
+ /**
8
+ * JP Container
9
+ *
10
+ * @param {ContainerProps} props - Component properties.
11
+ * @returns {React.ReactElement} Container component.
12
+ */
13
+ const Container: React.FC< ContainerProps > = ( {
14
+ children,
15
+ fluid = false,
16
+ className,
17
+ horizontalGap = 1,
18
+ horizontalSpacing = 1,
19
+ } ) => {
20
+ const containerStyle = useMemo( () => {
21
+ const padding = `calc( var(--horizontal-spacing) * ${ horizontalSpacing } )`;
22
+ const rowGap = `calc( var(--horizontal-spacing) * ${ horizontalGap } )`;
23
+
24
+ return {
25
+ paddingTop: padding,
26
+ paddingBottom: padding,
27
+ rowGap,
28
+ };
29
+ }, [ horizontalGap, horizontalSpacing ] );
30
+
31
+ const containerClassName = classNames( className, styles.container, {
32
+ [ styles.fluid ]: fluid,
33
+ } );
34
+
35
+ return (
36
+ <div className={ containerClassName } style={ containerStyle }>
37
+ { children }
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default Container;
@@ -0,0 +1,35 @@
1
+ @use "sass:map";
2
+ @import "../breakpoints.module.scss";
3
+
4
+ @mixin container($size) {
5
+ $paddings: ("sm": "16px", "md": "18px", "lg": "24px");
6
+ $padding: map.get($paddings, #{$size});
7
+
8
+ @include media(#{$size}) using ($columns) {
9
+ padding: 0 #{$padding};
10
+ grid-template-columns: repeat( #{$columns}, minmax(0, 1fr) );
11
+ }
12
+ }
13
+
14
+ .container {
15
+ --max-container-width: 1128px;
16
+ // vertical spacing
17
+ --vertical-gutter: 24px;
18
+ // horizontal spacing
19
+ --horizontal-spacing: 8px;
20
+
21
+ display: grid;
22
+ column-gap: var(--vertical-gutter);
23
+ max-width: var(--max-container-width);
24
+ margin: 0 auto;
25
+ width: 100%;
26
+
27
+ @include container( "sm" );
28
+ @include container( "md" );
29
+ @include container( "lg" );
30
+
31
+ &.fluid {
32
+ max-width: none;
33
+ padding: unset;
34
+ }
35
+ }
@@ -0,0 +1,145 @@
1
+ import Text from '../../text';
2
+ import Col from '../col';
3
+ import Container from '../container';
4
+ import useBreakpointMatch from '../use-breakpoint-match';
5
+ import styles from './styles.module.scss';
6
+
7
+ const Layout = ( { items, fluid, horizontalGap, horizontalSpacing } ) => {
8
+ return (
9
+ <Container
10
+ className={ styles.container }
11
+ horizontalSpacing={ horizontalSpacing }
12
+ fluid={ fluid }
13
+ horizontalGap={ horizontalGap }
14
+ >
15
+ { items.map( ( { sm, lg, md }, idx ) => {
16
+ const smText = Number.isInteger( sm?.start ) ? JSON.stringify( sm ) : sm;
17
+ const mdText = Number.isInteger( md?.start ) ? JSON.stringify( md ) : md;
18
+ const lgText = Number.isInteger( lg?.start ) ? JSON.stringify( lg ) : lg;
19
+
20
+ return (
21
+ <Col
22
+ sm={ sm }
23
+ md={ md }
24
+ lg={ lg }
25
+ className={ styles.col }
26
+ key={ `${ smText }${ mdText }${ lgText }${ idx }` }
27
+ >
28
+ { sm ? `sm=${ smText } ` : '' }
29
+ { md ? `md=${ mdText } ` : '' }
30
+ { lg ? `lg=${ lgText } ` : '' }
31
+ </Col>
32
+ );
33
+ } ) }
34
+ <Col>
35
+ <Container fluid horizontalSpacing={ 0 } horizontalGap={ 1 }>
36
+ <Col className={ styles.col }>Composition Example</Col>
37
+ <Col className={ styles.col }>Composition Example</Col>
38
+ </Container>
39
+ </Col>
40
+ </Container>
41
+ );
42
+ };
43
+
44
+ export default {
45
+ title: 'JS Packages/Components/Layout',
46
+ component: Layout,
47
+ };
48
+
49
+ const Template = args => <Layout { ...args } />;
50
+ export const Default = Template.bind( {} );
51
+ Default.args = {
52
+ fluid: false,
53
+ horizontalSpacing: 10,
54
+ horizontalGap: 5,
55
+ items: [
56
+ {
57
+ sm: 2,
58
+ md: 5,
59
+ lg: 4,
60
+ },
61
+ {
62
+ sm: 2,
63
+ md: 3,
64
+ lg: { start: 6, end: 12 },
65
+ },
66
+ {
67
+ sm: 2,
68
+ md: 3,
69
+ lg: 6,
70
+ },
71
+ {
72
+ sm: 2,
73
+ md: 5,
74
+ lg: { start: 9, end: 12 },
75
+ },
76
+ {
77
+ sm: 2,
78
+ md: 5,
79
+ lg: 4,
80
+ },
81
+ {
82
+ sm: 2,
83
+ md: 3,
84
+ lg: 8,
85
+ },
86
+ ],
87
+ };
88
+
89
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
90
+ export const BreakpointMatch = args => {
91
+ const [ isSm, isGtSm, isMd, isLtOrMd, isLtMd, isGtOrMd, isGtMd, isLessThanLg, isLg ] =
92
+ useBreakpointMatch(
93
+ [ 'sm', 'sm', 'md', 'md', 'md', 'md', 'md', 'lg', 'lg' ],
94
+ [ null, '>', null, '<=', '<', '>=', '>', '<', null ]
95
+ );
96
+
97
+ return (
98
+ <Container>
99
+ { /* SMALL */ }
100
+ <Text variant="headline-small">Small</Text>
101
+ <Col>
102
+ <Text variant="title-small">Is Small</Text>
103
+ <Text className={ isSm ? styles.yes : styles.no }>{ isSm ? 'Yes' : 'False' }</Text>
104
+ </Col>
105
+ <Col>
106
+ <Text variant="title-small">Is greater than Small</Text>
107
+ <Text className={ isGtSm ? styles.yes : styles.no }>{ isGtSm ? 'Yes' : 'False' }</Text>
108
+ </Col>
109
+ { /* MEDIUM */ }
110
+ <Text variant="headline-small">Medium</Text>
111
+ <Col>
112
+ <Text variant="title-small">Is Medium</Text>
113
+ <Text className={ isMd ? styles.yes : styles.no }>{ isMd ? 'Yes' : 'False' }</Text>
114
+ </Col>
115
+ <Col>
116
+ <Text variant="title-small">Is less then Medium</Text>
117
+ <Text className={ isLtMd ? styles.yes : styles.no }>{ isLtMd ? 'Yes' : 'False' }</Text>
118
+ </Col>
119
+ <Col>
120
+ <Text variant="title-small">Is less then OR Medium</Text>
121
+ <Text className={ isLtOrMd ? styles.yes : styles.no }>{ isLtOrMd ? 'Yes' : 'False' }</Text>
122
+ </Col>
123
+ <Col>
124
+ <Text variant="title-small">Is greater then Medium</Text>
125
+ <Text className={ isGtMd ? styles.yes : styles.no }>{ isGtMd ? 'Yes' : 'False' }</Text>
126
+ </Col>
127
+ <Col>
128
+ <Text variant="title-small">Is greater then OR Medium</Text>
129
+ <Text className={ isGtOrMd ? styles.yes : styles.no }>{ isGtOrMd ? 'Yes' : 'False' }</Text>
130
+ </Col>
131
+ { /* LARGE */ }
132
+ <Text variant="headline-small">Large</Text>
133
+ <Col>
134
+ <Text variant="title-small">Is Large</Text>
135
+ <Text className={ isLg ? styles.yes : styles.no }>{ isLg ? 'Yes' : 'False' }</Text>
136
+ </Col>
137
+ <Col>
138
+ <Text variant="title-small">Is less than Large</Text>
139
+ <Text className={ isLessThanLg ? styles.yes : styles.no }>
140
+ { isLessThanLg ? 'Yes' : 'False' }
141
+ </Text>
142
+ </Col>
143
+ </Container>
144
+ );
145
+ };
@@ -0,0 +1,22 @@
1
+ .container {
2
+ background: var(--jp-gray-50);
3
+ }
4
+
5
+ .col {
6
+ padding: 20px;
7
+ background: var(--jp-gray-80);
8
+ font-size: 1rem;
9
+ color: var(--jp-white-off);
10
+ }
11
+
12
+ .yes {
13
+ padding: var(--spacing-base);
14
+ background-color: var(--jp-green-0);
15
+ border: 1px solid var(--jp-green-50);
16
+ }
17
+
18
+ .no {
19
+ padding: var(--spacing-base);
20
+ background-color: var(--jp-red-0);
21
+ border: 1px solid var(--jp-red-50);
22
+ }
@@ -0,0 +1,55 @@
1
+ type ColSpan = number | { start: number; end: number };
2
+
3
+ export type ColProps = {
4
+ /**
5
+ * Custom className to be inserted.
6
+ */
7
+ className?: string;
8
+
9
+ /**
10
+ * Colspan for small viewport. Needs to be an integer.
11
+ */
12
+ sm?: ColSpan;
13
+
14
+ /**
15
+ * Colstart for medium viewport. Needs to be an integer.
16
+ */
17
+ md?: ColSpan;
18
+
19
+ /**
20
+ * Colstart for large viewport. Needs to be an integer.
21
+ */
22
+ lg?: ColSpan;
23
+
24
+ /**
25
+ * Children to be inserted.
26
+ */
27
+ children?: React.ReactNode;
28
+ };
29
+
30
+ export type ContainerProps = {
31
+ /**
32
+ * Make container not having a max width.
33
+ */
34
+ fluid?: boolean;
35
+
36
+ /**
37
+ * Custom className to be inserted.
38
+ */
39
+ className?: string;
40
+
41
+ /**
42
+ * Number of spacing (top / bottom), it gets mutiplied by 8px. Needs to be an integer
43
+ */
44
+ horizontalSpacing?: number;
45
+
46
+ /**
47
+ * Number of gap betwen rows, it gets multipled by 8px. Needs to be an integer
48
+ */
49
+ horizontalGap?: number;
50
+
51
+ /**
52
+ * Children to be inserted.
53
+ */
54
+ children?: React.ReactNode;
55
+ };
@@ -0,0 +1,43 @@
1
+ # useBreakpointMatch
2
+
3
+ Utility to match against breakpoints.
4
+
5
+ [ Storybook Reference ](https://automattic.github.io/jetpack-storybook/?path=/story/js-packages-components-layout--breakpoint-match)
6
+
7
+ ## Usage
8
+
9
+ ```jsx
10
+ import { useBreakpointMatch } from '@automattic/jetpack-components';
11
+ const [ isLg ] = useBreakpointMatch('lg')
12
+ return isLg && <Component />
13
+ ```
14
+
15
+ ## Parameters
16
+
17
+ ### breakpointToMatch
18
+
19
+ Single or Array of breakpoints to match against.
20
+
21
+ - Type: `String`|`Array<String>`
22
+ - Required: `true`
23
+
24
+ ```javascript
25
+ useBreakpointMatch('lg');
26
+ useBreakpointMatch([ 'lg', 'sm' ]);
27
+ ```
28
+
29
+ ### operator
30
+
31
+ A Single or Array of operators to match less, equal, or greater than the breakpoint.
32
+
33
+ In Array, it matches against the same index from breakpoint.
34
+
35
+ - Type: `String`|`Array<String>`
36
+ - Required: `false`
37
+
38
+ #### Example
39
+
40
+ ```javascript
41
+ useBreakpointMatch('md', '<=');
42
+ useBreakpointMatch([ 'lg', 'sm' ], ['<', '>']);
43
+ ```
@@ -0,0 +1,9 @@
1
+ declare module '*.module.css' {
2
+ const classes: { [ key: string ]: string };
3
+ export default classes;
4
+ }
5
+
6
+ declare module '*.module.scss' {
7
+ const classes: { [ key: string ]: string };
8
+ export default classes;
9
+ }
@@ -0,0 +1,79 @@
1
+ import { useMediaQuery } from '@wordpress/compose';
2
+ import breakpointsValues from '../breakpoints.module.scss';
3
+
4
+ const BREAKPOINTS = [ 'sm', 'md', 'lg' ] as const;
5
+
6
+ type Breakpoints = ( typeof BREAKPOINTS )[ number ];
7
+
8
+ type Operators = '<' | '<=' | '>' | '>=';
9
+
10
+ type Matches = { sm: boolean; md: boolean; lg: boolean };
11
+
12
+ const getMediaByOperator = (
13
+ breakpoint: Breakpoints,
14
+ operator: Operators,
15
+ matches: Matches
16
+ ): boolean => {
17
+ const breakpointIndex = BREAKPOINTS.indexOf( breakpoint );
18
+ const breakpointIndexPlusOne = breakpointIndex + 1;
19
+ const isEqual = operator.includes( '=' );
20
+
21
+ let allNeededBreakpoints = [];
22
+
23
+ if ( operator.startsWith( '<' ) ) {
24
+ allNeededBreakpoints = BREAKPOINTS.slice(
25
+ 0,
26
+ isEqual ? breakpointIndexPlusOne : breakpointIndex
27
+ );
28
+ }
29
+
30
+ if ( operator.startsWith( '>' ) ) {
31
+ allNeededBreakpoints = BREAKPOINTS.slice( isEqual ? breakpointIndex : breakpointIndexPlusOne );
32
+ }
33
+
34
+ return allNeededBreakpoints?.length
35
+ ? allNeededBreakpoints.some( brk => matches[ brk ] )
36
+ : matches[ breakpoint ];
37
+ };
38
+
39
+ /**
40
+ * Hook to match if current viewport is equal, greater or less than expected breakpoint
41
+ *
42
+ * @param {(Breakpoints | Array< Breakpoints >)} breakpointToMatch - An single breakpoint or list of breakpoints to match.
43
+ * @param {(Operators | Array< Operators >)} operatorToMatch - An single operator or list of them. It should follow the same sequence than breakpoints.
44
+ * @returns {Array<boolean>} - List of matches, following breakpoints sequence.
45
+ * @example
46
+ *
47
+ * ```es6
48
+ * useBreakpointMatch('sm')
49
+ * useBreakpointMatch('lg', '<')
50
+ * useBreakpointMatch([ 'lg', 'sm' ], [ '<', null ])
51
+ * ```
52
+ */
53
+ const useBreakpointMatch = (
54
+ breakpointToMatch: Breakpoints | Array< Breakpoints >,
55
+ operatorToMatch?: Operators | Array< Operators >
56
+ ) => {
57
+ const breakpoints: Array< Breakpoints > = Array.isArray( breakpointToMatch )
58
+ ? breakpointToMatch
59
+ : [ breakpointToMatch ];
60
+
61
+ const operators: Array< Operators > = Array.isArray( operatorToMatch )
62
+ ? operatorToMatch
63
+ : [ operatorToMatch ];
64
+
65
+ const [ smKey, mdKey, lgKey ] = BREAKPOINTS;
66
+
67
+ const sm = useMediaQuery( breakpointsValues[ smKey ] );
68
+ const md = useMediaQuery( breakpointsValues[ mdKey ] );
69
+ const lg = useMediaQuery( breakpointsValues[ lgKey ] );
70
+
71
+ const matches: Matches = { sm, md, lg };
72
+
73
+ return breakpoints.map( ( breakpoint, idx ) => {
74
+ const operator = operators[ idx ];
75
+ return operator ? getMediaByOperator( breakpoint, operator, matches ) : matches[ breakpoint ];
76
+ } );
77
+ };
78
+
79
+ export default useBreakpointMatch;
@@ -0,0 +1,22 @@
1
+ LoadingPlaceholder
2
+ =========
3
+
4
+ This component is used in case we want to create a skeleton loader.
5
+
6
+ ## General Usage:
7
+
8
+ ```js
9
+ import { LoadingPlaceholder } from '@automattic/jetpack-components';
10
+ render() {
11
+ return (
12
+ <Placeholder width="60%" height={ 30 } />
13
+ );
14
+ }
15
+ ```
16
+
17
+ ## Props
18
+
19
+ - `width`: an optional placeholder width
20
+ - `height`: an optional placeholder height.
21
+ - `children`: an optional react child
22
+ - `className`: an optional class name.
@@ -0,0 +1,23 @@
1
+ import classNames from 'classnames';
2
+ import React from 'react';
3
+ import styles from './style.module.scss';
4
+
5
+ const LoadingPlaceholder = ( {
6
+ children = null,
7
+ width = null,
8
+ height = null,
9
+ className = '',
10
+ }: {
11
+ children?: React.ReactNode;
12
+ width?: number | string;
13
+ height?: number;
14
+ className?: string;
15
+ } ) => {
16
+ return (
17
+ <div className={ classNames( styles.placeholder, className ) } style={ { width, height } }>
18
+ { children }
19
+ </div>
20
+ );
21
+ };
22
+
23
+ export default LoadingPlaceholder;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import LoadingPlaceholder from '..';
5
+ /**
6
+ * Types
7
+ */
8
+ import type { ComponentStory, ComponentMeta } from '@storybook/react';
9
+
10
+ export default {
11
+ title: 'JS Packages/Components/Loading Placeholder',
12
+ component: LoadingPlaceholder,
13
+ parameters: {
14
+ layout: 'centered',
15
+ },
16
+ } as ComponentMeta< typeof LoadingPlaceholder >;
17
+
18
+ const Template: ComponentStory< typeof LoadingPlaceholder > = args => (
19
+ <LoadingPlaceholder { ...args } />
20
+ );
21
+
22
+ export const Fluid = Template.bind( {} );
23
+ Fluid.decorators = [
24
+ Story => (
25
+ <div
26
+ style={ {
27
+ width: '200px',
28
+ height: '300px',
29
+ } }
30
+ >
31
+ <Story />
32
+ </div>
33
+ ),
34
+ ];
35
+
36
+ Fluid.argTypes = {
37
+ width: {
38
+ table: {
39
+ disable: true,
40
+ },
41
+ },
42
+ height: {
43
+ table: {
44
+ disable: true,
45
+ },
46
+ },
47
+ };
48
+
49
+ Fluid.args = {
50
+ width: null,
51
+ height: null,
52
+ };
53
+
54
+ export const Fixed = Template.bind( {} );
55
+
56
+ Fixed.args = {
57
+ width: 200,
58
+ height: 300,
59
+ };
60
+
61
+ Fixed.argTypes = {
62
+ width: {
63
+ control: {
64
+ type: 'range',
65
+ min: 0,
66
+ max: 500,
67
+ step: 1,
68
+ },
69
+ },
70
+ height: {
71
+ control: {
72
+ type: 'range',
73
+ min: 0,
74
+ max: 500,
75
+ step: 1,
76
+ },
77
+ },
78
+ };
@@ -0,0 +1,18 @@
1
+ @keyframes pulse {
2
+ 0% {
3
+ opacity: .6;
4
+ }
5
+ 50% {
6
+ opacity: 1;
7
+ }
8
+ 100% {
9
+ opacity: .6;
10
+ }
11
+ }
12
+
13
+ .placeholder {
14
+ background-color: var( --jp-gray );
15
+ animation: pulse 1.5s infinite;
16
+ height: 100%;
17
+ width: 100%;
18
+ }
@@ -0,0 +1,98 @@
1
+ import { Icon, warning, info, check, close } from '@wordpress/icons';
2
+ import classNames from 'classnames';
3
+ import React from 'react';
4
+ import styles from './style.module.scss';
5
+
6
+ type NoticeProps = {
7
+ /** The severity of the alert. */
8
+ level: 'error' | 'warning' | 'info' | 'success';
9
+
10
+ /** The title of the notice */
11
+ title: string;
12
+
13
+ /** A list of action elements to show across the bottom */
14
+ actions?: React.ReactNode[];
15
+
16
+ /** Hide close button */
17
+ hideCloseButton?: boolean;
18
+
19
+ /** Method to call when the close button is clicked */
20
+ onClose?: () => void;
21
+
22
+ /** Children to be rendered inside the alert. */
23
+ children: React.ReactNode;
24
+ };
25
+
26
+ const getIconByLevel = ( level: NoticeProps[ 'level' ] ) => {
27
+ switch ( level ) {
28
+ case 'error':
29
+ return warning;
30
+ case 'warning':
31
+ return warning;
32
+ case 'info':
33
+ return info;
34
+ case 'success':
35
+ return check;
36
+ default:
37
+ return warning;
38
+ }
39
+ };
40
+
41
+ /**
42
+ * Notice component
43
+ *
44
+ * @param {object} props - The component properties.
45
+ * @param {string} props.level - The notice level: error, warning, info, success.
46
+ * @param {boolean} props.hideCloseButton - Whether to hide the close button.
47
+ * @param {Function} props.onClose - The function to call when the close button is clicked.
48
+ * @param {string} props.title - The title of the notice.
49
+ * @param {React.ReactNode[]} props.actions - Actions to show across the bottom of the bar.
50
+ * @param {React.Component} props.children - The notice content.
51
+ * @returns {React.ReactElement} The `Notice` component.
52
+ */
53
+ const Notice: React.FC< NoticeProps > = ( {
54
+ level,
55
+ title,
56
+ children,
57
+ actions,
58
+ hideCloseButton,
59
+ onClose,
60
+ } ) => {
61
+ const classes = classNames( styles.container, styles[ `is-${ level }` ] );
62
+
63
+ return (
64
+ <div className={ classes }>
65
+ <div className={ styles[ 'icon-wrapper' ] }>
66
+ <Icon icon={ getIconByLevel( level ) } className={ styles.icon } />
67
+ </div>
68
+
69
+ <div className={ styles[ 'main-content' ] }>
70
+ <div className={ styles.title }>{ title }</div>
71
+ { children }
72
+
73
+ { actions && actions.length > 0 && (
74
+ <div className={ styles[ 'action-bar' ] }>
75
+ { actions.map( ( action, index ) => (
76
+ <div key={ index } className={ styles.action }>
77
+ { action }
78
+ </div>
79
+ ) ) }
80
+ </div>
81
+ ) }
82
+ </div>
83
+
84
+ { ! hideCloseButton && (
85
+ <button aria-label="close" className={ styles[ 'close-button' ] } onClick={ onClose }>
86
+ <Icon icon={ close } />
87
+ </button>
88
+ ) }
89
+ </div>
90
+ );
91
+ };
92
+
93
+ Notice.defaultProps = {
94
+ level: 'info',
95
+ hideCloseButton: false,
96
+ };
97
+
98
+ export default Notice;