newspack-components 3.0.0-alpha.2 → 3.0.0-alpha.3

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 (217) hide show
  1. package/babel.config.cjs.js +26 -0
  2. package/babel.config.js +1 -0
  3. package/copy-styles.js +10 -2
  4. package/dist/esm/accordion/index.js +42 -0
  5. package/dist/esm/accordion/style.scss +31 -0
  6. package/dist/esm/action-card/index.js +218 -0
  7. package/dist/esm/action-card/style.scss +483 -0
  8. package/dist/esm/autocomplete-tokenfield/index.js +261 -0
  9. package/dist/esm/autocomplete-tokenfield/style.scss +49 -0
  10. package/dist/esm/autocomplete-with-suggestions/index.js +274 -0
  11. package/dist/esm/autocomplete-with-suggestions/style.scss +163 -0
  12. package/dist/esm/button/style.scss +11 -0
  13. package/dist/esm/button-card/index.js +64 -0
  14. package/dist/esm/button-card/style.scss +180 -0
  15. package/dist/esm/card/index.js +43 -0
  16. package/dist/esm/card/style.scss +168 -0
  17. package/dist/esm/category-autocomplete/index.js +183 -0
  18. package/dist/esm/category-autocomplete/style.scss +34 -0
  19. package/dist/esm/color-picker/index.js +59 -0
  20. package/dist/esm/color-picker/style.scss +37 -0
  21. package/dist/esm/consts.js +1 -0
  22. package/dist/esm/custom-select-control/index.js +37 -0
  23. package/dist/esm/custom-select-control/style.scss +93 -0
  24. package/dist/esm/date-range-picker/index.js +31 -0
  25. package/dist/esm/date-range-picker/style.scss +148 -0
  26. package/dist/esm/footer/index.js +99 -0
  27. package/dist/esm/footer/style.scss +82 -0
  28. package/dist/esm/form-token-field/index.js +49 -0
  29. package/dist/esm/form-token-field/style.scss +37 -0
  30. package/dist/esm/global-notices/index.js +30 -0
  31. package/dist/esm/grid/style.scss +166 -0
  32. package/dist/esm/handoff/index.js +175 -0
  33. package/dist/esm/handoff-message/index.js +47 -0
  34. package/dist/esm/hooks/useObjectState.js +30 -0
  35. package/dist/esm/hooks/useObjectState.test.js +82 -0
  36. package/dist/esm/hooks/useOnClickOutside.js +31 -0
  37. package/dist/esm/image-upload/index.js +140 -0
  38. package/dist/esm/image-upload/index.test.js +34 -0
  39. package/dist/esm/image-upload/style.scss +103 -0
  40. package/dist/esm/index.js +47 -0
  41. package/dist/esm/info-button/index.js +42 -0
  42. package/dist/esm/info-button/style.scss +18 -0
  43. package/dist/esm/modal/index.js +39 -0
  44. package/dist/esm/modal/style.scss +56 -0
  45. package/dist/esm/newspack-icon/index.js +50 -0
  46. package/dist/esm/newspack-icon/style.scss +26 -0
  47. package/dist/esm/newspack-logo/index.js +46 -0
  48. package/dist/esm/newspack-logo/style.scss +30 -0
  49. package/dist/esm/notice/index.js +65 -0
  50. package/dist/esm/notice/style.scss +111 -0
  51. package/dist/esm/patrons-logo/index.js +70 -0
  52. package/dist/esm/plugin-installer/index.js +289 -0
  53. package/dist/esm/plugin-installer/style.scss +72 -0
  54. package/dist/esm/plugin-settings/SettingsSection.js +133 -0
  55. package/dist/esm/plugin-settings/index.js +220 -0
  56. package/dist/esm/plugin-settings/style.scss +7 -0
  57. package/dist/esm/plugin-toggle/index.js +216 -0
  58. package/dist/esm/plugin-toggle/style.scss +20 -0
  59. package/dist/esm/popover/index.js +41 -0
  60. package/dist/esm/popover/style.scss +161 -0
  61. package/dist/esm/position-control/index.js +106 -0
  62. package/dist/esm/position-control/style.scss +66 -0
  63. package/dist/esm/progress-bar/index.js +68 -0
  64. package/dist/esm/progress-bar/index.test.js +108 -0
  65. package/dist/esm/progress-bar/style.scss +42 -0
  66. package/dist/esm/proxied-imports/router.js +8 -0
  67. package/dist/esm/radio-control/index.js +37 -0
  68. package/dist/esm/radio-control/style.scss +92 -0
  69. package/dist/esm/section-header/index.js +67 -0
  70. package/dist/esm/section-header/style.scss +45 -0
  71. package/dist/esm/select-control/ButtonGroupControl.js +53 -0
  72. package/dist/esm/select-control/GroupedSelectControl.js +78 -0
  73. package/dist/esm/select-control/index.js +51 -0
  74. package/dist/esm/select-control/style.scss +108 -0
  75. package/dist/esm/settings/MinMaxSetting.js +53 -0
  76. package/dist/esm/settings/SettingsCard.js +38 -0
  77. package/dist/esm/settings/SettingsSection.js +26 -0
  78. package/dist/esm/settings/index.js +9 -0
  79. package/dist/esm/settings/style.scss +119 -0
  80. package/dist/esm/sortable-newsletter-list-control/index.js +127 -0
  81. package/dist/esm/sortable-newsletter-list-control/style.scss +45 -0
  82. package/dist/esm/steps-list/index.js +43 -0
  83. package/dist/esm/steps-list/style.scss +11 -0
  84. package/dist/esm/steps-list-item/index.js +47 -0
  85. package/dist/esm/steps-list-item/style.scss +47 -0
  86. package/dist/esm/style-card/index.js +74 -0
  87. package/dist/esm/style-card/style.scss +94 -0
  88. package/dist/esm/style.scss +55 -0
  89. package/dist/esm/tabbed-navigation/index.js +53 -0
  90. package/dist/esm/tabbed-navigation/style.scss +86 -0
  91. package/dist/esm/text-control/style.scss +32 -0
  92. package/dist/esm/utils/index.js +29 -0
  93. package/dist/esm/waiting/index.js +44 -0
  94. package/dist/esm/waiting/style.scss +27 -0
  95. package/dist/esm/web-preview/index.js +183 -0
  96. package/dist/esm/web-preview/style.scss +155 -0
  97. package/dist/esm/with-wizard/index.js +320 -0
  98. package/dist/esm/with-wizard/style.scss +282 -0
  99. package/dist/esm/with-wizard-screen/index.js +109 -0
  100. package/dist/esm/with-wizard-screen/style.scss +160 -0
  101. package/dist/esm/wizard/components/WizardError.js +66 -0
  102. package/dist/esm/wizard/index.js +119 -0
  103. package/dist/esm/wizard/store/index.js +155 -0
  104. package/dist/esm/wizard/store/utils.js +14 -0
  105. package/package.json +7 -4
  106. package/dist/button/index.js +0 -51
  107. package/dist/button/index.tsx +0 -48
  108. package/dist/grid/index.js +0 -44
  109. package/dist/grid/index.tsx +0 -34
  110. package/dist/hooks/index.js +0 -29
  111. package/dist/hooks/index.ts +0 -15
  112. package/dist/hooks/usePrompt.js +0 -47
  113. package/dist/hooks/usePrompt.ts +0 -46
  114. package/dist/plugin-toggle/README.md +0 -53
  115. package/dist/text-control/index.js +0 -76
  116. package/dist/text-control/index.tsx +0 -71
  117. /package/dist/{accordion → cjs/accordion}/index.js +0 -0
  118. /package/dist/{accordion → cjs/accordion}/style.scss +0 -0
  119. /package/dist/{action-card → cjs/action-card}/index.js +0 -0
  120. /package/dist/{action-card → cjs/action-card}/style.scss +0 -0
  121. /package/dist/{autocomplete-tokenfield → cjs/autocomplete-tokenfield}/index.js +0 -0
  122. /package/dist/{autocomplete-tokenfield → cjs/autocomplete-tokenfield}/style.scss +0 -0
  123. /package/dist/{autocomplete-with-suggestions → cjs/autocomplete-with-suggestions}/index.js +0 -0
  124. /package/dist/{autocomplete-with-suggestions → cjs/autocomplete-with-suggestions}/style.scss +0 -0
  125. /package/dist/{button → cjs/button}/style.scss +0 -0
  126. /package/dist/{button-card → cjs/button-card}/index.js +0 -0
  127. /package/dist/{button-card → cjs/button-card}/style.scss +0 -0
  128. /package/dist/{card → cjs/card}/index.js +0 -0
  129. /package/dist/{card → cjs/card}/style.scss +0 -0
  130. /package/dist/{category-autocomplete → cjs/category-autocomplete}/index.js +0 -0
  131. /package/dist/{category-autocomplete → cjs/category-autocomplete}/style.scss +0 -0
  132. /package/dist/{color-picker → cjs/color-picker}/index.js +0 -0
  133. /package/dist/{color-picker → cjs/color-picker}/style.scss +0 -0
  134. /package/dist/{consts.js → cjs/consts.js} +0 -0
  135. /package/dist/{custom-select-control → cjs/custom-select-control}/index.js +0 -0
  136. /package/dist/{custom-select-control → cjs/custom-select-control}/style.scss +0 -0
  137. /package/dist/{date-range-picker → cjs/date-range-picker}/index.js +0 -0
  138. /package/dist/{date-range-picker → cjs/date-range-picker}/style.scss +0 -0
  139. /package/dist/{footer → cjs/footer}/index.js +0 -0
  140. /package/dist/{footer → cjs/footer}/style.scss +0 -0
  141. /package/dist/{form-token-field → cjs/form-token-field}/index.js +0 -0
  142. /package/dist/{form-token-field → cjs/form-token-field}/style.scss +0 -0
  143. /package/dist/{global-notices → cjs/global-notices}/index.js +0 -0
  144. /package/dist/{grid → cjs/grid}/style.scss +0 -0
  145. /package/dist/{handoff → cjs/handoff}/index.js +0 -0
  146. /package/dist/{handoff-message → cjs/handoff-message}/index.js +0 -0
  147. /package/dist/{hooks → cjs/hooks}/useObjectState.js +0 -0
  148. /package/dist/{hooks → cjs/hooks}/useObjectState.test.js +0 -0
  149. /package/dist/{hooks → cjs/hooks}/useOnClickOutside.js +0 -0
  150. /package/dist/{image-upload → cjs/image-upload}/index.js +0 -0
  151. /package/dist/{image-upload → cjs/image-upload}/index.test.js +0 -0
  152. /package/dist/{image-upload → cjs/image-upload}/style.scss +0 -0
  153. /package/dist/{index.js → cjs/index.js} +0 -0
  154. /package/dist/{info-button → cjs/info-button}/index.js +0 -0
  155. /package/dist/{info-button → cjs/info-button}/style.scss +0 -0
  156. /package/dist/{modal → cjs/modal}/index.js +0 -0
  157. /package/dist/{modal → cjs/modal}/style.scss +0 -0
  158. /package/dist/{newspack-icon → cjs/newspack-icon}/index.js +0 -0
  159. /package/dist/{newspack-icon → cjs/newspack-icon}/style.scss +0 -0
  160. /package/dist/{newspack-logo → cjs/newspack-logo}/index.js +0 -0
  161. /package/dist/{newspack-logo → cjs/newspack-logo}/style.scss +0 -0
  162. /package/dist/{notice → cjs/notice}/index.js +0 -0
  163. /package/dist/{notice → cjs/notice}/style.scss +0 -0
  164. /package/dist/{patrons-logo → cjs/patrons-logo}/index.js +0 -0
  165. /package/dist/{plugin-installer → cjs/plugin-installer}/index.js +0 -0
  166. /package/dist/{plugin-installer → cjs/plugin-installer}/style.scss +0 -0
  167. /package/dist/{plugin-settings → cjs/plugin-settings}/SettingsSection.js +0 -0
  168. /package/dist/{plugin-settings → cjs/plugin-settings}/index.js +0 -0
  169. /package/dist/{plugin-settings → cjs/plugin-settings}/style.scss +0 -0
  170. /package/dist/{plugin-toggle → cjs/plugin-toggle}/index.js +0 -0
  171. /package/dist/{plugin-toggle → cjs/plugin-toggle}/style.scss +0 -0
  172. /package/dist/{popover → cjs/popover}/index.js +0 -0
  173. /package/dist/{popover → cjs/popover}/style.scss +0 -0
  174. /package/dist/{position-control → cjs/position-control}/index.js +0 -0
  175. /package/dist/{position-control → cjs/position-control}/style.scss +0 -0
  176. /package/dist/{progress-bar → cjs/progress-bar}/index.js +0 -0
  177. /package/dist/{progress-bar → cjs/progress-bar}/index.test.js +0 -0
  178. /package/dist/{progress-bar → cjs/progress-bar}/style.scss +0 -0
  179. /package/dist/{proxied-imports → cjs/proxied-imports}/router.js +0 -0
  180. /package/dist/{radio-control → cjs/radio-control}/index.js +0 -0
  181. /package/dist/{radio-control → cjs/radio-control}/style.scss +0 -0
  182. /package/dist/{section-header → cjs/section-header}/index.js +0 -0
  183. /package/dist/{section-header → cjs/section-header}/style.scss +0 -0
  184. /package/dist/{select-control → cjs/select-control}/ButtonGroupControl.js +0 -0
  185. /package/dist/{select-control → cjs/select-control}/GroupedSelectControl.js +0 -0
  186. /package/dist/{select-control → cjs/select-control}/index.js +0 -0
  187. /package/dist/{select-control → cjs/select-control}/style.scss +0 -0
  188. /package/dist/{settings → cjs/settings}/MinMaxSetting.js +0 -0
  189. /package/dist/{settings → cjs/settings}/SettingsCard.js +0 -0
  190. /package/dist/{settings → cjs/settings}/SettingsSection.js +0 -0
  191. /package/dist/{settings → cjs/settings}/index.js +0 -0
  192. /package/dist/{settings → cjs/settings}/style.scss +0 -0
  193. /package/dist/{sortable-newsletter-list-control → cjs/sortable-newsletter-list-control}/index.js +0 -0
  194. /package/dist/{sortable-newsletter-list-control → cjs/sortable-newsletter-list-control}/style.scss +0 -0
  195. /package/dist/{steps-list → cjs/steps-list}/index.js +0 -0
  196. /package/dist/{steps-list → cjs/steps-list}/style.scss +0 -0
  197. /package/dist/{steps-list-item → cjs/steps-list-item}/index.js +0 -0
  198. /package/dist/{steps-list-item → cjs/steps-list-item}/style.scss +0 -0
  199. /package/dist/{style-card → cjs/style-card}/index.js +0 -0
  200. /package/dist/{style-card → cjs/style-card}/style.scss +0 -0
  201. /package/dist/{style.scss → cjs/style.scss} +0 -0
  202. /package/dist/{tabbed-navigation → cjs/tabbed-navigation}/index.js +0 -0
  203. /package/dist/{tabbed-navigation → cjs/tabbed-navigation}/style.scss +0 -0
  204. /package/dist/{text-control → cjs/text-control}/style.scss +0 -0
  205. /package/dist/{utils → cjs/utils}/index.js +0 -0
  206. /package/dist/{waiting → cjs/waiting}/index.js +0 -0
  207. /package/dist/{waiting → cjs/waiting}/style.scss +0 -0
  208. /package/dist/{web-preview → cjs/web-preview}/index.js +0 -0
  209. /package/dist/{web-preview → cjs/web-preview}/style.scss +0 -0
  210. /package/dist/{with-wizard → cjs/with-wizard}/index.js +0 -0
  211. /package/dist/{with-wizard → cjs/with-wizard}/style.scss +0 -0
  212. /package/dist/{with-wizard-screen → cjs/with-wizard-screen}/index.js +0 -0
  213. /package/dist/{with-wizard-screen → cjs/with-wizard-screen}/style.scss +0 -0
  214. /package/dist/{wizard → cjs/wizard}/components/WizardError.js +0 -0
  215. /package/dist/{wizard → cjs/wizard}/index.js +0 -0
  216. /package/dist/{wizard → cjs/wizard}/store/index.js +0 -0
  217. /package/dist/{wizard → cjs/wizard}/store/utils.js +0 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Grid
