Skip to content

Commit 2cee4d6

Browse files
authored
Merge branch 'dev' into format/link-data-attributes
2 parents ea1d209 + 932c17d commit 2cee4d6

File tree

13 files changed

+498
-4
lines changed

13 files changed

+498
-4
lines changed

_playground/blueprint-local.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{
22
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
33
"landingPage": "/wp-admin/post.php?post=4&action=edit",
4+
"preferredVersions": {
5+
"php": "8.2",
6+
"wp": "6.7"
7+
},
48
"login": true,
59
"features": {
610
"networking": true

blablablocks-formats.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,12 @@ function blablablocks_formats_enqueue_assets()
138138
wp_enqueue_style('blablablocks-formats-styles');
139139
}
140140

141-
$needs_marker = blablablocks_has_format('has-marker-format');
142-
$needs_infotip = blablablocks_has_format('has-infotip-format');
141+
$needs_marker = blablablocks_has_format('has-marker-format');
142+
$needs_infotip = blablablocks_has_format('has-infotip-format');
143+
$needs_fontsize = blablablocks_has_format('has-font-size-format');
143144

144-
// If neither format is present, do nothing.
145-
if (! $needs_marker && ! $needs_infotip) {
145+
// If no format is present, do nothing.
146+
if (! $needs_marker && ! $needs_infotip && ! $needs_fontsize) {
146147
return;
147148
}
148149

@@ -156,5 +157,8 @@ function blablablocks_formats_enqueue_assets()
156157
if ($needs_infotip) {
157158
wp_enqueue_script('blablablocks-infotip-format-asset');
158159
}
160+
161+
// Font-size format doesn't need additional scripts on frontend
162+
// The inline styles handle the rendering
159163
}
160164
add_action('enqueue_block_assets', 'blablablocks_formats_enqueue_assets');

src/clear-formats/edit.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __, sprintf } from '@wordpress/i18n';
5+
import { useState } from '@wordpress/element';
6+
import { RichTextToolbarButton } from '@wordpress/block-editor';
7+
import {
8+
Modal,
9+
Button,
10+
__experimentalText as Text,
11+
__experimentalHStack as HStack,
12+
} from '@wordpress/components';
13+
14+
/**
15+
* Internal dependencies
16+
*/
17+
import { clearFormatsIcon } from './icon';
18+
import { useClearFormats } from './hooks';
19+
20+
/**
21+
* Edit component for clearing all formats.
22+
*
23+
* @param {Object} props - The component properties.
24+
* @param {Object} props.value - The current value of the rich text.
25+
* @param {Function} props.onChange - Function to update the rich text value.
26+
* @return {JSX.Element} - The rendered clear formats button.
27+
*/
28+
export function Edit( { value, onChange } ) {
29+
const [ isModalOpen, setIsModalOpen ] = useState( false );
30+
const { hasSelection, clearFormats } = useClearFormats( {
31+
value,
32+
onChange,
33+
} );
34+
35+
const handleClearFormats = () => {
36+
clearFormats();
37+
setIsModalOpen( false );
38+
};
39+
40+
// Dynamic confirmation message based on selection
41+
const selectionType = hasSelection
42+
? __( 'text', 'blablablocks-formats' )
43+
: __( 'block', 'blablablocks-formats' );
44+
45+
const confirmationMessage = sprintf(
46+
/* translators: %s: selection type (text/block) */
47+
__(
48+
'Are you sure you want to remove all formatting (bold, italic, links, etc.) from the selected %s?',
49+
'blablablocks-formats'
50+
),
51+
selectionType
52+
);
53+
54+
return (
55+
<>
56+
<RichTextToolbarButton
57+
icon={ clearFormatsIcon }
58+
title={ __( 'Clear formatting', 'blablablocks-formats' ) }
59+
onClick={ () => setIsModalOpen( true ) }
60+
/>
61+
62+
{ isModalOpen && (
63+
<Modal
64+
title={ __( 'Clear All Formats', 'blablablocks-formats' ) }
65+
onRequestClose={ () => setIsModalOpen( false ) }
66+
size="small"
67+
>
68+
<Text as="p" highlightWords={ [ 'text', 'block' ] }>
69+
{ confirmationMessage }
70+
</Text>
71+
<HStack
72+
spacing={ 2 }
73+
justify="flex-end"
74+
style={ { marginTop: '24px' } }
75+
>
76+
<Button
77+
variant="tertiary"
78+
onClick={ () => setIsModalOpen( false ) }
79+
>
80+
{ __( 'Cancel', 'blablablocks-formats' ) }
81+
</Button>
82+
<Button
83+
variant="primary"
84+
onClick={ handleClearFormats }
85+
isDestructive
86+
>
87+
{ __( 'Clear', 'blablablocks-formats' ) }
88+
</Button>
89+
</HStack>
90+
</Modal>
91+
) }
92+
</>
93+
);
94+
}

