Skip to content

Commit e790b98

Browse files
aaronrobertshawjasmussenramonjdannezazut-hamano
authored
Editor: allow selecting which block styles to apply globally (#79839)
Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org> Co-authored-by: jasmussen <joen@git.wordpress.org> Co-authored-by: ramonjd <ramonopoly@git.wordpress.org> Co-authored-by: annezazu <annezazu@git.wordpress.org> Co-authored-by: t-hamano <wildworks@git.wordpress.org> Co-authored-by: fcoveram <fcoveram@git.wordpress.org>
1 parent 38093c0 commit e790b98

11 files changed

Lines changed: 1775 additions & 178 deletions

File tree

packages/editor/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### New Features
6+
7+
- The "Apply globally" control now opens a review modal so you can choose which of a block's modified styles are pushed to Global Styles, showing each style's current and new value ([#79839](https://github.com/WordPress/gutenberg/pull/79839)).
8+
59
## 14.51.0 (2026-07-14)
610

711
### New Features
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { Modal } from '@wordpress/components';
5+
import { DataViewsPicker } from '@wordpress/dataviews';
6+
import { __, sprintf } from '@wordpress/i18n';
7+
import { getBlockType } from '@wordpress/blocks';
8+
import { useMemo, useState } from '@wordpress/element';
9+
10+
/**
11+
* Internal dependencies
12+
*/
13+
import { useGlobalStyles } from '../../components/global-styles/hooks';
14+
import { useReviewRows } from './use-review-rows';
15+
16+
// Show a simple table with a checkbox at the start of each row.
17+
const DEFAULT_LAYOUTS = { pickerTable: {} };
18+
19+
const getItemId = ( row ) => row.id;
20+
21+
/**
22+
* Modal for reviewing a block's changed styles and choosing which ones to apply
23+
* to every block of the same type.
24+
*
25+
* Each style is a row in the table and starts out selected. Apply pushes only
26+
* the rows that are still selected, and is turned off when none are. Closing
27+
* the modal or pressing Escape leaves the block untouched.
28+
*
29+
* @param {Object} props Component props.
30+
* @param {string} props.name Block name.
31+
* @param {Array} props.rows The block's changed styles, grouped into rows.
32+
* @param {Function} props.onApply Called with the selected rows to apply.
33+
* @param {Function} props.onRequestClose Called to close the modal.
34+
*/
35+
export default function ApplyGloballyModal( {
36+
name,
37+
rows,
38+
onApply,
39+
onRequestClose,
40+
} ) {
41+
const { merged } = useGlobalStyles();
42+
const reviewRows = useReviewRows( rows, merged, name );
43+
44+
const [ selection, setSelection ] = useState( () =>
45+
reviewRows.map( ( row ) => row.id )
46+
);
47+
const [ view, setView ] = useState( () => ( {
48+
type: 'pickerTable',
49+
titleField: 'label',
50+
fields: [ 'current', 'new' ],
51+
page: 1,
52+
perPage: reviewRows.length,
53+
layout: { enableMoving: false },
54+
} ) );
55+
56+
const fields = useMemo(
57+
() => [
58+
{
59+
id: 'label',
60+
label: __( 'Style' ),
61+
enableSorting: false,
62+
enableHiding: false,
63+
filterBy: false,
64+
getValue: ( { item } ) => item.label,
65+
render: ( { item } ) => item.label,
66+
},
67+
{
68+
id: 'current',
69+
label: __( 'Current' ),
70+
enableSorting: false,
71+
enableHiding: false,
72+
filterBy: false,
73+
getValue: ( { item } ) => item.formattedCurrentValue,
74+
render: ( { item } ) => (
75+
<span className="editor-push-changes-to-global-styles-modal__value">
76+
{ item.formattedCurrentValue }
77+
</span>
78+
),
79+
},
80+
{
81+
id: 'new',
82+
label: __( 'New' ),
83+
enableSorting: false,
84+
enableHiding: false,
85+
filterBy: false,
86+
getValue: ( { item } ) => item.formattedNewValue,
87+
render: ( { item } ) => (
88+
<span className="editor-push-changes-to-global-styles-modal__value">
89+
{ item.formattedNewValue }
90+
</span>
91+
),
92+
},
93+
],
94+
[]
95+
);
96+
97+
const actions = useMemo(
98+
() => [
99+
{
100+
id: 'apply',
101+
label: __( 'Apply' ),
102+
isPrimary: true,
103+
supportsBulk: true,
104+
callback( items ) {
105+
onApply( items );
106+
onRequestClose();
107+
},
108+
},
109+
],
110+
[ onApply, onRequestClose ]
111+
);
112+
113+
const blockTitle = getBlockType( name )?.title;
114+
115+
return (
116+
<Modal
117+
title={ sprintf(
118+
// translators: %s: Title of the block e.g. 'Heading'.
119+
__( 'Apply %s styles globally' ),
120+
blockTitle
121+
) }
122+
onRequestClose={ onRequestClose }
123+
size="large"
124+
className="editor-push-changes-to-global-styles-modal"
125+
>
126+
<p>
127+
{ sprintf(
128+
// translators: %s: Title of the block e.g. 'Heading'.
129+
__(
130+
'Choose which styles to make default for all %s blocks.'
131+
),
132+
blockTitle
133+
) }
134+
</p>
135+
<DataViewsPicker
136+
data={ reviewRows }
137+
fields={ fields }
138+
view={ view }
139+
onChangeView={ setView }
140+
actions={ actions }
141+
selection={ selection }
142+
onChangeSelection={ setSelection }
143+
getItemId={ getItemId }
144+
paginationInfo={ {
145+
totalItems: reviewRows.length,
146+
totalPages: 1,
147+
} }
148+
defaultLayouts={ DEFAULT_LAYOUTS }
149+
search={ false }
150+
itemListLabel={ __( 'Styles to apply' ) }
151+
>
152+
<DataViewsPicker.Layout />
153+
<DataViewsPicker.Footer />
154+
</DataViewsPicker>
155+
</Modal>
156+
);
157+
}

0 commit comments

Comments
 (0)