question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

A color picker 100% functional !

See original GitHub issue

EDIT: if you are using Trix 2.0+ read the tutorial but instead of using this stimulus_controller, please use the stimulus_controller here: https://github.com/basecamp/trix/issues/985#issuecomment-1307422240

After a good time of reading issues and thinking I finally could create a fully functional color picker for Trix

This also works when reloading the editor page because I call reset after the config.

I also added text-align center icon to center blocks

trix2

For this to work, just wrap your rich_text_area in a div with data-controller="trix" and add a data: { trix_target: 'editor' } to the rich_text_area

<div class="control" data-controller="trix">
        <%= f.rich_text_area :description, placeholder: t('products.edit.description_placeholder'),
                              data: { trix_target: 'editor' } %>
</div>

Also add a stimulus controller called trix-controller.js and then update the stimulus manifest

update the Stimulus manifest with ./bin/rails stimulus:manifest:update

import { Controller } from '@hotwired/stimulus'
import Trix from 'trix'

// Connects to data-controller="trix"
export default class extends Controller {
  static targets = ['editor', 'foregroundColorPicker', 'backgroundColorPicker']

  connect () {
    this.initTrix()
    this.reloadOriginalContent()
  }

  initTrix () {
    if (this.hasForegroundColorPickerTarget) { return }

    Trix.config.blockAttributes.heading1.tagName = 'h3'
    this.addForegroundButtonInToolbar()
    this.addBackgroundButtonInToolbar()
    this.addTextAlignCenterButtonInToolbar()
  }

  reloadOriginalContent () {
    this.editorTarget.reset()
  }

  openForegroundColorPicker () {
    this.foregroundColorPickerTarget.click()
  }

  openBackgroundColorPicker () {
    this.backgroundColorPickerTarget.click()
  }

  foregroundColorChanged () {
    this.editorTarget.editor.activateAttribute('foregroundColor', this.foregroundColorPickerTarget.value)
  }

  backgroundColorChanged () {
    this.editorTarget.editor.activateAttribute('backgroundColor', this.backgroundColorPickerTarget.value)
  }

  addForegroundButtonInToolbar () {
    Trix.config.textAttributes.foregroundColor = {
      styleProperty: 'color',
      inheritable: true
    }

    this.element
      .querySelector('.trix-button-group.trix-button-group--text-tools')
      .insertAdjacentHTML('beforeend', this.foregroundColorButtons)
  }

  addBackgroundButtonInToolbar () {
    Trix.config.textAttributes.backgroundColor = {
      styleProperty: 'backgroundColor',
      inheritable: true
    }

    this.element
      .querySelector('.trix-button-group.trix-button-group--text-tools')
      .insertAdjacentHTML('beforeend', this.backgroundColorButtons)
  }

  addTextAlignCenterButtonInToolbar () {
    Trix.config.blockAttributes.textAlignCenter = {
      tagName: 'centered-div'
    }

    this.element
      .querySelector('.trix-button-group.trix-button-group--block-tools')
      .insertAdjacentHTML('beforeend', this.textAlignButtons)
  }

  get foregroundColorButtons () {
    return `<input type="color" style="width:0;height:0;padding:0;margin-top:20px;visibility:hidden"
                   data-trix-target="foregroundColorPicker" data-action="trix#foregroundColorChanged">
            <button type="button" class="trix-button" data-action="click->trix#openForegroundColorPicker" title="Text color">
              <span class="icon"><i class="fas fa-palette fa-lg"></i></span>
            </button>`
  }

  get backgroundColorButtons () {
    return `<input type="color" style="width:0;height:0;padding:0;margin-top:20px;visibility:hidden"
                   data-trix-target="backgroundColorPicker" data-action="trix#backgroundColorChanged">
            <button type="button" class="trix-button" data-action="click->trix#openBackgroundColorPicker" title="Text background color">
              <span class="icon"><i class="fas fa-fill-drip fa-lg"></i></span>
            </button>`
  }

  get textAlignButtons () {
    return `<button type="button" class="trix-button" data-trix-attribute="textAlignCenter">
              <span class="icon"><i class="fas fa-align-center fa-lg"></i></span>
            </button>`
  }
}

You may want to replace the icon <span class="icon"><i class="fas fa-palette"></i></span> (I use fontawesome, feel free to use whatever you like, maybe a 🎨 icon would work)

this solves https://github.com/basecamp/trix/issues/498 https://github.com/basecamp/trix/issues/606 https://github.com/basecamp/trix/issues/655 and many others.

For the centered text you will need to:

Add this css

centered-div {
  display: block;
  text-align: center;
}

Also add centered-div as allowed tags (I have this in my application.rb)

config.after_initialize do
      ActionText::ContentHelper.allowed_attributes.add 'style'
      ActionText::ContentHelper.allowed_attributes.add 'controls'
      ActionText::ContentHelper.allowed_attributes.add 'poster'

      ActionText::ContentHelper.allowed_tags.add 'video'
      ActionText::ContentHelper.allowed_tags.add 'source'
      ActionText::ContentHelper.allowed_tags.add 'centered-div'
    end

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:7
  • Comments:6

github_iconTop GitHub Comments

