?
avatar thednp
thednp
22 Feb 2021

Problem

As discussed previously with @dgrammatiko, we need to remove jQuery minicolors (less SCSS to compile, and one less jQuery dependency) and replace it with something fresh, reliable and play nice with our repeatable fields via custom elements.

Solution

The new <color picker> you are about to see.

<color-picker id="myColorPicker" value="rgb(20,120,150)" format="rgb"></color-picker>

...becomes something like this:
ColorPicker

DEMO

Codepen link right here. Updated with every change.

Features

  • implements TinyColor for color parsing, validation. conversion and [hue, saturation, lightness] computation;
  • concept design is inspired by the 7+ years old PitPik/colorPicker, the best color picker I know (unfortunately won't fit into our today's needs, it needs heavy changes to make it work with custom elements);
  • all possible events implemented for controls, as well as color inputs ([red, green, blue], [hue, saturation, lightness], etc);
  • HEX / RGB(a) / HSL(a) color formats supported, TinyColor will convert automatically bunch of things like rgba() to rgb() or hsla() to hsl() when color alpha is 1, or transparent to rgba(0,0,0,0) and even color name like red to rgb(255,0,0);
  • it fires joomla.colorpicker.change event on every control change or every type inside inputs, but take effect after a 500ms delay, when TinyColor validates the input color and triggers the change;
  • all modern ES6+ codebase, might require some polyfill for IE10+ (I will later update this post with a full list);
  • mobile friendly: the color picker is about 25% smaller on mobiles (the main input, color-dropdown and mobile keyboard all fit into viewport), color controls are more spaced to make it easy to tap, and fully implements touch events in a way that scroll is prevented when the color dropdown is shown;
  • automatic positioning for the color-dropdown on showing it and on window scroll while open; if the color-dropdown exceeds both top and bottom edge, it will be positioned where it has most space;
  • light, fast and memory efficient JavaScript prototype;
  • strict and efficient event listener management (while in default state, only a single listener is attached to the color-picker element, but when open and only then, additional listeners are added, scroll, mousemove, keyup, etc), no memory leaks are allowed.

Notes - this goes specifically to @dgrammatiko

  • the Event.prototype.path is no longer required, the tabindex attribute solved the original problem, however I had to change all the way event listeners are managed to be able to add/remove them easily and avoid memory leaks;
  • again I've changed a lot of functions, removed all redundant code, everything should be snappy as expected;
  • the cursor issue is still a thing from time to time, hard to track it down;
  • changing one of the controls, the color picker is now aware of the value of the other controls;
  • most of the issues discussed previously have been solved;
  • I'm thinking of a feature to make the color-dropdown smaller on mobile, it's too hard to handle;
  • there's a observeInputs method, I don't really know what's that all about; perhaps it's a custom-elements feature or perhaps what was originally intended was already implemented by me by any chance?

Quirks

  • TinyColor has the bad habit of resetting the HUE when the input LIGHTNESS is 0;
  • all events implemented, might need some additional testing on mobile, especially on iPhone (I tested on Android with Brave, all good for me), I expect a lot of these quirks to come forward;

Development status

  • I'm about to start implementing <color-picker> in Joomla, this section will be updated with changes and news, stay tuned.

Test, play and provide feedback.

Cheers!

avatar thednp thednp - open - 22 Feb 2021
avatar joomla-cms-bot joomla-cms-bot - change - 22 Feb 2021
Labels Added: ?
avatar joomla-cms-bot joomla-cms-bot - labeled - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar dgrammatiko
dgrammatiko - comment - 22 Feb 2021

I would say ship it as is but I think I need to ask for a switch of the tinycolor to this package: https://github.com/scttcper/tinycolor (reason is the one I used back when I was playing with this was/is ES5 but we'll be better if we use an ES Module)

Great job, let me know if you need any help bridging the PHP parts

avatar thednp
thednp - comment - 22 Feb 2021

@dgrammatiko if we don't implement some crazy stuff like hex8 or percentage rgba, we can actually include some utilities from tinycolor into our color-picker: we only need parse and 3-4 conversion functions + saturation, which should be, IDK, 250 bytes of code?

Please test on mobile.

avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp
thednp - comment - 22 Feb 2021

I agree about the switch.

avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar thednp thednp - change - 22 Feb 2021
The description was changed
avatar thednp thednp - edited - 22 Feb 2021
avatar brianteeman
brianteeman - comment - 22 Feb 2021

Based on the codepen the accessibility is better than the current option but should really be tested by the accessibility team

avatar thednp
thednp - comment - 22 Feb 2021

