Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 8, 2022 11:12 pm GMT

Add font-size controls to Trix's toolbar

This is a third blog-post on extending Trix with some new abilities. You can read the previous ones here

Off we go

In this part we will add another ability to our Trix's attributes. This time we will try adding a font-size controls, much like Google Docs does it. Onwards.

Registering the extension

As with all other extensions we added, we need to inform trix that to recognise the new attribute we are adding, and so, we modify setupTrix method, and add the following.

setupTrix() { Trix.config.textAttributes.fontSize = {   styleProperty: "font-size",   inheritable: 1 } this.trix = this.element.querySelector("trix-editor")}

Now, because the font-size value is a dynamic value, i.e it's from user input, and the value isn't a constant, we use the form which is used for dynamic extensions. See this for more information.

Adding Markup

Next up, we add some markup that makes the font-size controls visible to the user.

Font size controls

Stimulus Controller

The logic for handling the font-size is a bit too much to place inside the Trix controller, it's already growing, and we should strive to put each tool into it's own controller.

export default class extends Controller {  static targets = ["input"]  static values = {    size: { type: Number, default: 14 }  }  onKeyPress(e) {    if(e.key === "Enter") {      e.preventDefault()      this.submit()    }  }  increase() {    this.dispatch("change", {      detail: new Font(++this.sizeValue),    })  }  decrease() {    this.dispatch("change", {      detail: new Font(--this.sizeValue)    })  }  // private  submit() {    this.sizeValue = this.inputTarget.value    this.dispatch("change", {      detail: new Font(this.sizeValue),    })  }  sizeValueChanged() {    this.inputTarget.value = this.sizeValue  }}

The class is simple, it has two public methods, increase and decrease, each whom will add one or deduct one from the value.

When the value changes we dispatch an event that the trix_controller listens to. The Font class is a simple object that allows the trix_controller to either get the value in px or rem.

class Font {  constructor(size) {    this.size = size  }  get rem() {    return `${this.size * 0.0625}rem`  }  get px() {    return `${this.size}px`  }}

It uses JavaScript's getters to return the size in either px or rem, as the client wishes so.

Now, let's listen for the event inside the Trix controller.

First up, we need to listen to the event,

<divdata-action="color-picker:change->trix#changeColor font-size:change->trix#changeSelectionFontSize"

notice that on font-size:change event, we invoke changeSelectionFontSize

changeSelectionFontSize({ detail: font }) {  this.trixEditor.activateAttribute("fontSize", font.px)}

Notice, we are simply getting the font-size in pixels by calling Font#px getter.

Syncing

Now, it can happen that different parts of the content have different font-sizes. We need to update the font-size <input> with the font-size at the current cursor location.

This should also be very straightforward. We need to listen to each keypress on the editor. Then, determine if the current Piece has the fontSize attribute, if so, we notify font_size controller to sync it's state with cursor position. Translated into code, it looks like this, we add to the TrixController#sync, which is called on each keystroke.

sync() {  if (this.pieceAtCursor.attributes.has("fontSize")) {    this.dispatch("font-size:sync", {      target: this.fontSizeControlsTarget,      detail: this.pieceAtCursor.getAttribute("fontSize")    })  }}get pieceAtCursor() {  return this.trixEditorDocument.getPieceAtPosition(this.trixEditor.getPosition())}

When we detect that the current piece has the fontSize attribute, we alert FontSizeController to sync it's internal state with the editor. The payload(detail) will be font-size of the piece, which we get by calling Piece#getAttribute.

Next, let's wire the FontSizeController to correctly update it's internal state.

sync({ detail: fontSizeString }) {  this.sizeValue = Font.rawNumberFrom(fontSizeString)}class Font {  static rawNumberFrom(fontSizeString) {    return Number.parseInt(fontSizeString)  }}

The payload will be a font-size string, i.e in the format of number{type}, so we call Font.rawNumberFrom static methods which gets the number in the string. We make use of JavaScript's built in Number.parseInt which correctly extracts the number from the string.

Via input

It can happen that the user enters a specific font-size into the input, and when they press Enter we submit by dispatching a change event.

Because the font-size input, when focused, will steal the active state from the trix editor, we need to remember the user's selection, so that next time we activate the font-size attribute, we activate it on the user's original selection.

First, let's listen for the focus event

<input type="number"  data-trix-target="fontSizeInput"  data-font-size-target="input"  data-action="focus->trix#markSelection keydown->font-size#onKeyPress"

Notice the focus->trix#markSelection

  markSelection() {    this.trixEditor.activateAttribute("frozen")    this.fontSizeInputTarget.focus()    this.trix.blur()  }

Because calling activateAttribute will cause trix to focus, after activating the frozen attribute we blur.

Gotcha: the frozen attribute ships by default in Trix. It's a simple attribute that allows to communicate visual feedback to the user and give the impression that the selected text is in fact still selected.

.

Notice that, when the font-size input is focused, the "Frozen" text is still highlighted, that is because we activated the frozen attribute.

To remove the frozen attribute after the font-size was applied on the selection, we simply tell trix to remove it.

changeSelectionFontSize({ detail: font }) {  this.trixEditor.activateAttribute("fontSize", font.px)  this.trixEditor.deactivateAttribute("frozen")}

If we don't remove the frozen attribute, we will end up with a weird UI state, see below gif.

.

After the font-size is applied and the user continues writing, the "Frozen" text still appears to be selected, however because we are explicitly telling Trix to remove the attribute. We end up with something far better, like this.

.

There are still a few more edge-cases to cover. But, that should be enough for you to add font-size controls to your Trix toolbars.

You can clone the repository here

Hope you enjoyed this one. Good day, and Happy Coding!.

Resources


Original Link: https://dev.to/rockwell/add-font-size-controls-to-trixs-toolbar-1hgd

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To