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

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 (227) 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/cjs/button/index.js +56 -0
  5. package/dist/cjs/grid/index.js +37 -0
  6. package/dist/cjs/hooks/index.js +25 -0
  7. package/dist/cjs/hooks/usePrompt.js +49 -0
  8. package/dist/cjs/text-control/index.js +64 -0
  9. package/dist/esm/accordion/index.js +42 -0
  10. package/dist/esm/accordion/style.scss +31 -0
  11. package/dist/esm/action-card/index.js +218 -0
  12. package/dist/esm/action-card/style.scss +483 -0
  13. package/dist/esm/autocomplete-tokenfield/index.js +261 -0
  14. package/dist/esm/autocomplete-tokenfield/style.scss +49 -0
  15. package/dist/esm/autocomplete-with-suggestions/index.js +274 -0
  16. package/dist/esm/autocomplete-with-suggestions/style.scss +163 -0
  17. package/dist/esm/button/index.js +48 -0
  18. package/dist/esm/button/style.scss +11 -0
  19. package/dist/esm/button-card/index.js +64 -0
  20. package/dist/esm/button-card/style.scss +180 -0
  21. package/dist/esm/card/index.js +43 -0
  22. package/dist/esm/card/style.scss +168 -0
  23. package/dist/esm/category-autocomplete/index.js +183 -0
  24. package/dist/esm/category-autocomplete/style.scss +34 -0
  25. package/dist/esm/color-picker/index.js +59 -0
  26. package/dist/esm/color-picker/style.scss +37 -0
  27. package/dist/esm/consts.js +1 -0
  28. package/dist/esm/custom-select-control/index.js +37 -0
  29. package/dist/esm/custom-select-control/style.scss +93 -0
  30. package/dist/esm/date-range-picker/index.js +31 -0
  31. package/dist/esm/date-range-picker/style.scss +148 -0
  32. package/dist/esm/footer/index.js +99 -0
  33. package/dist/esm/footer/style.scss +82 -0
  34. package/dist/esm/form-token-field/index.js +49 -0
  35. package/dist/esm/form-token-field/style.scss +37 -0
  36. package/dist/esm/global-notices/index.js +30 -0
  37. package/dist/esm/grid/index.js +29 -0
  38. package/dist/esm/grid/style.scss +166 -0
  39. package/dist/esm/handoff/index.js +175 -0
  40. package/dist/esm/handoff-message/index.js +47 -0
  41. package/dist/esm/hooks/index.js +17 -0
  42. package/dist/esm/hooks/useObjectState.js +30 -0
  43. package/dist/esm/hooks/useObjectState.test.js +82 -0
  44. package/dist/esm/hooks/useOnClickOutside.js +31 -0
  45. package/dist/esm/hooks/usePrompt.js +40 -0
  46. package/dist/esm/image-upload/index.js +140 -0
  47. package/dist/esm/image-upload/index.test.js +34 -0
  48. package/dist/esm/image-upload/style.scss +103 -0
  49. package/dist/esm/index.js +47 -0
  50. package/dist/esm/info-button/index.js +42 -0
  51. package/dist/esm/info-button/style.scss +18 -0
  52. package/dist/esm/modal/index.js +39 -0
  53. package/dist/esm/modal/style.scss +56 -0
  54. package/dist/esm/newspack-icon/index.js +50 -0
  55. package/dist/esm/newspack-icon/style.scss +26 -0
  56. package/dist/esm/newspack-logo/index.js +46 -0
  57. package/dist/esm/newspack-logo/style.scss +30 -0
  58. package/dist/esm/notice/index.js +65 -0
  59. package/dist/esm/notice/style.scss +111 -0
  60. package/dist/esm/patrons-logo/index.js +70 -0
  61. package/dist/esm/plugin-installer/index.js +289 -0
  62. package/dist/esm/plugin-installer/style.scss +72 -0
  63. package/dist/esm/plugin-settings/SettingsSection.js +133 -0
  64. package/dist/esm/plugin-settings/index.js +220 -0
  65. package/dist/esm/plugin-settings/style.scss +7 -0
  66. package/dist/esm/plugin-toggle/index.js +216 -0
  67. package/dist/esm/plugin-toggle/style.scss +20 -0
  68. package/dist/esm/popover/index.js +41 -0
  69. package/dist/esm/popover/style.scss +161 -0
  70. package/dist/esm/position-control/index.js +106 -0
  71. package/dist/esm/position-control/style.scss +66 -0
  72. package/dist/esm/progress-bar/index.js +68 -0
  73. package/dist/esm/progress-bar/index.test.js +108 -0
  74. package/dist/esm/progress-bar/style.scss +42 -0
  75. package/dist/esm/proxied-imports/router.js +8 -0
  76. package/dist/esm/radio-control/index.js +37 -0
  77. package/dist/esm/radio-control/style.scss +92 -0
  78. package/dist/esm/section-header/index.js +67 -0
  79. package/dist/esm/section-header/style.scss +45 -0
  80. package/dist/esm/select-control/ButtonGroupControl.js +53 -0
  81. package/dist/esm/select-control/GroupedSelectControl.js +78 -0
  82. package/dist/esm/select-control/index.js +51 -0
  83. package/dist/esm/select-control/style.scss +108 -0
  84. package/dist/esm/settings/MinMaxSetting.js +53 -0
  85. package/dist/esm/settings/SettingsCard.js +38 -0
  86. package/dist/esm/settings/SettingsSection.js +26 -0
  87. package/dist/esm/settings/index.js +9 -0
  88. package/dist/esm/settings/style.scss +119 -0
  89. package/dist/esm/sortable-newsletter-list-control/index.js +127 -0
  90. package/dist/esm/sortable-newsletter-list-control/style.scss +45 -0
  91. package/dist/esm/steps-list/index.js +43 -0
  92. package/dist/esm/steps-list/style.scss +11 -0
  93. package/dist/esm/steps-list-item/index.js +47 -0
  94. package/dist/esm/steps-list-item/style.scss +47 -0
  95. package/dist/esm/style-card/index.js +74 -0
  96. package/dist/esm/style-card/style.scss +94 -0
  97. package/dist/esm/style.scss +55 -0
  98. package/dist/esm/tabbed-navigation/index.js +53 -0
  99. package/dist/esm/tabbed-navigation/style.scss +86 -0
  100. package/dist/esm/text-control/index.js +56 -0
  101. package/dist/esm/text-control/style.scss +32 -0
  102. package/dist/esm/utils/index.js +29 -0
  103. package/dist/esm/waiting/index.js +44 -0
  104. package/dist/esm/waiting/style.scss +27 -0
  105. package/dist/esm/web-preview/index.js +183 -0
  106. package/dist/esm/web-preview/style.scss +155 -0
  107. package/dist/esm/with-wizard/index.js +320 -0
  108. package/dist/esm/with-wizard/style.scss +282 -0
  109. package/dist/esm/with-wizard-screen/index.js +109 -0
  110. package/dist/esm/with-wizard-screen/style.scss +160 -0
  111. package/dist/esm/wizard/components/WizardError.js +66 -0
  112. package/dist/esm/wizard/index.js +119 -0
  113. package/dist/esm/wizard/store/index.js +155 -0
  114. package/dist/esm/wizard/store/utils.js +14 -0
  115. package/package.json +8 -4
  116. package/dist/button/index.js +0 -51
  117. package/dist/button/index.tsx +0 -48
  118. package/dist/grid/index.js +0 -44
  119. package/dist/grid/index.tsx +0 -34
  120. package/dist/hooks/index.js +0 -29
  121. package/dist/hooks/index.ts +0 -15
  122. package/dist/hooks/usePrompt.js +0 -47
  123. package/dist/hooks/usePrompt.ts +0 -46
  124. package/dist/plugin-toggle/README.md +0 -53
  125. package/dist/text-control/index.js +0 -76
  126. package/dist/text-control/index.tsx +0 -71
  127. /package/dist/{accordion → cjs/accordion}/index.js +0 -0
  128. /package/dist/{accordion → cjs/accordion}/style.scss +0 -0
  129. /package/dist/{action-card → cjs/action-card}/index.js +0 -0
  130. /package/dist/{action-card → cjs/action-card}/style.scss +0 -0
  131. /package/dist/{autocomplete-tokenfield → cjs/autocomplete-tokenfield}/index.js +0 -0
  132. /package/dist/{autocomplete-tokenfield → cjs/autocomplete-tokenfield}/style.scss +0 -0
  133. /package/dist/{autocomplete-with-suggestions → cjs/autocomplete-with-suggestions}/index.js +0 -0
  134. /package/dist/{autocomplete-with-suggestions → cjs/autocomplete-with-suggestions}/style.scss +0 -0
  135. /package/dist/{button → cjs/button}/style.scss +0 -0
  136. /package/dist/{button-card → cjs/button-card}/index.js +0 -0
  137. /package/dist/{button-card → cjs/button-card}/style.scss +0 -0
  138. /package/dist/{card → cjs/card}/index.js +0 -0
  139. /package/dist/{card → cjs/card}/style.scss +0 -0
  140. /package/dist/{category-autocomplete → cjs/category-autocomplete}/index.js +0 -0
  141. /package/dist/{category-autocomplete → cjs/category-autocomplete}/style.scss +0 -0
  142. /package/dist/{color-picker → cjs/color-picker}/index.js +0 -0
  143. /package/dist/{color-picker → cjs/color-picker}/style.scss +0 -0
  144. /package/dist/{consts.js → cjs/consts.js} +0 -0
  145. /package/dist/{custom-select-control → cjs/custom-select-control}/index.js +0 -0
  146. /package/dist/{custom-select-control → cjs/custom-select-control}/style.scss +0 -0
  147. /package/dist/{date-range-picker → cjs/date-range-picker}/index.js +0 -0
  148. /package/dist/{date-range-picker → cjs/date-range-picker}/style.scss +0 -0
  149. /package/dist/{footer → cjs/footer}/index.js +0 -0
  150. /package/dist/{footer → cjs/footer}/style.scss +0 -0
  151. /package/dist/{form-token-field → cjs/form-token-field}/index.js +0 -0
  152. /package/dist/{form-token-field → cjs/form-token-field}/style.scss +0 -0
  153. /package/dist/{global-notices → cjs/global-notices}/index.js +0 -0
  154. /package/dist/{grid → cjs/grid}/style.scss +0 -0
  155. /package/dist/{handoff → cjs/handoff}/index.js +0 -0
  156. /package/dist/{handoff-message → cjs/handoff-message}/index.js +0 -0
  157. /package/dist/{hooks → cjs/hooks}/useObjectState.js +0 -0
  158. /package/dist/{hooks → cjs/hooks}/useObjectState.test.js +0 -0
  159. /package/dist/{hooks → cjs/hooks}/useOnClickOutside.js +0 -0
  160. /package/dist/{image-upload → cjs/image-upload}/index.js +0 -0
  161. /package/dist/{image-upload → cjs/image-upload}/index.test.js +0 -0
  162. /package/dist/{image-upload → cjs/image-upload}/style.scss +0 -0
  163. /package/dist/{index.js → cjs/index.js} +0 -0
  164. /package/dist/{info-button → cjs/info-button}/index.js +0 -0
  165. /package/dist/{info-button → cjs/info-button}/style.scss +0 -0
  166. /package/dist/{modal → cjs/modal}/index.js +0 -0
  167. /package/dist/{modal → cjs/modal}/style.scss +0 -0
  168. /package/dist/{newspack-icon → cjs/newspack-icon}/index.js +0 -0
  169. /package/dist/{newspack-icon → cjs/newspack-icon}/style.scss +0 -0
  170. /package/dist/{newspack-logo → cjs/newspack-logo}/index.js +0 -0
  171. /package/dist/{newspack-logo → cjs/newspack-logo}/style.scss +0 -0
  172. /package/dist/{notice → cjs/notice}/index.js +0 -0
  173. /package/dist/{notice → cjs/notice}/style.scss +0 -0
  174. /package/dist/{patrons-logo → cjs/patrons-logo}/index.js +0 -0
  175. /package/dist/{plugin-installer → cjs/plugin-installer}/index.js +0 -0
  176. /package/dist/{plugin-installer → cjs/plugin-installer}/style.scss +0 -0
  177. /package/dist/{plugin-settings → cjs/plugin-settings}/SettingsSection.js +0 -0
  178. /package/dist/{plugin-settings → cjs/plugin-settings}/index.js +0 -0
  179. /package/dist/{plugin-settings → cjs/plugin-settings}/style.scss +0 -0
  180. /package/dist/{plugin-toggle → cjs/plugin-toggle}/index.js +0 -0
  181. /package/dist/{plugin-toggle → cjs/plugin-toggle}/style.scss +0 -0
  182. /package/dist/{popover → cjs/popover}/index.js +0 -0
  183. /package/dist/{popover → cjs/popover}/style.scss +0 -0
  184. /package/dist/{position-control → cjs/position-control}/index.js +0 -0
  185. /package/dist/{position-control → cjs/position-control}/style.scss +0 -0
  186. /package/dist/{progress-bar → cjs/progress-bar}/index.js +0 -0
  187. /package/dist/{progress-bar → cjs/progress-bar}/index.test.js +0 -0
  188. /package/dist/{progress-bar → cjs/progress-bar}/style.scss +0 -0
  189. /package/dist/{proxied-imports → cjs/proxied-imports}/router.js +0 -0
  190. /package/dist/{radio-control → cjs/radio-control}/index.js +0 -0
  191. /package/dist/{radio-control → cjs/radio-control}/style.scss +0 -0
  192. /package/dist/{section-header → cjs/section-header}/index.js +0 -0
  193. /package/dist/{section-header → cjs/section-header}/style.scss +0 -0
  194. /package/dist/{select-control → cjs/select-control}/ButtonGroupControl.js +0 -0
  195. /package/dist/{select-control → cjs/select-control}/GroupedSelectControl.js +0 -0
  196. /package/dist/{select-control → cjs/select-control}/index.js +0 -0
  197. /package/dist/{select-control → cjs/select-control}/style.scss +0 -0
  198. /package/dist/{settings → cjs/settings}/MinMaxSetting.js +0 -0
  199. /package/dist/{settings → cjs/settings}/SettingsCard.js +0 -0
  200. /package/dist/{settings → cjs/settings}/SettingsSection.js +0 -0
  201. /package/dist/{settings → cjs/settings}/index.js +0 -0
  202. /package/dist/{settings → cjs/settings}/style.scss +0 -0
  203. /package/dist/{sortable-newsletter-list-control → cjs/sortable-newsletter-list-control}/index.js +0 -0
  204. /package/dist/{sortable-newsletter-list-control → cjs/sortable-newsletter-list-control}/style.scss +0 -0
  205. /package/dist/{steps-list → cjs/steps-list}/index.js +0 -0
  206. /package/dist/{steps-list → cjs/steps-list}/style.scss +0 -0
  207. /package/dist/{steps-list-item → cjs/steps-list-item}/index.js +0 -0
  208. /package/dist/{steps-list-item → cjs/steps-list-item}/style.scss +0 -0
  209. /package/dist/{style-card → cjs/style-card}/index.js +0 -0
  210. /package/dist/{style-card → cjs/style-card}/style.scss +0 -0
  211. /package/dist/{style.scss → cjs/style.scss} +0 -0
  212. /package/dist/{tabbed-navigation → cjs/tabbed-navigation}/index.js +0 -0
  213. /package/dist/{tabbed-navigation → cjs/tabbed-navigation}/style.scss +0 -0
  214. /package/dist/{text-control → cjs/text-control}/style.scss +0 -0
  215. /package/dist/{utils → cjs/utils}/index.js +0 -0
  216. /package/dist/{waiting → cjs/waiting}/index.js +0 -0
  217. /package/dist/{waiting → cjs/waiting}/style.scss +0 -0
  218. /package/dist/{web-preview → cjs/web-preview}/index.js +0 -0
  219. /package/dist/{web-preview → cjs/web-preview}/style.scss +0 -0
  220. /package/dist/{with-wizard → cjs/with-wizard}/index.js +0 -0
  221. /package/dist/{with-wizard → cjs/with-wizard}/style.scss +0 -0
  222. /package/dist/{with-wizard-screen → cjs/with-wizard-screen}/index.js +0 -0
  223. /package/dist/{with-wizard-screen → cjs/with-wizard-screen}/style.scss +0 -0
  224. /package/dist/{wizard → cjs/wizard}/components/WizardError.js +0 -0
  225. /package/dist/{wizard → cjs/wizard}/index.js +0 -0
  226. /package/dist/{wizard → cjs/wizard}/store/index.js +0 -0
  227. /package/dist/{wizard → cjs/wizard}/store/utils.js +0 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Ads Settings Section.
