newspack-components 4.2.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 +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
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { store as coreStore } from '@wordpress/core-data';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Hook to get custom byline data.
|
|
9
|
+
*
|
|
10
|
+
* @param {number} postId Post ID.
|
|
11
|
+
* @param {string} postType Post type.
|
|
12
|
+
* @return {Object} Custom byline data.
|
|
13
|
+
*/
|
|
14
|
+
export function useCustomByline( postId, postType ) {
|
|
15
|
+
const { bylineActive, bylineContent } = useSelect(
|
|
16
|
+
select => {
|
|
17
|
+
const { getEditedEntityRecord } = select( coreStore );
|
|
18
|
+
const postRecord = getEditedEntityRecord( 'postType', postType, postId );
|
|
19
|
+
return {
|
|
20
|
+
bylineActive: postRecord?.meta?._newspack_byline_active || false,
|
|
21
|
+
bylineContent: postRecord?.meta?._newspack_byline || '',
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
[ postId, postType ]
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return { bylineActive, bylineContent };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Extract author IDs from custom byline shortcode content.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} bylineContent Byline content with [Author id=X]...[/Author] shortcodes.
|
|
34
|
+
* @return {Array} Array of author IDs (integers).
|
|
35
|
+
*/
|
|
36
|
+
export function extractAuthorIdsFromByline( bylineContent ) {
|
|
37
|
+
if ( ! bylineContent ) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const regex = /\[Author\s+id\s*=\s*(\d+)\]/gi;
|
|
41
|
+
const ids = [];
|
|
42
|
+
let match;
|
|
43
|
+
while ( ( match = regex.exec( bylineContent ) ) !== null ) {
|
|
44
|
+
ids.push( parseInt( match[ 1 ], 10 ) );
|
|
45
|
+
}
|
|
46
|
+
return ids;
|
|
47
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { renderHook } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useSelect } from '@wordpress/data';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import { useCustomByline, extractAuthorIdsFromByline } from './use-custom-byline';
|
|
15
|
+
|
|
16
|
+
jest.mock( '@wordpress/data', () => ( {
|
|
17
|
+
useSelect: jest.fn(),
|
|
18
|
+
} ) );
|
|
19
|
+
|
|
20
|
+
jest.mock( '@wordpress/core-data', () => ( {
|
|
21
|
+
store: 'core',
|
|
22
|
+
} ) );
|
|
23
|
+
|
|
24
|
+
describe( 'useCustomByline', () => {
|
|
25
|
+
beforeEach( () => {
|
|
26
|
+
jest.clearAllMocks();
|
|
27
|
+
} );
|
|
28
|
+
|
|
29
|
+
it( 'should return inactive byline when meta is not set', () => {
|
|
30
|
+
useSelect.mockImplementation( callback =>
|
|
31
|
+
callback( () => ( {
|
|
32
|
+
getEditedEntityRecord: () => ( {} ),
|
|
33
|
+
} ) )
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const { result } = renderHook( () => useCustomByline( 123, 'post' ) );
|
|
37
|
+
|
|
38
|
+
expect( result.current.bylineActive ).toBe( false );
|
|
39
|
+
expect( result.current.bylineContent ).toBe( '' );
|
|
40
|
+
} );
|
|
41
|
+
|
|
42
|
+
it( 'should return inactive byline when meta exists but byline is inactive', () => {
|
|
43
|
+
useSelect.mockImplementation( callback =>
|
|
44
|
+
callback( () => ( {
|
|
45
|
+
getEditedEntityRecord: () => ( {
|
|
46
|
+
meta: {
|
|
47
|
+
_newspack_byline_active: false,
|
|
48
|
+
_newspack_byline: 'Some content',
|
|
49
|
+
},
|
|
50
|
+
} ),
|
|
51
|
+
} ) )
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const { result } = renderHook( () => useCustomByline( 123, 'post' ) );
|
|
55
|
+
|
|
56
|
+
expect( result.current.bylineActive ).toBe( false );
|
|
57
|
+
expect( result.current.bylineContent ).toBe( 'Some content' );
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
it( 'should return active byline with content', () => {
|
|
61
|
+
const bylineContent = 'By [Author id=5]Jane Doe[/Author]';
|
|
62
|
+
|
|
63
|
+
useSelect.mockImplementation( callback =>
|
|
64
|
+
callback( () => ( {
|
|
65
|
+
getEditedEntityRecord: () => ( {
|
|
66
|
+
meta: {
|
|
67
|
+
_newspack_byline_active: true,
|
|
68
|
+
_newspack_byline: bylineContent,
|
|
69
|
+
},
|
|
70
|
+
} ),
|
|
71
|
+
} ) )
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const { result } = renderHook( () => useCustomByline( 123, 'post' ) );
|
|
75
|
+
|
|
76
|
+
expect( result.current.bylineActive ).toBe( true );
|
|
77
|
+
expect( result.current.bylineContent ).toBe( bylineContent );
|
|
78
|
+
} );
|
|
79
|
+
|
|
80
|
+
it( 'should handle null post record gracefully', () => {
|
|
81
|
+
useSelect.mockImplementation( callback =>
|
|
82
|
+
callback( () => ( {
|
|
83
|
+
getEditedEntityRecord: () => null,
|
|
84
|
+
} ) )
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const { result } = renderHook( () => useCustomByline( 123, 'post' ) );
|
|
88
|
+
|
|
89
|
+
expect( result.current.bylineActive ).toBe( false );
|
|
90
|
+
expect( result.current.bylineContent ).toBe( '' );
|
|
91
|
+
} );
|
|
92
|
+
} );
|
|
93
|
+
|
|
94
|
+
describe( 'extractAuthorIdsFromByline', () => {
|
|
95
|
+
it( 'should return empty array for empty content', () => {
|
|
96
|
+
expect( extractAuthorIdsFromByline( '' ) ).toEqual( [] );
|
|
97
|
+
expect( extractAuthorIdsFromByline( null ) ).toEqual( [] );
|
|
98
|
+
expect( extractAuthorIdsFromByline( undefined ) ).toEqual( [] );
|
|
99
|
+
} );
|
|
100
|
+
|
|
101
|
+
it( 'should extract single author ID', () => {
|
|
102
|
+
const byline = 'By [Author id=5]Jane Doe[/Author]';
|
|
103
|
+
expect( extractAuthorIdsFromByline( byline ) ).toEqual( [ 5 ] );
|
|
104
|
+
} );
|
|
105
|
+
|
|
106
|
+
it( 'should extract multiple author IDs', () => {
|
|
107
|
+
const byline = 'By [Author id=5]Jane Doe[/Author] and [Author id=12]John Smith[/Author]';
|
|
108
|
+
expect( extractAuthorIdsFromByline( byline ) ).toEqual( [ 5, 12 ] );
|
|
109
|
+
} );
|
|
110
|
+
|
|
111
|
+
it( 'should handle content with no author shortcodes', () => {
|
|
112
|
+
const byline = 'By Some Random Text';
|
|
113
|
+
expect( extractAuthorIdsFromByline( byline ) ).toEqual( [] );
|
|
114
|
+
} );
|
|
115
|
+
|
|
116
|
+
it( 'should handle byline with HTML entities', () => {
|
|
117
|
+
const byline = 'By [Author id=17]Darth Vader[/Author] with love';
|
|
118
|
+
expect( extractAuthorIdsFromByline( byline ) ).toEqual( [ 17 ] );
|
|
119
|
+
} );
|
|
120
|
+
|
|
121
|
+
it( 'should return integers, not strings', () => {
|
|
122
|
+
const byline = '[Author id=123]Test[/Author]';
|
|
123
|
+
const result = extractAuthorIdsFromByline( byline );
|
|
124
|
+
expect( result ).toEqual( [ 123 ] );
|
|
125
|
+
expect( typeof result[ 0 ] ).toBe( 'number' );
|
|
126
|
+
} );
|
|
127
|
+
|
|
128
|
+
it( 'should tolerate whitespace and case variations in shortcode', () => {
|
|
129
|
+
expect( extractAuthorIdsFromByline( '[author id=7]Name[/Author]' ) ).toEqual( [ 7 ] );
|
|
130
|
+
expect( extractAuthorIdsFromByline( '[Author id = 5]Name[/Author]' ) ).toEqual( [ 5 ] );
|
|
131
|
+
expect( extractAuthorIdsFromByline( '[AUTHOR ID=3]Name[/Author]' ) ).toEqual( [ 3 ] );
|
|
132
|
+
} );
|
|
133
|
+
} );
|
package/shared/scss/_mixins.scss
CHANGED
|
@@ -10,3 +10,57 @@
|
|
|
10
10
|
position: absolute !important;
|
|
11
11
|
word-wrap: normal !important; /* Many screen reader and browser combinations announce broken words as they would appear visually. */
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
// Circular social button style
|
|
15
|
+
// Used by: author-profile-social, author-social-link blocks
|
|
16
|
+
// Hex fallbacks from newspack-block-theme theme.json defaults.
|
|
17
|
+
@mixin socialButton {
|
|
18
|
+
border-radius: 50%; // Circular
|
|
19
|
+
display: grid;
|
|
20
|
+
place-items: center;
|
|
21
|
+
text-decoration: none;
|
|
22
|
+
|
|
23
|
+
// Use :not(.wp-element-button) to beat wp-elements parent link colour rules,
|
|
24
|
+
// which use :where() and therefore have lower specificity.
|
|
25
|
+
&:not(.wp-element-button) {
|
|
26
|
+
background: var(--icon-background, var(--wp--preset--color--base-2, #f0f0f0));
|
|
27
|
+
color: var(--icon-color, var(--wp--preset--color--contrast, #1e1e1e));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@media not (prefers-reduced-motion) {
|
|
31
|
+
transition: transform 100ms ease;
|
|
32
|
+
}
|
|
33
|
+
// Sizing - makes circular by using equal width/height
|
|
34
|
+
// --icon-size controls the circle diameter (e.g., 36px)
|
|
35
|
+
// Icon inside is 2/3 of circle size (e.g., 24px icon in 36px circle)
|
|
36
|
+
aspect-ratio: 1;
|
|
37
|
+
width: calc(var(--icon-size, 24px) * 1.5);
|
|
38
|
+
height: calc(var(--icon-size, 24px) * 1.5);
|
|
39
|
+
padding: 0;
|
|
40
|
+
|
|
41
|
+
&:hover {
|
|
42
|
+
background: var(--icon-background, var(--wp--preset--color--base-2, #f0f0f0));
|
|
43
|
+
color: var(--icon-color, var(--wp--preset--color--contrast, #1e1e1e));
|
|
44
|
+
text-decoration: none;
|
|
45
|
+
transform: scale(1.1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&:focus {
|
|
49
|
+
outline: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&:focus-visible {
|
|
53
|
+
outline: 2px solid;
|
|
54
|
+
outline-offset: 1px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// SVG icon sizing - icon is 2/3 of button size
|
|
58
|
+
// If button is 36px, icon is 24px (24/36 = 2/3)
|
|
59
|
+
svg,
|
|
60
|
+
span {
|
|
61
|
+
display: block;
|
|
62
|
+
fill: currentcolor;
|
|
63
|
+
width: var(--icon-size, 24px);
|
|
64
|
+
height: var(--icon-size, 24px);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/accordion/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
|
2
|
-
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* WordPress dependencies
|
|
6
3
|
*/
|
|
@@ -17,11 +14,15 @@ import classNames from 'classnames';
|
|
|
17
14
|
*/
|
|
18
15
|
import './style.scss';
|
|
19
16
|
|
|
20
|
-
const Accordion = ( { children, title } ) => {
|
|
21
|
-
const [ isOpen, setIsOpen ] = useState(
|
|
17
|
+
const Accordion = ( { children, title, defaultOpen = false } ) => {
|
|
18
|
+
const [ isOpen, setIsOpen ] = useState( defaultOpen );
|
|
22
19
|
return (
|
|
23
|
-
<details
|
|
24
|
-
|
|
20
|
+
<details
|
|
21
|
+
className={ classNames( 'newspack-accordion', { 'newspack-accordion--is-open': isOpen } ) }
|
|
22
|
+
open={ isOpen }
|
|
23
|
+
onToggle={ e => setIsOpen( e.currentTarget.open ) }
|
|
24
|
+
>
|
|
25
|
+
<summary>
|
|
25
26
|
{ title }
|
|
26
27
|
<Icon className="newspack-accordion__icon" icon={ chevronRight } size={ 24 } />
|
|
27
28
|
</summary>
|
|
@@ -6,6 +6,7 @@ export interface ActionCardProps {
|
|
|
6
6
|
description?: string | React.ReactNode;
|
|
7
7
|
actionText?: React.ReactNode | string | null;
|
|
8
8
|
badge?: string;
|
|
9
|
+
badgeLevel?: 'success' | 'info' | 'warning' | 'error';
|
|
9
10
|
className?: string;
|
|
10
11
|
indent?: string;
|
|
11
12
|
notification?: string | Error | null;
|
|
@@ -13,8 +14,10 @@ export interface ActionCardProps {
|
|
|
13
14
|
isMedium?: boolean;
|
|
14
15
|
disabled?: boolean | string;
|
|
15
16
|
hasGreyHeader?: boolean;
|
|
17
|
+
heading?: number;
|
|
16
18
|
toggleChecked?: boolean;
|
|
17
|
-
toggleOnChange?: (
|
|
19
|
+
toggleOnChange?: (a: boolean) => void;
|
|
20
|
+
togglePosition?: 'leading' | 'trailing';
|
|
18
21
|
actionContent?: boolean | React.ReactNode | null;
|
|
19
22
|
error?: Error | string | null;
|
|
20
23
|
handoff?: string | null;
|
|
@@ -33,8 +36,9 @@ export interface ActionCardProps {
|
|
|
33
36
|
noMargin?: boolean;
|
|
34
37
|
collapse?: boolean;
|
|
35
38
|
expandable?: boolean;
|
|
39
|
+
isExpanded?: boolean;
|
|
36
40
|
draggable?: boolean;
|
|
37
41
|
dragIndex?: number;
|
|
38
|
-
onDragCallback?: (
|
|
39
|
-
dragWrapperRef?: React.MutableRefObject<
|
|
42
|
+
onDragCallback?: (index: number) => void;
|
|
43
|
+
dragWrapperRef?: React.MutableRefObject<HTMLDivElement | null>;
|
|
40
44
|
}
|
package/src/action-card/index.js
CHANGED
|
@@ -29,15 +29,19 @@ import classnames from 'classnames';
|
|
|
29
29
|
*/
|
|
30
30
|
const ActionCard = ( {
|
|
31
31
|
badge,
|
|
32
|
-
badgeLevel
|
|
32
|
+
badgeLevel,
|
|
33
33
|
className,
|
|
34
34
|
checkbox,
|
|
35
35
|
children,
|
|
36
36
|
collapse,
|
|
37
37
|
disabled,
|
|
38
38
|
title,
|
|
39
|
+
heading = 2,
|
|
39
40
|
description,
|
|
40
41
|
handoff,
|
|
42
|
+
handoffUrl,
|
|
43
|
+
bannerText,
|
|
44
|
+
bannerButtonText,
|
|
41
45
|
editLink,
|
|
42
46
|
href,
|
|
43
47
|
notification,
|
|
@@ -60,11 +64,13 @@ const ActionCard = ( {
|
|
|
60
64
|
titleLink,
|
|
61
65
|
toggleChecked = false,
|
|
62
66
|
toggleOnChange,
|
|
67
|
+
togglePosition = 'leading',
|
|
63
68
|
hasGreyHeader,
|
|
64
69
|
hasWhiteHeader,
|
|
65
70
|
noBorder,
|
|
66
71
|
isPending,
|
|
67
72
|
expandable = false,
|
|
73
|
+
isExpanded,
|
|
68
74
|
isButtonEnabled = false,
|
|
69
75
|
// Draggable props. All are required to enable drag sorting.
|
|
70
76
|
draggable = false,
|
|
@@ -72,11 +78,17 @@ const ActionCard = ( {
|
|
|
72
78
|
dragWrapperRef,
|
|
73
79
|
onDragCallback,
|
|
74
80
|
} ) => {
|
|
75
|
-
const [ expanded, setExpanded ] = useState(
|
|
81
|
+
const [ expanded, setExpanded ] = useState( Boolean( isExpanded ) );
|
|
76
82
|
const [ dragging, setDragging ] = useState( false );
|
|
77
83
|
const [ targetIndex, setTargetIndex ] = useState( null );
|
|
78
84
|
const [ dragRef, setDragRef ] = useState( null );
|
|
79
85
|
|
|
86
|
+
useEffect( () => {
|
|
87
|
+
if ( typeof isExpanded === 'boolean' ) {
|
|
88
|
+
setExpanded( isExpanded );
|
|
89
|
+
}
|
|
90
|
+
}, [ isExpanded ] );
|
|
91
|
+
|
|
80
92
|
useEffect( () => {
|
|
81
93
|
if ( dragWrapperRef && ! dragRef ) {
|
|
82
94
|
setDragRef( dragWrapperRef );
|
|
@@ -109,14 +121,18 @@ const ActionCard = ( {
|
|
|
109
121
|
return url ? { backgroundImage: `url(${ url })` } : {};
|
|
110
122
|
};
|
|
111
123
|
const titleProps = toggleOnChange && ! titleLink && ! disabled ? { onClick: () => toggleOnChange( ! toggleChecked ), tabIndex: '0' } : {};
|
|
124
|
+
const togglePositionClass = togglePosition === 'trailing' ? 'is-toggle-trailing' : 'is-toggle-leading';
|
|
112
125
|
const hasInternalLink = href && href.indexOf( 'http' ) !== 0;
|
|
113
126
|
const isDisplayingSecondaryAction = secondaryActionText && onSecondaryActionClick;
|
|
114
127
|
const badges = ! Array.isArray( badge ) && badge ? [ badge ] : badge;
|
|
128
|
+
const HeadingTag = `h${ heading }`;
|
|
115
129
|
|
|
116
|
-
const
|
|
130
|
+
const cardContent = (
|
|
117
131
|
<>
|
|
118
132
|
<div className="newspack-action-card__region newspack-action-card__region-top">
|
|
119
|
-
{ toggleOnChange &&
|
|
133
|
+
{ toggleOnChange && (
|
|
134
|
+
<ToggleControl checked={ toggleChecked } onChange={ toggleOnChange } disabled={ disabled } className={ togglePositionClass } />
|
|
135
|
+
) }
|
|
120
136
|
{ image && ! toggleOnChange && (
|
|
121
137
|
<div className="newspack-action-card__region newspack-action-card__region-left">
|
|
122
138
|
<a href={ imageLink }>
|
|
@@ -140,7 +156,7 @@ const ActionCard = ( {
|
|
|
140
156
|
) }
|
|
141
157
|
<div className="newspack-action-card__region newspack-action-card__region-center">
|
|
142
158
|
<Grid columns={ 1 } gutter={ 8 } noMargin>
|
|
143
|
-
<
|
|
159
|
+
<HeadingTag>
|
|
144
160
|
<span className="newspack-action-card__title" { ...titleProps }>
|
|
145
161
|
{ titleLink && <a href={ titleLink }>{ title }</a> }
|
|
146
162
|
{ ! titleLink && expandable && (
|
|
@@ -159,7 +175,7 @@ const ActionCard = ( {
|
|
|
159
175
|
{ badgeText }
|
|
160
176
|
</span>
|
|
161
177
|
) ) }
|
|
162
|
-
</
|
|
178
|
+
</HeadingTag>
|
|
163
179
|
{ description && (
|
|
164
180
|
<p>
|
|
165
181
|
{ typeof description === 'string' && description }
|
|
@@ -174,7 +190,18 @@ const ActionCard = ( {
|
|
|
174
190
|
{ actionContent && actionContent }
|
|
175
191
|
{ actionText &&
|
|
176
192
|
( handoff ? (
|
|
177
|
-
<Handoff
|
|
193
|
+
<Handoff
|
|
194
|
+
plugin={ handoff }
|
|
195
|
+
editLink={ editLink }
|
|
196
|
+
bannerText={ bannerText }
|
|
197
|
+
bannerButtonText={ bannerButtonText }
|
|
198
|
+
compact
|
|
199
|
+
isLink
|
|
200
|
+
>
|
|
201
|
+
{ actionText }
|
|
202
|
+
</Handoff>
|
|
203
|
+
) : handoffUrl ? (
|
|
204
|
+
<Handoff url={ handoffUrl } bannerText={ bannerText } bannerButtonText={ bannerButtonText } compact isLink>
|
|
178
205
|
{ actionText }
|
|
179
206
|
</Handoff>
|
|
180
207
|
) : onClick || hasInternalLink ? (
|
|
@@ -224,9 +251,9 @@ const ActionCard = ( {
|
|
|
224
251
|
{ 'warning' === notificationLevel && <Notice noticeText={ notification } isWarning rawHTML={ notificationHTML } /> }
|
|
225
252
|
</div>
|
|
226
253
|
) }
|
|
227
|
-
{ children && ( ( expandable && expanded ) || ! expandable )
|
|
254
|
+
{ children && ( ( expandable && expanded ) || ! expandable ) ? (
|
|
228
255
|
<div className="newspack-action-card__region-children">{ children }</div>
|
|
229
|
-
) }
|
|
256
|
+
) : null }
|
|
230
257
|
</>
|
|
231
258
|
);
|
|
232
259
|
|
|
@@ -289,7 +316,7 @@ const ActionCard = ( {
|
|
|
289
316
|
<Card className={ classes } onClick={ simple && onClick } id={ id ?? null } noBorder={ noBorder }>
|
|
290
317
|
<div className="newspack-action-card__draggable-controls">
|
|
291
318
|
<div className="drag-handle" draggable onDragStart={ onDraggableStart } onDragEnd={ onDraggableEnd }>
|
|
292
|
-
<Icon icon={ dragHandle }
|
|
319
|
+
<Icon icon={ dragHandle } />
|
|
293
320
|
</div>
|
|
294
321
|
<div className="movers">
|
|
295
322
|
<Button
|
|
@@ -306,7 +333,7 @@ const ActionCard = ( {
|
|
|
306
333
|
/>
|
|
307
334
|
</div>
|
|
308
335
|
</div>
|
|
309
|
-
|
|
336
|
+
{ cardContent }
|
|
310
337
|
</Card>
|
|
311
338
|
) }
|
|
312
339
|
</Draggable>
|
|
@@ -316,7 +343,7 @@ const ActionCard = ( {
|
|
|
316
343
|
|
|
317
344
|
return (
|
|
318
345
|
<Card className={ classes } onClick={ simple && onClick } id={ id ?? null } noBorder={ noBorder }>
|
|
319
|
-
|
|
346
|
+
{ cardContent }
|
|
320
347
|
</Card>
|
|
321
348
|
);
|
|
322
349
|
};
|
|
@@ -260,6 +260,16 @@
|
|
|
260
260
|
@media screen and (min-width: 744px) {
|
|
261
261
|
margin-bottom: 0;
|
|
262
262
|
margin-right: 24px;
|
|
263
|
+
|
|
264
|
+
&.is-toggle-trailing {
|
|
265
|
+
margin-left: 24px;
|
|
266
|
+
margin-right: 0;
|
|
267
|
+
order: 999;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
label {
|
|
272
|
+
display: none;
|
|
263
273
|
}
|
|
264
274
|
|
|
265
275
|
.components-base-control__field {
|
|
@@ -433,13 +443,21 @@
|
|
|
433
443
|
text-decoration: inherit;
|
|
434
444
|
}
|
|
435
445
|
|
|
436
|
-
.newspack-action-card__region-children {
|
|
437
|
-
border-top: 1px solid wp-colors.$gray-
|
|
446
|
+
> .newspack-action-card__region-children {
|
|
447
|
+
border-top: 1px solid wp-colors.$gray-300;
|
|
438
448
|
padding-top: 24px;
|
|
439
449
|
|
|
440
450
|
+ .newspack-action-card__region-children {
|
|
441
451
|
border-top: none;
|
|
442
452
|
}
|
|
453
|
+
|
|
454
|
+
> * + * {
|
|
455
|
+
margin-top: 24px !important;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.newspack-action-card__region-children:has(> div:not(:empty)) {
|
|
459
|
+
margin-top: 16px;
|
|
460
|
+
}
|
|
443
461
|
}
|
|
444
462
|
|
|
445
463
|
&.is-medium .newspack-action-card__region-children {
|
|
@@ -469,6 +487,11 @@
|
|
|
469
487
|
margin-left: 8px;
|
|
470
488
|
}
|
|
471
489
|
}
|
|
490
|
+
|
|
491
|
+
hr:not(.newspack-divider) {
|
|
492
|
+
background: wp-colors.$gray-100;
|
|
493
|
+
margin: 0;
|
|
494
|
+
}
|
|
472
495
|
}
|
|
473
496
|
|
|
474
497
|
.newspack-card {
|
|
@@ -120,7 +120,7 @@ class AutocompleteTokenField extends Component {
|
|
|
120
120
|
Object.keys( validValues ).forEach( key => {
|
|
121
121
|
if ( validValues[ key ] === label ) {
|
|
122
122
|
// Preserve numeric or string type of values. Object.keys will convert numbers to strings.
|
|
123
|
-
const value =
|
|
123
|
+
const value = /^\d+$/.test( key.toString() ) ? parseInt( key ) : key.toString();
|
|
124
124
|
acc.push( { value, label } );
|
|
125
125
|
}
|
|
126
126
|
} );
|
|
@@ -131,7 +131,7 @@ class AutocompleteTokenField extends Component {
|
|
|
131
131
|
|
|
132
132
|
return labels.map( label =>
|
|
133
133
|
Object.keys( validValues )
|
|
134
|
-
.map( key => (
|
|
134
|
+
.map( key => ( /^\d+$/.test( key.toString() ) ? parseInt( key ) : key.toString() ) )
|
|
135
135
|
.find( key => validValues[ key ] === label )
|
|
136
136
|
);
|
|
137
137
|
}
|