3
+ */
4
+
5
+ @use "~@wordpress/base-styles/colors" as wp-colors;
6
+
7
+ .newspack-grid {
8
+ display: grid;
9
+ grid-gap: 32px;
10
+ grid-auto-rows: min-content;
11
+ grid-template-columns: 1fr;
12
+ margin: 32px 0;
13
+
14
+ // No Margin
15
+ &--no-margin {
16
+ margin: 0;
17
+ }
18
+
19
+ // Gutter 0
20
+ &__gutter-0 {
21
+ grid-gap: 0;
22
+ }
23
+
24
+ // Gutter 8
25
+ &__gutter-8 {
26
+ grid-gap: 8px;
27
+ }
28
+
29
+ // Gutter 16
30
+ &__gutter-16 {
31
+ grid-gap: 16px;
32
+ }
33
+
34
+ // Gutter 24
35
+ &__gutter-24 {
36
+ grid-gap: 24px;
37
+ }
38
+
39
+ // Gutter 32
40
+ &__gutter-32 {
41
+ grid-gap: 32px;
42
+ }
43
+
44
+ // Row Gap 0
45
+ &__row-gap-0 {
46
+ grid-row-gap: 0;
47
+ }
48
+
49
+ // Row Gap 8
50
+ &__row-gap-8 {
51
+ grid-row-gap: 8px;
52
+ }
53
+
54
+ // Row Gap 16
55
+ &__row-gap-16 {
56
+ grid-row-gap: 16px;
57
+ }
58
+
59
+ // Row Gap 32
60
+ &__row-gap-32 {
61
+ grid-row-gap: 32px;
62
+ }
63
+
64
+ // Gutter 64
65
+ &__gutter-64 {
66
+ grid-gap: 64px;
67
+ }
68
+
69
+ // Columns 6
70
+ &__columns-6 {
71
+ grid-template-columns: repeat(2, 1fr);
72
+ }
73
+
74
+ // Media Queries - 744px
75
+ @media screen and ( min-width: 744px ) {
76
+ &__columns-2,
77
+ &__columns-3,
78
+ &__columns-4 {
79
+ grid-template-columns: repeat(2, 1fr);
80
+ }
81
+
82
+ &__columns-6 {
83
+ grid-template-columns: repeat(3, 1fr);
84
+ }
85
+ }
86
+
87
+ // Media Queries - 1128px
88
+ @media screen and ( min-width: 1128px ) {
89
+ // Columns 3
90
+ &__columns-3 {
91
+ grid-template-columns: repeat(3, 1fr);
92
+ }
93
+
94
+ // Columns 4
95
+ &__columns-4 {
96
+ grid-template-columns: repeat(4, 1fr);
97
+ }
98
+
99
+ // Columns 6
100
+ &__columns-6 {
101
+ grid-template-columns: repeat(6, 1fr);
102
+ }
103
+
104
+ // Gutter 48
105
+ &__gutter-48 {
106
+ grid-gap: 48px;
107
+ }
108
+
109
+ // Gutter 64
110
+ &__gutter-64 {
111
+ grid-gap: 64px;
112
+ }
113
+ }
114
+
115
+ // Children
116
+ > * {
117
+ margin-bottom: 0 !important;
118
+ margin-top: 0 !important;
119
+ }
120
+
121
+ .components-base-control {
122
+ &__field,
123
+ &__help {
124
+ margin-bottom: 0;
125
+ }
126
+ }
127
+
128
+ .components-form-token-field {
129
+ &__input-container {
130
+ margin-bottom: 0;
131
+ }
132
+ }
133
+
134
+ // Cards
135
+ > .newspack-card {
136
+ > *:first-child {
137
+ margin-top: 0 !important;
138
+ }
139
+
140
+ > *:last-child {
141
+ margin-bottom: 0 !important;
142
+ }
143
+ }
144
+
145
+ // Table-like
146
+ &__thead {
147
+ background: rgba(black, 0.025);
148
+ border-bottom: 1px solid wp-colors.$gray-300;
149
+ border-top: 1px solid wp-colors.$gray-300;
150
+ color: wp-colors.$gray-900;
151
+
152
+ > *:not(.screen-reader-text) {
153
+ padding: 8px;
154
+ }
155
+ }
156
+
157
+ &__tbody {
158
+ border-bottom: 1px solid wp-colors.$gray-300;
159
+ padding: 8px 0;
160
+ }
161
+
162
+ &__thead + &__tbody,
163
+ &__tbody + &__tbody {
164
+ margin-top: -32px;
165
+ }
166
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Handoff
3
+ */
4
+
5
+ /**
6
+ * WordPress dependencies.
7
+ */
8
+ import apiFetch from '@wordpress/api-fetch';
9
+ import { Component, Fragment } from '@wordpress/element';
10
+ import { __ } from '@wordpress/i18n';
11
+
12
+ /**
13
+ * Internal dependencies.
14
+ */
15
+ import { Button, Card, Modal, Waiting } from '../';
16
+
17
+ /**
18
+ * External dependencies.
19
+ */
20
+ import assign from 'lodash/assign';
21
+ import classnames from 'classnames';
22
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
23
+ class Handoff extends Component {
24
+ constructor() {
25
+ super(...arguments);
26
+ this.state = {
27
+ pluginInfo: [],
28
+ showModal: false
29
+ };
30
+ }
31
+ componentDidMount = () => {
32
+ this._isMounted = true;
33
+ const {
34
+ plugin
35
+ } = this.props;
36
+ this.retrievePluginInfo(plugin);
37
+ };
38
+ componentWillUnmount = () => {
39
+ this._isMounted = false;
40
+ };
41
+ retrievePluginInfo = plugin => {
42
+ const {
43
+ onReady
44
+ } = this.props;
45
+ apiFetch({
46
+ path: '/newspack/v1/plugins/' + plugin
47
+ }).then(pluginInfo => {
48
+ if (this._isMounted) {
49
+ onReady(pluginInfo);
50
+ this.setState({
51
+ pluginInfo
52
+ });
53
+ }
54
+ });
55
+ };
56
+ textForPlugin = pluginInfo => {
57
+ const defaults = {
58
+ modalBody: null,
59
+ modalTitle: pluginInfo.Name && `${__('Manage', 'newspack-plugin')} ${pluginInfo.Name}`,
60
+ primaryButton: pluginInfo.Name && `${__('Manage', 'newspack-plugin')} ${pluginInfo.Name}`,
61
+ primaryModalButton: __('Manage', 'newspack-plugin'),
62
+ dismissModalButton: __('Dismiss', 'newspack-plugin')
63
+ };
64
+ return assign(defaults, this.props);
65
+ };
66
+ goToPlugin = plugin => {
67
+ const {
68
+ editLink,
69
+ showOnBlockEditor
70
+ } = this.props;
71
+ apiFetch({
72
+ path: '/newspack/v1/plugins/' + plugin + '/handoff',
73
+ method: 'POST',
74
+ data: {
75
+ editLink,
76
+ handoffReturnUrl: window && window.location.href,
77
+ showOnBlockEditor: showOnBlockEditor ? true : false
78
+ }
79
+ }).then(response => {
80
+ window.location.href = response.HandoffLink;
81
+ });
82
+ };
83
+
84
+ /**
85
+ * Render.
86
+ */
87
+ render() {
88
+ const {
89
+ className,
90
+ children,
91
+ compact,
92
+ useModal,
93
+ // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
94
+ modalTitle: _modalTitle,
95
+ // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
96
+ modalBody: _modalBody,
97
+ // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
98
+ onReady,
99
+ // eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
100
+ editLink,
101
+ ...otherProps
102
+ } = this.props;
103
+ const {
104
+ pluginInfo,
105
+ showModal
106
+ } = this.state;
107
+ const {
108
+ modalBody,
109
+ modalTitle,
110
+ primaryButton,
111
+ primaryModalButton,
112
+ dismissModalButton
113
+ } = this.textForPlugin(pluginInfo);
114
+ const {
115
+ Configured,
116
+ Name,
117
+ Slug,
118
+ Status
119
+ } = pluginInfo;
120
+ const classes = classnames(Configured && 'is-configured', className);
121
+ return /*#__PURE__*/_jsxs(Fragment, {
122
+ children: [Name && 'active' === Status && /*#__PURE__*/_jsx(Button, {
123
+ className: classes,
124
+ isSecondary: !otherProps.isPrimary && !otherProps.isTertiary && !otherProps.isLink,
125
+ ...otherProps,
126
+ onClick: () => useModal ? this.setState({
127
+ showModal: true
128
+ }) : this.goToPlugin(Slug),
129
+ children: children ? children : primaryButton
130
+ }), Name && 'active' !== Status && /*#__PURE__*/_jsx(Button, {
131
+ className: classes,
132
+ variant: "secondary",
133
+ disabled: true,
134
+ ...otherProps,
135
+ children: Name + __(' not installed', 'newspack-plugin')
136
+ }), !Name && /*#__PURE__*/_jsx(Button, {
137
+ className: classes,
138
+ isSecondary: !otherProps.isPrimary && !otherProps.isTertiary && !otherProps.isLink,
139
+ ...otherProps,
140
+ children: /*#__PURE__*/_jsxs(Fragment, {
141
+ children: [!compact && /*#__PURE__*/_jsx(Waiting, {
142
+ isLeft: true
143
+ }), __('Retrieving Plugin Info', 'newspack-plugin')]
144
+ })
145
+ }), showModal && /*#__PURE__*/_jsxs(Modal, {
146
+ title: modalTitle,
147
+ onRequestClose: () => this.setState({
148
+ showModal: false
149
+ }),
150
+ children: [/*#__PURE__*/_jsx("p", {
151
+ children: modalBody
152
+ }), /*#__PURE__*/_jsxs(Card, {
153
+ buttonsCard: true,
154
+ noBorder: true,
155
+ className: "justify-end",
156
+ children: [/*#__PURE__*/_jsx(Button, {
157
+ variant: "secondary",
158
+ onClick: () => this.setState({
159
+ showModal: false
160
+ }),
161
+ children: dismissModalButton
162
+ }), /*#__PURE__*/_jsx(Button, {
163
+ variant: "primary",
164
+ onClick: () => this.goToPlugin(Slug),
165
+ children: primaryModalButton
166
+ })]
167
+ })]
168
+ })]
169
+ });
170
+ }
171
+ }
172
+ Handoff.defaultProps = {
173
+ onReady: () => {}
174
+ };
175
+ export default Handoff;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import { useEffect, useState } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies.
8
+ */
9
+ import { HANDOFF_KEY } from '../consts';
10
+ import { Notice } from '../';
11
+
12
+ /**
13
+ * Handoff Message Component.
14
+ */
15
+ import { jsx as _jsx } from "react/jsx-runtime";
16
+ export default function HandoffMessage() {
17
+ const [handoffMessage, setHandoffMessage] = useState(false);
18
+ useEffect(() => {
19
+ // Slight delay to allow for localStorage to be updated by RAS component.
20
+ setTimeout(() => {
21
+ const handoff = JSON.parse(localStorage.getItem(HANDOFF_KEY));
22
+ if (handoff?.message) {
23
+ setHandoffMessage(handoff.message);
24
+ } else {
25
+ setHandoffMessage(false);
26
+ }
27
+
28
+ // Clean up the notification if navigating away from the relevant page.
29
+ if (handoff?.url && -1 === window.location.href.indexOf(handoff.url)) {
30
+ window.localStorage.removeItem(HANDOFF_KEY);
31
+ setHandoffMessage(false);
32
+ }
33
+ }, 100);
34
+
35
+ // Clean up the notification when unmounting.
36
+ return () => window.localStorage.removeItem(HANDOFF_KEY);
37
+ }, []);
38
+ if (!handoffMessage) {
39
+ return null;
40
+ }
41
+ return /*#__PURE__*/_jsx(Notice, {
42
+ isHandoff: true,
43
+ isDismissible: false,
44
+ rawHTML: true,
45
+ noticeText: handoffMessage
46
+ });
47
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState } from '@wordpress/element';
5
+ import isArray from 'lodash/isArray';
6
+ import mergeWith from 'lodash/mergeWith';
7
+ const mergeCustomizer = (objValue, srcValue) => {
8
+ if (isArray(objValue)) {
9
+ // If it's an array, replace it (instead of concatenating).
10
+ return srcValue;
11
+ }
12
+ };
13
+
14
+ /**
15
+ * A useState for an object.
16
+ * Nested objects will be nested, but arrays replaced.
17
+ */
18
+ export default ((initial = {}) => {
19
+ const [stateObject, setStateObject] = useState(initial);
20
+ const runUpdate = update => setStateObject(_stateObject => mergeWith({}, _stateObject, update, mergeCustomizer));
21
+ const updateStateObject = keyOrUpdate => {
22
+ if (typeof keyOrUpdate === 'string') {
23
+ return value => runUpdate({
24
+ [keyOrUpdate]: value
25
+ });
26
+ }
27
+ runUpdate(keyOrUpdate);
28
+ };
29
+ return [stateObject, updateStateObject];
30
+ });
@@ -0,0 +1,82 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import useObjectState from './useObjectState';
4
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
+ const INIT_STATE = {
6
+ name: 'Foo',
7
+ widgets: [1],
8
+ attributes: {
9
+ bar: 0,
10
+ baz: 1
11
+ }
12
+ };
13
+ const TestComponent = () => {
14
+ const [state, updateState] = useObjectState(INIT_STATE);
15
+ return /*#__PURE__*/_jsxs("div", {
16
+ children: [/*#__PURE__*/_jsx("input", {
17
+ placeholder: "state",
18
+ onChange: () => {},
19
+ value: JSON.stringify(state)
20
+ }), /*#__PURE__*/_jsx("button", {
21
+ onClick: () => updateState({
22
+ widgets: []
23
+ }),
24
+ children: "Remove widgets"
25
+ }), /*#__PURE__*/_jsx("button", {
26
+ onClick: () => updateState({
27
+ widgets: [1]
28
+ }),
29
+ children: "Add widget"
30
+ }), /*#__PURE__*/_jsx("button", {
31
+ onClick: () => updateState({
32
+ attributes: {
33
+ bar: 2
34
+ }
35
+ }),
36
+ children: "Nested update"
37
+ }), /*#__PURE__*/_jsx("input", {
38
+ type: "text",
39
+ value: state.name,
40
+ onChange: e => updateState({
41
+ name: e.target.value
42
+ }),
43
+ placeholder: "name"
44
+ })]
45
+ });
46
+ };
47
+ describe('useObjectState', () => {
48
+ const getState = () => JSON.parse(screen.getByPlaceholderText('state').getAttribute('value'));
49
+ beforeEach(() => {
50
+ render( /*#__PURE__*/_jsx(TestComponent, {}));
51
+ });
52
+ it('updates arrays', () => {
53
+ expect(getState()).toStrictEqual(INIT_STATE);
54
+ screen.getByText('Remove widgets').click();
55
+ expect(getState()).toMatchObject({
56
+ widgets: []
57
+ });
58
+ screen.getByText('Add widget').click();
59
+ expect(getState()).toMatchObject({
60
+ widgets: [1]
61
+ });
62
+ });
63
+ it('updates a simple value', () => {
64
+ fireEvent.change(screen.getByPlaceholderText('name'), {
65
+ target: {
66
+ value: 'Ramon'
67
+ }
68
+ });
69
+ expect(getState()).toMatchObject({
70
+ name: 'Ramon'
71
+ });
72
+ });
73
+ it('updates a nested object', () => {
74
+ screen.getByText('Nested update').click();
75
+ expect(getState()).toMatchObject({
76
+ attributes: {
77
+ bar: 2,
78
+ baz: 1
79
+ }
80
+ });
81
+ });
82
+ });
@@ -0,0 +1,31 @@
1
+ // https://usehooks.com/useOnClickOutside/
2
+
3
+ /**
4
+ * External dependencies.
5
+ */
6
+ import { useEffect } from '@wordpress/element';
7
+ const useOnClickOutside = (ref, handler) => {
8
+ useEffect(() => {
9
+ const listener = event => {
10
+ // Do nothing if clicking ref's element or descendent elements
11
+ if (!ref.current || ref.current.contains(event.target)) {
12
+ return;
13
+ }
14
+ handler(event);
15
+ };
16
+ document.addEventListener('mousedown', listener);
17
+ document.addEventListener('touchstart', listener);
18
+ return () => {
19
+ document.removeEventListener('mousedown', listener);
20
+ document.removeEventListener('touchstart', listener);
21
+ };
22
+ },
23
+ // Add ref and handler to effect dependencies
24
+ // It's worth noting that because passed in handler is a new ...
25
+ // ... function on every render that will cause this effect ...
26
+ // ... callback/cleanup to run every render. It's not a big deal ...
27
+ // ... but to optimize you can wrap handler in useCallback before ...
28
+ // ... passing it into this hook.
29
+ [ref, handler]);
30
+ };
31
+ export default useOnClickOutside;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Image Upload
3
+ */
4
+
5
+ /**
6
+ * WordPress dependencies.
7
+ */
8
+ import { Component } from '@wordpress/element';
9
+ import { __ } from '@wordpress/i18n';
10
+
11
+ /**
12
+ * Internal dependencies.
13
+ */
14
+ import { Button, InfoButton } from '../';
15
+ import './style.scss';
16
+
17
+ /**
18
+ * External dependencies.
19
+ */
20
+ import classnames from 'classnames';
21
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
22
+ class ImageUpload extends Component {
23
+ /**
24
+ * Constructor.
25
+ */
26
+ constructor() {
27
+ super(...arguments);
28
+ this.state = {
29
+ frame: false
30
+ };
31
+ }
32
+
33
+ /**
34
+ * Open the WP media modal.
35
+ */
36
+ openModal = () => {
37
+ if (this.state.frame) {
38
+ this.state.frame.open();
39
+ return;
40
+ }
41
+ this.setState({
42
+ frame: wp.media({
43
+ title: __('Select or upload image'),
44
+ button: {
45
+ text: __('Select')
46
+ },
47
+ library: {
48
+ type: 'image'
49
+ },
50
+ multiple: false
51
+ })
52
+ }, () => {
53
+ this.state.frame.on('select', this.handleImageSelect);
54
+ this.state.frame.open();
55
+ });
56
+ };
57
+
58
+ /**
59
+ * Update the state when an image is selected from the media modal.
60
+ */
61
+ handleImageSelect = () => {
62
+ const {
63
+ onChange
64
+ } = this.props;
65
+ const attachment = this.state.frame.state().get('selection').first().toJSON();
66
+ onChange(attachment);
67
+ };
68
+
69
+ /**
70
+ * Render.
71
+ */
72
+ render = () => {
73
+ const {
74
+ buttonLabel,
75
+ className,
76
+ disabled,
77
+ help,
78
+ image,
79
+ info,
80
+ isCovering,
81
+ label,
82
+ onChange,
83
+ style = {}
84
+ } = this.props;
85
+ const classes = classnames('newspack-image-upload__image', {
86
+ 'newspack-image-upload__image--has-image': image
87
+ }, {
88
+ 'newspack-image-upload__image--covering': isCovering
89
+ });
90
+ return /*#__PURE__*/_jsxs("div", {
91
+ className: classnames('newspack-image-upload', className),
92
+ children: [/*#__PURE__*/_jsxs("div", {
93
+ className: "newspack-image-upload__header",
94
+ children: [label && /*#__PURE__*/_jsx("label", {
95
+ className: "newspack-image-upload__label",
96
+ children: label
97
+ }), info && /*#__PURE__*/_jsx(InfoButton, {
98
+ text: info
99
+ })]
100
+ }), /*#__PURE__*/_jsx("div", {
101
+ className: classes,
102
+ style: {
103
+ ...style
104
+ },
105
+ children: image?.url ? /*#__PURE__*/_jsxs(_Fragment, {
106
+ children: [/*#__PURE__*/_jsx("img", {
107
+ "data-testid": "image-upload",
108
+ src: image.url,
109
+ alt: __('Image preview', 'newspack-plugin')
110
+ }), /*#__PURE__*/_jsxs("div", {
111
+ className: "newspack-image-upload__controls",
112
+ children: [/*#__PURE__*/_jsx(Button, {
113
+ disabled: disabled,
114
+ onClick: this.openModal,
115
+ isLink: true,
116
+ children: __('Replace', 'newspack-plugin')
117
+ }), /*#__PURE__*/_jsx("span", {
118
+ className: "sep"
119
+ }), /*#__PURE__*/_jsx(Button, {
120
+ disabled: disabled,
121
+ onClick: () => onChange(null),
122
+ isLink: true,
123
+ isDestructive: true,
124
+ children: __('Remove', 'newspack-plugin')
125
+ })]
126
+ })]
127
+ }) : /*#__PURE__*/_jsx(Button, {
128
+ disabled: disabled,
129
+ onClick: this.openModal,
130
+ isLink: true,
131
+ children: buttonLabel ? buttonLabel : __('Upload', 'newspack-plugin')
132
+ })
133
+ }), help && /*#__PURE__*/_jsx("p", {
134
+ className: "newspack-image-upload__help",
135
+ children: help
136
+ })]
137
+ });
138
+ };
139
+ }
140
+ export default ImageUpload;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render } from '@testing-library/react';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import ImageUpload from './';
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ describe('ImageUpload', () => {
12
+ it('should render an add image button', () => {
13
+ const {
14
+ getByText
15
+ } = render( /*#__PURE__*/_jsx(ImageUpload, {}));
16
+ expect(getByText('Upload')).toBeInTheDocument();
17
+ });
18
+ it('should render replace and remove buttons if there is an image provided', () => {
19
+ const image = {
20
+ id: 1234,
21
+ url: 'https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg'
22
+ };
23
+ const {
24
+ getByText,
25
+ getByTestId
26
+ } = render( /*#__PURE__*/_jsx(ImageUpload, {
27
+ image: image
28
+ }));
29
+ expect(getByText('Remove')).toBeInTheDocument();
30
+ expect(getByText('Replace')).toBeInTheDocument();
31
+ expect(getByTestId('image-upload')).toBeInTheDocument();
32
+ expect(getByTestId('image-upload').getAttribute('src')).toEqual(image.url);
33
+ });
34
+ });