Skip to content

Commit

Permalink
Rich text: formats: allow format to filter value when changing tag na…
Browse files Browse the repository at this point in the history
…me (#35516)

* Rich text: formats: allow format to filter value when changing tag name

* Do not add a transparent background-color if already set

* Fix undefined values in the list of attributes, which would cause the rich-text component to break

* Do not skip the entire loop iteration if key does not exist in _attributes

* Format library: text-color: Explain use of __unstableFilterAttributeValue

* Remove `export` for `parseCSS`

* Make sure to delete undefined registeredAttributes

* Handle format attributes on rich-text init

* Only handle changes for `text-color` formats upon init

* Be a bit more defensive when accessing record.current.formats

* Prepend the `addedCSS` to prevent double `;`

Existing CSS rules already end with a semicolon, and joining it with the `background-color` rule would result in something like:

```
color:#e511be;;background-color:rgba(0, 0, 0, 0)
```

Which is benign AFAIK, but doesn't look right. Best to prepend the `background-color` rule, since it doesn't include a `;`, but the `join` will take care of adding it when joining it with the other existing rules, if any.

Co-authored-by: Marcelo Serpa <[email protected]>
Co-authored-by: Miguel Fonseca <[email protected]>
  • Loading branch information
3 people committed Oct 20, 2021
1 parent 369b65c commit d4eb1bf
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 14 deletions.
18 changes: 18 additions & 0 deletions packages/format-library/src/text-color/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,23 @@ export const textColor = {
style: 'style',
class: 'class',
},
/*
* Since this format relies on the <mark> tag, it's important to
* prevent the default yellow background color applied by most
* browsers. The solution is to detect when this format is used with a
* text color but no background color, and in such cases to override
* the default styling with a transparent background.
*
* @see https://github.com/WordPress/gutenberg/pull/35516
*/
__unstableFilterAttributeValue( key, value ) {
if ( key !== 'style' ) return value;
// We should not add a background-color if it's already set
if ( value && value.includes( 'background-color' ) ) return value;
const addedCSS = [ 'background-color', 'rgba(0, 0, 0, 0)' ].join( ':' );
// Prepend `addedCSS` to avoid a double `;;` as any the existing CSS
// rules will already include a `;`.
return value ? [ addedCSS, value ].join( ';' ) : addedCSS;
},
edit: TextColorEdit,
};
40 changes: 40 additions & 0 deletions packages/rich-text/src/component/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,21 @@ export function useRichText( {

if ( ! record.current ) {
setRecordFromProps();
// Sometimes formats are added programmatically and we need to make
// sure it's persisted to the block store / markup. If these formats
// are not applied, they could cause inconsistencies between the data
// in the visual editor and the frontend. Right now, it's only relevant
// to the `core/text-color` format, which is applied at runtime in
// certain circunstances. See the `__unstableFilterAttributeValue`
// function in `packages/format-library/src/text-color/index.js`.
// @todo find a less-hacky way of solving this.

const hasRelevantInitFormat =
record.current?.formats[ 0 ]?.[ 0 ]?.type === 'core/text-color';

if ( hasRelevantInitFormat ) {
handleChangesUponInit( record.current );
}
} else if (
selectionStart !== record.current.start ||
selectionEnd !== record.current.end
Expand Down Expand Up @@ -153,6 +168,31 @@ export function useRichText( {
forceRender();
}

function handleChangesUponInit( newRecord ) {
record.current = newRecord;

_value.current = toHTMLString( {
value: __unstableBeforeSerialize
? {
...newRecord,
formats: __unstableBeforeSerialize( newRecord ),
}
: newRecord,
multilineTag,
preserveWhiteSpace,
} );

const { formats, text } = newRecord;

registry.batch( () => {
onChange( _value.current, {
__unstableFormats: formats,
__unstableText: text,
} );
} );
forceRender();
}

function applyFromProps() {
setRecordFromProps();
applyRecord( record.current );
Expand Down
38 changes: 24 additions & 14 deletions packages/rich-text/src/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,6 @@ function createEmptyValue() {
};
}

function simpleFindKey( object, value ) {
for ( const key in object ) {
if ( object[ key ] === value ) {
return key;
}
}
}

function toFormat( { type, attributes } ) {
let formatType;

Expand Down Expand Up @@ -94,15 +86,33 @@ function toFormat( { type, attributes } ) {

const registeredAttributes = {};
const unregisteredAttributes = {};
const _attributes = { ...attributes };

for ( const name in attributes ) {
const key = simpleFindKey( formatType.attributes, name );
for ( const key in formatType.attributes ) {
const name = formatType.attributes[ key ];

if ( key ) {
registeredAttributes[ key ] = attributes[ name ];
} else {
unregisteredAttributes[ name ] = attributes[ name ];
registeredAttributes[ key ] = _attributes[ name ];

if ( formatType.__unstableFilterAttributeValue ) {
registeredAttributes[
key
] = formatType.__unstableFilterAttributeValue(
key,
registeredAttributes[ key ]
);
}

// delete the attribute and what's left is considered
// to be unregistered.
delete _attributes[ name ];

if ( typeof registeredAttributes[ key ] === 'undefined' ) {
delete registeredAttributes[ key ];
}
}

for ( const name in _attributes ) {
unregisteredAttributes[ name ] = attributes[ name ];
}

return {
Expand Down

0 comments on commit d4eb1bf

Please sign in to comment.