2reactions
silva96commented, Nov 8, 2022

UPDATE: for trix 2.0+ the controller is slightly different (and better, less hacky)

import { Controller } from '@hotwired/stimulus'
import Trix from 'trix'
const { lang } = Trix.config

// Connects to data-controller="trix"
export default class extends Controller {
  static targets = ['editor', 'foregroundColorPicker', 'backgroundColorPicker']

  connect () {
    document.addEventListener('trix-before-initialize', () => {
      this.initTrix()
    })
  }

  initTrix () {
    Trix.config.blockAttributes.heading1.tagName = 'h3'
    Trix.config.toolbar.getDefaultHTML = this.getDefaultHTML.bind(this)
    this.addForegroundButtonConfig()
    this.addBackgroundButtonConfig()
    this.addTextAlignCenterButtonConfig()
  }

  openForegroundColorPicker () {
    this.foregroundColorPickerTarget.click()
  }

  openBackgroundColorPicker () {
    this.backgroundColorPickerTarget.click()
  }

  foregroundColorChanged () {
    this.editorTarget.editor.activateAttribute('foregroundColor', this.foregroundColorPickerTarget.value)
  }

  backgroundColorChanged () {
    this.editorTarget.editor.activateAttribute('backgroundColor', this.backgroundColorPickerTarget.value)
  }

  addForegroundButtonConfig () {
    Trix.config.textAttributes.foregroundColor = {
      styleProperty: 'color',
      inheritable: true
    }
  }

  addBackgroundButtonConfig () {
    Trix.config.textAttributes.backgroundColor = {
      styleProperty: 'backgroundColor',
      inheritable: true
    }
  }

  addTextAlignCenterButtonConfig () {
    Trix.config.blockAttributes.textAlignCenter = {
      tagName: 'centered-div'
    }
  }

  getDefaultHTML () {
    return `<div class="trix-button-row">
      <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">${lang.bold}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
        ${this.foregroundColorButtons}
        ${this.backgroundColorButtons}
      </span>
      <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1">${lang.heading1}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1">${lang.quote}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="${lang.code}" tabindex="-1">${lang.code}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1">${lang.bullets}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1">${lang.numbers}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1">${lang.outdent}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1">${lang.indent}</button>
        ${this.textAlignButtons}
      </span>
      <span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1">${lang.attachFiles}</button>
      </span>
      <span class="trix-button-group-spacer"></span>
      <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools">
        <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1">${lang.undo}</button>
        <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1">${lang.redo}</button>
      </span>
    </div>
    <div class="trix-dialogs" data-trix-dialogs>
      <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href">
        <div class="trix-dialog__link-fields">
          <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input>
          <div class="trix-button-group">
            <input type="button" class="trix-button trix-button--dialog" value="${lang.link}" data-trix-method="setAttribute">
            <input type="button" class="trix-button trix-button--dialog" value="${lang.unlink}" data-trix-method="removeAttribute">
          </div>
        </div>
      </div>
    </div>`
  }

  get foregroundColorButtons () {
    return `<input type="color" style="width:0;height:0;padding:0;margin-top:20px;visibility:hidden"
                   data-trix-target="foregroundColorPicker" data-action="trix#foregroundColorChanged">
            <button type="button" class="trix-button" data-action="click->trix#openForegroundColorPicker" title="Text color">
              <span class="icon"><i class="fas fa-palette fa-lg"></i></span>
            </button>`
  }

  get backgroundColorButtons () {
    return `<input type="color" style="width:0;height:0;padding:0;margin-top:20px;visibility:hidden"
                   data-trix-target="backgroundColorPicker" data-action="trix#backgroundColorChanged">
            <button type="button" class="trix-button" data-action="click->trix#openBackgroundColorPicker" title="Text background color">
              <span class="icon"><i class="fas fa-fill-drip fa-lg"></i></span>
            </button>`
  }

  get textAlignButtons () {
    return `<button type="button" class="trix-button" data-trix-attribute="textAlignCenter">
              <span class="icon"><i class="fas fa-align-center fa-lg"></i></span>
            </button>`
  }
}
0reactions
neugedcommented, Nov 30, 2022

In trix 2.0 it’s not needed! (since we init trix on the event trix-before-initialize, so it always initialize properly)

Thanks, you are right. With the upgrade to 2.0.1 we do not need the call anymore. 👍

Read more comments on GitHub >

github_iconTop Results From Across the Web

a-color-picker
A color picker for web app. ... The default picker is created with HSL, RGB and HEX controls. The acp-color attribute is used...
Read more >
a-color-picker - npm
Start using a-color-picker in your project by running `npm i a-color-picker`. ... Set onchange property with a handler function.
Read more >
HTML Color Picker - W3Schools
Well organized and easy to understand Web building tutorials with lots of examples of how to use HTML, CSS, JavaScript, SQL, Python, PHP,...
Read more >
Building a Color Picker with Python | by Conor O'Sullivan
Simple picker — selects a colour from a single image; Complex picker—selects ... To create this picker, we start with the onclick function....
Read more >
Modular, design-conscious color picker widget for JavaScript
An HSV color picker widget for JavaScript, with a modern SVG-based user interface.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found