src/clear-formats/hooks.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { useCallback, useMemo } from '@wordpress/element';
5+
import { removeFormat, create, getActiveFormats } from '@wordpress/rich-text';
6+
7+
/**
8+
* Provides helpers for clearing formats from a rich text value.
9+
*
10+
* @param {Object} options - Hook options.
11+
* @param {Object} options.value - Current rich text value.
12+
* @param {Function} options.onChange - Callback to update the value.
13+
* @return {{hasSelection: boolean, clearFormats: Function}} Hook results.
14+
*/
15+
export const useClearFormats = ( { value, onChange } ) => {
16+
const hasSelection = useMemo(
17+
() => value.start !== value.end,
18+
[ value.start, value.end ]
19+
);
20+
21+
const clearFormats = useCallback( () => {
22+
let newValue = value;
23+
24+
if ( hasSelection ) {
25+
const formats = getActiveFormats( value );
26+
27+
formats.forEach( ( format ) => {
28+
newValue = removeFormat(
29+
newValue,
30+
format.type,
31+
value.start,
32+
value.end
33+
);
34+
} );
35+
36+
if ( value.formats ) {
37+
const formatTypes = new Set();
38+
39+
for ( let index = value.start; index < value.end; index++ ) {
40+
if ( value.formats[ index ] ) {
41+
value.formats[ index ].forEach( ( format ) => {
42+
formatTypes.add( format.type );
43+
} );
44+
}
45+
}
46+
47+
formatTypes.forEach( ( formatType ) => {
48+
newValue = removeFormat(
49+
newValue,
50+
formatType,
51+
value.start,
52+
value.end
53+
);
54+
} );
55+
}
56+
57+
onChange( newValue );
58+
return;
59+
}
60+
61+
newValue = create( { text: value.text } );
62+
onChange( newValue );
63+
}, [ hasSelection, onChange, value ] );
64+
65+
return { hasSelection, clearFormats };
66+
};

src/clear-formats/icon.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export const clearFormatsIcon = (
2+
<svg
3+
width="24"
4+
height="24"
5+
viewBox="0 0 24 24"
6+
fill="none"
7+
xmlns="http://www.w3.org/2000/svg"
8+
>
9+
<path
10+
stroke="currentColor"
11+
strokeLinecap="round"
12+
strokeLinejoin="round"
13+
strokeWidth="2"
14+
d="M7 6.2V5h12v1.2M7 19h6m.2-14-1.677 6.523M9.6 19l1.029-4M5 5l6.523 6.523M19 19l-7.477-7.477"
15+
/>
16+
</svg>
17+
);

src/clear-formats/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import { registerFormatType } from '@wordpress/rich-text';
6+
7+
/**
8+
* Internal dependencies
9+
*/
10+
import { Edit } from './edit';
11+
12+
/**
13+
* Registers the Clear All Formats button.
14+
* This is not a traditional format but a toolbar button to clear formats.
15+
*/
16+
registerFormatType( 'blablablocks/clear-formats', {
17+
title: __( 'Clear formatting', 'blablablocks-formats' ),
18+
tagName: 'mark', // Using 'mark' to avoid conflict with core formats that use 'span'
19+
className: null,
20+
edit: Edit,
21+
} );

src/font-size/edit.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import { useState } from '@wordpress/element';
6+
import { RichTextToolbarButton } from '@wordpress/block-editor';
7+
import { textHorizontal } from '@wordpress/icons';
8+
9+
/**
10+
* Internal dependencies
11+
*/
12+
import InlineUI from './inline-ui';
13+
14+
/**
15+
* Edit component for the FontSize format in the block editor.
16+
*
17+
* @param {Object} props - The component properties.
18+
* @param {Object} props.value - The current value of the rich text.
19+
* @param {Function} props.onChange - Function to update the rich text value.
20+
* @param {boolean} props.isActive - Indicates if the format is currently active.
21+
* @param {Object} props.contentRef - Reference to the editable content element.
22+
* @param {Object} props.activeAttributes - The currently active attributes.
23+
* @return {JSX.Element} - The rendered FontSize format.
24+
*/
25+
export function Edit({
26+
value,
27+
onChange,
28+
isActive,
29+
contentRef,
30+
activeAttributes,
31+
}) {
32+
const [isSettingOpen, setIsSettingOpen] = useState(false);
33+
34+
return (
35+
<>
36+
<RichTextToolbarButton
37+
icon={textHorizontal}
38+
title={__('Font Size', 'blablablocks-formats')}
39+
onClick={() => setIsSettingOpen(true)}
40+
isActive={isActive}
41+
/>
42+
43+
{isSettingOpen && (
44+
<InlineUI
45+
value={value}
46+
onChange={onChange}
47+
onClose={() => setIsSettingOpen(false)}
48+
activeAttributes={activeAttributes}
49+
contentRef={contentRef.current}
50+
isActive={isActive}
51+
/>
52+
)}
53+
</>
54+
);
55+
}

src/font-size/editor.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Editor styles for the font-size format.
3+
*/
4+
5+
.block-editor-format-toolbar__blablablocks-font-size-popover {
6+
.components-popover__content {
7+
min-width: 20.625rem;
8+
padding: 16px;
9+
}
10+
11+
.reset-button {
12+
margin-top: 1rem;
13+
display: block;
14+
margin-left: auto;
15+
}
16+
}

0 commit comments

Comments
 (0)