diff --git a/app/assets/stylesheets/components/forms.scss b/app/assets/stylesheets/components/forms.scss index c438ea9fe..ea977c6c5 100644 --- a/app/assets/stylesheets/components/forms.scss +++ b/app/assets/stylesheets/components/forms.scss @@ -285,7 +285,6 @@ textarea.crayons-textfield.crayons-textfield--ghost { &__input { padding-left: var(--input-padding-left); - max-width: calc(100% - var(--input-padding-left)); } &__swatch { diff --git a/app/javascript/crayons/formElements/ColorPicker/ColorPicker.jsx b/app/javascript/crayons/formElements/ColorPicker/ColorPicker.jsx index 3cecf3987..dba6d2ebb 100644 --- a/app/javascript/crayons/formElements/ColorPicker/ColorPicker.jsx +++ b/app/javascript/crayons/formElements/ColorPicker/ColorPicker.jsx @@ -1,5 +1,6 @@ import { h, Fragment } from 'preact'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; import { useState, useLayoutEffect } from 'preact/hooks'; import { HexColorPicker, HexColorInput } from 'react-colorful'; import { initializeDropdown } from '@utilities/dropdownUtils'; @@ -35,7 +36,10 @@ export const ColorPicker = ({ /> ( - +
{/* Disabled as the ColorPicker component attaches the correct ID to the input */} {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */} - +
); Default.args = { diff --git a/app/javascript/packs/colorPicker.jsx b/app/javascript/packs/colorPicker.jsx new file mode 100644 index 000000000..03bd8ae10 --- /dev/null +++ b/app/javascript/packs/colorPicker.jsx @@ -0,0 +1,30 @@ +import { h, render } from 'preact'; +import { ColorPicker } from '@crayons'; + +// Find any color picker inputs on the page and replace them with the Preact enhanced component +const colorInputs = document.querySelectorAll('[data-color-picker]'); + +for (const input of colorInputs) { + const { labelText } = input.dataset; + const inputProps = {}; + + // Copy any specific attributes to the new input + const { attributes: inputAttributes } = input; + for (const attr of inputAttributes) { + inputProps[attr.name] = attr.value; + } + + // The third `replaceNode` argument here makes sure that the new picker is rendered in the correct position within the parentElement + // However, Preact is unable to do a VDOM diff that allows a straight replacement of one input for the other, so we also need to remove it manually on line 29 + render( + , + input.parentElement, + input, + ); + input.remove(); +} diff --git a/app/views/tags/edit.html.erb b/app/views/tags/edit.html.erb index a9bf89169..f51608dde 100644 --- a/app/views/tags/edit.html.erb +++ b/app/views/tags/edit.html.erb @@ -39,8 +39,8 @@
- <%= label_tag :bg_color_hex, I18n.t("views.tags.edit.form.bg_color_hex.label"), class: "crayons-field__label" %> - <%= color_field_tag "tag[bg_color_hex]", @tag.bg_color_hex.presence || "#000000", placeholder: "#000000", class: "crayons-color-selector crayons-color-selector--full" %> + <%= label_tag :tag_bg_color_hex, I18n.t("views.tags.edit.form.bg_color_hex.label"), class: "crayons-field__label" %> + <%= text_field_tag "tag[bg_color_hex]", @tag.bg_color_hex.presence || "#000000", placeholder: "#000000", class: "crayons-textfield", data: { color_picker: true, label_text: I18n.t("views.tags.edit.form.bg_color_hex.label") } %>
@@ -60,3 +60,4 @@
<% end %> +<%= javascript_packs_with_chunks_tag "colorPicker", defer: true %> diff --git a/cypress/integration/seededFlows/tagsFlows/editTag.spec.js b/cypress/integration/seededFlows/tagsFlows/editTag.spec.js new file mode 100644 index 000000000..b24136f91 --- /dev/null +++ b/cypress/integration/seededFlows/tagsFlows/editTag.spec.js @@ -0,0 +1,46 @@ +describe('Edit tag', () => { + beforeEach(() => { + cy.testSetup(); + cy.fixture('users/adminUser.json').as('user'); + + cy.get('@user').then((user) => { + cy.loginAndVisit(user, '/t/tag1/edit'); + }); + }); + + it('enhances the color input with the rich ColorPicker', () => { + // Both a button and an input should be available + cy.findByRole('button', { name: 'Tag color' }).as('popoverButton'); + cy.findByRole('textbox', { name: 'Tag color' }).as('input'); + + // Input should be pre-filled with the current bg_color_hex + cy.get('@input').should('have.value', '#672c99'); + // Button should open and close a picker + cy.get('@popoverButton') + .should('have.attr', 'aria-expanded', 'false') + .click() + .should('have.attr', 'aria-expanded', 'true'); + + cy.findByLabelText('Color').should('be.visible'); + + cy.get('@popoverButton') + .click() + .should('have.attr', 'aria-expanded', 'false'); + cy.findByLabelText('Color').should('not.be.visible'); + }); + + it('changes the tag color', () => { + // Make sure the enhanced component is now visible + cy.findByRole('button', { name: 'Tag color' }); + + cy.findByRole('textbox', { name: 'Tag color' }).clear().type('ababab'); + cy.findByRole('button', { name: 'Save' }).click(); + + // Wait for confirmation + cy.findByText(/Tag successfully updated!/); + cy.findByRole('textbox', { name: 'Tag color' }).should( + 'have.value', + '#ababab', + ); + }); +}); diff --git a/spec/support/seeds/seeds_e2e.rb b/spec/support/seeds/seeds_e2e.rb index dae27f68e..d4b566802 100644 --- a/spec/support/seeds/seeds_e2e.rb +++ b/spec/support/seeds/seeds_e2e.rb @@ -591,7 +591,7 @@ seeder.create_if_none(Tag) do tags.each do |tagname| tag = Tag.create!( name: tagname, - bg_color_hex: Faker::Color.hex_color, + bg_color_hex: "#672c99", text_color_hex: Faker::Color.hex_color, supported: true, )