@brianteeman feel free to tag them in.

avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp
thednp - comment - 23 Feb 2021

@brianteeman I've changed the mobile view of the color picker, please take a minute to test the demo. Also check the updated initial note for changes.

As for accessibility, it will all come together at the point where we have it implemented as is, a proof of concept design into PHP of Joomla 4, then we can speak about accessibility and probably ARIA.

avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp thednp - change - 23 Feb 2021
The description was changed
avatar thednp thednp - edited - 23 Feb 2021
avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko I've started working on implementation in this repo. Couple of quick questions:

  • where should the newer tinycolor source go? I initially uploaded to build/media_source/vendor/tinycolor but then I realized that build/media_source/system/js/fields/tinycolor is probably better;
  • the ES6+ sources uploaded are generated locally from .ts sources, or should we use the .ts?
  • which Joomla form field should we modify? the one that was originally using minicolors? or create a new one?

Let me know.

avatar Bakual
Bakual - comment - 23 Feb 2021

Stupid question maybe, but what speaks against just using <input type="color">? Looks to be good supported by browsers.
Or is there an important feature missing in the native element?

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

Stupid question maybe, but what speaks against just using

It doesn't support all 3 modes that Joomla has right now

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

@thednp

  • please use build/media_source/system/js/fields/tinycolor.w-c.es6.js mind the .w-c.es6.js it's important for the tools!!
  • we don't support typescript right now, so it needs to be plain js
  • modify the one that was originally using minicolors, there is a layout advanced iirc and that should be the one used for this picker
  • the js needs one more piece of small code that will attach a hidden field with the name and the id of the field and value the value of the custom element, so the old form post continue to work as before. Let me know if you want me to post this code
avatar Bakual
Bakual - comment - 23 Feb 2021

It doesn't support all 3 modes that Joomla has right now

Chrome does support RGD, HEX and HSL. It even has a color picker to pick any color on your screen. Looks quite nice.
But yeah, haven't tested with other browsers. They may be different.

avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko the <input type="color"> supports HSL, RGB, HEX.

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

@dgrammatiko the supports HSL, RGB, HEX.
Chrome does support RGD, HEX and HSL.

I meant the alpha part, too early here also according to MDN the returned value is ALWAYS hex: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/color

<input> elements of type color provide a user interface element that lets a user specify a color, either by using a visual color picker interface or by entering the color into a text field in #rrggbb hexadecimal format
avatar brianteeman
brianteeman - comment - 23 Feb 2021

I did a pr a long time ago to use html5 color but it was rejected because it doesnt support alpha/transparency

avatar thednp
thednp - comment - 23 Feb 2021

@Bakual my problem is the accuracy, aside from alpha control missing. The native color input is really small making it hard to really do some accurate color picking. With this component you can do it much easier, even on mobile devices.

Another limitation is the possibility to customize, it's just not possible to customize the color popup.

Plus stuff like tinycolor can really prove to be handy in front-end design!

avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko I need a build script or at least a suggestion for tinycolor to concatenate all code into a single file.

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

@thednp we have rollup but at the moment we need to patch the build tools as it's not yet used everywhere. I'll post you the changes needed later on today

avatar thednp
thednp - comment - 23 Feb 2021

Right, meanwhile I will start doing some PHP.

avatar thednp
thednp - comment - 23 Feb 2021

@Bakual you got me thinking of a combination of input color and an input type range combined into a custom element, but it still needs some work and utilities. It should work but won't give us much in terms of flexibility, accuracy and customization. It would be a hustle free with events though.

avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko I've prepared the compiled files I need to work with, I'm now looking at the PHP side of libraries\src\Form\Field\ColorField.php and the $layout = 'joomla.form.field.color' is nowhere to be found.

Which files do we need to change in the PHP side? I'm thinking maybe creating a new layout for the existing ColorField.php form field for now. Just to get to working.

avatar thednp
thednp - comment - 23 Feb 2021

Another quick one: (can I) / (should I) use parts of the color-picker template shadowroot in the PHP layout?

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

Another quick one: (can I) / (should I) use parts of the color-picker template shadowroot in the PHP layout?

What do you mean? Do you want to pretender the label and input? You could but you have to use named slots <slot name="lablel"></slot> check https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot

If you're referring to css parts please don't, use css variables or https://developer.mozilla.org/en-US/docs/Web/CSS/::part

avatar thednp
thednp - comment - 23 Feb 2021

I will probably use a slot, I want to give the main input the value and its ID. Other suggestions? I can just let it go the way it is, our script will transfer the ID and value to the input already.

avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko after some time tinkering to setup the wasm, I got the color picker working on my end, now I need to know what's the best to do in order to transfer the attributes to the <input> in the shadowRoot.

I can cleanup the JS code, some labels are unnecessary within Joomla, and transfer all attributes to the main input, all via JS, with or without <slot> which is something I don't quite understand. Is that something I can use to transfer data into the shadowRoot?

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

Try this code to expose the data to the parent form:

hiddenInput() {
  if (!this.hiddenInput) {
    this.hiddenInput = document.createElement('input');
    this.hiddenInput.type = 'hidden';
    this.hiddenInput.name = this.name;
    this.hiddenInput.value = this.value;
    this.form.appendChild(this.hiddenInput);
  } else {
    this.hiddenInput.name = this.name;
    this.hiddenInput.value = this.value;
  }
}

connectedCallback() {
  // existing code, after render
  this.form = this.closest('form');

  if (this.form) {
    this.form.addEventListener('submit', this.hiddenInput)
  }
}

disconnectedCallback() {
   if (this.form) {
    this.form.removeEventListener('submit', this.hiddenInput)
  }
}
avatar thednp
thednp - comment - 23 Feb 2021

He, it doesn't work because bind. However look what solution I found:

<color-picker<?php echo $format; ?>>
<input type="hidden" name="<?php echo $name; ?>" id="<?php echo $id; ?>" value="<?php echo $this->escape($color); ?>"
<?php
	 echo $hint,
		$class,
		$position,
		$control,
		$readonly,
		$disabled,
		$required,
		$onchange,
		$autocomplete,
		$autofocus,
		$format,
		$keywords,
		$direction,
		$validate,
		$dataAttribute;
?>/>
</color-picker>

Then I can just call

updateInputs() {
  this.querySelector('input[type="hidden"]').value = newValue;
}

On form submit I get no error and the proper value coming from the db. Sweet.

I will now cleanup the JS code and commit to my git repo for review. There's a lot of unnecessary code now.

avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko is it possible to set a single <template id="joomla-color-picker"> per document instance? We need a way to set all those labels for lightness, saturation and such.

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

