newspack-components 4.3.0 → 4.4.0-alpha.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/colors/colors.module.scss +52 -2
- package/copy-styles.js +3 -2
- package/dist/cjs/accordion/index.js +17 -12
- package/dist/cjs/action-card/index.js +176 -139
- package/dist/cjs/autocomplete-tokenfield/index.js +254 -234
- package/dist/cjs/autocomplete-with-latest-posts/index.js +172 -110
- package/dist/cjs/autocomplete-with-suggestions/index.js +229 -126
- package/dist/cjs/badge/index.js +7 -7
- package/dist/cjs/box-contrast/index.js +19 -15
- package/dist/cjs/button/index.js +41 -26
- 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 +110 -52
- package/dist/cjs/card/index.js +74 -67
- package/dist/cjs/card/style-core.scss +93 -25
- package/dist/cjs/card/style.scss +2 -2
- 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 +36 -16
- package/dist/cjs/card-sortable-list/index.js +176 -140
- 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 +86 -22
- 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 +26 -21
- package/dist/cjs/footer/index.js +36 -30
- package/dist/cjs/form-token-field/index.js +51 -40
- package/dist/cjs/global-notices/index.js +5 -5
- package/dist/cjs/grid/index.js +25 -19
- package/dist/cjs/grid/style.scss +6 -1
- 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 +136 -104
- 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 +22 -19
- package/dist/cjs/modal/style.scss +4 -0
- package/dist/cjs/newspack-icon/index.js +45 -38
- 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 +103 -58
- package/dist/cjs/section-header/style.scss +31 -11
- 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/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 -37
- package/dist/cjs/web-preview/index.js +217 -211
- package/dist/cjs/with-wizard/index.js +362 -364
- package/dist/cjs/with-wizard/style.scss +4 -54
- package/dist/cjs/with-wizard-screen/index.js +54 -58
- package/dist/cjs/with-wizard-screen/style.scss +41 -3
- package/dist/cjs/wizard/components/WizardError.js +20 -18
- package/dist/cjs/wizard/components/WizardSnackbar.js +26 -23
- package/dist/cjs/wizard/index.js +176 -114
- package/dist/cjs/wizard/store/index.js +171 -123
- package/dist/cjs/wizard/store/utils.js +13 -8
- package/dist/esm/accordion/index.js +14 -9
- package/dist/esm/action-card/index.js +168 -123
- package/dist/esm/autocomplete-tokenfield/index.js +248 -222
- package/dist/esm/autocomplete-with-latest-posts/index.js +169 -103
- package/dist/esm/autocomplete-with-suggestions/index.js +226 -119
- package/dist/esm/badge/index.js +5 -5
- package/dist/esm/box-contrast/index.js +15 -11
- package/dist/esm/button/index.js +39 -21
- package/dist/esm/button-props/button-props.js +1 -1
- package/dist/esm/card/core-card.js +109 -47
- package/dist/esm/card/index.js +69 -54
- package/dist/esm/card/style-core.scss +93 -25
- package/dist/esm/card/style.scss +2 -2
- 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 +33 -14
- package/dist/esm/card-sortable-list/index.js +170 -126
- 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 +85 -18
- 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 +24 -16
- package/dist/esm/footer/index.js +34 -28
- package/dist/esm/form-token-field/index.js +46 -27
- package/dist/esm/global-notices/index.js +3 -3
- package/dist/esm/grid/index.js +23 -14
- package/dist/esm/grid/style.scss +6 -1
- 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 +7 -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 +20 -13
- package/dist/esm/modal/style.scss +4 -0
- package/dist/esm/newspack-icon/index.js +40 -25
- 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 +102 -57
- package/dist/esm/section-header/style.scss +31 -11
- 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/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 -24
- package/dist/esm/web-preview/index.js +213 -201
- package/dist/esm/with-wizard/index.js +360 -358
- package/dist/esm/with-wizard/style.scss +4 -54
- package/dist/esm/with-wizard-screen/index.js +48 -46
- package/dist/esm/with-wizard-screen/style.scss +41 -3
- package/dist/esm/wizard/components/WizardError.js +18 -16
- package/dist/esm/wizard/components/WizardSnackbar.js +23 -17
- package/dist/esm/wizard/index.js +171 -103
- package/dist/esm/wizard/store/index.js +169 -116
- package/dist/esm/wizard/store/utils.js +13 -6
- package/package.json +30 -16
- package/release.config.js +1 -0
- package/shared/hooks/use-coauthors.js +195 -27
- package/shared/hooks/use-coauthors.test.js +232 -6
- package/shared/scss/_mixins.scss +13 -5
- package/src/accordion/index.js +8 -7
- package/src/action-card/index.js +15 -1
- package/src/badge/index.tsx +3 -1
- package/src/card/core-card.js +95 -18
- package/src/card/index.js +1 -0
- package/src/card/style-core.scss +93 -25
- package/src/card/style.scss +2 -2
- 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/index.tsx +28 -3
- package/src/card-sortable-list/index.tsx +27 -4
- 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 +74 -6
- package/src/dataviews/index.tsx +34 -0
- package/src/dataviews/style.scss +9 -0
- package/src/grid/style.scss +6 -1
- 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 +7 -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/style.scss +4 -0
- package/src/plugin-installer/index.js +30 -19
- package/src/section-header/index.js +56 -24
- package/src/section-header/style.scss +31 -11
- package/src/select-control/index.js +4 -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/with-wizard/style.scss +4 -54
- package/src/with-wizard-screen/style.scss +41 -3
- package/src/wizard/index.js +90 -53
- package/src/wizard/store/index.js +2 -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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies.
|
|
3
3
|
*/
|
|
4
|
-
import { ColorPicker as ColorPickerComponent } from '@wordpress/components';
|
|
4
|
+
import { BaseControl, ColorPicker as ColorPickerComponent } from '@wordpress/components';
|
|
5
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
5
6
|
import { useState, useRef } from '@wordpress/element';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -26,35 +27,41 @@ const { InteractiveDiv } = utils;
|
|
|
26
27
|
*
|
|
27
28
|
* @param {Object} props - Component props.
|
|
28
29
|
* @param {JSX.Element|string} props.label - Label for the color picker.
|
|
30
|
+
* @param {JSX.Element|string} props.help - Help text for the color picker.
|
|
29
31
|
* @param {string} [props.color] - Default color.
|
|
30
32
|
* @param {Function} props.onChange - Function to call when the color changes.
|
|
31
33
|
* @param {string} [props.className] - Additional class name.
|
|
32
34
|
* @return {JSX.Element} ColorPicker component.
|
|
33
35
|
*/
|
|
34
|
-
const ColorPicker = ( { label, color = '#
|
|
36
|
+
const ColorPicker = ( { label, help, color = '#ffffff', onChange, className } ) => {
|
|
35
37
|
const [ isExpanded, setIsExpanded ] = useState( false );
|
|
36
38
|
const ref = useRef();
|
|
39
|
+
const id = useInstanceId( ColorPicker, 'newspack-color-picker' );
|
|
40
|
+
const labelId = `${ id }-label`;
|
|
37
41
|
const colordColor = colord( color );
|
|
38
42
|
hooks.useOnClickOutside( ref, () => setIsExpanded( false ) );
|
|
39
43
|
return (
|
|
40
|
-
<
|
|
41
|
-
<
|
|
42
|
-
|
|
44
|
+
<BaseControl id={ id } className={ classnames( 'newspack-color-picker', className ) } help={ help } __nextHasNoMarginBottom>
|
|
45
|
+
<BaseControl.VisualLabel id={ labelId }>{ label }</BaseControl.VisualLabel>
|
|
43
46
|
<InteractiveDiv
|
|
47
|
+
id={ id }
|
|
48
|
+
aria-labelledby={ labelId }
|
|
49
|
+
aria-describedby={ help ? `${ id }__help` : undefined }
|
|
50
|
+
aria-expanded={ isExpanded }
|
|
44
51
|
className={ 'newspack-color-picker__expander' }
|
|
45
52
|
onClick={ () => setIsExpanded( ! isExpanded ) }
|
|
46
53
|
style={ {
|
|
47
54
|
backgroundColor: color,
|
|
48
|
-
color: colordColor.contrast() > colordColor.contrast( '#
|
|
55
|
+
color: colordColor.contrast() > colordColor.contrast( '#000000' ) ? '#ffffff' : '#000000',
|
|
49
56
|
} }
|
|
50
57
|
>
|
|
51
58
|
{ color }
|
|
52
59
|
</InteractiveDiv>
|
|
53
60
|
|
|
54
61
|
<div className="newspack-color-picker__main" ref={ ref }>
|
|
55
|
-
{ isExpanded && <ColorPickerComponent color={ color } onChange={
|
|
62
|
+
{ isExpanded && <ColorPickerComponent color={ color } onChange={ onChange } enableAlpha={ false } /> }
|
|
56
63
|
</div>
|
|
57
|
-
</
|
|
64
|
+
</BaseControl>
|
|
58
65
|
);
|
|
59
66
|
};
|
|
60
67
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import ColorPicker from './';
|
|
10
|
+
|
|
11
|
+
describe( 'ColorPicker', () => {
|
|
12
|
+
it( 'should render the label', () => {
|
|
13
|
+
const { getByText } = render( <ColorPicker label="Background color" onChange={ () => {} } /> );
|
|
14
|
+
expect( getByText( 'Background color' ) ).toBeInTheDocument();
|
|
15
|
+
} );
|
|
16
|
+
|
|
17
|
+
it( 'should render help text', () => {
|
|
18
|
+
const { getByText } = render( <ColorPicker label="Background color" help="Choose a color" onChange={ () => {} } /> );
|
|
19
|
+
expect( getByText( 'Choose a color' ) ).toBeInTheDocument();
|
|
20
|
+
} );
|
|
21
|
+
|
|
22
|
+
it( 'should start collapsed', () => {
|
|
23
|
+
const { getByRole } = render( <ColorPicker label="Background color" onChange={ () => {} } /> );
|
|
24
|
+
expect( getByRole( 'button' ) ).toHaveAttribute( 'aria-expanded', 'false' );
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
it( 'should expand when the expander is clicked', () => {
|
|
28
|
+
const { getByRole } = render( <ColorPicker label="Background color" onChange={ () => {} } /> );
|
|
29
|
+
const expander = getByRole( 'button' );
|
|
30
|
+
fireEvent.click( expander );
|
|
31
|
+
expect( expander ).toHaveAttribute( 'aria-expanded', 'true' );
|
|
32
|
+
} );
|
|
33
|
+
|
|
34
|
+
it( 'should associate label via aria-labelledby', () => {
|
|
35
|
+
const { getByRole, getByText } = render( <ColorPicker label="Background color" onChange={ () => {} } /> );
|
|
36
|
+
const expander = getByRole( 'button' );
|
|
37
|
+
const label = getByText( 'Background color' );
|
|
38
|
+
expect( expander.getAttribute( 'aria-labelledby' ) ).toBe( label.id );
|
|
39
|
+
} );
|
|
40
|
+
|
|
41
|
+
it( 'should associate help text via aria-describedby when help is provided', () => {
|
|
42
|
+
const { getByRole, getByText } = render( <ColorPicker label="Background color" help="Choose a color" onChange={ () => {} } /> );
|
|
43
|
+
const expander = getByRole( 'button' );
|
|
44
|
+
const help = getByText( 'Choose a color' );
|
|
45
|
+
expect( expander.getAttribute( 'aria-describedby' ) ).toBe( help.id );
|
|
46
|
+
} );
|
|
47
|
+
|
|
48
|
+
it( 'should not set aria-describedby when no help is provided', () => {
|
|
49
|
+
const { getByRole } = render( <ColorPicker label="Background color" onChange={ () => {} } /> );
|
|
50
|
+
expect( getByRole( 'button' ) ).not.toHaveAttribute( 'aria-describedby' );
|
|
51
|
+
} );
|
|
52
|
+
} );
|
|
@@ -2,31 +2,29 @@
|
|
|
2
2
|
* Color Picker
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
+
@use "~@wordpress/base-styles/variables" as wp-vars;
|
|
7
|
+
|
|
5
8
|
.newspack-color-picker {
|
|
6
9
|
position: relative;
|
|
7
|
-
|
|
8
|
-
&__label {
|
|
9
|
-
margin-bottom: 8px;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
10
|
&__expander {
|
|
13
|
-
box-shadow: inset 0 0 0 1px
|
|
14
|
-
border-radius:
|
|
15
|
-
height:
|
|
16
|
-
padding:
|
|
11
|
+
box-shadow: inset 0 0 0 1px rgba(wp-colors.$black, 0.54);
|
|
12
|
+
border-radius: wp-vars.$radius-small;
|
|
13
|
+
height: wp-vars.$grid-unit-80;
|
|
14
|
+
padding: wp-vars.$grid-unit-10;
|
|
17
15
|
text-align: right;
|
|
18
16
|
text-transform: uppercase;
|
|
19
17
|
|
|
20
18
|
&:focus-visible {
|
|
21
19
|
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
|
|
22
|
-
border-color: white;
|
|
20
|
+
border-color: wp-colors.$white;
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
&__main {
|
|
27
|
-
background: white;
|
|
28
|
-
box-shadow:
|
|
29
|
-
margin:
|
|
25
|
+
background: wp-colors.$white;
|
|
26
|
+
box-shadow: wp-vars.$elevation-small;
|
|
27
|
+
margin: wp-vars.$grid-unit-10 0 0;
|
|
30
28
|
position: absolute;
|
|
31
29
|
z-index: 2;
|
|
32
30
|
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# ConfirmDialog
|
|
2
|
+
|
|
3
|
+
A modal confirmation dialog that intercepts client-side navigation when there are unsaved changes. Built on top of WordPress's `__experimentalConfirmDialog`. The dialog is invisible until a navigation attempt is blocked; when `when` becomes `true` and the user navigates away, the dialog appears automatically and resumes or cancels the navigation based on the user's choice.
|
|
4
|
+
|
|
5
|
+
For most imperative use cases (confirming a destructive action, guarding an action behind an unsaved-changes check) prefer the [`useConfirmDialog` hook](#useconfirmdialog-hook) over using `ConfirmDialog` directly.
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `cancelButtonText` | `string` | — | Label for the cancel button. |
|
|
12
|
+
| `children` | `React.ReactNode` | — | Content rendered in the modal body. |
|
|
13
|
+
| `className` | `string` | — | Additional CSS class. |
|
|
14
|
+
| `confirmButtonText` | `string` | — | Label for the confirm button. |
|
|
15
|
+
| `hideTitle` | `boolean` | — | When `true`, hides the modal title and the × close button. |
|
|
16
|
+
| `isDestructive` | `boolean` | — | When `true`, applies destructive (e.g. red) styling to the confirm button. |
|
|
17
|
+
| `isOpen` | `boolean` | `false` | When `true`, shows the dialog immediately without blocking navigation. Use this for imperative confirmation (e.g. confirming a destructive action on a button click). |
|
|
18
|
+
| `size` | `'small'` \| `'medium'` \| `'large'` \| `'x-large'` \| `'full'` | `'small'` | Controls the width of the modal. |
|
|
19
|
+
| `title` | `string` | — | Title displayed in the modal header. |
|
|
20
|
+
| `when` | `boolean` | `false` | When `true`, blocks router navigation and shows the dialog on any attempted navigation. Set this to reflect whether the current form has unsaved changes. |
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```jsx
|
|
25
|
+
import { ConfirmDialog } from 'newspack-components';
|
|
26
|
+
|
|
27
|
+
// Guard navigation when a form has unsaved changes.
|
|
28
|
+
// The dialog appears automatically when the user tries to navigate away.
|
|
29
|
+
<ConfirmDialog
|
|
30
|
+
when={ hasUnsavedChanges }
|
|
31
|
+
title="Unsaved changes"
|
|
32
|
+
confirmButtonText="Leave anyway"
|
|
33
|
+
cancelButtonText="Stay"
|
|
34
|
+
isDestructive
|
|
35
|
+
>
|
|
36
|
+
You have unsaved changes. Are you sure you want to leave?
|
|
37
|
+
</ConfirmDialog>
|
|
38
|
+
|
|
39
|
+
// Larger modal with a custom size
|
|
40
|
+
<ConfirmDialog
|
|
41
|
+
when={ hasUnsavedChanges }
|
|
42
|
+
size="medium"
|
|
43
|
+
title="Discard changes?"
|
|
44
|
+
confirmButtonText="Discard"
|
|
45
|
+
cancelButtonText="Keep editing"
|
|
46
|
+
>
|
|
47
|
+
Your changes will be lost if you leave this page.
|
|
48
|
+
</ConfirmDialog>
|
|
49
|
+
|
|
50
|
+
// Guard both navigation and an imperative action with a single dialog instance.
|
|
51
|
+
// isOpen triggers the dialog immediately (e.g. on a button click) without
|
|
52
|
+
// blocking navigation. Both when and isOpen can be used together.
|
|
53
|
+
const [ pendingAction, setPendingAction ] = useState( null );
|
|
54
|
+
<ConfirmDialog
|
|
55
|
+
when={ hasUnsavedChanges }
|
|
56
|
+
isOpen={ !! pendingAction }
|
|
57
|
+
confirmButtonText="Discard changes"
|
|
58
|
+
isDestructive
|
|
59
|
+
hideTitle
|
|
60
|
+
onConfirm={ () => {
|
|
61
|
+
pendingAction?.();
|
|
62
|
+
setPendingAction( null );
|
|
63
|
+
} }
|
|
64
|
+
onCancel={ () => setPendingAction( null ) }
|
|
65
|
+
>
|
|
66
|
+
You have unsaved changes that will be lost. Discard changes?
|
|
67
|
+
</ConfirmDialog>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## `useConfirmDialog` hook
|
|
73
|
+
|
|
74
|
+
A higher-level hook that wraps `ConfirmDialog` and manages the pending-action state for you. Prefer this over using `ConfirmDialog` directly when you need imperative confirmation.
|
|
75
|
+
|
|
76
|
+
```jsx
|
|
77
|
+
import { useConfirmDialog } from 'newspack-components';
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Options
|
|
81
|
+
|
|
82
|
+
Accepts all `ConfirmDialog` props except `isOpen`, `onConfirm`, `onCancel`, and `children`, plus:
|
|
83
|
+
|
|
84
|
+
| Option | Type | Default | Description |
|
|
85
|
+
|--------|------|---------|-------------|
|
|
86
|
+
| `message` | `React.ReactNode` | — | Content rendered in the modal body. |
|
|
87
|
+
| `when` | `boolean` | — | When explicitly `false`, `requestConfirm` skips the dialog and invokes the callback immediately. Omit (or pass `true`) to always show the dialog. Also controls router navigation blocking, same as the `when` prop on `ConfirmDialog`. |
|
|
88
|
+
|
|
89
|
+
### Returns
|
|
90
|
+
|
|
91
|
+
| Key | Type | Description |
|
|
92
|
+
|-----|------|-------------|
|
|
93
|
+
| `confirmDialog` | `React.ReactElement` | The dialog element — render this somewhere in your JSX. |
|
|
94
|
+
| `requestConfirm` | `( callback: () => void ) => void` | Call with a callback to request confirmation. Shows the dialog (unless `when` is `false`); invokes the callback only if the user confirms. |
|
|
95
|
+
|
|
96
|
+
### Usage
|
|
97
|
+
|
|
98
|
+
```jsx
|
|
99
|
+
// Always-confirm dialog (e.g. destructive delete action).
|
|
100
|
+
const { confirmDialog, requestConfirm } = useConfirmDialog( {
|
|
101
|
+
title: 'Are you sure?',
|
|
102
|
+
confirmButtonText: 'Delete',
|
|
103
|
+
isDestructive: true,
|
|
104
|
+
message: 'This will permanently delete the item and cannot be undone.',
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
// Render the dialog element in JSX:
|
|
108
|
+
{ confirmDialog }
|
|
109
|
+
|
|
110
|
+
// Call requestConfirm when the user initiates the action:
|
|
111
|
+
<Button onClick={ () => requestConfirm( handleDelete ) }>Delete</Button>
|
|
112
|
+
|
|
113
|
+
// Conditional dialog — skips confirmation when there are no unsaved changes.
|
|
114
|
+
// Combines navigation blocking with imperative use in a single instance.
|
|
115
|
+
const { confirmDialog, requestConfirm } = useConfirmDialog( {
|
|
116
|
+
when: isDirty,
|
|
117
|
+
message: 'You have unsaved changes that will be lost. Discard changes?',
|
|
118
|
+
confirmButtonText: 'Discard changes',
|
|
119
|
+
isDestructive: true,
|
|
120
|
+
hideTitle: true,
|
|
121
|
+
} );
|
|
122
|
+
|
|
123
|
+
{ confirmDialog }
|
|
124
|
+
|
|
125
|
+
// In an action handler — shows the dialog only if isDirty, otherwise
|
|
126
|
+
// calls the callback immediately:
|
|
127
|
+
requestConfirm( () => handleToggleEnabled( newConfig ) );
|
|
128
|
+
```
|
|
@@ -5,8 +5,14 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* WordPress dependencies.
|
|
7
7
|
*/
|
|
8
|
-
import { forwardRef } from '@wordpress/element';
|
|
9
8
|
import { __experimentalConfirmDialog as BaseComponent } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
|
|
9
|
+
import { forwardRef, useCallback, useEffect, useRef, useState } from '@wordpress/element';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies.
|
|
13
|
+
*/
|
|
14
|
+
import Router from '../proxied-imports/router';
|
|
15
|
+
const { useHistory } = Router;
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* External dependencies.
|
|
@@ -23,11 +29,13 @@ type ConfirmDialogProps = {
|
|
|
23
29
|
hideTitle?: boolean;
|
|
24
30
|
title?: string;
|
|
25
31
|
isDestructive?: boolean;
|
|
32
|
+
isOpen?: boolean;
|
|
33
|
+
onConfirm?: () => void;
|
|
34
|
+
onCancel?: () => void;
|
|
26
35
|
cancelButtonText?: string;
|
|
27
36
|
confirmButtonText?: string;
|
|
28
|
-
onConfirm: () => void;
|
|
29
|
-
onCancel: () => void;
|
|
30
37
|
children?: React.ReactNode;
|
|
38
|
+
when?: boolean;
|
|
31
39
|
};
|
|
32
40
|
|
|
33
41
|
const sizeClassMap = {
|
|
@@ -38,10 +46,70 @@ const sizeClassMap = {
|
|
|
38
46
|
full: 'newspack-modal--size-full',
|
|
39
47
|
};
|
|
40
48
|
|
|
49
|
+
const noOp = () => {};
|
|
50
|
+
|
|
41
51
|
function ConfirmDialog(
|
|
42
|
-
{
|
|
52
|
+
{
|
|
53
|
+
className,
|
|
54
|
+
size = 'small',
|
|
55
|
+
hideTitle,
|
|
56
|
+
isDestructive,
|
|
57
|
+
onConfirm = noOp,
|
|
58
|
+
onCancel = noOp,
|
|
59
|
+
when = false,
|
|
60
|
+
isOpen = false,
|
|
61
|
+
...otherProps
|
|
62
|
+
}: ConfirmDialogProps,
|
|
43
63
|
ref: React.Ref< HTMLDivElement >
|
|
44
64
|
) {
|
|
65
|
+
const [ showDialog, setShowDialog ] = useState( isOpen );
|
|
66
|
+
const history = useHistory();
|
|
67
|
+
const pendingNavigation = useRef< ( () => void ) | null >( null );
|
|
68
|
+
|
|
69
|
+
const handleOnConfirm = useCallback( () => {
|
|
70
|
+
setShowDialog( false );
|
|
71
|
+
pendingNavigation.current?.();
|
|
72
|
+
pendingNavigation.current = null;
|
|
73
|
+
onConfirm();
|
|
74
|
+
}, [ onConfirm, pendingNavigation ] );
|
|
75
|
+
|
|
76
|
+
const handleOnCancel = useCallback( () => {
|
|
77
|
+
setShowDialog( false );
|
|
78
|
+
pendingNavigation.current = null;
|
|
79
|
+
onCancel();
|
|
80
|
+
}, [ onCancel, pendingNavigation ] );
|
|
81
|
+
|
|
82
|
+
// Block navigation when there are unsaved changes.
|
|
83
|
+
useEffect( () => {
|
|
84
|
+
if ( ! when ) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const unblock = history.block( ( location: string, action: string ) => {
|
|
88
|
+
pendingNavigation.current = () => {
|
|
89
|
+
unblock();
|
|
90
|
+
if ( action === 'REPLACE' ) {
|
|
91
|
+
history.replace( location );
|
|
92
|
+
} else {
|
|
93
|
+
history.push( location );
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
setShowDialog( true );
|
|
97
|
+
return false;
|
|
98
|
+
} );
|
|
99
|
+
return unblock;
|
|
100
|
+
}, [ when, history ] );
|
|
101
|
+
|
|
102
|
+
// Show the dialog imperatively without blocking navigation.
|
|
103
|
+
useEffect( () => {
|
|
104
|
+
if ( isOpen ) {
|
|
105
|
+
setShowDialog( true );
|
|
106
|
+
}
|
|
107
|
+
}, [ isOpen ] );
|
|
108
|
+
|
|
109
|
+
if ( ! showDialog ) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
45
113
|
const classes = classnames(
|
|
46
114
|
'newspack-modal',
|
|
47
115
|
sizeClassMap[ size ],
|
|
@@ -55,8 +123,8 @@ function ConfirmDialog(
|
|
|
55
123
|
className={ classes }
|
|
56
124
|
{ ...otherProps }
|
|
57
125
|
ref={ ref }
|
|
58
|
-
onConfirm={
|
|
59
|
-
onCancel={
|
|
126
|
+
onConfirm={ handleOnConfirm }
|
|
127
|
+
onCancel={ handleOnCancel }
|
|
60
128
|
__experimentalHideHeader={ false }
|
|
61
129
|
/>
|
|
62
130
|
);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataViews
|
|
3
|
+
*
|
|
4
|
+
* Wrapper around @wordpress/dataviews with Newspack styling.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WordPress dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { DataViews as BaseDataViews } from '@wordpress/dataviews';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* External dependencies
|
|
14
|
+
*/
|
|
15
|
+
import classnames from 'classnames';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Internal dependencies
|
|
19
|
+
*/
|
|
20
|
+
import './style.scss';
|
|
21
|
+
|
|
22
|
+
type DataViewsProps = React.ComponentProps< typeof BaseDataViews > & {
|
|
23
|
+
className?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default function DataViews( { className, ...props }: DataViewsProps ) {
|
|
27
|
+
return (
|
|
28
|
+
<div className={ classnames( 'newspack-dataviews', className ) }>
|
|
29
|
+
<BaseDataViews { ...props } />
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type { Action, Field, View } from '@wordpress/dataviews';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/* stylelint-disable no-invalid-position-at-import-rule */
|
|
2
|
+
@import "@wordpress/dataviews/build-style/style.css";
|
|
3
|
+
|
|
4
|
+
.newspack-dataviews {
|
|
5
|
+
/* Make sure full-width DataViews aligns with the 48px margin. */
|
|
6
|
+
.newspack-wizard__content--full-width & {
|
|
7
|
+
margin-top: -16px;
|
|
8
|
+
}
|
|
9
|
+
}
|
package/src/grid/style.scss
CHANGED
|
@@ -117,6 +117,11 @@
|
|
|
117
117
|
grid-template-columns: repeat(6, 1fr);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// Columns 12
|
|
121
|
+
&__columns-12 {
|
|
122
|
+
grid-template-columns: repeat(12, 1fr);
|
|
123
|
+
}
|
|
124
|
+
|
|
120
125
|
// Gutter 48
|
|
121
126
|
&__gutter-48 {
|
|
122
127
|
grid-gap: 48px;
|
|
@@ -217,4 +222,4 @@
|
|
|
217
222
|
&__tbody + &__tbody {
|
|
218
223
|
margin-top: -32px;
|
|
219
224
|
}
|
|
220
|
-
}
|
|
225
|
+
}
|
|
@@ -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 };
|