Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions blablablocks-formats.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ function blablablocks_formats_enqueue_assets()
wp_enqueue_style('blablablocks-formats-styles');
}

$needs_marker = blablablocks_has_format('has-marker-format');
$needs_infotip = blablablocks_has_format('has-infotip-format');
$needs_fontsize = blablablocks_has_format('has-font-size-format');
$needs_marker = blablablocks_has_format('has-marker-format');
$needs_infotip = blablablocks_has_format('has-infotip-format');
$needs_changecase = blablablocks_has_format('has-change-case-format');
$needs_fontsize = blablablocks_has_format('has-font-size-format');

// If no format is present, do nothing.
if (! $needs_marker && ! $needs_infotip && ! $needs_fontsize) {
if (! $needs_marker && ! $needs_infotip && ! $needs_fontsize && ! $needs_changecase) {
return;
}

Expand Down
8 changes: 8 additions & 0 deletions src/change-case/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/
.block-editor-format-toolbar__lubus-changecase-popover > div {
padding: 12px;
}
186 changes: 186 additions & 0 deletions src/change-case/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import {
reset,
formatCapitalize,
formatLowercase,
formatUppercase,
} from '@wordpress/icons';
import {
Popover,
__experimentalToggleGroupControl as ToggleGroupControl,
__experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon,
} from '@wordpress/components';
import {
useAnchor,
applyFormat,
removeFormat,
registerFormatType,
} from '@wordpress/rich-text';
import { RichTextToolbarButton } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import './editor.scss';
import './style.scss';

const name = 'lubus/change-case';
const title = 'Change Case';

/**
* Main icon for toolbar button
*/
const ChangeCaseIcon = () => (
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="none" d="M0 0h24v24H0V0z" />
<path d="M9 4v3h5v12h3V7h5V4H9zm-6 8h3v7h3v-7h3V9H3v3z" fill="currentColor" />
</svg>
);

/**
* Text transform options matching WordPress core
*/
const TEXT_TRANSFORMS = [
{
label: __( 'None' ),
value: 'none',
icon: reset,
},
{
label: __( 'Uppercase' ),
value: 'uppercase',
icon: formatUppercase,
},
{
label: __( 'Lowercase' ),
value: 'lowercase',
icon: formatLowercase,
},
{
label: __( 'Capitalize' ),
value: 'capitalize',
icon: formatCapitalize,
},
];

/**
* Format edit
*/
function EditButton( props ) {
const { value, onChange, onFocus, isActive, contentRef, activeAttributes } = props;

const [ isPopoverOpen, setIsPopoverOpen ] = useState( false );

const anchor = useAnchor( {
editableContentElement: contentRef.current,
settings: { isActive },
} );

// Get the currently active case type from the class attribute
const activeClass = activeAttributes?.class || '';
let activeCaseType = activeClass.replace( 'has-', '' ).replace( '-case', '' );

// Map our class names to WordPress core values
if ( activeCaseType === 'titlecase' ) {
activeCaseType = 'capitalize';
}
if ( !activeCaseType ) {
activeCaseType = 'none';
}

// Check if selection contains multiple words (for capitalize validation)
const selectedText = value.text.slice( value.start, value.end );
const hasMultipleWords = selectedText.trim().split( /\s+/ ).length > 1;

// Filter options based on selection
const availableOptions = TEXT_TRANSFORMS.filter( ( option ) => {
// Show capitalize only for multi-word selections
if ( option.value === 'capitalize' && ! hasMultipleWords ) {
return false;
}
return true;
} );

function handleChange( newValue ) {
// Remove any existing case format first
let newFormattedValue = removeFormat( value, name );

// If newValue is not 'none', apply the format
if ( newValue && newValue !== 'none' ) {
// Map WordPress core values to our class names
let caseType = newValue;
if ( newValue === 'capitalize' ) {
caseType = 'titlecase';
}

const className = `has-${ caseType }-case`;
newFormattedValue = applyFormat( newFormattedValue, {
type: name,
attributes: {
class: className,
},
} );
}

onChange( newFormattedValue );
onFocus();
setIsPopoverOpen( false );
}

return (
<>
<RichTextToolbarButton
icon={ ChangeCaseIcon }
title={ title }
onClick={ () => setIsPopoverOpen( true ) }
isActive={ isActive }
/>
{ isPopoverOpen && (
<Popover
anchor={ anchor }
onClose={ () => setIsPopoverOpen( false ) }
placement="bottom"
shift
offset={ 10 }
>
<div style={ { padding: '8px' } }>
<ToggleGroupControl
__next40pxDefaultSize
__nextHasNoMarginBottom
isBlock
label={ __( 'Letter case' ) }
value={ activeCaseType }
onChange={ handleChange }
>
{ availableOptions.map( ( option ) => (
<ToggleGroupControlOptionIcon
key={ option.value }
value={ option.value }
icon={ option.icon }
label={ option.label }
/>
) ) }
</ToggleGroupControl>
</div>
</Popover>
) }
</>
);
}

/**
* Register Change Case Format.
*/
registerFormatType( name, {
title,
tagName: 'span',
className: 'has-change-case-format',
edit: EditButton,
attributes: {
class: 'class',
},
} );
16 changes: 16 additions & 0 deletions src/change-case/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*/

.has-uppercase-case {
text-transform: uppercase;
}

.has-lowercase-case {
text-transform: lowercase;
}

.has-titlecase-case {
text-transform: capitalize;
}
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
*/
import './marker';
import './infotip';
import './change-case';
import './font-size';
import './clear-formats';