'How to change the font size of the bullets of an unordered list item in draftjs?
I have a rich text editor built using draftjs. I implemented the functions for changing the font size, font family, and color of the text in the editor. I also implemented the functionality of adding unordered and ordered list items.
The issue is whenever I add an unordered or ordered list to a block of text, the font size of the bullet is always fixed and it does not correspond to the size of the text in that block.
For example the bullet size is always 10px even if the text has a font size of 20px or 40px or 10px. So, is there any way to make the bullet size the same as the size of the text in that block.
Google slides exhibit the correct behaviour, like the font size of the bullet changes depending upon the size of the text in that block.
So can anyone help me in finding a solution for this issue where I can change the style of the bullet depending upon the style of the text in that block.
Solution 1:[1]
Here is some workaround working for me: completely remove the base bullets and replace them using draftjs style of the first character of each li. Those are then rendered by the blockRendererFn callback of the Editor:
First, remove the normal list styling and prepare yours:
ul, ol {
list-style: none!important;
margin-left: 0!important;
li {
.liContent {
display: flex;
div { width: 100%; }
.bullet {
align-self: center;
margin-right: .5em;
}
}
&::before, &::marker {
display: none !important; // Not working everytimes (?!), thus content = ''
content: '';
}
}
}
Then, simply adapt this code for your needs (you may add whatever bullets/levels you need in the baseBullets constant:
const orderedList = 0, unorderedList = 1;
const baseBullets = [[1, 'a'], ['•', '?', '?']];
const leavingLevel = 0, initiatingLevel = 1, crossingLevel = 2;
// Returns the previous or the next bullet of a given bullet
function GetSisterBullet(idx, type, whichSister) {
if (type === orderedList) {
if (Number.isInteger(idx)) return idx + whichSister;
else return String.fromCharCode(idx.charCodeAt(0) + whichSister); // Let's assume, for now, that we won't have more than 26 sublevels...
} return idx;
}
// Gets the bullet of the very first entry of a given level
function GetLevelBaseBullet(depth, type, action) {
let curLevelBaseIdx = baseBullets[type][depth % baseBullets[type].length];
return action === leavingLevel ? GetSisterBullet(curLevelBaseIdx, type, -1) : curLevelBaseIdx;
}
// Set the bullet to be displayed for the next list/sublist entry
function SetLevelNextEntryBullet(type, depth, action = crossingLevel) {
switch (action) {
case crossingLevel: listEntriesLastIdx[type][depth] = GetSisterBullet(listEntriesLastIdx[type][depth], type, 1); break;
case leavingLevel:
listEntriesLastIdx[type].splice(depth, 1);
if (depth > 0 && !listEntriesLastIdx[type][depth - 1]) // Happens when two separate lists fellow each other
listEntriesLastIdx[type][depth - 1] = GetLevelBaseBullet(depth - 1, type, initiatingLevel); //
break;
default: listEntriesLastIdx[type][depth] = GetLevelBaseBullet(depth, type, action); break;
}
}
// And finaly, the Editor blockRendererFn callback
const handleBlockRender = block => {
let blockType = -1;
switch (block.getType()) {
case 'ordered-list-item': blockType = orderedList; break;
case 'unordered-list-item': blockType = unorderedList; break;
default: break;
}
if (blockType >= 0) { // List block/tree
// Update the levels entries counters
if (block.depth == curListLvl)
SetLevelNextEntryBullet(blockType, curListLvl)
else {
if (!listEntriesLastIdx[blockType])
listEntriesLastIdx[blockType] = [];
//-----
if (block.depth < curListLvl) SetLevelNextEntryBullet(blockType, curListLvl, leavingLevel);
else SetLevelNextEntryBullet(blockType, block.depth, listEntriesLastIdx[blockType][block.depth] ? undefined : initiatingLevel);
curListLvl = block.depth;
}
// Rendering
let levelIndexToDisplay = listEntriesLastIdx[blockType][curListLvl]; // Important to pass through an other variable because of the callback it will be used in
let HTMLStyles = EditorStylesToHTMLStyles(block.getInlineStyleAt(0)); // See bellow for this function definition, if you don't have your own function already
return {
component: props =>
<div className="liContent">
<span className="bullet" style={HTMLStyles}>{`${levelIndexToDisplay}${blockType === orderedList ? '.' : ''}`}</span>
<EditorBlock {...props} />
</div>
};
}
else {
// Leaving the actual list tree
listEntriesLastIdx = [];
curListLvl = -1;
}
// Rendering all other blocks here, if needed, or return nothing for the generic rendering
...
};
And, if you don't have yours, the functions which retrieve the HTML style at a given position of draftjs content, to also adapt depending on your needs:
function EditorStylesToHTMLStyles(editorStyles) {
return editorStyles
.map(editorStyle => GetHTMLStyles(editorStyle))
.toArray()
.reduce((acc, styles) => { return { ...acc, ...styles }; }, {});
}
function GetHTMLStyles(editorStyle) {
let matches = null;
if (matches = editorStyle.match(/fontsize-(.*)/))
return { fontSize: matches[1] + 'px' };
else if (matches = editorStyle.match(/color-(.*)/))
return { color: matches[1] };
else if (matches = editorStyle.match(/fontfamily-(.*)/))
return { fontFamily: matches[1] };
else switch (editorStyle) {
case 'BOLD': return { fontWeight: 'bold' };
case 'ITALIC': return { fontStyle: 'italic' };
case 'SUPERSCRIPT': return { fontSize: '.7rem', position: 'relative', top: '-.5rem' };
case 'SUBSCRIPT': return { fontSize: '.7rem', position: 'relative', bottom: '-.5rem' };
case 'UNDERLINE': return { textDecoration: 'underline' };
case 'STRIKETHROUGH': return { textDecoration: 'line-through' };
default: return {};
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | MamorukunBE |