newspack-components 4.2.0 → 4.4.0-epic-editor-refactor.1
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.
- package/CHANGELOG.md +11 -0
- package/DEVELOPMENT.md +868 -0
- package/copy-styles.js +3 -2
- package/dist/cjs/accordion/index.js +17 -12
- package/dist/cjs/action-card/index.js +186 -140
- package/dist/cjs/action-card/style.scss +25 -2
- package/dist/cjs/autocomplete-tokenfield/index.js +254 -234
- package/dist/cjs/autocomplete-with-latest-posts/index.js +351 -0
- package/dist/cjs/autocomplete-with-latest-posts/style.scss +150 -0
- package/dist/cjs/autocomplete-with-suggestions/index.js +229 -126
- package/dist/cjs/badge/index.js +32 -0
- package/dist/cjs/badge/style.scss +36 -0
- package/dist/cjs/box-contrast/index.js +19 -15
- package/dist/cjs/button/index.js +41 -24
- package/dist/cjs/button-props/button-props.js +5 -5
- package/dist/cjs/button-props/index.js +2 -2
- package/dist/cjs/card/core-card.js +199 -0
- package/dist/cjs/card/index.js +75 -35
- package/dist/cjs/card/style-core.scss +295 -0
- package/dist/cjs/card/style.scss +4 -4
- package/dist/cjs/card-feature/index.js +141 -0
- package/dist/cjs/card-feature/style.scss +75 -0
- package/dist/cjs/card-form/index.js +144 -0
- package/dist/cjs/card-form/style.scss +20 -0
- package/dist/cjs/card-settings-group/index.js +69 -0
- package/dist/cjs/card-settings-group/style.scss +33 -0
- package/dist/cjs/card-sortable-list/index.js +426 -0
- package/dist/cjs/card-sortable-list/style.scss +48 -0
- package/dist/cjs/category-autocomplete/index.js +175 -155
- package/dist/cjs/color-picker/index.js +41 -23
- package/dist/cjs/color-picker/index.test.js +82 -0
- package/dist/cjs/color-picker/style.scss +11 -13
- package/dist/cjs/confirm-dialog/index.js +123 -0
- package/dist/cjs/consts.js +1 -1
- package/dist/cjs/custom-select-control/index.js +39 -28
- package/dist/cjs/dataviews/index.js +38 -0
- package/dist/cjs/dataviews/style.scss +9 -0
- package/dist/cjs/divider/index.js +47 -0
- package/dist/cjs/divider/style.scss +51 -0
- package/dist/cjs/footer/index.js +36 -30
- package/dist/cjs/form-token-field/index.js +51 -40
- package/dist/cjs/form-token-field/style.scss +0 -5
- package/dist/cjs/global-notices/index.js +5 -5
- package/dist/cjs/grid/index.js +25 -18
- package/dist/cjs/grid/style.scss +67 -8
- package/dist/cjs/handoff/index.js +204 -156
- package/dist/cjs/handoff-message/index.js +12 -7
- package/dist/cjs/hooks/index.js +10 -8
- package/dist/cjs/hooks/use-confirm-dialog.js +79 -0
- package/dist/cjs/hooks/use-unsaved-changes-dialog.js +144 -0
- package/dist/cjs/hooks/useObjectState.js +21 -12
- package/dist/cjs/hooks/useObjectState.test.js +55 -33
- package/dist/cjs/hooks/useOnClickOutside.js +6 -6
- package/dist/cjs/hooks/usePrompt.js +10 -13
- package/dist/cjs/image-upload/index.js +114 -123
- package/dist/cjs/image-upload/index.test.js +11 -13
- package/dist/cjs/image-upload/style.scss +12 -40
- package/dist/cjs/index.js +166 -92
- package/dist/cjs/info-button/index.js +43 -32
- package/dist/cjs/integration-icons/active-campaign.js +22 -0
- package/dist/cjs/integration-icons/constant-contact.js +28 -0
- package/dist/cjs/integration-icons/fundraise-up.js +25 -0
- package/dist/cjs/integration-icons/index.js +48 -0
- package/dist/cjs/integration-icons/mailchimp.js +19 -0
- package/dist/cjs/integration-icons/salesforce.js +17 -0
- package/dist/cjs/integration-icons/wisepops.js +20 -0
- package/dist/cjs/modal/index.js +29 -19
- package/dist/cjs/modal/style.scss +47 -13
- package/dist/cjs/newspack-icon/index.js +45 -38
- package/dist/cjs/newspack-icon/style.scss +5 -3
- package/dist/cjs/notice/index.js +64 -55
- package/dist/cjs/plugin-installer/index.js +259 -253
- package/dist/cjs/plugin-settings/SettingsSection.js +66 -60
- package/dist/cjs/plugin-settings/index.js +217 -200
- package/dist/cjs/plugin-toggle/index.js +192 -199
- package/dist/cjs/popover/index.js +41 -28
- package/dist/cjs/position-control/index.js +24 -23
- package/dist/cjs/progress-bar/index.js +71 -59
- package/dist/cjs/progress-bar/index.test.js +62 -68
- package/dist/cjs/proxied-imports/router.js +3 -3
- package/dist/cjs/radio-control/index.js +40 -27
- package/dist/cjs/section-header/index.js +143 -39
- package/dist/cjs/section-header/style.scss +129 -4
- package/dist/cjs/select-control/ButtonGroupControl.js +26 -21
- package/dist/cjs/select-control/GroupedSelectControl.js +41 -35
- package/dist/cjs/select-control/index.js +52 -40
- package/dist/cjs/settings/MinMaxSetting.js +30 -20
- package/dist/cjs/settings/SettingsCard.js +20 -17
- package/dist/cjs/settings/SettingsSection.js +22 -21
- package/dist/cjs/settings/index.js +5 -5
- package/dist/cjs/sortable-newsletter-list-control/index.js +78 -57
- package/dist/cjs/steps-list/index.js +44 -34
- package/dist/cjs/steps-list-item/index.js +47 -39
- package/dist/cjs/style-card/index.js +70 -63
- package/dist/cjs/style.scss +2 -0
- package/dist/cjs/tabbed-navigation/index.js +38 -36
- package/dist/cjs/text-control/index.js +27 -25
- package/dist/cjs/utils/color.js +4 -4
- package/dist/cjs/utils/editor-toolbar-back-button.js +61 -0
- package/dist/cjs/utils/index.js +31 -19
- package/dist/cjs/utils/style.scss +8 -0
- package/dist/cjs/waiting/index.js +48 -35
- package/dist/cjs/waiting/style.scss +4 -0
- package/dist/cjs/web-preview/index.js +219 -154
- package/dist/cjs/web-preview/style.scss +20 -53
- package/dist/cjs/with-wizard/index.js +362 -364
- package/dist/cjs/with-wizard/style.scss +28 -60
- package/dist/cjs/with-wizard-screen/index.js +54 -58
- package/dist/cjs/with-wizard-screen/style.scss +77 -10
- package/dist/cjs/wizard/components/WizardError.js +20 -18
- package/dist/cjs/wizard/components/WizardSnackbar.js +73 -0
- package/dist/cjs/wizard/components/style.scss +48 -0
- package/dist/cjs/wizard/index.js +207 -64
- package/dist/cjs/wizard/store/index.js +191 -97
- package/dist/cjs/wizard/store/utils.js +13 -8
- package/dist/esm/accordion/index.js +14 -9
- package/dist/esm/action-card/index.js +178 -124
- package/dist/esm/action-card/style.scss +25 -2
- package/dist/esm/autocomplete-tokenfield/index.js +248 -222
- package/dist/esm/autocomplete-with-latest-posts/index.js +347 -0
- package/dist/esm/autocomplete-with-latest-posts/style.scss +150 -0
- package/dist/esm/autocomplete-with-suggestions/index.js +226 -119
- package/dist/esm/badge/index.js +24 -0
- package/dist/esm/badge/style.scss +36 -0
- package/dist/esm/box-contrast/index.js +15 -11
- package/dist/esm/button/index.js +39 -19
- package/dist/esm/button-props/button-props.js +1 -1
- package/dist/esm/card/core-card.js +195 -0
- package/dist/esm/card/index.js +70 -22
- package/dist/esm/card/style-core.scss +295 -0
- package/dist/esm/card/style.scss +4 -4
- package/dist/esm/card-feature/index.js +131 -0
- package/dist/esm/card-feature/style.scss +75 -0
- package/dist/esm/card-form/index.js +134 -0
- package/dist/esm/card-form/style.scss +20 -0
- package/dist/esm/card-settings-group/index.js +61 -0
- package/dist/esm/card-settings-group/style.scss +33 -0
- package/dist/esm/card-sortable-list/index.js +425 -0
- package/dist/esm/card-sortable-list/style.scss +48 -0
- package/dist/esm/category-autocomplete/index.js +168 -140
- package/dist/esm/color-picker/index.js +39 -21
- package/dist/esm/color-picker/index.test.js +78 -0
- package/dist/esm/color-picker/style.scss +11 -13
- package/dist/esm/confirm-dialog/index.js +116 -0
- package/dist/esm/consts.js +1 -1
- package/dist/esm/custom-select-control/index.js +34 -15
- package/dist/esm/dataviews/index.js +34 -0
- package/dist/esm/dataviews/style.scss +9 -0
- package/dist/esm/divider/index.js +42 -0
- package/dist/esm/divider/style.scss +51 -0
- package/dist/esm/footer/index.js +34 -28
- package/dist/esm/form-token-field/index.js +46 -27
- package/dist/esm/form-token-field/style.scss +0 -5
- package/dist/esm/global-notices/index.js +3 -3
- package/dist/esm/grid/index.js +23 -13
- package/dist/esm/grid/style.scss +67 -8
- package/dist/esm/handoff/index.js +199 -143
- package/dist/esm/handoff-message/index.js +10 -6
- package/dist/esm/hooks/index.js +8 -6
- package/dist/esm/hooks/use-confirm-dialog.js +73 -0
- package/dist/esm/hooks/use-unsaved-changes-dialog.js +136 -0
- package/dist/esm/hooks/useObjectState.js +19 -9
- package/dist/esm/hooks/useObjectState.test.js +54 -32
- package/dist/esm/hooks/useOnClickOutside.js +4 -4
- package/dist/esm/hooks/usePrompt.js +9 -11
- package/dist/esm/image-upload/index.js +110 -111
- package/dist/esm/image-upload/index.test.js +11 -13
- package/dist/esm/image-upload/style.scss +12 -40
- package/dist/esm/index.js +13 -1
- package/dist/esm/info-button/index.js +38 -19
- package/dist/esm/integration-icons/active-campaign.js +16 -0
- package/dist/esm/integration-icons/constant-contact.js +22 -0
- package/dist/esm/integration-icons/fundraise-up.js +19 -0
- package/dist/esm/integration-icons/index.js +6 -0
- package/dist/esm/integration-icons/mailchimp.js +13 -0
- package/dist/esm/integration-icons/salesforce.js +11 -0
- package/dist/esm/integration-icons/wisepops.js +14 -0
- package/dist/esm/modal/index.js +27 -13
- package/dist/esm/modal/style.scss +47 -13
- package/dist/esm/newspack-icon/index.js +40 -25
- package/dist/esm/newspack-icon/style.scss +5 -3
- package/dist/esm/notice/index.js +59 -42
- package/dist/esm/plugin-installer/index.js +255 -243
- package/dist/esm/plugin-settings/SettingsSection.js +61 -50
- package/dist/esm/plugin-settings/index.js +212 -189
- package/dist/esm/plugin-toggle/index.js +187 -190
- package/dist/esm/popover/index.js +35 -16
- package/dist/esm/position-control/index.js +22 -18
- package/dist/esm/progress-bar/index.js +66 -49
- package/dist/esm/progress-bar/index.test.js +61 -67
- package/dist/esm/radio-control/index.js +34 -15
- package/dist/esm/section-header/index.js +140 -38
- package/dist/esm/section-header/style.scss +129 -4
- package/dist/esm/select-control/ButtonGroupControl.js +23 -18
- package/dist/esm/select-control/GroupedSelectControl.js +38 -30
- package/dist/esm/select-control/index.js +47 -27
- package/dist/esm/settings/MinMaxSetting.js +27 -16
- package/dist/esm/settings/SettingsCard.js +18 -13
- package/dist/esm/settings/SettingsSection.js +20 -19
- package/dist/esm/settings/index.js +3 -3
- package/dist/esm/sortable-newsletter-list-control/index.js +74 -53
- package/dist/esm/steps-list/index.js +39 -21
- package/dist/esm/steps-list-item/index.js +42 -26
- package/dist/esm/style-card/index.js +65 -50
- package/dist/esm/style.scss +2 -0
- package/dist/esm/tabbed-navigation/index.js +35 -33
- package/dist/esm/text-control/index.js +25 -19
- package/dist/esm/utils/color.js +4 -4
- package/dist/esm/utils/editor-toolbar-back-button.js +53 -0
- package/dist/esm/utils/index.js +29 -16
- package/dist/esm/utils/style.scss +8 -0
- package/dist/esm/waiting/index.js +43 -22
- package/dist/esm/waiting/style.scss +4 -0
- package/dist/esm/web-preview/index.js +218 -147
- package/dist/esm/web-preview/style.scss +20 -53
- package/dist/esm/with-wizard/index.js +360 -358
- package/dist/esm/with-wizard/style.scss +28 -60
- package/dist/esm/with-wizard-screen/index.js +48 -46
- package/dist/esm/with-wizard-screen/style.scss +77 -10
- package/dist/esm/wizard/components/WizardError.js +18 -16
- package/dist/esm/wizard/components/WizardSnackbar.js +70 -0
- package/dist/esm/wizard/components/style.scss +48 -0
- package/dist/esm/wizard/index.js +207 -58
- package/dist/esm/wizard/store/index.js +189 -90
- package/dist/esm/wizard/store/utils.js +13 -6
- package/package.json +30 -17
- package/release.config.js +1 -0
- package/shared/author-context.js +26 -0
- package/shared/hooks/use-coauthors.js +388 -0
- package/shared/hooks/use-coauthors.test.js +850 -0
- package/shared/hooks/use-custom-byline.js +47 -0
- package/shared/hooks/use-custom-byline.test.js +133 -0
- package/shared/scss/_mixins.scss +54 -0
- package/src/accordion/index.js +8 -7
- package/src/action-card/action-card.d.ts +7 -3
- package/src/action-card/index.js +39 -12
- package/src/action-card/style.scss +25 -2
- package/src/autocomplete-tokenfield/index.js +2 -2
- package/src/autocomplete-with-latest-posts/index.js +290 -0
- package/src/autocomplete-with-latest-posts/style.scss +150 -0
- package/src/badge/index.tsx +26 -0
- package/src/badge/style.scss +36 -0
- package/src/button/index.tsx +3 -2
- package/src/card/core-card.js +224 -0
- package/src/card/index.js +40 -1
- package/src/card/style-core.scss +295 -0
- package/src/card/style.scss +4 -4
- package/src/card-feature/README.md +188 -0
- package/src/card-feature/index.tsx +186 -0
- package/src/card-feature/style.scss +75 -0
- package/src/card-form/README.md +113 -0
- package/src/card-form/index.tsx +128 -0
- package/src/card-form/style.scss +20 -0
- package/src/card-settings-group/README.md +43 -0
- package/src/card-settings-group/index.tsx +78 -0
- package/src/card-settings-group/style.scss +33 -0
- package/src/card-sortable-list/README.md +51 -0
- package/src/card-sortable-list/index.tsx +435 -0
- package/src/card-sortable-list/style.scss +48 -0
- package/src/color-picker/index.js +15 -8
- package/src/color-picker/index.test.js +52 -0
- package/src/color-picker/style.scss +11 -13
- package/src/confirm-dialog/README.md +128 -0
- package/src/confirm-dialog/index.tsx +132 -0
- package/src/dataviews/index.tsx +34 -0
- package/src/dataviews/style.scss +9 -0
- package/src/divider/README.md +25 -0
- package/src/divider/index.js +31 -0
- package/src/divider/style.scss +51 -0
- package/src/form-token-field/style.scss +0 -5
- package/src/grid/index.tsx +2 -1
- package/src/grid/style.scss +67 -8
- package/src/handoff/README.md +93 -0
- package/src/handoff/index.js +46 -8
- package/src/hooks/index.ts +2 -1
- package/src/hooks/use-confirm-dialog.tsx +80 -0
- package/src/hooks/use-unsaved-changes-dialog.tsx +140 -0
- package/src/image-upload/index.js +10 -15
- package/src/image-upload/style.scss +12 -40
- package/src/index.js +13 -1
- package/src/integration-icons/active-campaign.js +14 -0
- package/src/integration-icons/constant-contact.js +22 -0
- package/src/integration-icons/fundraise-up.js +18 -0
- package/src/integration-icons/index.js +6 -0
- package/src/integration-icons/mailchimp.js +10 -0
- package/src/integration-icons/salesforce.js +10 -0
- package/src/integration-icons/wisepops.js +14 -0
- package/src/modal/index.js +12 -3
- package/src/modal/style.scss +47 -13
- package/src/newspack-icon/style.scss +5 -3
- package/src/plugin-installer/index.js +30 -19
- package/src/section-header/index.js +105 -14
- package/src/section-header/style.scss +129 -4
- package/src/select-control/index.js +4 -0
- package/src/style.scss +2 -0
- package/src/utils/editor-toolbar-back-button.tsx +48 -0
- package/src/utils/index.js +6 -0
- package/src/utils/style.scss +8 -0
- package/src/waiting/index.js +2 -1
- package/src/waiting/style.scss +4 -0
- package/src/web-preview/index.js +90 -35
- package/src/web-preview/style.scss +20 -53
- package/src/with-wizard/index.js +1 -1
- package/src/with-wizard/style.scss +28 -60
- package/src/with-wizard-screen/style.scss +77 -10
- package/src/wizard/components/WizardSnackbar.js +58 -0
- package/src/wizard/components/style.scss +48 -0
- package/src/wizard/index.js +152 -21
- package/src/wizard/store/index.js +28 -2
- package/dist/cjs/button-card/index.js +0 -72
- package/dist/cjs/button-card/style.scss +0 -180
- package/dist/esm/button-card/index.js +0 -64
- package/dist/esm/button-card/style.scss +0 -180
- package/src/button-card/index.js +0 -52
- package/src/button-card/style.scss +0 -180
package/src/grid/style.scss
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
// No Margin
|
|
15
15
|
&--no-margin {
|
|
16
|
-
margin: 0;
|
|
16
|
+
margin: 0 !important;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Gutter 0
|
|
@@ -41,6 +41,11 @@
|
|
|
41
41
|
grid-gap: 32px;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// Gutter 64
|
|
45
|
+
&__gutter-64 {
|
|
46
|
+
grid-gap: 64px;
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
// Row Gap 0
|
|
45
50
|
&__row-gap-0 {
|
|
46
51
|
grid-row-gap: 0;
|
|
@@ -61,11 +66,6 @@
|
|
|
61
66
|
grid-row-gap: 32px;
|
|
62
67
|
}
|
|
63
68
|
|
|
64
|
-
// Gutter 64
|
|
65
|
-
&__gutter-64 {
|
|
66
|
-
grid-gap: 64px;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
69
|
// Columns 6
|
|
70
70
|
&__columns-6 {
|
|
71
71
|
grid-template-columns: repeat(2, 1fr);
|
|
@@ -77,6 +77,14 @@
|
|
|
77
77
|
&__columns-3,
|
|
78
78
|
&__columns-4 {
|
|
79
79
|
grid-template-columns: repeat(2, 1fr);
|
|
80
|
+
|
|
81
|
+
> [start] {
|
|
82
|
+
grid-column-start: 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
> [end] {
|
|
86
|
+
grid-column-end: -1;
|
|
87
|
+
}
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
&__columns-6 {
|
|
@@ -84,8 +92,8 @@
|
|
|
84
92
|
}
|
|
85
93
|
}
|
|
86
94
|
|
|
87
|
-
// Media Queries -
|
|
88
|
-
@media screen and ( min-width:
|
|
95
|
+
// Media Queries - 1054px
|
|
96
|
+
@media screen and ( min-width: 1054px ) {
|
|
89
97
|
// Columns 3
|
|
90
98
|
&__columns-3 {
|
|
91
99
|
grid-template-columns: repeat(3, 1fr);
|
|
@@ -94,6 +102,14 @@
|
|
|
94
102
|
// Columns 4
|
|
95
103
|
&__columns-4 {
|
|
96
104
|
grid-template-columns: repeat(4, 1fr);
|
|
105
|
+
|
|
106
|
+
> [start="2"] {
|
|
107
|
+
grid-column-start: 2;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
> [end="4"] {
|
|
111
|
+
grid-column-end: 4;
|
|
112
|
+
}
|
|
97
113
|
}
|
|
98
114
|
|
|
99
115
|
// Columns 6
|
|
@@ -101,6 +117,11 @@
|
|
|
101
117
|
grid-template-columns: repeat(6, 1fr);
|
|
102
118
|
}
|
|
103
119
|
|
|
120
|
+
// Columns 12
|
|
121
|
+
&__columns-12 {
|
|
122
|
+
grid-template-columns: repeat(12, 1fr);
|
|
123
|
+
}
|
|
124
|
+
|
|
104
125
|
// Gutter 48
|
|
105
126
|
&__gutter-48 {
|
|
106
127
|
grid-gap: 48px;
|
|
@@ -116,6 +137,44 @@
|
|
|
116
137
|
> * {
|
|
117
138
|
margin-bottom: 0 !important;
|
|
118
139
|
margin-top: 0 !important;
|
|
140
|
+
> h1:first-child,
|
|
141
|
+
> h2:first-child,
|
|
142
|
+
> h3:first-child,
|
|
143
|
+
> h4:first-child,
|
|
144
|
+
> h5:first-child,
|
|
145
|
+
> h6:first-child {
|
|
146
|
+
margin-top: 0;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Borders
|
|
151
|
+
&__borders {
|
|
152
|
+
grid-gap: 0 !important;
|
|
153
|
+
> * {
|
|
154
|
+
border-bottom: 1px solid wp-colors.$gray-300;
|
|
155
|
+
&:last-child {
|
|
156
|
+
border-bottom: none;
|
|
157
|
+
}
|
|
158
|
+
@media screen and ( min-width: 744px ) {
|
|
159
|
+
border-bottom: none;
|
|
160
|
+
border-right: 1px solid wp-colors.$gray-300;
|
|
161
|
+
&:last-child {
|
|
162
|
+
border-right: none;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
&.newspack-grid__gutter-8 > * {
|
|
167
|
+
padding: 8px;
|
|
168
|
+
}
|
|
169
|
+
&.newspack-grid__gutter-16 > * {
|
|
170
|
+
padding: 16px;
|
|
171
|
+
}
|
|
172
|
+
&.newspack-grid__gutter-32 > * {
|
|
173
|
+
padding: 32px;
|
|
174
|
+
}
|
|
175
|
+
&.newspack-grid__gutter-64 > * {
|
|
176
|
+
padding: 64px;
|
|
177
|
+
}
|
|
119
178
|
}
|
|
120
179
|
|
|
121
180
|
.components-base-control {
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Handoff
|
|
2
|
+
|
|
3
|
+
Navigates the user to another admin page and displays a return banner at the top of the destination so they can find their way back.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
1. The user clicks the Handoff button.
|
|
8
|
+
2. A POST request registers the current URL as the return destination and stores optional banner customisations.
|
|
9
|
+
3. The user is redirected to the destination page.
|
|
10
|
+
4. A banner appears at the top of that page with a "Back to Newspack" button (or custom text) that returns them to the origin.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### With a URL
|
|
15
|
+
|
|
16
|
+
Use the `url` prop to hand off to any WordPress admin URL. No plugin needs to be installed.
|
|
17
|
+
|
|
18
|
+
```jsx
|
|
19
|
+
<Handoff url="/wp-admin/admin.php?page=newspack-dashboard#/">
|
|
20
|
+
Go to Dashboard
|
|
21
|
+
</Handoff>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### With a managed plugin slug
|
|
25
|
+
|
|
26
|
+
Use the `plugin` prop to hand off to a Newspack-managed plugin. The button is automatically disabled if the plugin is not installed or inactive.
|
|
27
|
+
|
|
28
|
+
```jsx
|
|
29
|
+
<Handoff plugin="jetpack">
|
|
30
|
+
Configure Jetpack
|
|
31
|
+
</Handoff>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use `editLink` to override the destination to a specific page within the plugin:
|
|
35
|
+
|
|
36
|
+
```jsx
|
|
37
|
+
<Handoff plugin="wordpress-seo" editLink="/wp-admin/admin.php?page=wpseo_dashboard">
|
|
38
|
+
Configure Yoast SEO
|
|
39
|
+
</Handoff>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Via ActionCard
|
|
43
|
+
|
|
44
|
+
`ActionCard` accepts `handoffUrl` (URL-based) or `handoff` (plugin slug) as convenience props that render a `Handoff` as the action button. `bannerText` and `bannerButtonText` are supported on both:
|
|
45
|
+
|
|
46
|
+
```jsx
|
|
47
|
+
<ActionCard
|
|
48
|
+
title="My Feature"
|
|
49
|
+
actionText="Configure"
|
|
50
|
+
handoffUrl="/wp-admin/admin.php?page=my-settings"
|
|
51
|
+
bannerText="Return here once you're done."
|
|
52
|
+
bannerButtonText="Back to My Feature"
|
|
53
|
+
/>
|
|
54
|
+
|
|
55
|
+
<ActionCard
|
|
56
|
+
title="Jetpack"
|
|
57
|
+
actionText="Configure"
|
|
58
|
+
handoff="jetpack"
|
|
59
|
+
editLink="/wp-admin/admin.php?page=jetpack#/settings"
|
|
60
|
+
bannerText="Return here once you're done."
|
|
61
|
+
bannerButtonText="Back to My Feature"
|
|
62
|
+
/>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Props
|
|
66
|
+
|
|
67
|
+
| Prop | Type | Description |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `url` | `string` | Admin URL to hand off to. Use this or `plugin`, not both. |
|
|
70
|
+
| `plugin` | `string` | Slug of a Newspack-managed plugin to hand off to. |
|
|
71
|
+
| `editLink` | `string` | Overrides the destination URL when using `plugin`. |
|
|
72
|
+
| `bannerText` | `string` | Custom body text for the return banner. Defaults to "Return to Newspack after completing configuration". |
|
|
73
|
+
| `bannerButtonText` | `string` | Custom label for the return button. Defaults to "Back to Newspack". |
|
|
74
|
+
| `showOnBlockEditor` | `bool` | Show the return banner inside the block editor. Default `false`. |
|
|
75
|
+
| `useModal` | `bool` | Show a confirmation modal before navigating. |
|
|
76
|
+
| `modalTitle` | `string` | Title for the confirmation modal. |
|
|
77
|
+
| `modalBody` | `string` | Body text for the confirmation modal. |
|
|
78
|
+
| `onReady` | `func` | Called with plugin info once loaded (plugin mode only). |
|
|
79
|
+
| `children` | `node` | Button label. Falls back to "Manage {Plugin Name}" in plugin mode. |
|
|
80
|
+
|
|
81
|
+
All other props are passed through to the underlying `Button` component (`isPrimary`, `isLink`, `isTertiary`, `className`, etc.).
|
|
82
|
+
|
|
83
|
+
## Banner customisation
|
|
84
|
+
|
|
85
|
+
```jsx
|
|
86
|
+
<Handoff
|
|
87
|
+
url="/wp-admin/admin.php?page=my-settings"
|
|
88
|
+
bannerText="Finish your configuration, then come back here."
|
|
89
|
+
bannerButtonText="Back to My Feature"
|
|
90
|
+
>
|
|
91
|
+
Open Settings
|
|
92
|
+
</Handoff>
|
|
93
|
+
```
|
package/src/handoff/index.js
CHANGED
|
@@ -31,8 +31,10 @@ class Handoff extends Component {
|
|
|
31
31
|
|
|
32
32
|
componentDidMount = () => {
|
|
33
33
|
this._isMounted = true;
|
|
34
|
-
const { plugin } = this.props;
|
|
35
|
-
|
|
34
|
+
const { plugin, url } = this.props;
|
|
35
|
+
if ( plugin && ! url ) {
|
|
36
|
+
this.retrievePluginInfo( plugin );
|
|
37
|
+
}
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
componentWillUnmount = () => {
|
|
@@ -60,8 +62,25 @@ class Handoff extends Component {
|
|
|
60
62
|
return assign( defaults, this.props );
|
|
61
63
|
};
|
|
62
64
|
|
|
65
|
+
goToUrl = () => {
|
|
66
|
+
const { url, showOnBlockEditor, bannerText, bannerButtonText } = this.props;
|
|
67
|
+
apiFetch( {
|
|
68
|
+
path: '/newspack/v1/handoff',
|
|
69
|
+
method: 'POST',
|
|
70
|
+
data: {
|
|
71
|
+
destinationUrl: url,
|
|
72
|
+
handoffReturnUrl: window && window.location.href,
|
|
73
|
+
showOnBlockEditor: showOnBlockEditor ? true : false,
|
|
74
|
+
bannerText,
|
|
75
|
+
bannerButtonText,
|
|
76
|
+
},
|
|
77
|
+
} ).then( response => {
|
|
78
|
+
window.location.href = response.HandoffLink;
|
|
79
|
+
} );
|
|
80
|
+
};
|
|
81
|
+
|
|
63
82
|
goToPlugin = plugin => {
|
|
64
|
-
const { editLink, showOnBlockEditor } = this.props;
|
|
83
|
+
const { editLink, showOnBlockEditor, bannerText, bannerButtonText } = this.props;
|
|
65
84
|
apiFetch( {
|
|
66
85
|
path: '/newspack/v1/plugins/' + plugin + '/handoff',
|
|
67
86
|
method: 'POST',
|
|
@@ -69,6 +88,8 @@ class Handoff extends Component {
|
|
|
69
88
|
editLink,
|
|
70
89
|
handoffReturnUrl: window && window.location.href,
|
|
71
90
|
showOnBlockEditor: showOnBlockEditor ? true : false,
|
|
91
|
+
bannerText,
|
|
92
|
+
bannerButtonText,
|
|
72
93
|
},
|
|
73
94
|
} ).then( response => {
|
|
74
95
|
window.location.href = response.HandoffLink;
|
|
@@ -92,30 +113,47 @@ class Handoff extends Component {
|
|
|
92
113
|
onReady,
|
|
93
114
|
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
|
|
94
115
|
editLink,
|
|
116
|
+
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
|
|
117
|
+
bannerText,
|
|
118
|
+
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
|
|
119
|
+
bannerButtonText,
|
|
120
|
+
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
|
|
121
|
+
url,
|
|
95
122
|
...otherProps
|
|
96
123
|
} = this.props;
|
|
97
124
|
const { pluginInfo, showModal } = this.state;
|
|
98
125
|
const { modalBody, modalTitle, primaryButton, primaryModalButton, dismissModalButton } = this.textForPlugin( pluginInfo );
|
|
99
126
|
const { Configured, Name, Slug, Status } = pluginInfo;
|
|
100
127
|
const classes = classnames( Configured && 'is-configured', className );
|
|
128
|
+
const goTo = () => ( url ? this.goToUrl() : this.goToPlugin( Slug ) );
|
|
101
129
|
return (
|
|
102
130
|
<Fragment>
|
|
103
|
-
{
|
|
131
|
+
{ url && (
|
|
132
|
+
<Button
|
|
133
|
+
className={ classes }
|
|
134
|
+
isSecondary={ ! otherProps.isPrimary && ! otherProps.isTertiary && ! otherProps.isLink }
|
|
135
|
+
{ ...otherProps }
|
|
136
|
+
onClick={ () => ( useModal && children ? this.setState( { showModal: true } ) : goTo() ) }
|
|
137
|
+
>
|
|
138
|
+
{ children ? children : primaryButton }
|
|
139
|
+
</Button>
|
|
140
|
+
) }
|
|
141
|
+
{ ! url && Name && 'active' === Status && (
|
|
104
142
|
<Button
|
|
105
143
|
className={ classes }
|
|
106
144
|
isSecondary={ ! otherProps.isPrimary && ! otherProps.isTertiary && ! otherProps.isLink }
|
|
107
145
|
{ ...otherProps }
|
|
108
|
-
onClick={ () => ( useModal ? this.setState( { showModal: true } ) :
|
|
146
|
+
onClick={ () => ( useModal ? this.setState( { showModal: true } ) : goTo() ) }
|
|
109
147
|
>
|
|
110
148
|
{ children ? children : primaryButton }
|
|
111
149
|
</Button>
|
|
112
150
|
) }
|
|
113
|
-
{ Name && 'active' !== Status && (
|
|
151
|
+
{ ! url && Name && 'active' !== Status && (
|
|
114
152
|
<Button className={ classes } variant="secondary" disabled { ...otherProps }>
|
|
115
153
|
{ Name + __( ' not installed', 'newspack-plugin' ) }
|
|
116
154
|
</Button>
|
|
117
155
|
) }
|
|
118
|
-
{ ! Name && (
|
|
156
|
+
{ ! url && ! Name && (
|
|
119
157
|
<Button
|
|
120
158
|
className={ classes }
|
|
121
159
|
isSecondary={ ! otherProps.isPrimary && ! otherProps.isTertiary && ! otherProps.isLink }
|
|
@@ -134,7 +172,7 @@ class Handoff extends Component {
|
|
|
134
172
|
<Button variant="secondary" onClick={ () => this.setState( { showModal: false } ) }>
|
|
135
173
|
{ dismissModalButton }
|
|
136
174
|
</Button>
|
|
137
|
-
<Button variant="primary" onClick={
|
|
175
|
+
<Button variant="primary" onClick={ goTo }>
|
|
138
176
|
{ primaryModalButton }
|
|
139
177
|
</Button>
|
|
140
178
|
</Card>
|
package/src/hooks/index.ts
CHANGED
|
@@ -6,10 +6,11 @@ import { useRef } from '@wordpress/element';
|
|
|
6
6
|
import usePrompt from './usePrompt';
|
|
7
7
|
import useObjectState from './useObjectState';
|
|
8
8
|
import useOnClickOutside from './useOnClickOutside';
|
|
9
|
+
import useConfirmDialog from './use-confirm-dialog';
|
|
9
10
|
|
|
10
11
|
const useUniqueId = ( prefix: string ) => {
|
|
11
12
|
const id = useRef( `${ prefix }-${ Math.round( Math.random() * 99999 ) }` );
|
|
12
13
|
return id.current;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
|
-
export default { usePrompt, useObjectState, useOnClickOutside, useUniqueId };
|
|
16
|
+
export default { usePrompt, useObjectState, useOnClickOutside, useUniqueId, useConfirmDialog };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies.
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback, useRef, useState } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies.
|
|
8
|
+
*/
|
|
9
|
+
import ConfirmDialog from '../confirm-dialog';
|
|
10
|
+
|
|
11
|
+
type UseConfirmDialogOptions = {
|
|
12
|
+
when?: boolean;
|
|
13
|
+
message: React.ReactNode;
|
|
14
|
+
title?: string;
|
|
15
|
+
confirmButtonText?: string;
|
|
16
|
+
cancelButtonText?: string;
|
|
17
|
+
isDestructive?: boolean;
|
|
18
|
+
hideTitle?: boolean;
|
|
19
|
+
size?: 'small' | 'medium' | 'large' | 'x-large' | 'full';
|
|
20
|
+
className?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type UseConfirmDialogResult = {
|
|
24
|
+
confirmDialog: React.ReactElement;
|
|
25
|
+
requestConfirm: ( callback: () => void ) => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A hook that encapsulates the ConfirmDialog component and provides a
|
|
30
|
+
* `requestConfirm` function for imperative use.
|
|
31
|
+
*
|
|
32
|
+
* Calling `requestConfirm( callback )` will show a confirmation dialog.
|
|
33
|
+
* If the user confirms, `callback` is invoked. If the user cancels, it is not.
|
|
34
|
+
*
|
|
35
|
+
* When `when` is explicitly `false`, `requestConfirm( callback )` calls
|
|
36
|
+
* `callback` immediately without showing the dialog. This is useful for
|
|
37
|
+
* guarding actions that are only destructive when there are unsaved changes
|
|
38
|
+
* (e.g. `when={ isDirty }`). When `when` is omitted or `true`, the dialog
|
|
39
|
+
* is always shown.
|
|
40
|
+
*
|
|
41
|
+
* The `confirmDialog` element must be rendered somewhere in the component's
|
|
42
|
+
* JSX for the dialog to appear.
|
|
43
|
+
*/
|
|
44
|
+
function useConfirmDialog( options: UseConfirmDialogOptions ): UseConfirmDialogResult {
|
|
45
|
+
const { message, when, ...dialogProps } = options;
|
|
46
|
+
const [ pendingAction, setPendingAction ] = useState< ( () => void ) | null >( null );
|
|
47
|
+
|
|
48
|
+
// Keep a ref so `requestConfirm` can always read the latest `when` value
|
|
49
|
+
// without needing to be recreated on every render.
|
|
50
|
+
const whenRef = useRef( when );
|
|
51
|
+
whenRef.current = when;
|
|
52
|
+
|
|
53
|
+
const requestConfirm = useCallback( ( callback: () => void ) => {
|
|
54
|
+
if ( whenRef.current !== false ) {
|
|
55
|
+
// Store as a thunk to opt out of React's functional-update interpretation.
|
|
56
|
+
setPendingAction( () => callback );
|
|
57
|
+
} else {
|
|
58
|
+
callback();
|
|
59
|
+
}
|
|
60
|
+
}, [] );
|
|
61
|
+
|
|
62
|
+
const confirmDialog = (
|
|
63
|
+
<ConfirmDialog
|
|
64
|
+
{ ...dialogProps }
|
|
65
|
+
when={ when }
|
|
66
|
+
isOpen={ !! pendingAction }
|
|
67
|
+
onConfirm={ () => {
|
|
68
|
+
pendingAction?.();
|
|
69
|
+
setPendingAction( null );
|
|
70
|
+
} }
|
|
71
|
+
onCancel={ () => setPendingAction( null ) }
|
|
72
|
+
>
|
|
73
|
+
{ message }
|
|
74
|
+
</ConfirmDialog>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return { confirmDialog, requestConfirm };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default useConfirmDialog;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies.
|
|
3
|
+
*/
|
|
4
|
+
import { useEffect, useRef } from '@wordpress/element';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies.
|
|
9
|
+
*/
|
|
10
|
+
import useConfirmDialog from './use-confirm-dialog';
|
|
11
|
+
|
|
12
|
+
type UseUnsavedChangesDialogOptions = {
|
|
13
|
+
when: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Stack of mounted guards; the last entry owns the document-level handler so
|
|
17
|
+
// only the most-recently-mounted guard prompts when several are active. Using a
|
|
18
|
+
// stack keeps ownership correct under out-of-order unmounts.
|
|
19
|
+
const activeGuards: symbol[] = [];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns true when `href` resolves to the same origin as the current page —
|
|
23
|
+
* i.e. it is an internal navigation that would unload the wizard. External
|
|
24
|
+
* `https://...` links, `mailto:`, `tel:`, and other schemes navigate to a new
|
|
25
|
+
* context (new tab, mail client, dialer) without unloading the wizard, and
|
|
26
|
+
* must not trigger the discard-changes prompt.
|
|
27
|
+
*/
|
|
28
|
+
function isSameOriginNavigation( link: HTMLAnchorElement ): boolean {
|
|
29
|
+
try {
|
|
30
|
+
const url = new URL( link.href, window.location.href );
|
|
31
|
+
return url.origin === window.location.origin && ( url.protocol === 'http:' || url.protocol === 'https:' );
|
|
32
|
+
} catch ( e ) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Shared unsaved-changes guard. Wraps `useConfirmDialog` with standardized
|
|
39
|
+
* messaging, intercepts same-origin link clicks so the dialog fires instead
|
|
40
|
+
* of a silent navigation, and adds a `beforeunload` listener as the last-resort
|
|
41
|
+
* guard for refresh / tab-close (browser-native, cannot be styled). The
|
|
42
|
+
* returned `confirmDialog` element must be rendered in JSX.
|
|
43
|
+
*
|
|
44
|
+
* Single-consumer constraint: the click handler is attached at the document
|
|
45
|
+
* level in capture phase. Two simultaneously-active instances will both fire
|
|
46
|
+
* a dialog. A development-only warning surfaces this.
|
|
47
|
+
*/
|
|
48
|
+
function useUnsavedChangesDialog( { when }: UseUnsavedChangesDialogOptions ) {
|
|
49
|
+
const { confirmDialog, requestConfirm } = useConfirmDialog( {
|
|
50
|
+
when,
|
|
51
|
+
message: __( 'You have unsaved changes that will be lost. Discard changes?', 'newspack-plugin' ),
|
|
52
|
+
confirmButtonText: __( 'Discard changes', 'newspack-plugin' ),
|
|
53
|
+
hideTitle: true,
|
|
54
|
+
} );
|
|
55
|
+
|
|
56
|
+
// Tracks navigation the user has already approved via our custom dialog so
|
|
57
|
+
// the beforeunload guard doesn't fire a second native prompt on top of it.
|
|
58
|
+
const isNavigatingRef = useRef( false );
|
|
59
|
+
|
|
60
|
+
useEffect( () => {
|
|
61
|
+
if ( ! when ) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const ownerId = Symbol( 'unsaved-changes-guard' );
|
|
65
|
+
activeGuards.push( ownerId );
|
|
66
|
+
if ( process.env.NODE_ENV !== 'production' && activeGuards.length > 1 ) {
|
|
67
|
+
// eslint-disable-next-line no-console
|
|
68
|
+
console.warn(
|
|
69
|
+
'useUnsavedChangesDialog: more than one active instance detected. ' +
|
|
70
|
+
'Document-level click capture will fire a dialog per instance — ensure only one guard is active at a time.'
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const handler = ( e: MouseEvent ) => {
|
|
74
|
+
// Only the top-of-stack guard prompts, so concurrent guards can't stack dialogs.
|
|
75
|
+
if ( activeGuards[ activeGuards.length - 1 ] !== ownerId ) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if ( e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0 ) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const target = e.target as HTMLElement | null;
|
|
82
|
+
const link = target?.closest( 'a[href]' ) as HTMLAnchorElement | null;
|
|
83
|
+
if ( ! link ) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const href = link.getAttribute( 'href' );
|
|
87
|
+
if ( ! href || href.startsWith( '#' ) || href.startsWith( 'javascript:' ) ) {
|
|
88
|
+
// All `#`-prefixed links are skipped here: plain anchors
|
|
89
|
+
// (`#section`) are scroll targets, and HashRouter paths
|
|
90
|
+
// (`#/route`) are intercepted by `ConfirmDialog`'s built-in
|
|
91
|
+
// `history.block` listener instead. Routing them through
|
|
92
|
+
// `window.location.href` here would trigger a hashchange
|
|
93
|
+
// that the still-active block re-catches, double-prompting.
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if ( link.target && link.target !== '_self' ) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// Skip mailto:, tel:, external origins, and any non-http(s) scheme —
|
|
100
|
+
// they don't unload the wizard, so a discard prompt would be wrong.
|
|
101
|
+
if ( ! isSameOriginNavigation( link ) ) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
e.stopPropagation();
|
|
106
|
+
const destination = link.href;
|
|
107
|
+
requestConfirm( () => {
|
|
108
|
+
isNavigatingRef.current = true;
|
|
109
|
+
window.location.href = destination;
|
|
110
|
+
} );
|
|
111
|
+
};
|
|
112
|
+
document.addEventListener( 'click', handler, true );
|
|
113
|
+
return () => {
|
|
114
|
+
document.removeEventListener( 'click', handler, true );
|
|
115
|
+
const idx = activeGuards.indexOf( ownerId );
|
|
116
|
+
if ( idx !== -1 ) {
|
|
117
|
+
activeGuards.splice( idx, 1 );
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}, [ when, requestConfirm ] );
|
|
121
|
+
|
|
122
|
+
useEffect( () => {
|
|
123
|
+
if ( ! when ) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const handler = ( e: BeforeUnloadEvent ) => {
|
|
127
|
+
if ( isNavigatingRef.current ) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
e.returnValue = '';
|
|
132
|
+
};
|
|
133
|
+
window.addEventListener( 'beforeunload', handler );
|
|
134
|
+
return () => window.removeEventListener( 'beforeunload', handler );
|
|
135
|
+
}, [ when ] );
|
|
136
|
+
|
|
137
|
+
return { confirmDialog, requestConfirm };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export default useUnsavedChangesDialog;
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Component } from '@wordpress/element';
|
|
9
9
|
import { __ } from '@wordpress/i18n';
|
|
10
|
+
import { BaseControl } from '@wordpress/components';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Internal dependencies.
|
|
13
14
|
*/
|
|
14
|
-
import { Button
|
|
15
|
+
import { Button } from '../';
|
|
15
16
|
import './style.scss';
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -72,41 +73,35 @@ class ImageUpload extends Component {
|
|
|
72
73
|
* Render.
|
|
73
74
|
*/
|
|
74
75
|
render = () => {
|
|
75
|
-
const { buttonLabel, className, disabled, help, image,
|
|
76
|
+
const { buttonLabel, className, disabled, help, image, isCovering, label, onChange, style = {} } = this.props;
|
|
76
77
|
const classes = classnames(
|
|
77
78
|
'newspack-image-upload__image',
|
|
78
79
|
{ 'newspack-image-upload__image--has-image': image },
|
|
79
80
|
{ 'newspack-image-upload__image--covering': isCovering }
|
|
80
81
|
);
|
|
81
82
|
return (
|
|
82
|
-
<
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
{ label && <label className="newspack-image-upload__label">{ label }</label> }
|
|
86
|
-
{ info && <InfoButton text={ info } /> }
|
|
87
|
-
</div>
|
|
88
|
-
<div className={ classes } style={ { ...style } }>
|
|
83
|
+
<BaseControl __nextHasNoMarginBottom className={ classnames( 'newspack-image-upload', className ) } help={ help }>
|
|
84
|
+
{ label && <BaseControl.VisualLabel>{ label }</BaseControl.VisualLabel> }
|
|
85
|
+
<div className={ classes } style={ style }>
|
|
89
86
|
{ image?.url ? (
|
|
90
87
|
<>
|
|
91
88
|
<img data-testid="image-upload" src={ image.url } alt={ __( 'Image preview', 'newspack-plugin' ) } />
|
|
92
89
|
<div className="newspack-image-upload__controls">
|
|
93
|
-
<Button disabled={ disabled } onClick={ this.openModal }
|
|
90
|
+
<Button disabled={ disabled } onClick={ this.openModal } variant="tertiary">
|
|
94
91
|
{ __( 'Replace', 'newspack-plugin' ) }
|
|
95
92
|
</Button>
|
|
96
|
-
<
|
|
97
|
-
<Button disabled={ disabled } onClick={ () => onChange( null ) } isLink isDestructive>
|
|
93
|
+
<Button disabled={ disabled } onClick={ () => onChange( null ) } variant="tertiary" isDestructive>
|
|
98
94
|
{ __( 'Remove', 'newspack-plugin' ) }
|
|
99
95
|
</Button>
|
|
100
96
|
</div>
|
|
101
97
|
</>
|
|
102
98
|
) : (
|
|
103
|
-
<Button disabled={ disabled } onClick={ this.openModal }
|
|
99
|
+
<Button disabled={ disabled } onClick={ this.openModal } variant="tertiary">
|
|
104
100
|
{ buttonLabel ? buttonLabel : __( 'Upload', 'newspack-plugin' ) }
|
|
105
101
|
</Button>
|
|
106
102
|
) }
|
|
107
103
|
</div>
|
|
108
|
-
|
|
109
|
-
</div>
|
|
104
|
+
</BaseControl>
|
|
110
105
|
);
|
|
111
106
|
};
|
|
112
107
|
}
|