newspack-components 4.1.0 → 4.3.0
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/colors/colors.module.scss +1 -1
- package/dist/cjs/action-card/index.js +21 -12
- package/dist/cjs/action-card/style.scss +32 -14
- package/dist/cjs/autocomplete-tokenfield/index.js +2 -2
- package/dist/cjs/autocomplete-with-latest-posts/index.js +289 -0
- package/dist/cjs/autocomplete-with-latest-posts/style.scss +150 -0
- package/dist/cjs/badge/index.js +32 -0
- package/dist/cjs/badge/style.scss +36 -0
- package/dist/cjs/button/index.js +2 -0
- package/dist/cjs/card/core-card.js +141 -0
- package/dist/cjs/card/index.js +33 -0
- package/dist/cjs/card/style-core.scss +227 -0
- package/dist/cjs/card/style.scss +2 -2
- package/dist/cjs/card-settings-group/index.js +49 -0
- package/dist/cjs/card-settings-group/style.scss +33 -0
- package/dist/cjs/card-sortable-list/index.js +390 -0
- package/dist/cjs/card-sortable-list/style.scss +48 -0
- package/dist/cjs/confirm-dialog/index.js +59 -0
- package/dist/cjs/divider/index.js +42 -0
- package/dist/cjs/divider/style.scss +51 -0
- package/dist/cjs/form-token-field/style.scss +0 -5
- package/dist/cjs/grid/index.js +2 -1
- package/dist/cjs/grid/style.scss +63 -9
- package/dist/cjs/index.js +42 -0
- package/dist/cjs/modal/index.js +11 -4
- package/dist/cjs/modal/style.scss +43 -13
- package/dist/cjs/newspack-icon/style.scss +5 -3
- package/dist/cjs/popover/style.scss +1 -1
- package/dist/cjs/section-header/index.js +76 -17
- package/dist/cjs/section-header/style.scss +109 -4
- package/dist/cjs/style.scss +2 -0
- package/dist/cjs/waiting/index.js +3 -1
- package/dist/cjs/waiting/style.scss +4 -0
- package/dist/cjs/web-preview/index.js +98 -39
- package/dist/cjs/web-preview/style.scss +20 -53
- package/dist/cjs/with-wizard/index.js +1 -1
- package/dist/cjs/with-wizard/style.scss +24 -6
- package/dist/cjs/with-wizard-screen/style.scss +39 -10
- package/dist/cjs/wizard/components/WizardSnackbar.js +70 -0
- package/dist/cjs/wizard/components/style.scss +48 -0
- package/dist/cjs/wizard/index.js +97 -16
- package/dist/cjs/wizard/store/index.js +46 -0
- package/dist/esm/action-card/index.js +21 -12
- package/dist/esm/action-card/style.scss +32 -14
- package/dist/esm/autocomplete-tokenfield/index.js +2 -2
- package/dist/esm/autocomplete-with-latest-posts/index.js +281 -0
- package/dist/esm/autocomplete-with-latest-posts/style.scss +150 -0
- package/dist/esm/badge/index.js +24 -0
- package/dist/esm/badge/style.scss +36 -0
- package/dist/esm/button/index.js +2 -0
- package/dist/esm/card/core-card.js +133 -0
- package/dist/esm/card/index.js +33 -0
- package/dist/esm/card/style-core.scss +227 -0
- package/dist/esm/card/style.scss +2 -2
- package/dist/esm/card-settings-group/index.js +42 -0
- package/dist/esm/card-settings-group/style.scss +33 -0
- package/dist/esm/card-sortable-list/index.js +381 -0
- package/dist/esm/card-sortable-list/style.scss +48 -0
- package/dist/esm/confirm-dialog/index.js +49 -0
- package/dist/esm/divider/index.js +34 -0
- package/dist/esm/divider/style.scss +51 -0
- package/dist/esm/form-token-field/style.scss +0 -5
- package/dist/esm/grid/index.js +2 -1
- package/dist/esm/grid/style.scss +63 -9
- package/dist/esm/index.js +6 -0
- package/dist/esm/modal/index.js +11 -4
- package/dist/esm/modal/style.scss +43 -13
- package/dist/esm/newspack-icon/style.scss +5 -3
- package/dist/esm/popover/style.scss +1 -1
- package/dist/esm/section-header/index.js +75 -18
- package/dist/esm/section-header/style.scss +109 -4
- package/dist/esm/style.scss +2 -0
- package/dist/esm/waiting/index.js +3 -1
- package/dist/esm/waiting/style.scss +4 -0
- package/dist/esm/web-preview/index.js +101 -42
- package/dist/esm/web-preview/style.scss +20 -53
- package/dist/esm/with-wizard/index.js +1 -1
- package/dist/esm/with-wizard/style.scss +24 -6
- package/dist/esm/with-wizard-screen/style.scss +39 -10
- package/dist/esm/wizard/components/WizardSnackbar.js +64 -0
- package/dist/esm/wizard/components/style.scss +48 -0
- package/dist/esm/wizard/index.js +101 -20
- package/dist/esm/wizard/store/index.js +46 -0
- package/package.json +5 -6
- package/shared/author-context.js +26 -0
- package/shared/hooks/use-coauthors.js +220 -0
- package/shared/hooks/use-coauthors.test.js +624 -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 +46 -0
- package/src/action-card/action-card.d.ts +7 -3
- package/src/action-card/index.js +24 -11
- package/src/action-card/style.scss +32 -14
- 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 +24 -0
- package/src/badge/style.scss +36 -0
- package/src/button/index.tsx +3 -2
- package/src/card/core-card.js +147 -0
- package/src/card/index.js +39 -1
- package/src/card/style-core.scss +227 -0
- package/src/card/style.scss +2 -2
- package/src/card-settings-group/README.md +43 -0
- package/src/card-settings-group/index.tsx +53 -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 +412 -0
- package/src/card-sortable-list/style.scss +48 -0
- package/src/confirm-dialog/index.tsx +64 -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 +63 -9
- package/src/index.js +6 -0
- package/src/modal/index.js +12 -3
- package/src/modal/style.scss +43 -13
- package/src/newspack-icon/style.scss +5 -3
- package/src/popover/style.scss +1 -1
- package/src/section-header/index.js +72 -13
- package/src/section-header/style.scss +109 -4
- package/src/style.scss +2 -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 +24 -6
- package/src/with-wizard-screen/style.scss +39 -10
- package/src/wizard/components/WizardSnackbar.js +58 -0
- package/src/wizard/components/style.scss +48 -0
- package/src/wizard/index.js +108 -14
- package/src/wizard/store/index.js +26 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import debounce from 'lodash/debounce';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import apiFetch from '@wordpress/api-fetch';
|
|
10
|
+
import { Button, CheckboxControl, FormTokenField, Spinner } from '@wordpress/components';
|
|
11
|
+
import { decodeEntities } from '@wordpress/html-entities';
|
|
12
|
+
import { useEffect, useState } from '@wordpress/element';
|
|
13
|
+
import { __ } from '@wordpress/i18n';
|
|
14
|
+
import { addQueryArgs } from '@wordpress/url';
|
|
15
|
+
import './style.scss';
|
|
16
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
17
|
+
const AutocompleteWithLatestPosts = ({
|
|
18
|
+
fetchSuggestions = false,
|
|
19
|
+
// If passed, will use this function to fetch suggestions data.
|
|
20
|
+
help = __('Begin typing search term, click autocomplete result to select.', 'newspack-plugin'),
|
|
21
|
+
hideHelp = true,
|
|
22
|
+
// If true, all help text will be hidden.
|
|
23
|
+
hideFormTokenHelp = true,
|
|
24
|
+
// If true, hides FormTokenField's built-in help text.
|
|
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
|
+
selectedItems = [],
|
|
33
|
+
// Array of saved items.
|
|
34
|
+
suggestionsToFetch = 20 // Number of suggestions to fetch per query.
|
|
35
|
+
}) => {
|
|
36
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
37
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
38
|
+
const [suggestions, setSuggestions] = useState([]);
|
|
39
|
+
const [maxSuggestions, setMaxSuggestions] = useState(0);
|
|
40
|
+
const [searchSuggestions, setSearchSuggestions] = useState([]);
|
|
41
|
+
const [validValues, setValidValues] = useState({});
|
|
42
|
+
const [isSearching, setIsSearching] = useState(false);
|
|
43
|
+
// Leaving this in here so we can expand to use different post types in the future; right now it defaults to 'post'.
|
|
44
|
+
const postTypeToSearch = 'post';
|
|
45
|
+
const classNames = ['newspack-autocomplete-with-latest-posts'];
|
|
46
|
+
if (hideFormTokenHelp) {
|
|
47
|
+
classNames.push('hide-form-token-help');
|
|
48
|
+
}
|
|
49
|
+
if (hideHelp) {
|
|
50
|
+
classNames.push('hide-help');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Debounced function to update search suggestions.
|
|
55
|
+
*/
|
|
56
|
+
const debouncedUpdateSuggestions = debounce(input => {
|
|
57
|
+
if (!input || input.length < 2) {
|
|
58
|
+
setSearchSuggestions([]);
|
|
59
|
+
setIsSearching(false);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
setIsSearching(true);
|
|
63
|
+
handleFetchSuggestions(input, 0, postTypeToSearch).then(_suggestions => {
|
|
64
|
+
setSearchSuggestions(_suggestions);
|
|
65
|
+
// Update valid values for token conversion
|
|
66
|
+
const newValidValues = {
|
|
67
|
+
...validValues
|
|
68
|
+
};
|
|
69
|
+
_suggestions.forEach(suggestion => {
|
|
70
|
+
newValidValues[suggestion.value] = suggestion.label;
|
|
71
|
+
});
|
|
72
|
+
setValidValues(newValidValues);
|
|
73
|
+
}).finally(() => setIsSearching(false));
|
|
74
|
+
}, 500);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Fetch recent posts to show as suggestions.
|
|
78
|
+
*/
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
setIsLoading(true);
|
|
81
|
+
handleFetchSuggestions(null, 0, postTypeToSearch).then(_suggestions => {
|
|
82
|
+
if (0 < _suggestions.length) {
|
|
83
|
+
setSuggestions(_suggestions);
|
|
84
|
+
// Update valid values for token conversion
|
|
85
|
+
const newValidValues = {
|
|
86
|
+
...validValues
|
|
87
|
+
};
|
|
88
|
+
_suggestions.forEach(suggestion => {
|
|
89
|
+
newValidValues[suggestion.value] = suggestion.label;
|
|
90
|
+
});
|
|
91
|
+
setValidValues(newValidValues);
|
|
92
|
+
}
|
|
93
|
+
}).finally(() => setIsLoading(false));
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Fetch more suggestions.
|
|
98
|
+
*/
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (isLoadingMore) {
|
|
101
|
+
handleFetchSuggestions(null, suggestions.length, postTypeToSearch).then(_suggestions => {
|
|
102
|
+
if (0 < _suggestions.length) {
|
|
103
|
+
setSuggestions(suggestions.concat(_suggestions));
|
|
104
|
+
}
|
|
105
|
+
}).finally(() => setIsLoadingMore(false));
|
|
106
|
+
}
|
|
107
|
+
}, [isLoadingMore]);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* If passed a `fetchSuggestions` prop, use that, otherwise, build it based on the selected post type.
|
|
111
|
+
*/
|
|
112
|
+
const handleFetchSuggestions = fetchSuggestions ? fetchSuggestions : async (search = null, offset = 0, searchSlug = null) => {
|
|
113
|
+
const postTypeSlug = searchSlug || postTypeToSearch;
|
|
114
|
+
const endpoint = 'post' === postTypeSlug || 'page' === postTypeSlug ? postTypeSlug + 's' // Default post type endpoints are plural.
|
|
115
|
+
: postTypeSlug; // Custom post type endpoints are singular.
|
|
116
|
+
const response = await apiFetch({
|
|
117
|
+
parse: false,
|
|
118
|
+
path: addQueryArgs('/wp/v2/' + endpoint, {
|
|
119
|
+
search,
|
|
120
|
+
offset,
|
|
121
|
+
per_page: suggestionsToFetch,
|
|
122
|
+
_fields: 'id,title'
|
|
123
|
+
})
|
|
124
|
+
});
|
|
125
|
+
const total = parseInt(response.headers.get('x-wp-total') || 0);
|
|
126
|
+
const posts = await response.json();
|
|
127
|
+
setMaxSuggestions(total);
|
|
128
|
+
|
|
129
|
+
// Format suggestions for FormTokenField display.
|
|
130
|
+
return posts.reduce((acc, post) => {
|
|
131
|
+
acc.push({
|
|
132
|
+
value: parseInt(post.id),
|
|
133
|
+
label: decodeEntities(post?.title.rendered) || __('(no title)', 'newspack-plugin')
|
|
134
|
+
});
|
|
135
|
+
return acc;
|
|
136
|
+
}, []);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get labels for token values.
|
|
141
|
+
*/
|
|
142
|
+
const getLabelsForValues = values => {
|
|
143
|
+
return values.reduce((accumulator, value) => {
|
|
144
|
+
if (!value) {
|
|
145
|
+
return accumulator;
|
|
146
|
+
}
|
|
147
|
+
if (value.label) {
|
|
148
|
+
return [...accumulator, value.label];
|
|
149
|
+
}
|
|
150
|
+
return validValues[value] ? [...accumulator, validValues[value]] : accumulator;
|
|
151
|
+
}, []);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get values for token labels.
|
|
156
|
+
*/
|
|
157
|
+
const getValuesForLabels = labels => {
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
159
|
+
return labels.reduce((acc, label) => {
|
|
160
|
+
Object.keys(validValues).forEach(key => {
|
|
161
|
+
if (validValues[key] === label) {
|
|
162
|
+
const value = isNaN(parseInt(key)) ? key.toString() : parseInt(key);
|
|
163
|
+
acc.push({
|
|
164
|
+
value,
|
|
165
|
+
label
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return acc;
|
|
170
|
+
}, []);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Handle FormTokenField onChange.
|
|
175
|
+
*/
|
|
176
|
+
const handleTokenChange = tokenStrings => {
|
|
177
|
+
const newSelections = getValuesForLabels(tokenStrings);
|
|
178
|
+
|
|
179
|
+
// If only allowing one selection, just return the one selected item.
|
|
180
|
+
if (!multiSelect) {
|
|
181
|
+
const newSelection = newSelections[newSelections.length - 1]; // Get the last selected item
|
|
182
|
+
if (newSelection) {
|
|
183
|
+
return onChange([{
|
|
184
|
+
...newSelection,
|
|
185
|
+
postType: postTypeToSearch
|
|
186
|
+
}]);
|
|
187
|
+
}
|
|
188
|
+
return onChange([]);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// For multi-select, include currently selected post type in selection results.
|
|
192
|
+
onChange(newSelections.map(selection => ({
|
|
193
|
+
...selection,
|
|
194
|
+
postType: postTypeToSearch
|
|
195
|
+
})));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get tokens for FormTokenField.
|
|
200
|
+
*/
|
|
201
|
+
const getTokens = () => {
|
|
202
|
+
return getLabelsForValues(selectedItems);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Render a single suggestion object that can be clicked to select it immediately.
|
|
207
|
+
*
|
|
208
|
+
* @param {Object} suggestion Suggestion object with value and label keys.
|
|
209
|
+
*/
|
|
210
|
+
const renderSuggestion = suggestion => {
|
|
211
|
+
if (multiSelect) {
|
|
212
|
+
const isSelected = !!selectedItems.find(_selection => parseInt(_selection.value) === parseInt(suggestion.value) && _selection.label === suggestion.label);
|
|
213
|
+
return /*#__PURE__*/_jsx(CheckboxControl, {
|
|
214
|
+
checked: isSelected,
|
|
215
|
+
onChange: () => {
|
|
216
|
+
// For multi-select, we need to toggle the selection
|
|
217
|
+
const currentTokens = getTokens();
|
|
218
|
+
const suggestionLabel = suggestion.label;
|
|
219
|
+
if (isSelected) {
|
|
220
|
+
// Remove the suggestion
|
|
221
|
+
const newTokens = currentTokens.filter(token => token !== suggestionLabel);
|
|
222
|
+
handleTokenChange(newTokens);
|
|
223
|
+
} else {
|
|
224
|
+
// Add the suggestion
|
|
225
|
+
handleTokenChange([...currentTokens, suggestionLabel]);
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
label: suggestion.label
|
|
229
|
+
}, suggestion.value);
|
|
230
|
+
}
|
|
231
|
+
return /*#__PURE__*/_jsx(Button, {
|
|
232
|
+
isLink: true,
|
|
233
|
+
onClick: () => handleTokenChange([...getTokens(), suggestion.label]),
|
|
234
|
+
children: suggestion.label
|
|
235
|
+
}, suggestion.value);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Render a list of suggestions that can be clicked to select instead of searching by title.
|
|
240
|
+
*/
|
|
241
|
+
const renderSuggestions = () => {
|
|
242
|
+
if (0 === suggestions.length) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
const className = multiSelect ? 'newspack-autocomplete-with-latest-posts__search-suggestions-multiselect' : 'newspack-autocomplete-with-latest-posts__search-suggestions';
|
|
246
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
247
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
248
|
+
className: "newspack-autocomplete-with-latest-posts__search-suggestions-container",
|
|
249
|
+
children: [/*#__PURE__*/_jsx("p", {
|
|
250
|
+
className: "newspack-autocomplete-with-suggestions__label",
|
|
251
|
+
children: __('Latest Posts', 'newspack-plugin')
|
|
252
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
253
|
+
className: className,
|
|
254
|
+
children: [suggestions.map(renderSuggestion), suggestions.length < (maxItemsToSuggest || maxSuggestions) && /*#__PURE__*/_jsx(Button, {
|
|
255
|
+
disabled: isLoadingMore,
|
|
256
|
+
isSecondary: true,
|
|
257
|
+
onClick: () => setIsLoadingMore(true),
|
|
258
|
+
children: isLoadingMore ? __('Loading…', 'newspack-plugin') : __('Load more', 'newspack-plugin')
|
|
259
|
+
})]
|
|
260
|
+
})]
|
|
261
|
+
})
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
265
|
+
className: classNames.join(' '),
|
|
266
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
267
|
+
className: "newspack-autocomplete-with-latest-posts__input-container",
|
|
268
|
+
children: [/*#__PURE__*/_jsx(FormTokenField, {
|
|
269
|
+
value: getTokens(),
|
|
270
|
+
suggestions: searchSuggestions.map(suggestion => suggestion.label),
|
|
271
|
+
onChange: handleTokenChange,
|
|
272
|
+
onInputChange: debouncedUpdateSuggestions,
|
|
273
|
+
label: label,
|
|
274
|
+
help: !hideHelp && help,
|
|
275
|
+
__next40pxDefaultSize: true,
|
|
276
|
+
__nextHasNoMarginBottom: true
|
|
277
|
+
}), (isLoading || isSearching) && /*#__PURE__*/_jsx(Spinner, {})]
|
|
278
|
+
}), renderSuggestions()]
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
export default AutocompleteWithLatestPosts;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styles for AutocompleteWithLatestPosts component.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
+
|
|
7
|
+
.newspack-autocomplete-with-latest-posts {
|
|
8
|
+
display: grid;
|
|
9
|
+
gap: 16px;
|
|
10
|
+
width: 100%;
|
|
11
|
+
|
|
12
|
+
.components-select-control__input {
|
|
13
|
+
max-width: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.components-input-control__backdrop {
|
|
17
|
+
border-color: wp-colors.$gray-700 !important;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.newspack-autocomplete-with-latest-posts__label,
|
|
21
|
+
.components-form-token-field__label,
|
|
22
|
+
.components-input-control__label,
|
|
23
|
+
.components-checkbox-control__label {
|
|
24
|
+
color: wp-colors.$gray-900 !important;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.newspack-autocomplete-tokenfield__help {
|
|
28
|
+
font-size: inherit;
|
|
29
|
+
margin-bottom: 8px !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.components-form-token-field {
|
|
33
|
+
&__input-container {
|
|
34
|
+
border-color: wp-colors.$gray-700;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&__suggestion {
|
|
38
|
+
padding: 8px;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Hide the built-in "Separate with commas or the Enter key." help text when hideFormTokenHelp is true
|
|
43
|
+
&.hide-form-token-help .components-form-token-field__help {
|
|
44
|
+
display: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
p.newspack-autocomplete-with-latest-posts__label {
|
|
48
|
+
font-size: inherit;
|
|
49
|
+
margin: 0 0 8px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&__selected-items {
|
|
53
|
+
border-bottom: 1px solid wp-colors.$gray-700;
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-wrap: wrap;
|
|
56
|
+
gap: 8px;
|
|
57
|
+
margin-bottom: 16px;
|
|
58
|
+
padding-bottom: 12px;
|
|
59
|
+
|
|
60
|
+
p.newspack-autocomplete-with-latest-posts__label {
|
|
61
|
+
flex: 0 0 100%;
|
|
62
|
+
margin: 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&__selected-item-button.components-button.is-tertiary {
|
|
67
|
+
background-color: wp-colors.$gray-300;
|
|
68
|
+
border-radius: 2px;
|
|
69
|
+
color: wp-colors.$gray-900;
|
|
70
|
+
font-size: 13px;
|
|
71
|
+
height: auto;
|
|
72
|
+
margin: 0;
|
|
73
|
+
padding-left: 8px;
|
|
74
|
+
padding-right: 8px;
|
|
75
|
+
|
|
76
|
+
&::after {
|
|
77
|
+
content: "✕";
|
|
78
|
+
margin-left: 8px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&:hover {
|
|
82
|
+
box-shadow: none;
|
|
83
|
+
color: black;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&__search-suggestions,
|
|
88
|
+
&__search-suggestions-multiselect {
|
|
89
|
+
max-height: 220px;
|
|
90
|
+
overflow: visible auto;
|
|
91
|
+
margin: 0 -4px;
|
|
92
|
+
padding: 4px 4px 0;
|
|
93
|
+
|
|
94
|
+
.components-button {
|
|
95
|
+
display: block;
|
|
96
|
+
line-height: normal;
|
|
97
|
+
margin: auto;
|
|
98
|
+
|
|
99
|
+
&.is-link {
|
|
100
|
+
color: wp-colors.$gray-900;
|
|
101
|
+
padding: 8px;
|
|
102
|
+
text-decoration: none;
|
|
103
|
+
width: 100%;
|
|
104
|
+
|
|
105
|
+
&:active:not(:disabled),
|
|
106
|
+
&:hover:not(:disabled) {
|
|
107
|
+
background: wp-colors.$gray-900;
|
|
108
|
+
background: var(--wp-admin-theme-color);
|
|
109
|
+
color: white;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
&.is-secondary {
|
|
113
|
+
margin-bottom: 8px;
|
|
114
|
+
margin-top: 8px;
|
|
115
|
+
width: 100%;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&__search-suggestions {
|
|
121
|
+
border-radius: 2px;
|
|
122
|
+
border: 1px solid wp-colors.$gray-700;
|
|
123
|
+
padding: 0;
|
|
124
|
+
|
|
125
|
+
.components-button {
|
|
126
|
+
line-height: normal;
|
|
127
|
+
|
|
128
|
+
&:focus:not(:disabled) {
|
|
129
|
+
border-radius: 0;
|
|
130
|
+
box-shadow: inset 0 0 0 1.5px wp-colors.$gray-900;
|
|
131
|
+
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.is-secondary {
|
|
135
|
+
width: calc(100% - 16px);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Temp: CSS work-around.
|
|
141
|
+
.newspack-autocomplete-with-suggestions__label {
|
|
142
|
+
font-size: 11px;
|
|
143
|
+
font-weight: 500;
|
|
144
|
+
line-height: 1.4;
|
|
145
|
+
text-transform: uppercase;
|
|
146
|
+
display: block;
|
|
147
|
+
margin: 0 0 8px;
|
|
148
|
+
padding: 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import './style.scss';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* External dependencies
|
|
8
|
+
*/
|
|
9
|
+
import classnames from 'classnames';
|
|
10
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
+
/**
|
|
12
|
+
* Badge component
|
|
13
|
+
*/
|
|
14
|
+
const Badge = ({
|
|
15
|
+
text,
|
|
16
|
+
level = 'default'
|
|
17
|
+
}) => {
|
|
18
|
+
const classes = classnames('newspack-badge', `is-${level}`);
|
|
19
|
+
return /*#__PURE__*/_jsx("span", {
|
|
20
|
+
className: classes,
|
|
21
|
+
children: text
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
export default Badge;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badge
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
@use "~@wordpress/base-styles/colors" as wp-colors;
|
|
6
|
+
@use "../../../colors/colors.module" as colors;
|
|
7
|
+
|
|
8
|
+
$badge-colors: (
|
|
9
|
+
"info": colors.$primary-600,
|
|
10
|
+
"warning": wp-colors.$alert-yellow,
|
|
11
|
+
"error": wp-colors.$alert-red,
|
|
12
|
+
"success": wp-colors.$alert-green,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
.newspack-badge {
|
|
16
|
+
background-color: color-mix(in srgb, wp-colors.$white 90%, var(--base-color));
|
|
17
|
+
border-radius: 2px;
|
|
18
|
+
color: color-mix(in srgb, wp-colors.$black 50%, var(--base-color));
|
|
19
|
+
display: block;
|
|
20
|
+
flex: 0 0 auto;
|
|
21
|
+
font-size: 12px;
|
|
22
|
+
line-height: 1.5;
|
|
23
|
+
padding: 1px 4px;
|
|
24
|
+
|
|
25
|
+
&:where(.is-default) {
|
|
26
|
+
background-color: wp-colors.$gray-100;
|
|
27
|
+
color: wp-colors.$gray-800;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Generate color variants
|
|
31
|
+
@each $type, $color in $badge-colors {
|
|
32
|
+
&.is-#{$type} {
|
|
33
|
+
--base-color: #{$color};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
package/dist/esm/button/index.js
CHANGED
|
@@ -19,6 +19,7 @@ const {
|
|
|
19
19
|
} = Router;
|
|
20
20
|
const Button = ({
|
|
21
21
|
href,
|
|
22
|
+
loading = undefined,
|
|
22
23
|
onClick,
|
|
23
24
|
...otherProps
|
|
24
25
|
}) => {
|
|
@@ -42,6 +43,7 @@ const Button = ({
|
|
|
42
43
|
}
|
|
43
44
|
// @ts-expect-error - @wordpress/components' Button can only have either href or onClick, not both.
|
|
44
45
|
return /*#__PURE__*/_jsx(BaseComponent, {
|
|
46
|
+
loading: loading ? true : undefined,
|
|
45
47
|
...otherProps
|
|
46
48
|
});
|
|
47
49
|
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card using WP Core's Card component.
|
|
3
|
+
* https://wordpress.github.io/gutenberg/?path=/docs/components-card--docs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { __ } from '@wordpress/i18n';
|
|
10
|
+
import { Button, Card as CardWrapper, CardHeader, CardFooter, DropdownMenu, MenuItem, ToggleControl } from '@wordpress/components';
|
|
11
|
+
import { Icon, chevronDown, chevronRight, chevronUp, dragHandle, moreVertical } from '@wordpress/icons';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Internal dependencies
|
|
15
|
+
*/
|
|
16
|
+
import './style-core.scss';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* External dependencies
|
|
20
|
+
*/
|
|
21
|
+
import classNames from 'classnames';
|
|
22
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
|
+
const CoreCard = ({
|
|
24
|
+
actions,
|
|
25
|
+
actionType,
|
|
26
|
+
as,
|
|
27
|
+
buttonsCard,
|
|
28
|
+
className,
|
|
29
|
+
footer,
|
|
30
|
+
header,
|
|
31
|
+
icon,
|
|
32
|
+
iconBackgroundColor,
|
|
33
|
+
isActive,
|
|
34
|
+
isDraggable,
|
|
35
|
+
isFirstTarget,
|
|
36
|
+
isLastTarget,
|
|
37
|
+
isNarrow,
|
|
38
|
+
isSmall,
|
|
39
|
+
dragIndex,
|
|
40
|
+
onDragCallback = () => {},
|
|
41
|
+
onHeaderClick,
|
|
42
|
+
noBorder,
|
|
43
|
+
noMargin,
|
|
44
|
+
children = null,
|
|
45
|
+
...otherProps
|
|
46
|
+
}) => {
|
|
47
|
+
const classes = classNames('newspack-card--core', className, (buttonsCard || as === 'a') && 'newspack-card--core__buttons-card', isDraggable && 'newspack-card--core__is-draggable', isNarrow && 'newspack-card--core__is-narrow', isSmall && 'newspack-card--core__is-small', icon && 'newspack-card--core__has-icon', iconBackgroundColor && 'newspack-card--core__has-icon-background-color', isActive && 'newspack-card--core__is-active', children && 'newspack-card--core__has-children', noMargin && 'newspack-card--core__no-margin');
|
|
48
|
+
let sizeProps = isSmall ? 'small' : otherProps.size;
|
|
49
|
+
if (buttonsCard || as === 'a') {
|
|
50
|
+
if (!isSmall) {
|
|
51
|
+
sizeProps = 'large';
|
|
52
|
+
}
|
|
53
|
+
if (as !== 'a') {
|
|
54
|
+
otherProps.as = 'a'; // Render as an anchor tag.
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (noBorder) {
|
|
58
|
+
otherProps.isBorderless = true;
|
|
59
|
+
}
|
|
60
|
+
return /*#__PURE__*/_jsxs(CardWrapper, {
|
|
61
|
+
as: as,
|
|
62
|
+
className: classes,
|
|
63
|
+
...otherProps,
|
|
64
|
+
children: [(header || icon) && /*#__PURE__*/_jsxs(CardHeader, {
|
|
65
|
+
as: onHeaderClick ? 'button' : undefined,
|
|
66
|
+
className: classNames('newspack-card--core__header', isDraggable && 'newspack-card--core__header--is-draggable'),
|
|
67
|
+
size: sizeProps,
|
|
68
|
+
onClick: onHeaderClick,
|
|
69
|
+
children: [isDraggable && /*#__PURE__*/_jsxs("div", {
|
|
70
|
+
className: "newspack-card--core__header__draggable-controls",
|
|
71
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
72
|
+
className: "newspack-card--core__header__draggable-controls__drag-handle",
|
|
73
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
|
74
|
+
icon: dragHandle
|
|
75
|
+
})
|
|
76
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
77
|
+
className: "newspack-card--core__header__draggable-controls__move-buttons",
|
|
78
|
+
children: [/*#__PURE__*/_jsx(Button, {
|
|
79
|
+
icon: chevronUp,
|
|
80
|
+
onClick: () => onDragCallback(dragIndex, dragIndex - 1),
|
|
81
|
+
disabled: isFirstTarget,
|
|
82
|
+
label: __('Move one position up', 'newspack-plugin'),
|
|
83
|
+
size: "small"
|
|
84
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
85
|
+
icon: chevronDown,
|
|
86
|
+
onClick: () => onDragCallback(dragIndex, dragIndex + 1),
|
|
87
|
+
disabled: isLastTarget,
|
|
88
|
+
label: __('Move one position down', 'newspack-plugin'),
|
|
89
|
+
size: "small"
|
|
90
|
+
})]
|
|
91
|
+
})]
|
|
92
|
+
}), icon && /*#__PURE__*/_jsx("div", {
|
|
93
|
+
className: "newspack-card--core__icon",
|
|
94
|
+
children: /*#__PURE__*/_jsx(Icon, {
|
|
95
|
+
icon: icon,
|
|
96
|
+
height: isSmall ? 24 : 48,
|
|
97
|
+
width: isSmall ? 24 : 48
|
|
98
|
+
})
|
|
99
|
+
}), header && /*#__PURE__*/_jsx("div", {
|
|
100
|
+
className: "newspack-card--core__header-content",
|
|
101
|
+
children: header
|
|
102
|
+
}), !actions?.length > 0 && actionType === 'chevron' && /*#__PURE__*/_jsx(Icon, {
|
|
103
|
+
className: "newspack-card--core__action",
|
|
104
|
+
icon: chevronRight,
|
|
105
|
+
height: 24,
|
|
106
|
+
width: 24
|
|
107
|
+
}), !actions?.length > 0 && actionType === 'toggle' && /*#__PURE__*/_jsx(ToggleControl, {
|
|
108
|
+
className: "newspack-card--core__action",
|
|
109
|
+
label: otherProps.title,
|
|
110
|
+
hideLabelFromVision: true,
|
|
111
|
+
checked: isActive,
|
|
112
|
+
onChange: () => {}
|
|
113
|
+
}), actions?.length > 0 && /*#__PURE__*/_jsx(DropdownMenu, {
|
|
114
|
+
icon: moreVertical,
|
|
115
|
+
label: __('More', 'newspack-plugin'),
|
|
116
|
+
children: () => actions.map((action, index) => /*#__PURE__*/_jsx(MenuItem, {
|
|
117
|
+
icon: action.icon,
|
|
118
|
+
onClick: action.action,
|
|
119
|
+
disabled: action.disabled || false,
|
|
120
|
+
isDestructive: action.destructive || false,
|
|
121
|
+
children: action.label
|
|
122
|
+
}, index))
|
|
123
|
+
})]
|
|
124
|
+
}), children && /*#__PURE__*/_jsx("div", {
|
|
125
|
+
className: "newspack-card--core__body",
|
|
126
|
+
children: children
|
|
127
|
+
}), footer && /*#__PURE__*/_jsx(CardFooter, {
|
|
128
|
+
size: sizeProps,
|
|
129
|
+
children: footer
|
|
130
|
+
})]
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
export default CoreCard;
|
package/dist/esm/card/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { Component } from '@wordpress/element';
|
|
|
10
10
|
/**
|
|
11
11
|
* Internal dependencies
|
|
12
12
|
*/
|
|
13
|
+
import CoreCard from './core-card';
|
|
13
14
|
import './style.scss';
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -31,8 +32,40 @@ class Card extends Component {
|
|
|
31
32
|
isSmall,
|
|
32
33
|
isWhite,
|
|
33
34
|
noBorder,
|
|
35
|
+
// Pass as `true` to render using WP Core's Card component: https://wordpress.github.io/gutenberg/?path=/docs/components-card--docs
|
|
36
|
+
__experimentalCoreCard,
|
|
37
|
+
// Pass props supported by WP Core's Card component in this single prop.
|
|
38
|
+
__experimentalCoreProps = {
|
|
39
|
+
actionType: null,
|
|
40
|
+
// chevron | toggle | button | link | none
|
|
41
|
+
header: null,
|
|
42
|
+
// Pass a React component to render in a CardHeader component.
|
|
43
|
+
icon: null,
|
|
44
|
+
footer: null,
|
|
45
|
+
// Pass a React component to render in a CardFooter component.
|
|
46
|
+
noMargin: false,
|
|
47
|
+
isDraggable: false,
|
|
48
|
+
dragIndex: null,
|
|
49
|
+
onDragCallback: () => {}
|
|
50
|
+
},
|
|
34
51
|
...otherProps
|
|
35
52
|
} = this.props;
|
|
53
|
+
if (__experimentalCoreCard) {
|
|
54
|
+
const props = {
|
|
55
|
+
buttonsCard,
|
|
56
|
+
className,
|
|
57
|
+
isMedium,
|
|
58
|
+
isNarrow,
|
|
59
|
+
isSmall,
|
|
60
|
+
isWhite,
|
|
61
|
+
noBorder,
|
|
62
|
+
...otherProps,
|
|
63
|
+
...__experimentalCoreProps
|
|
64
|
+
};
|
|
65
|
+
return /*#__PURE__*/_jsx(CoreCard, {
|
|
66
|
+
...props
|
|
67
|
+
});
|
|
68
|
+
}
|
|
36
69
|
const classes = classNames('newspack-card', className, buttonsCard && 'newspack-card__buttons-card', headerActions && 'newspack-card__header-actions', isMedium && 'newspack-card__is-medium', isNarrow && 'newspack-card__is-narrow', isSmall && 'newspack-card__is-small', isWhite && 'newspack-card__is-white', noBorder && 'newspack-card__no-border');
|
|
37
70
|
return /*#__PURE__*/_jsx("div", {
|
|
38
71
|
className: classes,
|