Add transforms to and from core Image block

This commit is contained in:
Keith Solomon
2026-08-05 16:56:27 -05:00
parent d21d3c9ac2
commit 151b09ba90
3 changed files with 152 additions and 0 deletions
+2
View File
@@ -15,11 +15,13 @@ import edit from './edit';
import save from './save';
import { PRESETS, DEFAULT_PRESET, isValidPresetSlug } from './presets';
import { FilterPanel } from './inspector';
import { transforms } from './transforms';
registerBlockType( metadata.name, {
...metadata,
edit,
save,
transforms,
} );
/**
+84
View File
@@ -0,0 +1,84 @@
/**
* Block transforms for the Filtered Image block.
*
* - "To" core Image: copies image attributes, drops filter and intensity.
* - "From" core Image: copies image attributes, sets filter="normal",
* intensity=100.
*
* @package ImageFilters
*/
import { DEFAULT_PRESET } from './presets';
const IMAGE_ATTR_MAP = {
id: 'imageId',
url: 'imageUrl',
alt: 'imageAlt',
caption: 'caption',
width: 'width',
height: 'height',
href: 'linkUrl',
};
/**
* Maps a core/image-shaped attribute object to a Filtered Image
* attribute object.
*
* @param {Object} source
* @return {Object}
*/
function fromImageAttrs( source ) {
const out = {
filter: DEFAULT_PRESET,
intensity: 100,
imageId: 0,
imageUrl: '',
imageAlt: '',
width: undefined,
height: undefined,
linkUrl: '',
caption: '',
};
for ( const [ coreKey, ourKey ] of Object.entries( IMAGE_ATTR_MAP ) ) {
if ( source[ coreKey ] !== undefined ) {
out[ ourKey ] = source[ coreKey ];
}
}
return out;
}
/**
* Maps a Filtered Image attribute object back to a core/image-shaped
* attribute object.
*
* @param {Object} source
* @return {Object}
*/
function toImageAttrs( source ) {
const out = {};
for ( const [ coreKey, ourKey ] of Object.entries( IMAGE_ATTR_MAP ) ) {
if ( source[ ourKey ] !== undefined ) {
out[ coreKey ] = source[ ourKey ];
}
}
return out;
}
export const transforms = {
to: [
{
type: 'block',
blocks: [ 'core/image' ],
transform: ( attributes ) => toImageAttrs( attributes ),
},
],
from: [
{
type: 'block',
blocks: [ 'core/image' ],
transform: ( attributes ) => fromImageAttrs( attributes ),
},
],
};
export default transforms;
+66
View File
@@ -0,0 +1,66 @@
import { transforms } from '../../src/transforms';
describe( 'transforms', () => {
test( 'exposes a "to" transform targeting core/image', () => {
const to = transforms.to;
expect( Array.isArray( to ) ? to : [ to ] ).toEqual(
expect.arrayContaining( [
expect.objectContaining( {
type: 'block',
blocks: expect.arrayContaining( [ 'core/image' ] ),
} ),
] )
);
} );
test( 'exposes a "from" transform sourced from core/image', () => {
const from = transforms.from;
expect( Array.isArray( from ) ? from : [ from ] ).toEqual(
expect.arrayContaining( [
expect.objectContaining( {
type: 'block',
blocks: expect.arrayContaining( [ 'core/image' ] ),
} ),
] )
);
} );
test( 'to-transform drops filter and intensity', () => {
const to = Array.isArray( transforms.to ) ? transforms.to[ 0 ] : transforms.to;
const mapped = to.transform( {
filter: 'dramatic',
intensity: 80,
imageId: 12,
imageUrl: 'https://example.com/a.jpg',
imageAlt: 'A',
width: 100,
height: 100,
linkUrl: '',
caption: '',
} );
expect( mapped ).not.toHaveProperty( 'filter' );
expect( mapped ).not.toHaveProperty( 'intensity' );
expect( mapped.id ).toBe( 12 );
expect( mapped.url ).toBe( 'https://example.com/a.jpg' );
} );
test( 'from-transform normalises filter and intensity to defaults', () => {
const from = Array.isArray( transforms.from ) ? transforms.from[ 0 ] : transforms.from;
const mapped = from.transform( {
id: 12,
url: 'https://example.com/a.jpg',
alt: 'A',
caption: 'cap',
width: 100,
height: 100,
href: 'https://example.com',
} );
expect( mapped.filter ).toBe( 'normal' );
expect( mapped.intensity ).toBe( 100 );
expect( mapped.imageId ).toBe( 12 );
expect( mapped.imageUrl ).toBe( 'https://example.com/a.jpg' );
expect( mapped.imageAlt ).toBe( 'A' );
expect( mapped.caption ).toBe( 'cap' );
expect( mapped.linkUrl ).toBe( 'https://example.com' );
} );
} );