-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add option to add text color to specifix text inside RichText editor
- Loading branch information
1 parent
a7fbd6e
commit e4c915e
Showing
8 changed files
with
296 additions
and
7 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
@import "./image/style.scss"; | ||
@import "./link/style.scss"; | ||
@import "./text-color/style.scss"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { get } from 'lodash'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
import { useSelect } from '@wordpress/data'; | ||
import { useCallback, useMemo, useState } from '@wordpress/element'; | ||
import { RichTextToolbarButton } from '@wordpress/block-editor'; | ||
import { Dashicon } from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { default as InlineColorUI, getActiveColor } from './inline'; | ||
|
||
const name = 'core/text-color'; | ||
const title = __( 'Text Color' ); | ||
|
||
const EMPTY_ARRAY = []; | ||
|
||
function TextColorEdit( { value, onChange, isActive, activeAttributes } ) { | ||
const colors = useSelect( ( select ) => { | ||
const { getSettings } = select( 'core/block-editor' ); | ||
if ( getSettings ) { | ||
return get( getSettings(), [ 'colors' ], EMPTY_ARRAY ); | ||
} | ||
return EMPTY_ARRAY; | ||
} ); | ||
const [ isAddingColor, setIsAddingColor ] = useState( false ); | ||
const enableIsAddingColor = useCallback( () => setIsAddingColor( true ), [ | ||
setIsAddingColor, | ||
] ); | ||
const disableIsAddingColor = useCallback( () => setIsAddingColor( false ), [ | ||
setIsAddingColor, | ||
] ); | ||
const colorIndicatorStyle = useMemo( () => { | ||
const activeColor = getActiveColor( name, value, colors ); | ||
if ( ! activeColor ) { | ||
return undefined; | ||
} | ||
return { | ||
backgroundColor: activeColor, | ||
}; | ||
}, [ value, colors ] ); | ||
return ( | ||
<> | ||
<RichTextToolbarButton | ||
key={ isActive ? 'text-color' : 'text-color-not-active' } | ||
className="format-library-text-color-button" | ||
name={ isActive ? 'text-color' : undefined } | ||
icon={ | ||
<> | ||
<Dashicon icon="editor-textcolor" /> | ||
{ isActive && ( | ||
<span | ||
className="format-library-text-color-button__indicator" | ||
style={ colorIndicatorStyle } | ||
/> | ||
) } | ||
</> | ||
} | ||
title={ title } | ||
onClick={ enableIsAddingColor } | ||
/> | ||
{ isAddingColor && ( | ||
<InlineColorUI | ||
name={ name } | ||
addingColor={ isAddingColor } | ||
onClose={ disableIsAddingColor } | ||
isActive={ isActive } | ||
activeAttributes={ activeAttributes } | ||
value={ value } | ||
onChange={ onChange } | ||
/> | ||
) } | ||
</> | ||
); | ||
} | ||
|
||
export const textColor = { | ||
name, | ||
title, | ||
tagName: 'span', | ||
className: 'has-inline-color', | ||
attributes: { | ||
style: 'style', | ||
class: 'class', | ||
}, | ||
edit: TextColorEdit, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { get } from 'lodash'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useCallback, useMemo } from '@wordpress/element'; | ||
import { useSelect } from '@wordpress/data'; | ||
import { withSpokenMessages } from '@wordpress/components'; | ||
import { getRectangleFromRange } from '@wordpress/dom'; | ||
import { | ||
applyFormat, | ||
removeFormat, | ||
getActiveFormat, | ||
} from '@wordpress/rich-text'; | ||
import { | ||
ColorPalette, | ||
URLPopover, | ||
getColorClassName, | ||
getColorObjectByColorValue, | ||
getColorObjectByAttributeValues, | ||
} from '@wordpress/block-editor'; | ||
|
||
export function getActiveColor( formatName, formatValue, colors ) { | ||
const activeColorFormat = getActiveFormat( formatValue, formatName ); | ||
if ( ! activeColorFormat ) { | ||
return; | ||
} | ||
const styleColor = activeColorFormat.attributes.style; | ||
if ( styleColor ) { | ||
return styleColor.replace( new RegExp( `^color:\\s*` ), '' ); | ||
} | ||
const currentClass = activeColorFormat.attributes.class; | ||
if ( currentClass ) { | ||
const colorSlug = currentClass.replace( /.*has-(.*?)-color.*/, '$1' ); | ||
return getColorObjectByAttributeValues( colors, colorSlug ).color; | ||
} | ||
} | ||
|
||
const ColorPopoverAtLink = ( { isActive, addingColor, value, ...props } ) => { | ||
const anchorRect = useMemo( () => { | ||
const selection = window.getSelection(); | ||
const range = | ||
selection.rangeCount > 0 ? selection.getRangeAt( 0 ) : null; | ||
if ( ! range ) { | ||
return; | ||
} | ||
|
||
if ( addingColor ) { | ||
return getRectangleFromRange( range ); | ||
} | ||
|
||
let element = range.startContainer; | ||
|
||
// If the caret is right before the element, select the next element. | ||
element = element.nextElementSibling || element; | ||
|
||
while ( element.nodeType !== window.Node.ELEMENT_NODE ) { | ||
element = element.parentNode; | ||
} | ||
|
||
const closest = element.closest( 'span' ); | ||
if ( closest ) { | ||
return closest.getBoundingClientRect(); | ||
} | ||
}, [ isActive, addingColor, value.start, value.end ] ); | ||
|
||
if ( ! anchorRect ) { | ||
return null; | ||
} | ||
|
||
return <URLPopover anchorRect={ anchorRect } { ...props } />; | ||
}; | ||
|
||
const ColorPicker = ( { name, value, onChange } ) => { | ||
const colors = useSelect( ( select ) => { | ||
const { getSettings } = select( 'core/block-editor' ); | ||
return get( getSettings(), [ 'colors' ], [] ); | ||
} ); | ||
const onColorChange = useCallback( | ||
( color ) => { | ||
if ( color ) { | ||
const colorObject = getColorObjectByColorValue( colors, color ); | ||
onChange( | ||
applyFormat( value, { | ||
type: name, | ||
attributes: colorObject | ||
? { | ||
class: getColorClassName( | ||
'color', | ||
colorObject.slug | ||
), | ||
} | ||
: { | ||
style: `color:${ color }`, | ||
}, | ||
} ) | ||
); | ||
} else { | ||
onChange( removeFormat( value, name ) ); | ||
} | ||
}, | ||
[ colors, onChange ] | ||
); | ||
const activeColor = useMemo( () => getActiveColor( name, value, colors ), [ | ||
name, | ||
value, | ||
colors, | ||
] ); | ||
|
||
return <ColorPalette value={ activeColor } onChange={ onColorChange } />; | ||
}; | ||
|
||
const InlineColorUI = ( { | ||
name, | ||
value, | ||
onChange, | ||
onClose, | ||
isActive, | ||
addingColor, | ||
} ) => { | ||
return ( | ||
<ColorPopoverAtLink | ||
value={ value } | ||
isActive={ isActive } | ||
addingColor={ addingColor } | ||
onClose={ onClose } | ||
className="components-inline-color-popover" | ||
> | ||
<ColorPicker name={ name } value={ value } onChange={ onChange } /> | ||
</ColorPopoverAtLink> | ||
); | ||
}; | ||
|
||
export default withSpokenMessages( InlineColorUI ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
.components-inline-color__indicator { | ||
position: absolute; | ||
background: #000; | ||
height: 3px; | ||
width: 20px; | ||
bottom: 6px; | ||
left: auto; | ||
right: auto; | ||
margin: 0 5px; | ||
} | ||
|
||
.components-inline-color-popover { | ||
|
||
.components-popover__content { | ||
padding: 20px 18px; | ||
|
||
.components-color-palette { | ||
margin-top: 0.6rem; | ||
} | ||
|
||
.components-base-control__title { | ||
display: block; | ||
margin-bottom: 16px; | ||
font-weight: 600; | ||
color: #191e23; | ||
} | ||
|
||
.component-color-indicator { | ||
vertical-align: text-bottom; | ||
} | ||
} | ||
} | ||
|
||
.format-library-text-color-button { | ||
position: relative; | ||
} | ||
.format-library-text-color-button__indicator { | ||
height: 4px; | ||
width: 20px; | ||
position: absolute; | ||
bottom: 6px; | ||
left: 8px; | ||
} |