Should be doable (maning I haven't tested it) with something like

$template = '<template id="joomla-color-picker">...</template>';

if (!parent::$cache['some-unique-key-like-joomla-form-filed-template']) {
  echo $template;
  parent::$cache['some-unique-key-like-joomla-form-filed-template'] = true;
}

// The rest of the layout output
avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko what about creating a script that does that, with data fed via PHP? That method looks weird to me.

Update: disregard that, I'm lookin at core fields that use custom elements.

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

Update: disregard that, I'm lookin at core fields that use custom elements.

There's a fundamental difference here, this component is using Shadow Dom, the rest of the fields are all just custom elements (no shadow dom)

avatar thednp
thednp - comment - 23 Feb 2021

Correct, however, there's no need to create a unique template for each Document instance, nobody (in the DOM tree) complain, I'm just gonna populate the shadowRoot with a template defined inside the <color-picker> element.

avatar thednp
thednp - comment - 23 Feb 2021

@dgrammatiko sorry to bother again. Can Joomla form read input fields from inside shadowRoot?

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

No, also not a Joomla problem it's a limitation of web components used with posting forms (the ancient way), read my comment here: #32494 (comment) I already gave you the answer there

avatar thednp
thednp - comment - 23 Feb 2021

In that case, I'm going to do as explained here and it doesn't need that part

avatar dgrammatiko
dgrammatiko - comment - 23 Feb 2021

tbh I can't follow without seeing the actual code

avatar thednp
thednp - comment - 23 Feb 2021

I'm going to add a hidden input as the one that Joomla actually checks, and I'm going to update it with every color-picker change.

Im going to use template for the color picker form [hue, saturation, red] etc labels and other probably ARIA stuff.

When I'm done I'm gonna let you know.

avatar thednp
thednp - comment - 24 Feb 2021

@dgrammatiko I'm looking at the language files and I see JFIELD_COLOR_VALUE in 3 separate files

  • administrator/language/en-GB/joomla.ini;
  • language/en-GB/joomla.ini;
  • api/language/en-GB/joomla.ini.

Which one is it or all of them? My guess: the first two.

avatar dgrammatiko
dgrammatiko - comment - 24 Feb 2021

All of them ,althought I have no clue why the api has the same strings as the others, probably you can skip this one

avatar brianteeman
brianteeman - comment - 24 Feb 2021

For now all three of those should ideally be in sync with each other

avatar thednp
thednp - comment - 24 Feb 2021

Roger that.

avatar thednp
thednp - comment - 24 Feb 2021

Quick update:

joomla-color-picker-preview

Cleaning up code.

avatar dgrammatiko
dgrammatiko - comment - 24 Feb 2021

@thednp one thing as I was reading the code agian, the format could be any of ['rgb', 'hsl', 'hex', 'rgba', 'hsla', 'hexa'] meaning the alpha is dictated by the dev, not up to the user. Also we're missing the none and transparent values for the non alpha modes

avatar thednp
thednp - comment - 24 Feb 2021

@thednp one thing as I was reading the code agian, the format could be any of ['rgb', 'hsl', 'hex', 'rgba', 'hsla', 'hexa'] meaning the alpha is dictated by the dev, not up to the user. Also we're missing the none and transparent values for the non alpha modes

Most of that is not correct.

  • TinyColor doesn't recognize rgba, hsla formats, in PHP layout I've added stuff like $format = $format === 'rgba' ? 'rgb' : $format; also, when the extension developer sets format to something else than rgb, hex, hsl, it will default to hex;
  • TinyColor will convert any valid value (transparent, red) on its own to the specified format, except I don't know what will do when format is hex and user sets transparent, it will probably do #000;
  • Also our <color-picker> needs a valid color object from TinyColor to update its inputs and render the canvas elements.

The extension developer will set navyblue as default value for instance and TinyColor will do its thing on render.

avatar thednp
thednp - comment - 24 Feb 2021

@dgrammatiko

I can confirm: when format is set to hex the user input or default value set by extension developer of transparent become #000.

Basically you will never be able to add an invalid color value to the db.

avatar dgrammatiko
dgrammatiko - comment - 24 Feb 2021

once AGAIN: none and transparent are valid CSS colour values. If the current code disrepects that it's not an excuse to continue in the wrong path. Anyways my 2c

avatar thednp
thednp - comment - 24 Feb 2021

In my opinion that's not a problem. Here 2 strong args:

  • Devs can set a type="Color" field with control="advanced" and showon linked to another option that sets none OR custom (here the color picker kicks in)
  • In Bootstrap, if you set $primary: none;, it will mess up all possible calculations for its components; it will probably never compile something like darken('none',15%).

Chill out.

avatar dgrammatiko
dgrammatiko - comment - 24 Feb 2021

Devs can set a color-picker field with showon linked to another option that sets none OR custom (here the color picker kicks in)

Telling devs to do workarounds is not an argument

In Bootstrap...

I'm not relegious about Bootstrap or any other CSS framework, all of them have there own caveats. The thing here is that you point out what SASS/Bootstrap is doing but I'm raising an issue about the accepable values according to CSS working draft: https://drafts.csswg.org/css-color-4/#resolving-other-colors (and actually I got the none wrong, it's not a valid value). To recap: amongst the acceptable values are inherit, transparent and currentcolor and saying that devs need to do hacks to get these values seems to me weird and not so helpful. Also code wise all you have to do is append 3 buttons that set directly the value to these strings and have a simple conditional when getting the value from the attribute (maybe have a second this.finalValue indipendent of the tinycolor and for these cases initialise the tinycolor with #000 so nothing breaks.)

Finally opinios are fine but at the end of the day as web devs we're coding against the platform standards so your or my opinion is kinda irrelevant, it's what the specs dictate...

avatar thednp
thednp - comment - 24 Feb 2021

@dgrammatiko you're point is taken. This is what a color picker is supposed to do: get you a color from the entire rainbow. You want me to change TinyColor or adapt our color-picker to work with inherit, transparent and currentColor? I'm fine with either at this point.

I don't see the original advanced layout to say anything about these. Does the $keywords have anything to do with this?

BTW the none value is valid for props like background (or background-image) or display, not color or background-color.

I think you don't get it this time around. I'm not trying to find excuses, I'm pointing out the facts of a color picker. Nothing more or less. I also don't back down from a little more work.

In my templates if I set a color picker, I explicitly want my user to set a color because I want the compilers happy and layouts and color contrasts as I designed them to.

avatar thednp
thednp - comment - 24 Feb 2021

@dgrammatiko I can't create pull request to 4.0-dev

Can’t automatically merge. Don’t worry, you can still create the pull request.

... disregard that, solved partly.

avatar Quy Quy - change - 26 Feb 2021
Status New Closed
Closed_Date 0000-00-00 00:00:00 2021-02-26 14:58:01
Closed_By Quy
avatar Quy Quy - close - 26 Feb 2021
avatar Quy
Quy - comment - 26 Feb 2021

Closing per PR #32510. Thanks.

Add a Comment

Login with GitHub to post a comment