newspack-components 3.0.0-alpha.2 → 3.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/babel.config.cjs.js +26 -0
- package/babel.config.js +1 -0
- package/copy-styles.js +10 -2
- package/dist/cjs/button/index.js +56 -0
- package/dist/cjs/grid/index.js +37 -0
- package/dist/cjs/hooks/index.js +25 -0
- package/dist/cjs/hooks/usePrompt.js +49 -0
- package/dist/cjs/text-control/index.js +64 -0
- package/dist/esm/accordion/index.js +42 -0
- package/dist/esm/accordion/style.scss +31 -0
- package/dist/esm/action-card/index.js +218 -0
- package/dist/esm/action-card/style.scss +483 -0
- package/dist/esm/autocomplete-tokenfield/index.js +261 -0
- package/dist/esm/autocomplete-tokenfield/style.scss +49 -0
- package/dist/esm/autocomplete-with-suggestions/index.js +274 -0
- package/dist/esm/autocomplete-with-suggestions/style.scss +163 -0
- package/dist/esm/button/index.js +48 -0
- package/dist/esm/button/style.scss +11 -0
- package/dist/esm/button-card/index.js +64 -0
- package/dist/esm/button-card/style.scss +180 -0
- package/dist/esm/card/index.js +43 -0
- package/dist/esm/card/style.scss +168 -0
- package/dist/esm/category-autocomplete/index.js +183 -0
- package/dist/esm/category-autocomplete/style.scss +34 -0
- package/dist/esm/color-picker/index.js +59 -0
- package/dist/esm/color-picker/style.scss +37 -0
- package/dist/esm/consts.js +1 -0
- package/dist/esm/custom-select-control/index.js +37 -0
- package/dist/esm/custom-select-control/style.scss +93 -0
- package/dist/esm/date-range-picker/index.js +31 -0
- package/dist/esm/date-range-picker/style.scss +148 -0
- package/dist/esm/footer/index.js +99 -0
- package/dist/esm/footer/style.scss +82 -0
- package/dist/esm/form-token-field/index.js +49 -0
- package/dist/esm/form-token-field/style.scss +37 -0
- package/dist/esm/global-notices/index.js +30 -0
- package/dist/esm/grid/index.js +29 -0
- package/dist/esm/grid/style.scss +166 -0
- package/dist/esm/handoff/index.js +175 -0
- package/dist/esm/handoff-message/index.js +47 -0
- package/dist/esm/hooks/index.js +17 -0
- package/dist/esm/hooks/useObjectState.js +30 -0
- package/dist/esm/hooks/useObjectState.test.js +82 -0
- package/dist/esm/hooks/useOnClickOutside.js +31 -0
- package/dist/esm/hooks/usePrompt.js +40 -0
- package/dist/esm/image-upload/index.js +140 -0
- package/dist/esm/image-upload/index.test.js +34 -0
- package/dist/esm/image-upload/style.scss +103 -0
- package/dist/esm/index.js +47 -0
- package/dist/esm/info-button/index.js +42 -0
- package/dist/esm/info-button/style.scss +18 -0
- package/dist/esm/modal/index.js +39 -0
- package/dist/esm/modal/style.scss +56 -0
- package/dist/esm/newspack-icon/index.js +50 -0
- package/dist/esm/newspack-icon/style.scss +26 -0
- package/dist/esm/newspack-logo/index.js +46 -0
- package/dist/esm/newspack-logo/style.scss +30 -0
- package/dist/esm/notice/index.js +65 -0
- package/dist/esm/notice/style.scss +111 -0
- package/dist/esm/patrons-logo/index.js +70 -0
- package/dist/esm/plugin-installer/index.js +289 -0
- package/dist/esm/plugin-installer/style.scss +72 -0
- package/dist/esm/plugin-settings/SettingsSection.js +133 -0
- package/dist/esm/plugin-settings/index.js +220 -0
- package/dist/esm/plugin-settings/style.scss +7 -0
- package/dist/esm/plugin-toggle/index.js +216 -0
- package/dist/esm/plugin-toggle/style.scss +20 -0
- package/dist/esm/popover/index.js +41 -0
- package/dist/esm/popover/style.scss +161 -0
- package/dist/esm/position-control/index.js +106 -0
- package/dist/esm/position-control/style.scss +66 -0
- package/dist/esm/progress-bar/index.js +68 -0
- package/dist/esm/progress-bar/index.test.js +108 -0
- package/dist/esm/progress-bar/style.scss +42 -0
- package/dist/esm/proxied-imports/router.js +8 -0
- package/dist/esm/radio-control/index.js +37 -0
- package/dist/esm/radio-control/style.scss +92 -0
- package/dist/esm/section-header/index.js +67 -0
- package/dist/esm/section-header/style.scss +45 -0
- package/dist/esm/select-control/ButtonGroupControl.js +53 -0
- package/dist/esm/select-control/GroupedSelectControl.js +78 -0
- package/dist/esm/select-control/index.js +51 -0
- package/dist/esm/select-control/style.scss +108 -0
- package/dist/esm/settings/MinMaxSetting.js +53 -0
- package/dist/esm/settings/SettingsCard.js +38 -0
- package/dist/esm/settings/SettingsSection.js +26 -0
- package/dist/esm/settings/index.js +9 -0
- package/dist/esm/settings/style.scss +119 -0
- package/dist/esm/sortable-newsletter-list-control/index.js +127 -0
- package/dist/esm/sortable-newsletter-list-control/style.scss +45 -0
- package/dist/esm/steps-list/index.js +43 -0
- package/dist/esm/steps-list/style.scss +11 -0
- package/dist/esm/steps-list-item/index.js +47 -0
- package/dist/esm/steps-list-item/style.scss +47 -0
- package/dist/esm/style-card/index.js +74 -0
- package/dist/esm/style-card/style.scss +94 -0
- package/dist/esm/style.scss +55 -0
- package/dist/esm/tabbed-navigation/index.js +53 -0
- package/dist/esm/tabbed-navigation/style.scss +86 -0
- package/dist/esm/text-control/index.js +56 -0
- package/dist/esm/text-control/style.scss +32 -0
- package/dist/esm/utils/index.js +29 -0
- package/dist/esm/waiting/index.js +44 -0
- package/dist/esm/waiting/style.scss +27 -0
- package/dist/esm/web-preview/index.js +183 -0
- package/dist/esm/web-preview/style.scss +155 -0
- package/dist/esm/with-wizard/index.js +320 -0
- package/dist/esm/with-wizard/style.scss +282 -0
- package/dist/esm/with-wizard-screen/index.js +109 -0
- package/dist/esm/with-wizard-screen/style.scss +160 -0
- package/dist/esm/wizard/components/WizardError.js +66 -0
- package/dist/esm/wizard/index.js +119 -0
- package/dist/esm/wizard/store/index.js +155 -0
- package/dist/esm/wizard/store/utils.js +14 -0
- package/package.json +8 -4
- package/dist/button/index.js +0 -51
- package/dist/button/index.tsx +0 -48
- package/dist/grid/index.js +0 -44
- package/dist/grid/index.tsx +0 -34
- package/dist/hooks/index.js +0 -29
- package/dist/hooks/index.ts +0 -15
- package/dist/hooks/usePrompt.js +0 -47
- package/dist/hooks/usePrompt.ts +0 -46
- package/dist/plugin-toggle/README.md +0 -53
- package/dist/text-control/index.js +0 -76
- package/dist/text-control/index.tsx +0 -71
- /package/dist/{accordion → cjs/accordion}/index.js +0 -0
- /package/dist/{accordion → cjs/accordion}/style.scss +0 -0
- /package/dist/{action-card → cjs/action-card}/index.js +0 -0
- /package/dist/{action-card → cjs/action-card}/style.scss +0 -0
- /package/dist/{autocomplete-tokenfield → cjs/autocomplete-tokenfield}/index.js +0 -0
- /package/dist/{autocomplete-tokenfield → cjs/autocomplete-tokenfield}/style.scss +0 -0
- /package/dist/{autocomplete-with-suggestions → cjs/autocomplete-with-suggestions}/index.js +0 -0
- /package/dist/{autocomplete-with-suggestions → cjs/autocomplete-with-suggestions}/style.scss +0 -0
- /package/dist/{button → cjs/button}/style.scss +0 -0
- /package/dist/{button-card → cjs/button-card}/index.js +0 -0
- /package/dist/{button-card → cjs/button-card}/style.scss +0 -0
- /package/dist/{card → cjs/card}/index.js +0 -0
- /package/dist/{card → cjs/card}/style.scss +0 -0
- /package/dist/{category-autocomplete → cjs/category-autocomplete}/index.js +0 -0
- /package/dist/{category-autocomplete → cjs/category-autocomplete}/style.scss +0 -0
- /package/dist/{color-picker → cjs/color-picker}/index.js +0 -0
- /package/dist/{color-picker → cjs/color-picker}/style.scss +0 -0
- /package/dist/{consts.js → cjs/consts.js} +0 -0
- /package/dist/{custom-select-control → cjs/custom-select-control}/index.js +0 -0
- /package/dist/{custom-select-control → cjs/custom-select-control}/style.scss +0 -0
- /package/dist/{date-range-picker → cjs/date-range-picker}/index.js +0 -0
- /package/dist/{date-range-picker → cjs/date-range-picker}/style.scss +0 -0
- /package/dist/{footer → cjs/footer}/index.js +0 -0
- /package/dist/{footer → cjs/footer}/style.scss +0 -0
- /package/dist/{form-token-field → cjs/form-token-field}/index.js +0 -0
- /package/dist/{form-token-field → cjs/form-token-field}/style.scss +0 -0
- /package/dist/{global-notices → cjs/global-notices}/index.js +0 -0
- /package/dist/{grid → cjs/grid}/style.scss +0 -0
- /package/dist/{handoff → cjs/handoff}/index.js +0 -0
- /package/dist/{handoff-message → cjs/handoff-message}/index.js +0 -0
- /package/dist/{hooks → cjs/hooks}/useObjectState.js +0 -0
- /package/dist/{hooks → cjs/hooks}/useObjectState.test.js +0 -0
- /package/dist/{hooks → cjs/hooks}/useOnClickOutside.js +0 -0
- /package/dist/{image-upload → cjs/image-upload}/index.js +0 -0
- /package/dist/{image-upload → cjs/image-upload}/index.test.js +0 -0
- /package/dist/{image-upload → cjs/image-upload}/style.scss +0 -0
- /package/dist/{index.js → cjs/index.js} +0 -0
- /package/dist/{info-button → cjs/info-button}/index.js +0 -0
- /package/dist/{info-button → cjs/info-button}/style.scss +0 -0
- /package/dist/{modal → cjs/modal}/index.js +0 -0
- /package/dist/{modal → cjs/modal}/style.scss +0 -0
- /package/dist/{newspack-icon → cjs/newspack-icon}/index.js +0 -0
- /package/dist/{newspack-icon → cjs/newspack-icon}/style.scss +0 -0
- /package/dist/{newspack-logo → cjs/newspack-logo}/index.js +0 -0
- /package/dist/{newspack-logo → cjs/newspack-logo}/style.scss +0 -0
- /package/dist/{notice → cjs/notice}/index.js +0 -0
- /package/dist/{notice → cjs/notice}/style.scss +0 -0
- /package/dist/{patrons-logo → cjs/patrons-logo}/index.js +0 -0
- /package/dist/{plugin-installer → cjs/plugin-installer}/index.js +0 -0
- /package/dist/{plugin-installer → cjs/plugin-installer}/style.scss +0 -0
- /package/dist/{plugin-settings → cjs/plugin-settings}/SettingsSection.js +0 -0
- /package/dist/{plugin-settings → cjs/plugin-settings}/index.js +0 -0
- /package/dist/{plugin-settings → cjs/plugin-settings}/style.scss +0 -0
- /package/dist/{plugin-toggle → cjs/plugin-toggle}/index.js +0 -0
- /package/dist/{plugin-toggle → cjs/plugin-toggle}/style.scss +0 -0
- /package/dist/{popover → cjs/popover}/index.js +0 -0
- /package/dist/{popover → cjs/popover}/style.scss +0 -0
- /package/dist/{position-control → cjs/position-control}/index.js +0 -0
- /package/dist/{position-control → cjs/position-control}/style.scss +0 -0
- /package/dist/{progress-bar → cjs/progress-bar}/index.js +0 -0
- /package/dist/{progress-bar → cjs/progress-bar}/index.test.js +0 -0
- /package/dist/{progress-bar → cjs/progress-bar}/style.scss +0 -0
- /package/dist/{proxied-imports → cjs/proxied-imports}/router.js +0 -0
- /package/dist/{radio-control → cjs/radio-control}/index.js +0 -0
- /package/dist/{radio-control → cjs/radio-control}/style.scss +0 -0
- /package/dist/{section-header → cjs/section-header}/index.js +0 -0
- /package/dist/{section-header → cjs/section-header}/style.scss +0 -0
- /package/dist/{select-control → cjs/select-control}/ButtonGroupControl.js +0 -0
- /package/dist/{select-control → cjs/select-control}/GroupedSelectControl.js +0 -0
- /package/dist/{select-control → cjs/select-control}/index.js +0 -0
- /package/dist/{select-control → cjs/select-control}/style.scss +0 -0
- /package/dist/{settings → cjs/settings}/MinMaxSetting.js +0 -0
- /package/dist/{settings → cjs/settings}/SettingsCard.js +0 -0
- /package/dist/{settings → cjs/settings}/SettingsSection.js +0 -0
- /package/dist/{settings → cjs/settings}/index.js +0 -0
- /package/dist/{settings → cjs/settings}/style.scss +0 -0
- /package/dist/{sortable-newsletter-list-control → cjs/sortable-newsletter-list-control}/index.js +0 -0
- /package/dist/{sortable-newsletter-list-control → cjs/sortable-newsletter-list-control}/style.scss +0 -0
- /package/dist/{steps-list → cjs/steps-list}/index.js +0 -0
- /package/dist/{steps-list → cjs/steps-list}/style.scss +0 -0
- /package/dist/{steps-list-item → cjs/steps-list-item}/index.js +0 -0
- /package/dist/{steps-list-item → cjs/steps-list-item}/style.scss +0 -0
- /package/dist/{style-card → cjs/style-card}/index.js +0 -0
- /package/dist/{style-card → cjs/style-card}/style.scss +0 -0
- /package/dist/{style.scss → cjs/style.scss} +0 -0
- /package/dist/{tabbed-navigation → cjs/tabbed-navigation}/index.js +0 -0
- /package/dist/{tabbed-navigation → cjs/tabbed-navigation}/style.scss +0 -0
- /package/dist/{text-control → cjs/text-control}/style.scss +0 -0
- /package/dist/{utils → cjs/utils}/index.js +0 -0
- /package/dist/{waiting → cjs/waiting}/index.js +0 -0
- /package/dist/{waiting → cjs/waiting}/style.scss +0 -0
- /package/dist/{web-preview → cjs/web-preview}/index.js +0 -0
- /package/dist/{web-preview → cjs/web-preview}/style.scss +0 -0
- /package/dist/{with-wizard → cjs/with-wizard}/index.js +0 -0
- /package/dist/{with-wizard → cjs/with-wizard}/style.scss +0 -0
- /package/dist/{with-wizard-screen → cjs/with-wizard-screen}/index.js +0 -0
- /package/dist/{with-wizard-screen → cjs/with-wizard-screen}/style.scss +0 -0
- /package/dist/{wizard → cjs/wizard}/components/WizardError.js +0 -0
- /package/dist/{wizard → cjs/wizard}/index.js +0 -0
- /package/dist/{wizard → cjs/wizard}/store/index.js +0 -0
- /package/dist/{wizard → cjs/wizard}/store/utils.js +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autocomplete Token Field
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
+
|
|
7
|
+
.newspack-autocomplete-tokenfield {
|
|
8
|
+
.components-spinner {
|
|
9
|
+
margin: 0;
|
|
10
|
+
position: absolute;
|
|
11
|
+
right: 8px;
|
|
12
|
+
top: 8px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&__input-container {
|
|
16
|
+
position: relative;
|
|
17
|
+
|
|
18
|
+
&.has-label .components-spinner {
|
|
19
|
+
top: 32px;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Workaround for hard-coded help text in FormTokenField. */
|
|
24
|
+
.components-form-token-field {
|
|
25
|
+
> .components-form-token-field__help {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
> .components-form-token-field__token-text {
|
|
30
|
+
align-items: center;
|
|
31
|
+
display: flex;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.newspack-autocomplete-tokenfield__help {
|
|
36
|
+
color: wp-colors.$gray-700;
|
|
37
|
+
font-size: inherit;
|
|
38
|
+
margin-top: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.components-form-token-field__suggestions-list {
|
|
42
|
+
margin-left: 0;
|
|
43
|
+
padding-left: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.components-button:focus:not(:disabled) {
|
|
47
|
+
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import apiFetch from '@wordpress/api-fetch';
|
|
5
|
+
import { Button, CheckboxControl, SelectControl } from '@wordpress/components';
|
|
6
|
+
import { decodeEntities } from '@wordpress/html-entities';
|
|
7
|
+
import { useEffect, useState } from '@wordpress/element';
|
|
8
|
+
import { __, _x, sprintf } from '@wordpress/i18n';
|
|
9
|
+
import { addQueryArgs } from '@wordpress/url';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* External dependencies.
|
|
13
|
+
*/
|
|
14
|
+
import { AutocompleteTokenField } from '../';
|
|
15
|
+
import './style.scss';
|
|
16
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
17
|
+
const AutocompleteWithSuggestions = ({
|
|
18
|
+
fetchSavedPosts = false,
|
|
19
|
+
// If passed, will use this function to fetch saved data.
|
|
20
|
+
fetchSuggestions = false,
|
|
21
|
+
// If passed, will use this function to fetch suggestions data.
|
|
22
|
+
help = __('Begin typing search term, click autocomplete result to select.', 'newspack-plugin'),
|
|
23
|
+
hideHelp = false,
|
|
24
|
+
// If true, all help text will be hidden.
|
|
25
|
+
label = __('Search', 'newspack-plugin'),
|
|
26
|
+
maxItemsToSuggest = 0,
|
|
27
|
+
// If passed, will be used to determine "load more" state. Necessary if you want "load more" functionality when using a custom `fetchSuggestions` function.
|
|
28
|
+
multiSelect = false,
|
|
29
|
+
// If true, component can select multiple values at once.
|
|
30
|
+
onChange = false,
|
|
31
|
+
// Function to call when selections change.
|
|
32
|
+
onPostTypeChange = false,
|
|
33
|
+
// Funciton to call when the post type selector is changed.
|
|
34
|
+
postTypes = [{
|
|
35
|
+
slug: 'post',
|
|
36
|
+
label: 'Post'
|
|
37
|
+
}],
|
|
38
|
+
// If passed, will render a selector to change the post type queried for suggestions.
|
|
39
|
+
postTypeLabel = __('item', 'newspack-plugin'),
|
|
40
|
+
// String to describe the data being shown.
|
|
41
|
+
postTypeLabelPlural = __('items', 'newspack-plugin'),
|
|
42
|
+
// Plural string to describe the data being shown.
|
|
43
|
+
selectedItems = [],
|
|
44
|
+
// Array of saved items.
|
|
45
|
+
selectedPost = 0,
|
|
46
|
+
// Legacy prop when single-select was the only option.
|
|
47
|
+
suggestionsToFetch = 10 // Number of suggestions to fetch per query.
|
|
48
|
+
}) => {
|
|
49
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
50
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
51
|
+
const [suggestions, setSuggestions] = useState([]);
|
|
52
|
+
const [maxSuggestions, setMaxSuggestions] = useState(0);
|
|
53
|
+
const [postTypeToSearch, setPostTypeToSearch] = useState(postTypes[0].slug);
|
|
54
|
+
const classNames = ['newspack-autocomplete-with-suggestions'];
|
|
55
|
+
if (hideHelp) {
|
|
56
|
+
classNames.push('hide-help');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fetch recent posts to show as suggestions.
|
|
61
|
+
*/
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (onPostTypeChange) {
|
|
64
|
+
onPostTypeChange(postTypeToSearch);
|
|
65
|
+
}
|
|
66
|
+
setIsLoading(true);
|
|
67
|
+
handleFetchSuggestions(null, 0, postTypeToSearch).then(_suggestions => {
|
|
68
|
+
if (0 < _suggestions.length) {
|
|
69
|
+
setSuggestions(_suggestions);
|
|
70
|
+
}
|
|
71
|
+
}).finally(() => setIsLoading(false));
|
|
72
|
+
}, [postTypeToSearch]);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Fetch more suggestions.
|
|
76
|
+
*/
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (isLoadingMore) {
|
|
79
|
+
handleFetchSuggestions(null, suggestions.length, postTypeToSearch).then(_suggestions => {
|
|
80
|
+
if (0 < _suggestions.length) {
|
|
81
|
+
setSuggestions(suggestions.concat(_suggestions));
|
|
82
|
+
}
|
|
83
|
+
}).finally(() => setIsLoadingMore(false));
|
|
84
|
+
}
|
|
85
|
+
}, [isLoadingMore]);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* If passed a `fetchSavedPosts` prop, use that, otherwise, build it based on the selected post type.
|
|
89
|
+
*/
|
|
90
|
+
const handleFetchSaved = fetchSavedPosts ? fetchSavedPosts : async (postIds = [], searchSlug = null) => {
|
|
91
|
+
const postTypeSlug = searchSlug || postTypeToSearch;
|
|
92
|
+
const endpoint = 'post' === postTypeSlug || 'page' === postTypeSlug ? postTypeSlug + 's' // Default post type endpoints are plural.
|
|
93
|
+
: postTypeSlug; // Custom post type endpoints are singular.
|
|
94
|
+
const posts = await apiFetch({
|
|
95
|
+
path: addQueryArgs('/wp/v2/' + endpoint, {
|
|
96
|
+
per_page: 100,
|
|
97
|
+
include: postIds.join(','),
|
|
98
|
+
_fields: 'id,title'
|
|
99
|
+
})
|
|
100
|
+
});
|
|
101
|
+
return posts.map(post => ({
|
|
102
|
+
value: parseInt(post.id),
|
|
103
|
+
label: decodeEntities(post.title) || __('(no title)', 'newspack-plugin')
|
|
104
|
+
}));
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* If passed a `fetchSuggestions` prop, use that, otherwise, build it based on the selected post type.
|
|
109
|
+
*/
|
|
110
|
+
const handleFetchSuggestions = fetchSuggestions ? fetchSuggestions : async (search = null, offset = 0, searchSlug = null) => {
|
|
111
|
+
const postTypeSlug = searchSlug || postTypeToSearch;
|
|
112
|
+
const endpoint = 'post' === postTypeSlug || 'page' === postTypeSlug ? postTypeSlug + 's' // Default post type endpoints are plural.
|
|
113
|
+
: postTypeSlug; // Custom post type endpoints are singular.
|
|
114
|
+
const response = await apiFetch({
|
|
115
|
+
parse: false,
|
|
116
|
+
path: addQueryArgs('/wp/v2/' + endpoint, {
|
|
117
|
+
search,
|
|
118
|
+
offset,
|
|
119
|
+
per_page: suggestionsToFetch,
|
|
120
|
+
_fields: 'id,title'
|
|
121
|
+
})
|
|
122
|
+
});
|
|
123
|
+
const total = parseInt(response.headers.get('x-wp-total') || 0);
|
|
124
|
+
const posts = await response.json();
|
|
125
|
+
setMaxSuggestions(total);
|
|
126
|
+
|
|
127
|
+
// Format suggestions for FormTokenField display.
|
|
128
|
+
return posts.reduce((acc, post) => {
|
|
129
|
+
acc.push({
|
|
130
|
+
value: parseInt(post.id),
|
|
131
|
+
label: decodeEntities(post?.title.rendered) || __('(no title)', 'newspack-plugin')
|
|
132
|
+
});
|
|
133
|
+
return acc;
|
|
134
|
+
}, []);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Intercept onChange callback so we can decide whether to allow multiple selections.
|
|
139
|
+
*/
|
|
140
|
+
const handleOnChange = _selections => {
|
|
141
|
+
// If only allowing one selection, just return the one selected item.
|
|
142
|
+
if (!multiSelect) {
|
|
143
|
+
return onChange(_selections);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Handle legacy `selectedPost` prop.
|
|
147
|
+
const selections = selectedPost ? [...selectedItems, selectedPost] : [...selectedItems];
|
|
148
|
+
|
|
149
|
+
// Loop through new selections to determine whether to add or remove them.
|
|
150
|
+
_selections.forEach(_selection => {
|
|
151
|
+
const existingSelection = selections.findIndex(selection => parseInt(selection.value) === parseInt(_selection.value));
|
|
152
|
+
if (-1 < existingSelection) {
|
|
153
|
+
// If the selection is already selected, remove it.
|
|
154
|
+
selections.splice(existingSelection, 1);
|
|
155
|
+
} else {
|
|
156
|
+
// Otherwise, add it.
|
|
157
|
+
selections.push(_selection);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Include currently selected post type in selection results.
|
|
162
|
+
onChange(selections.map(selection => ({
|
|
163
|
+
...selection,
|
|
164
|
+
postType: postTypeToSearch
|
|
165
|
+
})));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Render selected item(s) for this component. Clicking on a selection deselects it.
|
|
170
|
+
*/
|
|
171
|
+
const renderSelections = () => {
|
|
172
|
+
// Handle legacy `selectedPost` prop.
|
|
173
|
+
const selections = selectedPost ? [...selectedItems, selectedPost] : selectedItems;
|
|
174
|
+
const selectedMessage = multiSelect ? sprintf(
|
|
175
|
+
// Translators: %1: the length of selections. %2: the selection leabel.
|
|
176
|
+
__('%1$s %2$s selected', 'newspack-plugin'), selections.length, selections.length > 1 ? postTypeLabelPlural : postTypeLabel) : sprintf(
|
|
177
|
+
// Translators: %s: The label for the selection.
|
|
178
|
+
__('Selected %s', 'newspack-plugin'), postTypeLabel);
|
|
179
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
180
|
+
className: "newspack-autocomplete-with-suggestions__selected-items",
|
|
181
|
+
children: [/*#__PURE__*/_jsxs("p", {
|
|
182
|
+
className: "newspack-autocomplete-with-suggestions__label",
|
|
183
|
+
children: [selectedMessage, 1 < selections.length && _x(' – ', 'separator character', 'newspack-plugin'), 1 < selections.length && /*#__PURE__*/_jsx(Button, {
|
|
184
|
+
onClick: () => onChange([]),
|
|
185
|
+
isLink: true,
|
|
186
|
+
isDestructive: true,
|
|
187
|
+
children: __('Clear all', 'newspack-plugin')
|
|
188
|
+
})]
|
|
189
|
+
}), selections.map(selection => /*#__PURE__*/_jsx(Button, {
|
|
190
|
+
className: "newspack-autocomplete-with-suggestions__selected-item-button",
|
|
191
|
+
isTertiary: true,
|
|
192
|
+
onClick: () => onChange(selections.filter(_selection => _selection.value !== selection.value)),
|
|
193
|
+
children: selection.label
|
|
194
|
+
}, selection.value))]
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Render post type select dropdown.
|
|
200
|
+
*/
|
|
201
|
+
const renderPostTypeSelect = () => {
|
|
202
|
+
return /*#__PURE__*/_jsx(SelectControl, {
|
|
203
|
+
label: sprintf(
|
|
204
|
+
// Translators: %s: The name of the type.
|
|
205
|
+
__('%s type', 'newspack-plugin'), postTypeLabel.charAt(0).toUpperCase() + postTypeLabel.slice(1)),
|
|
206
|
+
value: postTypeToSearch,
|
|
207
|
+
options: postTypes.map(postTypeOption => ({
|
|
208
|
+
label: postTypeOption.label,
|
|
209
|
+
value: postTypeOption.slug
|
|
210
|
+
})),
|
|
211
|
+
onChange: _postType => setPostTypeToSearch(_postType)
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Render a single suggestion object that can be clicked to select it immediately.
|
|
217
|
+
*
|
|
218
|
+
* @param {Object} suggestion Suggestion object with value and label keys.
|
|
219
|
+
*/
|
|
220
|
+
const renderSuggestion = suggestion => {
|
|
221
|
+
if (multiSelect) {
|
|
222
|
+
const selections = selectedPost ? [...selectedItems, selectedPost] : [...selectedItems];
|
|
223
|
+
const isSelected = !!selections.find(_selection => parseInt(_selection.value) === parseInt(suggestion.value) && _selection.label === suggestion.label);
|
|
224
|
+
return /*#__PURE__*/_jsx(CheckboxControl, {
|
|
225
|
+
checked: isSelected,
|
|
226
|
+
onChange: () => handleOnChange([suggestion]),
|
|
227
|
+
label: suggestion.label
|
|
228
|
+
}, suggestion.value);
|
|
229
|
+
}
|
|
230
|
+
return /*#__PURE__*/_jsx(Button, {
|
|
231
|
+
isLink: true,
|
|
232
|
+
onClick: () => handleOnChange([suggestion]),
|
|
233
|
+
children: suggestion.label
|
|
234
|
+
}, suggestion.value);
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Render a list of suggestions that can be clicked to select instead of searching by title.
|
|
239
|
+
*/
|
|
240
|
+
const renderSuggestions = () => {
|
|
241
|
+
if (0 === suggestions.length) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const className = multiSelect ? 'newspack-autocomplete-with-suggestions__search-suggestions-multiselect' : 'newspack-autocomplete-with-suggestions__search-suggestions';
|
|
245
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
246
|
+
children: [!hideHelp && /*#__PURE__*/_jsx("p", {
|
|
247
|
+
className: "newspack-autocomplete-with-suggestions__label",
|
|
248
|
+
children: /* Translators: %s: the name of a post type. */sprintf(__('Or, select a recent %s:', 'newspack-plugin'), postTypeLabel)
|
|
249
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
250
|
+
className: className,
|
|
251
|
+
children: [suggestions.map(renderSuggestion), suggestions.length < (maxItemsToSuggest || maxSuggestions) && /*#__PURE__*/_jsx(Button, {
|
|
252
|
+
disabled: isLoadingMore,
|
|
253
|
+
isSecondary: true,
|
|
254
|
+
onClick: () => setIsLoadingMore(true),
|
|
255
|
+
children: isLoadingMore ? __('Loading…', 'newspack-plugin') : __('Load more', 'newspack-plugin')
|
|
256
|
+
})]
|
|
257
|
+
})]
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
261
|
+
className: classNames.join(' '),
|
|
262
|
+
children: [0 < selectedItems.length && renderSelections(), 1 < postTypes.length && renderPostTypeSelect(), /*#__PURE__*/_jsx(AutocompleteTokenField, {
|
|
263
|
+
tokens: [],
|
|
264
|
+
onChange: handleOnChange,
|
|
265
|
+
fetchSuggestions: async search => handleFetchSuggestions(search, 0, postTypeToSearch),
|
|
266
|
+
fetchSavedInfo: postIds => handleFetchSaved(postIds),
|
|
267
|
+
label: label,
|
|
268
|
+
loading: isLoading,
|
|
269
|
+
help: !hideHelp && help,
|
|
270
|
+
returnFullObjects: true
|
|
271
|
+
}), renderSuggestions()]
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
export default AutocompleteWithSuggestions;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styles for AutocompleteWithSuggestions component.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
+
|
|
7
|
+
.newspack-autocomplete-with-suggestions {
|
|
8
|
+
width: 100%;
|
|
9
|
+
|
|
10
|
+
&.hide-help {
|
|
11
|
+
> .components-base-control,
|
|
12
|
+
> .newspack-autocomplete-tokenfield,
|
|
13
|
+
> .newspack-autocomplete-with-suggestions__search-suggestions,
|
|
14
|
+
> .newspack-autocomplete-with-suggestions__search-suggestions-multiselect {
|
|
15
|
+
margin-top: 16px;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
.components-select-control__input {
|
|
19
|
+
max-width: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.components-input-control__backdrop {
|
|
23
|
+
border-color: wp-colors.$gray-700 !important;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.newspack-autocomplete-with-suggestions__label,
|
|
27
|
+
.components-form-token-field__label,
|
|
28
|
+
.components-input-control__label,
|
|
29
|
+
.components-checkbox-control__label {
|
|
30
|
+
color: wp-colors.$gray-900 !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&__suggestions-spinner {
|
|
34
|
+
background: wp-colors.$gray-100;
|
|
35
|
+
border: 1px solid wp-colors.$gray-700;
|
|
36
|
+
border-radius: 2px;
|
|
37
|
+
cursor: progress;
|
|
38
|
+
margin: 16px 0;
|
|
39
|
+
padding: 32px;
|
|
40
|
+
|
|
41
|
+
.components-spinner {
|
|
42
|
+
display: block;
|
|
43
|
+
margin: 0 auto;
|
|
44
|
+
position: relative;
|
|
45
|
+
right: auto;
|
|
46
|
+
top: 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.newspack-autocomplete-tokenfield__help {
|
|
51
|
+
font-size: inherit;
|
|
52
|
+
margin-bottom: 8px !important;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.components-form-token-field {
|
|
56
|
+
&__input-container {
|
|
57
|
+
border-color: wp-colors.$gray-700;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
&__suggestions-list {
|
|
61
|
+
border-top-color: wp-colors.$gray-700;
|
|
62
|
+
margin: 4px -4px -2px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&__suggestion {
|
|
66
|
+
padding: 8px;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
p.newspack-autocomplete-with-suggestions__label {
|
|
71
|
+
font-size: inherit;
|
|
72
|
+
margin: 0 0 8px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&__selected-items {
|
|
76
|
+
border-bottom: 1px solid wp-colors.$gray-700;
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-wrap: wrap;
|
|
79
|
+
gap: 8px;
|
|
80
|
+
margin-bottom: 16px;
|
|
81
|
+
padding-bottom: 12px;
|
|
82
|
+
|
|
83
|
+
p.newspack-autocomplete-with-suggestions__label {
|
|
84
|
+
flex: 0 0 100%;
|
|
85
|
+
margin: 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&__selected-item-button.components-button.is-tertiary {
|
|
90
|
+
background-color: wp-colors.$gray-300;
|
|
91
|
+
border-radius: 2px;
|
|
92
|
+
color: wp-colors.$gray-900;
|
|
93
|
+
font-size: 13px;
|
|
94
|
+
height: auto;
|
|
95
|
+
margin: 0;
|
|
96
|
+
padding-left: 8px;
|
|
97
|
+
padding-right: 8px;
|
|
98
|
+
|
|
99
|
+
&::after {
|
|
100
|
+
content: "✕";
|
|
101
|
+
margin-left: 8px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&:hover {
|
|
105
|
+
box-shadow: none;
|
|
106
|
+
color: black;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&__search-suggestions,
|
|
111
|
+
&__search-suggestions-multiselect {
|
|
112
|
+
border-radius: 2px;
|
|
113
|
+
border: 1px solid wp-colors.$gray-700;
|
|
114
|
+
max-height: 178px;
|
|
115
|
+
overflow: visible auto;
|
|
116
|
+
padding: 8px 8px 0;
|
|
117
|
+
|
|
118
|
+
.components-button {
|
|
119
|
+
display: block;
|
|
120
|
+
line-height: normal;
|
|
121
|
+
margin: auto;
|
|
122
|
+
|
|
123
|
+
&.is-link {
|
|
124
|
+
color: wp-colors.$gray-900;
|
|
125
|
+
padding: 8px;
|
|
126
|
+
text-decoration: none;
|
|
127
|
+
width: 100%;
|
|
128
|
+
|
|
129
|
+
&:active:not(:disabled),
|
|
130
|
+
&:hover:not(:disabled) {
|
|
131
|
+
background: wp-colors.$gray-900;
|
|
132
|
+
background: var(--wp-admin-theme-color);
|
|
133
|
+
color: white;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
&.is-secondary {
|
|
137
|
+
margin-bottom: 8px;
|
|
138
|
+
margin-top: 8px;
|
|
139
|
+
width: 100%;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&__search-suggestions {
|
|
145
|
+
border-radius: 2px;
|
|
146
|
+
border: 1px solid wp-colors.$gray-700;
|
|
147
|
+
padding: 0;
|
|
148
|
+
|
|
149
|
+
.components-button {
|
|
150
|
+
line-height: normal;
|
|
151
|
+
|
|
152
|
+
&:focus:not(:disabled) {
|
|
153
|
+
border-radius: 0;
|
|
154
|
+
box-shadow: inset 0 0 0 1.5px wp-colors.$gray-900;
|
|
155
|
+
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
&.is-secondary {
|
|
159
|
+
width: calc(100% - 16px);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WordPress dependencies.
|
|
7
|
+
*/
|
|
8
|
+
import { Button as BaseComponent } from '@wordpress/components';
|
|
9
|
+
import { useState } from '@wordpress/element';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import Router from '../proxied-imports/router';
|
|
15
|
+
import './style.scss';
|
|
16
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
17
|
+
const {
|
|
18
|
+
useHistory
|
|
19
|
+
} = Router;
|
|
20
|
+
const Button = ({
|
|
21
|
+
href,
|
|
22
|
+
onClick,
|
|
23
|
+
...otherProps
|
|
24
|
+
}) => {
|
|
25
|
+
const history = useHistory();
|
|
26
|
+
const [isAwaitingOnClick, setIsAwaitingOnClick] = useState(false);
|
|
27
|
+
|
|
28
|
+
// If both onClick and href are present, await the onClick action an then redirect.
|
|
29
|
+
if (href && onClick) {
|
|
30
|
+
otherProps.onClick = async () => {
|
|
31
|
+
setIsAwaitingOnClick(true);
|
|
32
|
+
await onClick();
|
|
33
|
+
setIsAwaitingOnClick(false);
|
|
34
|
+
history.push((href || '').replace('#', ''));
|
|
35
|
+
};
|
|
36
|
+
} else {
|
|
37
|
+
otherProps.href = href;
|
|
38
|
+
otherProps.onClick = onClick;
|
|
39
|
+
}
|
|
40
|
+
if (isAwaitingOnClick) {
|
|
41
|
+
otherProps.disabled = true;
|
|
42
|
+
}
|
|
43
|
+
// @ts-ignore - @wordpress/components' Button can only have either href or onClick, not both.
|
|
44
|
+
return /*#__PURE__*/_jsx(BaseComponent, {
|
|
45
|
+
...otherProps
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
export default Button;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button Card
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* WordPress dependencies
|
|
7
|
+
*/
|
|
8
|
+
import { Component } from '@wordpress/element';
|
|
9
|
+
import { Icon, chevronRight } from '@wordpress/icons';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Internal dependencies
|
|
13
|
+
*/
|
|
14
|
+
import { Grid } from '../';
|
|
15
|
+
import './style.scss';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* External dependencies
|
|
19
|
+
*/
|
|
20
|
+
import classnames from 'classnames';
|
|
21
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
+
class ButtonCard extends Component {
|
|
23
|
+
/**
|
|
24
|
+
* Render
|
|
25
|
+
*/
|
|
26
|
+
render() {
|
|
27
|
+
const {
|
|
28
|
+
chevron,
|
|
29
|
+
className,
|
|
30
|
+
desc,
|
|
31
|
+
grouped,
|
|
32
|
+
icon,
|
|
33
|
+
isDestructive,
|
|
34
|
+
isPressed,
|
|
35
|
+
isSmall,
|
|
36
|
+
title,
|
|
37
|
+
...otherProps
|
|
38
|
+
} = this.props;
|
|
39
|
+
const classes = classnames('newspack-button-card', className, chevron && 'has-chevron', grouped && 'grouped', icon && 'has-icon', isDestructive && 'is-destructive', isPressed && 'is-pressed', isSmall && 'is-small');
|
|
40
|
+
return /*#__PURE__*/_jsxs("a", {
|
|
41
|
+
className: classes,
|
|
42
|
+
...otherProps,
|
|
43
|
+
children: [icon && /*#__PURE__*/_jsx(Icon, {
|
|
44
|
+
icon: icon,
|
|
45
|
+
height: 48,
|
|
46
|
+
width: 48
|
|
47
|
+
}), /*#__PURE__*/_jsxs(Grid, {
|
|
48
|
+
noMargin: true,
|
|
49
|
+
columns: 1,
|
|
50
|
+
gutter: 8,
|
|
51
|
+
children: [title && /*#__PURE__*/_jsx("h3", {
|
|
52
|
+
children: title
|
|
53
|
+
}), desc && /*#__PURE__*/_jsx("p", {
|
|
54
|
+
children: desc
|
|
55
|
+
})]
|
|
56
|
+
}), chevron && /*#__PURE__*/_jsx(Icon, {
|
|
57
|
+
icon: chevronRight,
|
|
58
|
+
height: 24,
|
|
59
|
+
width: 24
|
|
60
|
+
})]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export default ButtonCard;
|