3
+ */
4
+
5
+ /**
6
+ * WordPress dependencies
7
+ */
8
+ import { Fragment, useState } from '@wordpress/element';
9
+ import { applyFilters } from '@wordpress/hooks';
10
+ import { __ } from '@wordpress/i18n';
11
+ import { CheckboxControl } from '@wordpress/components';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import { ActionCard, Button, Grid, Notice, SelectControl, TextControl } from '../';
17
+ import './style.scss';
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ const isSelectControl = setting => {
20
+ return Array.isArray(setting.options) && setting.options.length;
21
+ };
22
+ const getControlComponent = setting => {
23
+ if (isSelectControl(setting)) {
24
+ return SelectControl;
25
+ }
26
+ switch (setting.type) {
27
+ case 'checkbox':
28
+ case 'boolean':
29
+ return CheckboxControl;
30
+ default:
31
+ return TextControl;
32
+ }
33
+ };
34
+ const getControlType = setting => {
35
+ switch (setting.type) {
36
+ case 'int':
37
+ case 'integer':
38
+ case 'float':
39
+ case 'number':
40
+ return 'number';
41
+ case 'string':
42
+ case 'text':
43
+ return 'text';
44
+ case 'password':
45
+ return 'password';
46
+ case 'boolean':
47
+ case 'checkbox':
48
+ return 'checkbox';
49
+ default:
50
+ return null;
51
+ }
52
+ };
53
+ const SettingsSection = props => {
54
+ const [saveDisabled, setSaveDisabled] = useState(true);
55
+ const {
56
+ error,
57
+ sectionKey,
58
+ active,
59
+ title,
60
+ description,
61
+ fields,
62
+ disabled,
63
+ onChange,
64
+ onUpdate
65
+ } = props;
66
+ const getControlProps = setting => ({
67
+ disabled,
68
+ name: `${setting.section}_${setting.key}`,
69
+ type: getControlType(setting),
70
+ label: setting.description,
71
+ help: setting.help || null,
72
+ options: setting.options?.map(option => ({
73
+ value: option.value,
74
+ label: option.name || option.label
75
+ })) || null,
76
+ value: setting.value,
77
+ multiple: isSelectControl(setting) && setting.multiple ? true : null,
78
+ checked: setting.type === 'boolean' ? !!setting.value : null,
79
+ onChange: value => {
80
+ onChange(setting.key, value);
81
+ setSaveDisabled(false);
82
+ }
83
+ });
84
+ const createFilter = (name, defaultComponent = null) => {
85
+ return applyFilters(`newspack.settingSection.${sectionKey}.${name}`, defaultComponent, props);
86
+ };
87
+ let columns = 2;
88
+ if (fields.length % 3 === 0) {
89
+ columns = 3;
90
+ } else if (fields.length === 1) {
91
+ columns = 1;
92
+ }
93
+ return /*#__PURE__*/_jsx(ActionCard, {
94
+ isMedium: true,
95
+ disabled: disabled,
96
+ title: title,
97
+ description: description,
98
+ toggleChecked: active,
99
+ hasGreyHeader: active || null === active,
100
+ toggleOnChange: active !== null ? value => onUpdate({
101
+ active: value
102
+ }) : null,
103
+ actionContent: (active || null === active) && createFilter('buttons', /*#__PURE__*/_jsx(Button, {
104
+ variant: "primary",
105
+ disabled: disabled || saveDisabled,
106
+ onClick: () => {
107
+ onUpdate();
108
+ setSaveDisabled(true);
109
+ },
110
+ children: __('Save Settings', 'newspack')
111
+ })),
112
+ children: (active || active === null) && /*#__PURE__*/_jsxs(Fragment, {
113
+ children: [error?.message && /*#__PURE__*/_jsx(Notice, {
114
+ noticeText: error.message,
115
+ isError: true
116
+ }), createFilter('beforeControls'), /*#__PURE__*/_jsx(Grid, {
117
+ columns: columns,
118
+ gutter: 32,
119
+ children: fields.map(setting => {
120
+ const Control = getControlComponent(setting); // eslint-disable-line @wordpress/no-unused-vars-before-return, no-unused-vars
121
+ return applyFilters(`newspack.settingsSection.${sectionKey}.control`, /*#__PURE__*/_jsx(Control, {
122
+ ...getControlProps(setting)
123
+ }, setting.key), {
124
+ sectionKey,
125
+ setting,
126
+ onChange
127
+ });
128
+ })
129
+ })]
130
+ })
131
+ });
132
+ };
133
+ export default SettingsSection;
@@ -0,0 +1,220 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies.
8
+ */
9
+ import apiFetch from '@wordpress/api-fetch';
10
+ import { Component, Fragment } from '@wordpress/element';
11
+ import { __ } from '@wordpress/i18n';
12
+
13
+ /**
14
+ * Internal dependencies.
15
+ */
16
+ import { SectionHeader, Notice } from '../';
17
+ import SettingsSection from './SettingsSection';
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ class PluginSettings extends Component {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.state = {
23
+ inFlight: false,
24
+ settings: {},
25
+ error: null
26
+ };
27
+ }
28
+ fetchSettings = () => {
29
+ const {
30
+ afterFetch,
31
+ pluginSlug,
32
+ isWizard
33
+ } = this.props;
34
+ this.setState({
35
+ inFlight: true
36
+ });
37
+ apiFetch({
38
+ path: isWizard ? `/newspack/v1/wizard/${pluginSlug}/settings` : `/${pluginSlug}/v1/settings`
39
+ }).then(settings => {
40
+ this.setState({
41
+ settings,
42
+ error: null
43
+ });
44
+ if ('function' === typeof afterFetch) {
45
+ afterFetch(settings);
46
+ }
47
+ }).catch(error => {
48
+ this.setState({
49
+ error
50
+ });
51
+ }).finally(() => {
52
+ this.setState({
53
+ inFlight: false
54
+ });
55
+ });
56
+ };
57
+ componentDidMount() {
58
+ this.fetchSettings();
59
+ }
60
+ getSettingsValues = sectionKey => {
61
+ return this.state.settings[sectionKey]?.reduce((map, setting) => {
62
+ map[setting.key] = setting.value;
63
+ return map;
64
+ }, {}) || {};
65
+ };
66
+ handleSettingChange = sectionKey => (key, value) => {
67
+ const sectionSettings = [...this.state.settings[sectionKey]];
68
+ sectionSettings.forEach(setting => {
69
+ if (setting.key === key) {
70
+ setting.value = value;
71
+ }
72
+ });
73
+ this.setState({
74
+ settings: {
75
+ ...this.state.settings,
76
+ [sectionKey]: sectionSettings
77
+ }
78
+ });
79
+ };
80
+ handleSectionUpdate = sectionKey => data => {
81
+ const {
82
+ afterUpdate,
83
+ pluginSlug,
84
+ isWizard
85
+ } = this.props;
86
+ this.setState({
87
+ inFlight: true
88
+ });
89
+ apiFetch({
90
+ path: isWizard ? `/newspack/v1/wizard/${pluginSlug}/settings` : `/${pluginSlug}/v1/settings`,
91
+ method: 'POST',
92
+ data: {
93
+ section: sectionKey,
94
+ settings: data ? data : this.getSettingsValues(sectionKey)
95
+ }
96
+ }).then(settings => {
97
+ this.setState({
98
+ settings: {
99
+ ...this.state.settings,
100
+ [sectionKey]: settings[sectionKey]
101
+ },
102
+ error: null
103
+ });
104
+ if ('function' === typeof afterUpdate) {
105
+ afterUpdate(settings);
106
+ }
107
+ }).catch(error => {
108
+ this.setState({
109
+ error
110
+ });
111
+ }).finally(() => {
112
+ this.setState({
113
+ inFlight: false
114
+ });
115
+ });
116
+ };
117
+
118
+ /**
119
+ * Get the section setting containing section information.
120
+ *
121
+ * @param {string} sectionKey The section name.
122
+ * @return {Object} The section setting.
123
+ */
124
+ getSectionInfo = sectionKey => {
125
+ return this.state.settings[sectionKey]?.find(setting => !setting.key || setting.key === 'active');
126
+ };
127
+
128
+ /**
129
+ * Get the section title.
130
+ *
131
+ * @param {string} sectionKey The section name.
132
+ * @return {string} The section title.
133
+ */
134
+ getSectionTitle = sectionKey => {
135
+ return this.getSectionInfo(sectionKey)?.description;
136
+ };
137
+
138
+ /**
139
+ * Get the section description.
140
+ *
141
+ * @param {string} sectionKey The section name.
142
+ * @return {string} The section description.
143
+ */
144
+ getSectionDescription = sectionKey => {
145
+ return this.getSectionInfo(sectionKey)?.help;
146
+ };
147
+
148
+ /**
149
+ * Get whether a section is active.
150
+ *
151
+ * @param {string} sectionKey The section name.
152
+ * @return {?boolean} Whether the section is active or not. Null if the section is not found or does not support activation.
153
+ */
154
+ isSectionActive = sectionKey => {
155
+ const {
156
+ settings
157
+ } = this.state;
158
+ const activation = settings[sectionKey]?.find(setting => setting.key === 'active');
159
+ if (!activation) {
160
+ return null;
161
+ }
162
+ return activation.value;
163
+ };
164
+
165
+ /**
166
+ * Get list of section field settings.
167
+ *
168
+ * @param {string} sectionKey The section name.
169
+ * @return {?Array} List of section fields.
170
+ */
171
+ getSectionFields = sectionKey => {
172
+ return this.state.settings[sectionKey]?.filter(setting => setting.key && setting.key !== 'active');
173
+ };
174
+
175
+ /**
176
+ * Render.
177
+ */
178
+ render() {
179
+ const {
180
+ title,
181
+ description,
182
+ hasGreyHeader,
183
+ children
184
+ } = this.props;
185
+ const {
186
+ settings,
187
+ inFlight,
188
+ error
189
+ } = this.state;
190
+ return /*#__PURE__*/_jsxs(Fragment, {
191
+ children: [title && /*#__PURE__*/_jsx(SectionHeader, {
192
+ title: title,
193
+ description: description
194
+ }), error && /*#__PURE__*/_jsx(Notice, {
195
+ isError: true,
196
+ noticeText: error.message
197
+ }), /*#__PURE__*/_jsxs("div", {
198
+ className: classnames('newspack-plugin-settings', {
199
+ 'newspack-wizard-section__is-loading': inFlight && !Object.keys(settings).length
200
+ }),
201
+ children: [Object.keys(settings).map(sectionKey => /*#__PURE__*/_jsx(SettingsSection, {
202
+ disabled: inFlight,
203
+ sectionKey: sectionKey,
204
+ title: this.getSectionTitle(sectionKey),
205
+ description: this.getSectionDescription(sectionKey),
206
+ active: this.isSectionActive(sectionKey),
207
+ fields: this.getSectionFields(sectionKey),
208
+ onChange: this.handleSettingChange(sectionKey),
209
+ onUpdate: this.handleSectionUpdate(sectionKey),
210
+ hasGreyHeader: hasGreyHeader
211
+ }, sectionKey)), children]
212
+ })]
213
+ });
214
+ }
215
+ }
216
+ PluginSettings.defaultProps = {
217
+ title: __('General Settings', 'newspack-plugin')
218
+ };
219
+ PluginSettings.Section = SettingsSection;
220
+ export default PluginSettings;
@@ -0,0 +1,7 @@
1
+ .newspack-card:not(.newspack-settings__no-border) {
2
+ .newspack-action-card__region-children {
3
+ > .newspack-grid {
4
+ margin: 32px 0 0 !important;
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,216 @@
1
+ /**
2
+ * WordPress dependencies.
3
+ */
4
+ import apiFetch from '@wordpress/api-fetch';
5
+ import { Component, Fragment } from '@wordpress/element';
6
+ import { __ } from '@wordpress/i18n';
7
+
8
+ /**
9
+ * Internal dependencies.
10
+ */
11
+ import { ActionCard, Waiting } from '../';
12
+ import './style.scss';
13
+
14
+ /**
15
+ * Plugin toggle group component.
16
+ */
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ class PluginToggle extends Component {
19
+ state = {
20
+ pluginInfo: {}
21
+ };
22
+ componentDidMount = () => {
23
+ this.retrievePluginInfo();
24
+ };
25
+
26
+ /**
27
+ * Retrieve complete data about Newspack plugins.
28
+ */
29
+ retrievePluginInfo = () => {
30
+ return new Promise(() => {
31
+ apiFetch({
32
+ path: '/newspack/v1/plugins/'
33
+ }).then(pluginInfo => this.setState({
34
+ pluginInfo
35
+ }));
36
+ });
37
+ };
38
+
39
+ /**
40
+ * Install/activate or remove a plugin.
41
+ */
42
+ managePlugin = (plugin, value) => {
43
+ const {
44
+ plugins
45
+ } = this.props;
46
+ const {
47
+ pluginInfo
48
+ } = this.state;
49
+ const action = value ? 'configure' : 'deactivate';
50
+ const params = {
51
+ path: `/newspack/v1/plugins/${plugin}/${action}/`,
52
+ method: 'post'
53
+ };
54
+ this.setState({
55
+ pluginInfo: {
56
+ ...pluginInfo,
57
+ [plugin]: {
58
+ ...pluginInfo[plugin],
59
+ inFlight: action
60
+ }
61
+ }
62
+ }, () => {
63
+ apiFetch(params).then(response => {
64
+ const {
65
+ shouldRefreshAfterUpdate
66
+ } = plugins[plugin];
67
+ this.setState(({
68
+ pluginInfo: currentPluginInfo
69
+ }) => ({
70
+ pluginInfo: {
71
+ ...currentPluginInfo,
72
+ [plugin]: response
73
+ }
74
+ }), () => shouldRefreshAfterUpdate && location.reload());
75
+ }).catch(e => {
76
+ this.setState({
77
+ pluginInfo: {
78
+ ...pluginInfo,
79
+ [plugin]: {
80
+ ...pluginInfo[plugin],
81
+ error: e.message || __('There was an error managing this plugin.', 'newspack-plugin')
82
+ }
83
+ }
84
+ });
85
+ });
86
+ });
87
+ };
88
+
89
+ /**
90
+ * Render.
91
+ */
92
+ render() {
93
+ const {
94
+ plugins
95
+ } = this.props;
96
+ const {
97
+ pluginInfo
98
+ } = this.state;
99
+ return this.prepareDataForRender(plugins, pluginInfo).map((plugin, index) => {
100
+ const {
101
+ name,
102
+ description,
103
+ href,
104
+ slug,
105
+ editPath
106
+ } = plugin;
107
+ const pluginStatus = this.isPluginInstalledAndActive(plugin);
108
+ const handoff = !href && pluginStatus && editPath ? slug : null;
109
+ const error = this.errorForPlugin(plugin);
110
+ return /*#__PURE__*/_jsx(ActionCard, {
111
+ className: this.classNameForPlugin(plugin),
112
+ title: name,
113
+ description: description,
114
+ actionText: this.actionTextForPlugin(plugin),
115
+ handoff: handoff,
116
+ href: href,
117
+ toggle: true,
118
+ toggleChecked: this.isPluginInstalledAndActive(plugin),
119
+ toggleOnChange: value => this.managePlugin(slug, value),
120
+ notification: error,
121
+ notificationHTML: error,
122
+ notificationLevel: "error"
123
+ }, index);
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Prepare plugins data for render. Change all keys to camelCase, merge API-fetched data with prop.
129
+ */
130
+ prepareDataForRender = (pluginsFromProps, pluginsFromAPI) => Object.keys(pluginsFromProps).map(pluginSlug => pluginsFromAPI[pluginSlug] ? Object.keys(pluginsFromAPI[pluginSlug]).reduce((accumulator, key) => ({
131
+ ...accumulator,
132
+ [key.charAt(0).toLowerCase() + key.slice(1)]: pluginsFromAPI[pluginSlug][key]
133
+ }), {}) : {}).map(plugin => Object.assign(plugin, pluginsFromProps[plugin.slug]));
134
+
135
+ /**
136
+ * Generate a classname for the ActionCard based on plugin state. Applies 'in-flight' class if an API is underway and 'loading' if the plugin data is not yet available.
137
+ */
138
+ classNameForPlugin = plugin => {
139
+ const {
140
+ status,
141
+ inFlight
142
+ } = plugin;
143
+ if (inFlight) {
144
+ return 'in-flight';
145
+ }
146
+ if (!status) {
147
+ return 'loading';
148
+ }
149
+ };
150
+
151
+ /**
152
+ * Generate the ActionCard action text for a plugin.
153
+ */
154
+ actionTextForPlugin = plugin => {
155
+ const {
156
+ actionText,
157
+ editPath,
158
+ href,
159
+ inFlight,
160
+ name
161
+ } = plugin;
162
+ // Show spinner when plugin data is unavailable, or when an API call is in flight.
163
+ if ('configure' === inFlight) {
164
+ return /*#__PURE__*/_jsxs(Fragment, {
165
+ children: [__('Installing…', 'newspack-plugin'), " ", /*#__PURE__*/_jsx(Waiting, {
166
+ isRight: true
167
+ })]
168
+ });
169
+ }
170
+ if ('deactivate' === inFlight) {
171
+ return /*#__PURE__*/_jsxs(Fragment, {
172
+ children: [__('Deactivating…', 'newspack-plugin'), " ", /*#__PURE__*/_jsx(Waiting, {
173
+ isRight: true
174
+ })]
175
+ });
176
+ }
177
+ if (!name) {
178
+ return /*#__PURE__*/_jsxs(Fragment, {
179
+ children: [__('Loading…', 'newspack-plugin'), " ", /*#__PURE__*/_jsx(Waiting, {
180
+ isRight: true
181
+ })]
182
+ });
183
+ }
184
+ // No action button at all if the plugin isn't installed and active.
185
+ if (!this.isPluginInstalledAndActive(plugin)) {
186
+ return null;
187
+ }
188
+ if (href || editPath) {
189
+ return actionText ? actionText : __('Configure', 'newspack-plugin');
190
+ }
191
+ };
192
+
193
+ /**
194
+ * Get error message for this plugin.
195
+ */
196
+ errorForPlugin = plugin => {
197
+ const {
198
+ slug
199
+ } = plugin;
200
+ const {
201
+ pluginInfo
202
+ } = this.state;
203
+ return pluginInfo[slug]?.error || null;
204
+ };
205
+
206
+ /**
207
+ * Get installation/activation status for a plugin.
208
+ */
209
+ isPluginInstalledAndActive = plugin => {
210
+ const {
211
+ status
212
+ } = plugin;
213
+ return status === 'active';
214
+ };
215
+ }
216
+ export default PluginToggle;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Plugin Toggle
3
+ */
4
+
5
+ @use "~@wordpress/base-styles/colors" as wp-colors;
6
+
7
+ .newspack-action-card {
8
+ &.in-flight,
9
+ &.loading {
10
+ opacity: 0.5;
11
+
12
+ .newspack-action-card__region-right {
13
+ .newspack-button {
14
+ color: wp-colors.$gray-700;
15
+ pointer-events: none;
16
+ text-decoration: none;
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { Popover as BaseComponent } from '@wordpress/components';
5
+ import { Component } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import './style.scss';
11
+
12
+ /**
13
+ * External dependencies
14
+ */
15
+ import classnames from 'classnames';
16
+
17
+ /**
18
+ * Popover
19
+ */
20
+ import { jsx as _jsx } from "react/jsx-runtime";
21
+ class Popover extends Component {
22
+ /**
23
+ * Render
24
+ */
25
+ render() {
26
+ const {
27
+ className,
28
+ padding,
29
+ ...otherProps
30
+ } = this.props;
31
+ const classes = classnames('newspack-popover', padding && 'newspack-popover__padding-' + padding, className);
32
+ return /*#__PURE__*/_jsx(BaseComponent, {
33
+ className: classes,
34
+ ...otherProps
35
+ });
36
+ }
37
+ }
38
+ Popover.defaultProps = {
39
+ padding: false
40
+ };
41
+ export default Popover;