@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,151 @@
1
+ import React, { useLayoutEffect, useRef } from 'react';
2
+ import styles from './globals.module.scss';
3
+ import { ThemeInstance, ThemeProviderProps } from './types';
4
+
5
+ export const typography = {
6
+ // Headline
7
+ '--font-headline-medium': '48px',
8
+ '--font-headline-small': '36px',
9
+ '--font-title-medium': '24px',
10
+ '--font-title-small': '20px',
11
+ '--font-body': '16px',
12
+ '--font-body-small': '14px',
13
+ '--font-body-extra-small': '12px',
14
+ // Deprecated
15
+ '--font-title-large': 'var(--font-headline-small)',
16
+ '--font-label': 'var(--font-body-extra-small)',
17
+ };
18
+
19
+ export const colors = {
20
+ '--jp-black': '#000000',
21
+ '--jp-black-80': '#2c3338',
22
+ // White
23
+ '--jp-white': '#ffffff',
24
+ '--jp-white-off': '#f9f9f6',
25
+ // Gray
26
+ '--jp-gray': '#dcdcde',
27
+ '--jp-gray-0': '#F6F7F7',
28
+ '--jp-gray-10': '#C3C4C7',
29
+ '--jp-gray-20': '#A7AAAD',
30
+ '--jp-gray-40': '#787C82',
31
+ '--jp-gray-50': '#646970',
32
+ '--jp-gray-60': '#50575E',
33
+ '--jp-gray-70': '#3C434A',
34
+ '--jp-gray-80': '#2C3338',
35
+ '--jp-gray-90': '#1d2327',
36
+ '--jp-gray-off': '#e2e2df',
37
+ // Red
38
+ '--jp-red-0': '#F7EBEC',
39
+ '--jp-red-5': '#FACFD2',
40
+ '--jp-red-40': '#E65054',
41
+ '--jp-red-50': '#D63638',
42
+ '--jp-red-60': '#B32D2E',
43
+ '--jp-red-70': '#8A2424',
44
+ '--jp-red-80': '#691C1C',
45
+ '--jp-red': '#d63639',
46
+ // Yellow
47
+ '--jp-yellow-5': '#F5E6B3',
48
+ '--jp-yellow-10': '#F2CF75',
49
+ '--jp-yellow-20': '#F0C930',
50
+ '--jp-yellow-30': '#DEB100',
51
+ '--jp-yellow-40': '#C08C00',
52
+ '--jp-yellow-50': '#9D6E00',
53
+ '--jp-yellow-60': '#7D5600',
54
+ // Blue
55
+ '--jp-blue-20': '#68B3E8',
56
+ '--jp-blue-40': '#1689DB',
57
+ // Pink
58
+ '--jp-pink': '#C9356E',
59
+ // Green
60
+ '--jp-green-0': '#f0f2eb',
61
+ '--jp-green-5': '#d0e6b8',
62
+ '--jp-green-10': '#9dd977',
63
+ '--jp-green-20': '#64ca43',
64
+ '--jp-green-30': '#2fb41f',
65
+ '--jp-green-40': '#069e08',
66
+ '--jp-green-50': '#008710',
67
+ '--jp-green-60': '#007117',
68
+ '--jp-green-70': '#005b18',
69
+ '--jp-green-80': '#004515',
70
+ '--jp-green-90': '#003010',
71
+ '--jp-green-100': '#001c09',
72
+ '--jp-green': '#069e08',
73
+ '--jp-green-primary': 'var( --jp-green-40 )',
74
+ '--jp-green-secondary': 'var( --jp-green-30 )',
75
+ };
76
+
77
+ export const borders = {
78
+ '--jp-border-radius': '4px',
79
+ '--jp-menu-border-height': '1px',
80
+ '--jp-underline-thickness': '2px',
81
+ };
82
+
83
+ export const spacing = {
84
+ '--spacing-base': '8px',
85
+ };
86
+
87
+ const globalThemeInstances: Record< string, ThemeInstance > = {};
88
+
89
+ const setup = ( root: HTMLElement, id: string, withGlobalStyles?: boolean ) => {
90
+ const tokens = { ...typography, ...colors, ...borders, ...spacing };
91
+ for ( const key in tokens ) {
92
+ root.style.setProperty( key, tokens[ key ] );
93
+ }
94
+
95
+ if ( withGlobalStyles ) {
96
+ root.classList.add( styles.global );
97
+ }
98
+
99
+ if ( ! id ) {
100
+ return;
101
+ }
102
+
103
+ // Register theme provider instance.
104
+ globalThemeInstances[ id ] = {
105
+ provided: true,
106
+ root,
107
+ };
108
+ };
109
+
110
+ /**
111
+ * ThemeProvider React component.
112
+ *
113
+ * @param {ThemeProviderProps} props - Component properties.
114
+ * @returns {React.ReactNode} ThemeProvider component.
115
+ */
116
+ const ThemeProvider: React.FC< ThemeProviderProps > = ( {
117
+ children = null,
118
+ targetDom,
119
+ id,
120
+ withGlobalStyles = true,
121
+ } ) => {
122
+ const themeWrapperRef = useRef< HTMLDivElement >();
123
+
124
+ // Check whether the theme provider instance is already registered.
125
+ const isAlreadyProvided = globalThemeInstances?.[ id ]?.provided;
126
+
127
+ useLayoutEffect( () => {
128
+ if ( isAlreadyProvided ) {
129
+ return;
130
+ }
131
+
132
+ if ( targetDom ) {
133
+ return setup( targetDom, id, withGlobalStyles );
134
+ }
135
+
136
+ if ( ! themeWrapperRef?.current ) {
137
+ return;
138
+ }
139
+
140
+ setup( themeWrapperRef.current, id, withGlobalStyles );
141
+ }, [ targetDom, themeWrapperRef, isAlreadyProvided, id, withGlobalStyles ] );
142
+
143
+ // Do not wrap when the DOM element target is defined.
144
+ if ( targetDom ) {
145
+ return children;
146
+ }
147
+
148
+ return <div ref={ themeWrapperRef }>{ children }</div>;
149
+ };
150
+
151
+ export default ThemeProvider;
@@ -0,0 +1,164 @@
1
+ import { Button } from '@wordpress/components';
2
+ import { useCopyToClipboard } from '@wordpress/compose';
3
+ import Col from '../../layout/col';
4
+ import Container from '../../layout/container';
5
+ import ThemeProvider, { typography, colors, borders, spacing } from '../index';
6
+ import styles from './style.module.scss';
7
+ import type { ComponentStory, ComponentMeta } from '@storybook/react';
8
+
9
+ /**
10
+ * Get the contrasting color for any hex color
11
+ * (c) 2019 Chris Ferdinandi, MIT License, https://gomakethings.com
12
+ * Derived from work by Brian Suda, https://24ways.org/2010/calculating-color-contrast/
13
+ *
14
+ * @param {string} hexcolor - hexcolor value
15
+ * @returns {string} The contrasting color (black or white)
16
+ */
17
+ function getContrast( hexcolor ) {
18
+ // If a leading # is provided, remove it
19
+ if ( hexcolor.slice( 0, 1 ) === '#' ) {
20
+ hexcolor = hexcolor.slice( 1 );
21
+ }
22
+
23
+ // If a three-character hexcode, make six-character
24
+ if ( hexcolor.length === 3 ) {
25
+ hexcolor = hexcolor
26
+ .split( '' )
27
+ .map( function ( hex ) {
28
+ return hex + hex;
29
+ } )
30
+ .join( '' );
31
+ }
32
+
33
+ // Convert to RGB value
34
+ const r = parseInt( hexcolor.substring( 0, 2 ), 16 );
35
+ const g = parseInt( hexcolor.substring( 2, 4 ), 16 );
36
+ const b = parseInt( hexcolor.substring( 4, 6 ), 16 );
37
+
38
+ // Get YIQ ratio
39
+ const yiq = ( r * 299 + g * 587 + b * 114 ) / 1000;
40
+
41
+ // Check contrast
42
+ return yiq >= 128 ? 'black' : 'white';
43
+ }
44
+ export default {
45
+ title: 'JS Packages/Components/Theme Provider',
46
+ } as ComponentMeta< typeof ThemeProvider >;
47
+
48
+ const noop = () => {
49
+ //
50
+ };
51
+
52
+ const ClipboardButton: React.FC< React.ComponentProps< typeof Button > > = ( {
53
+ text,
54
+ ...buttonProps
55
+ } ) => {
56
+ const ref = useCopyToClipboard( text, noop );
57
+ return <Button { ...buttonProps } ref={ ref } />;
58
+ };
59
+
60
+ const Section = ( { title, data, children = null } ) => (
61
+ <div className={ styles.section }>
62
+ <h1 className={ styles.title }>{ title }</h1>
63
+ <Container fluid>
64
+ { Object.keys( data ).map( key => (
65
+ <Col lg={ 3 } className={ styles.box }>
66
+ <Container fluid horizontalGap={ 2 }>
67
+ <Col className={ styles.key }>{ key }</Col>
68
+ { children && <Col className={ styles.example }>{ children( data[ key ] ) }</Col> }
69
+ <Col>
70
+ <div className={ styles[ 'value-label' ] }>Value</div>
71
+ <input
72
+ type="text"
73
+ value={ data[ key ] }
74
+ readOnly={ true }
75
+ className={ styles.value }
76
+ />
77
+ </Col>
78
+ </Container>
79
+ </Col>
80
+ ) ) }
81
+ </Container>
82
+ </div>
83
+ );
84
+
85
+ export const Tokens = () => (
86
+ <>
87
+ <Section title="Typography" data={ typography }>
88
+ { value => <div style={ { fontSize: value } }>Text</div> }
89
+ </Section>
90
+ <Section title="Colors" data={ colors }>
91
+ { value => (
92
+ <div className={ styles[ 'colors-example' ] } style={ { backgroundColor: value } } />
93
+ ) }
94
+ </Section>
95
+ <Section title="Borders" data={ borders } />
96
+ <Section title="Spacing" data={ spacing } />
97
+ </>
98
+ );
99
+ Tokens.parameters = {
100
+ docs: { source: { code: null } },
101
+ };
102
+
103
+ export const Typographies = args => (
104
+ <div className={ styles[ 'instances-wrapper' ] }>
105
+ { Object.keys( typography ).map( key => (
106
+ <div className={ styles[ 'font-instance' ] } style={ { fontSize: typography[ key ] } }>
107
+ { args?.[ 'Text Instance' ] || `${ key } (${ typography[ key ] } )` }
108
+
109
+ <ClipboardButton variant="tertiary" text={ key } className={ styles[ 'copy-button' ] }>
110
+ Copy
111
+ </ClipboardButton>
112
+ </div>
113
+ ) ) }
114
+ </div>
115
+ );
116
+
117
+ Typographies.args = {
118
+ [ 'Text Instance' ]: '',
119
+ };
120
+ Typographies.parameters = {
121
+ docs: { source: { code: null } },
122
+ };
123
+
124
+ export const Colors = () => (
125
+ <div className={ styles[ 'instances-wrapper' ] }>
126
+ { Object.keys( colors ).map( key => (
127
+ <div
128
+ className={ styles[ 'color-instance' ] }
129
+ style={ { backgroundColor: colors[ key ], color: getContrast( colors[ key ] ) } }
130
+ >
131
+ { `${ key } (${ colors[ key ].toUpperCase() } )` }
132
+
133
+ <ClipboardButton
134
+ variant="tertiary"
135
+ text={ key }
136
+ className={ styles[ 'copy-button' ] }
137
+ style={ { color: getContrast( colors[ key ] ) } }
138
+ >
139
+ Copy
140
+ </ClipboardButton>
141
+ </div>
142
+ ) ) }
143
+ </div>
144
+ );
145
+ Colors.parameters = {
146
+ docs: { source: { code: null } },
147
+ };
148
+
149
+ const Template: ComponentStory< typeof ThemeProvider > = args => (
150
+ <ThemeProvider { ...args }>
151
+ <div
152
+ style={ {
153
+ color: 'var( --jp-white )',
154
+ backgroundColor: 'var( --jp-pink )',
155
+ fontSize: 'var( --font-title-small )',
156
+ padding: 'var( --spacing-base ) calc( var( --spacing-base ) * 2 )',
157
+ borderRadius: 'var( --jp-border-radius )',
158
+ } }
159
+ >
160
+ Pink Jetpack Show
161
+ </div>
162
+ </ThemeProvider>
163
+ );
164
+ export const BasicUsage = Template.bind( {} );
@@ -0,0 +1,79 @@
1
+ .section {
2
+ width: 100%;
3
+ margin: auto;
4
+ padding: 8px 32px;
5
+ }
6
+
7
+ .key {
8
+ background-color: var(--jp-green-80);
9
+ border-radius: var(--jp-border-radius);
10
+ padding: 8px;
11
+ color: var(--jp-white);
12
+ font-weight: 600;
13
+ }
14
+
15
+ .box {
16
+ border: 1px solid var(--jp-gray);
17
+ border-radius: var(--jp-border-radius);
18
+ padding: 16px;
19
+ }
20
+
21
+ .example {
22
+ height: 40px;
23
+ display: flex;
24
+ align-items: center;
25
+ border: 1px solid var(--jp-gray);
26
+ border-radius: var(--jp-border-radius);
27
+ padding: 8px;
28
+ }
29
+
30
+ .value-label {
31
+ font-weight: 600;
32
+ font-size: var(--font-label);
33
+ margin: 8px 0;
34
+ }
35
+
36
+ .value {
37
+ width: 100%;
38
+ }
39
+
40
+ .colors-example {
41
+ width: 100%;
42
+ height: 100%;
43
+ }
44
+
45
+ .instances-wrapper {
46
+ display: flex;
47
+ flex-direction: column;
48
+ }
49
+
50
+ .font-instance {
51
+ margin: 10px 0;
52
+ padding: 20px 30px;
53
+ background-color: var( --jp-white );
54
+ border: 1px dotted var( --jp-gray-10 );
55
+ position: relative;
56
+ &:hover .copy-button {
57
+ opacity: 1;
58
+ }
59
+ }
60
+
61
+ .color-instance {
62
+ font-size: var( --font-title-small );
63
+ border: 1px dotted var( --jp-gray-10 );
64
+ min-height: 60px;
65
+ line-height: 60px;
66
+ padding: 10px;
67
+ margin: 10px 0;
68
+ position: relative;
69
+ &:hover .copy-button {
70
+ opacity: 1;
71
+ }
72
+ }
73
+
74
+ .copy-button {
75
+ opacity: 0.3;
76
+ position: absolute;
77
+ top: 5px;
78
+ right: 5px;
79
+ }
@@ -0,0 +1,25 @@
1
+ export type ThemeProviderProps = {
2
+ /**
3
+ * An optional id to register and identify the provider instance.
4
+ */
5
+ id?: string;
6
+
7
+ /**
8
+ * Target DOM element to store theme styles. Optional.
9
+ */
10
+ targetDom?: HTMLElement;
11
+
12
+ /**
13
+ * Content
14
+ */
15
+ children?: React.ReactElement;
16
+ /**
17
+ * Inser global/reset styles
18
+ */
19
+ withGlobalStyles?: boolean;
20
+ };
21
+
22
+ export type ThemeInstance = {
23
+ provided: boolean;
24
+ root: HTMLElement;
25
+ };
@@ -0,0 +1,5 @@
1
+ # Toggle Control
2
+
3
+ A wrapper component for applying Jetpack Emerald styles to the [ToggleControl](https://github.com/WordPress/gutenberg/tree/trunk/packages/components/src/form-toggle) component from `@wordpress/components`.
4
+
5
+ The documentation for the base `ToggleControl` component can be found via the [Gutenberg Handbook](https://developer.wordpress.org/block-editor/components/toggle-control/).
@@ -0,0 +1,67 @@
1
+ import { ToggleControl as WPToggleControl } from '@wordpress/components';
2
+ import classNames from 'classnames';
3
+ import { useCallback } from 'react';
4
+ import styles from './styles.module.scss';
5
+
6
+ interface ToggleControlProps {
7
+ /** Whether or not the toggle is currently enabled. */
8
+ checked?: boolean;
9
+
10
+ /** Custom class name to append to the component. */
11
+ className?: string;
12
+
13
+ /** Whether or not the toggle is currently disabled. */
14
+ disabled?: boolean;
15
+
16
+ /** Additional information to display below the toggle. */
17
+ help?: React.ReactNode;
18
+
19
+ /** Whether or not the toggling is currently toggling. */
20
+ toggling?: boolean;
21
+
22
+ /** The label for the toggle. */
23
+ label?: React.ReactNode;
24
+
25
+ /** A callback function invoked when the toggle is clicked. */
26
+ onChange: ( value: boolean ) => void;
27
+ }
28
+
29
+ const ToggleControl: React.FC< ToggleControlProps > = ( {
30
+ checked,
31
+ className,
32
+ disabled,
33
+ help,
34
+ toggling,
35
+ label,
36
+ onChange,
37
+ } ) => {
38
+ const showChecked =
39
+ toggling !== undefined ? ( checked && ! toggling ) || ( ! checked && toggling ) : checked;
40
+
41
+ const handleOnChange = useCallback(
42
+ ( value: boolean ) => {
43
+ // Don't toggle if the toggle is already toggling.
44
+ if ( toggling ) {
45
+ return;
46
+ }
47
+
48
+ onChange( value );
49
+ },
50
+ [ toggling, onChange ]
51
+ );
52
+
53
+ return (
54
+ <WPToggleControl
55
+ checked={ showChecked }
56
+ className={ classNames( styles.toggle, className, {
57
+ [ styles[ 'is-toggling' ] ]: toggling,
58
+ } ) }
59
+ disabled={ disabled }
60
+ help={ help }
61
+ label={ label }
62
+ onChange={ handleOnChange }
63
+ />
64
+ );
65
+ };
66
+
67
+ export default ToggleControl;
@@ -0,0 +1,83 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import ToggleControl from '..';
3
+
4
+ export default {
5
+ title: 'JS Packages/Components/Toggle Control',
6
+ component: ToggleControl,
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ };
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
13
+ export const Default = args => {
14
+ const [ checked, setChecked ] = useState( false );
15
+
16
+ const handleChecked = useCallback( () => {
17
+ setChecked( ! checked );
18
+ }, [ checked ] );
19
+
20
+ return <ToggleControl checked={ checked } onChange={ handleChecked } label="Code is poetry." />;
21
+ };
22
+
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
+ export const Slow = args => {
25
+ const [ loading, setLoading ] = useState( false );
26
+ const [ checked, setChecked ] = useState( false );
27
+
28
+ const handleChecked = useCallback( () => {
29
+ setLoading( true );
30
+ setTimeout( () => {
31
+ setLoading( false );
32
+ setChecked( ! checked );
33
+ }, 2000 );
34
+ }, [ checked ] );
35
+
36
+ return (
37
+ <ToggleControl
38
+ checked={ checked }
39
+ toggling={ loading }
40
+ onChange={ handleChecked }
41
+ label="Code is poetry."
42
+ />
43
+ );
44
+ };
45
+
46
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
47
+ export const Disabled = args => {
48
+ const [ checked, setChecked ] = useState( false );
49
+
50
+ const handleChecked = useCallback( () => {
51
+ setChecked( ! checked );
52
+ }, [ checked ] );
53
+
54
+ return (
55
+ <>
56
+ <ToggleControl checked={ true } disabled label="Code is poetry." onChange={ handleChecked } />
57
+ <ToggleControl
58
+ checked={ false }
59
+ disabled
60
+ label="Code is poetry."
61
+ onChange={ handleChecked }
62
+ />
63
+ </>
64
+ );
65
+ };
66
+
67
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
68
+ export const HelpText = args => {
69
+ const [ checked, setChecked ] = useState( false );
70
+
71
+ const handleChecked = useCallback( () => {
72
+ setChecked( ! checked );
73
+ }, [ checked ] );
74
+
75
+ return (
76
+ <ToggleControl
77
+ checked={ checked }
78
+ label="Code is poetry."
79
+ help="Code is poetry. Code is poetry. Code is poetry."
80
+ onChange={ handleChecked }
81
+ />
82
+ );
83
+ };
@@ -0,0 +1,41 @@
1
+ /// Toggle Control
2
+ ///
3
+ /// Overrides the @wordpress/components ToggleControl component.
4
+ /// @link https://github.com/WordPress/gutenberg/tree/trunk/packages/components/src/form-toggle
5
+ .toggle {
6
+ :global {
7
+ .components-form-toggle {
8
+ --wp-admin-theme-color: var( --jp-green-40 );
9
+
10
+ &__input:focus + .components-form-toggle__track {
11
+ box-shadow: 0 0 0 2px var( --jp-white ), 0 0 0 4px var( --jp-green-50 );
12
+ }
13
+
14
+ .components-form-toggle__track {
15
+ width: 48px;
16
+ height: 24px;
17
+ border-radius: 12px;
18
+ border-width: 2px;
19
+ }
20
+
21
+ .components-form-toggle__thumb {
22
+ width: 16px;
23
+ height: 16px;
24
+ top: 4px;
25
+ left: 4px;
26
+ }
27
+
28
+ &.is-checked .components-form-toggle__thumb {
29
+ transform: translateX( 24px );
30
+ }
31
+ }
32
+ }
33
+ }
34
+
35
+ .toggle.is-toggling {
36
+ :global {
37
+ .components-form-toggle {
38
+ opacity: .6;
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,26 @@
1
+ # Summary
2
+
3
+ This component adds a Zendesk chat widget via <script> tag to any page the componet is added to
4
+
5
+ WARNING: If you add this to a specific site, it will stay on the page until the browser reloads onto a page that does not load this widget. For example, if a section of the plugin is using `react-router-dom`, and the widget is loaded onto one specific route, it will not go away when a new route is taken since the page is not reloaded
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import React from 'react';
11
+ import { ZendeskChat } from '@automattic/jetpack-components';
12
+
13
+ const ExampleComponent = () => (
14
+ <ZendeskChat />
15
+ );
16
+ ```
17
+
18
+ ## Props
19
+
20
+ None
21
+
22
+ Because the chat is conditionally rendered based on Date and Time, no props are needed in order to render correctly.
23
+
24
+ ## Note
25
+
26
+ There is a wpcom/v2 API endpoint `/presales/chat?group=jp_presales` that returns whether or not chat is available at this time. This should be used when determining whether or not to render this component.
@@ -0,0 +1,2 @@
1
+ // This is not a secret, it can easily be found in the DOM
2
+ export const chatKey = 'd729d42c-b547-4750-a6f6-8b30534a5f12';
@@ -0,0 +1,22 @@
1
+ import { useEffect } from 'react';
2
+ import { chatKey } from './constants';
3
+ import type { ZendeskChatType } from './types';
4
+
5
+ export const ZendeskChat: ZendeskChatType = () => {
6
+ useEffect( () => {
7
+ const script = document.createElement( 'script' );
8
+ const container = document.getElementById( 'zendesk-chat-container' );
9
+
10
+ script.src = 'https://static.zdassets.com/ekr/snippet.js?key=' + encodeURIComponent( chatKey );
11
+ script.type = 'text/javascript';
12
+ script.id = 'ze-snippet';
13
+
14
+ if ( container ) {
15
+ container.appendChild( script );
16
+ }
17
+ }, [] );
18
+
19
+ return <div data-testid="zendesk-chat-container" id="zendesk-chat-container" />;
20
+ };
21
+
22
+ export default ZendeskChat;
@@ -0,0 +1,15 @@
1
+ import ZendeskChat from '../index';
2
+
3
+ export default {
4
+ title: 'JS Packages/Components/Zendesk Chat',
5
+ component: ZendeskChat,
6
+ parameters: {
7
+ backgrounds: {
8
+ default: 'dark',
9
+ },
10
+ },
11
+ };
12
+
13
+ const Template = args => <ZendeskChat { ...args } />;
14
+
15
+ export const _default = Template.bind( {} );