ExamplesPlaygroundReference Source

coral-spectrum/coral-component-colorinput/src/scripts/ColorInputColorProperties.js

  1. /**
  2. * Copyright 2019 Adobe. All rights reserved.
  3. * This file is licensed to you under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License. You may obtain a copy
  5. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. *
  7. * Unless required by applicable law or agreed to in writing, software distributed under
  8. * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
  9. * OF ANY KIND, either express or implied. See the License for the specific language
  10. * governing permissions and limitations under the License.
  11. */
  12.  
  13. import {BaseComponent} from '../../../coral-base-component';
  14. import BaseColorInputAbstractSubview from './BaseColorInputAbstractSubview';
  15. import Color from './Color';
  16. import '../../../coral-component-button';
  17. import '../../../coral-component-textfield';
  18. import './ColorInputSlider';
  19. import propertiesSubview from '../templates/colorProperties';
  20. import {commons, i18n} from '../../../coral-utils';
  21. import {Decorator} from '../../../coral-decorator';
  22.  
  23. const CLASSNAME = '_coral-ColorInput-colorProperties';
  24.  
  25. /**
  26. @class Coral.ColorInput.ColorProperties
  27. @classdesc A ColorInput Color properties component
  28. @htmltag coral-colorinput-colorproperties
  29. @extends {HTMLElement}
  30. @extends {BaseComponent}
  31. @extends {BaseColorInputAbstractSubview}
  32. */
  33. const ColorInputColorProperties = Decorator(class extends BaseColorInputAbstractSubview(BaseComponent(HTMLElement)) {
  34. /** @ignore */
  35. constructor() {
  36. super();
  37.  
  38. this._delegateEvents(commons.extend(this._events, {
  39. 'change [handle="redSlider"]': '_onRedSliderChange',
  40. 'change [handle="greenSlider"]': '_onGreenSliderChange',
  41. 'change [handle="blueSlider"]': '_onBlueSliderChange',
  42. 'change [handle="alphaSlider"]': '_onAlphaSliderChange',
  43. 'change ._coral-ColorInput-editHex': '_onChangeHex',
  44. 'change ._coral-ColorInput-editRgba': '_onChangeRgba'
  45. }));
  46.  
  47. // Templates
  48. this._elements = {};
  49. propertiesSubview.call(this._elements, {commons, i18n});
  50. }
  51.  
  52. /** @ignore */
  53. _onColorInputChange() {
  54. const newColor = this._colorinput.valueAsColor;
  55. const colorPreview = this._elements.colorPreview2;
  56. let rgba;
  57.  
  58. if (!newColor) {
  59. // update the colorPreview background color, state, and label
  60. colorPreview.setAttribute('aria-pressed', 'true');
  61. colorPreview.setAttribute('aria-label', i18n.get('Color not set'));
  62.  
  63. // reset Hex value to empty
  64. this._elements.hexInput.value = '';
  65. } else {
  66. rgba = newColor.rgba;
  67.  
  68. // update the colorPreview background color, state, and label
  69. colorPreview.style.backgroundColor = newColor.rgbValue;
  70. colorPreview.setAttribute('aria-pressed', 'false');
  71. colorPreview.setAttribute('aria-label', i18n.get('{value}, Color', {
  72. value: parseFloat(rgba.a) === 1 ? newColor.value : newColor.rgbaValue
  73. }));
  74.  
  75. // update the Hex input value
  76. this._elements.hexInput.value = newColor.hexValue.substr(1);
  77. }
  78.  
  79. const prefixes = ['red', 'green', 'blue', 'alpha'];
  80. const prefixesLength = prefixes.length;
  81. let prefix;
  82. let abbr;
  83. let isAlpha;
  84. let val;
  85.  
  86. // update rgba slider and input values
  87. for (let i = 0 ; i < prefixesLength ; i++) {
  88. prefix = prefixes[i];
  89. abbr = prefix.substr(0, 1);
  90. isAlpha = i === prefixesLength - 1;
  91.  
  92. // default slider and input value
  93. val = isAlpha ? 100 : 127;
  94.  
  95. // with new color, get appropriate RGBA value
  96. if (newColor) {
  97. if (!rgba) {
  98. val = '';
  99. } else if (isAlpha) {
  100. val = parseInt(rgba[abbr] * 100, 10);
  101. } else {
  102. val = rgba[abbr];
  103. }
  104. }
  105.  
  106. // update the slider and input values
  107. this._elements[`${prefix}Slider`].value = this._elements[`${prefix}Input`].value = val;
  108. }
  109.  
  110. if (colorPreview === document.activeElement) {
  111. // force blur and focus on colorButton so that new color or state is announced
  112. colorPreview.blur();
  113.  
  114. // delay focus by 100ms so that screen reader has time to adjust to label with updated color value
  115. window.setTimeout(() => {
  116. colorPreview.focus();
  117. }, 100);
  118. }
  119. }
  120.  
  121. /** @ignore */
  122. _onRedSliderChange(event) {
  123. this._elements.redInput.value = this._elements.redSlider.value;
  124. this._onChangeRgba(event);
  125. }
  126.  
  127. /** @ignore */
  128. _onGreenSliderChange(event) {
  129. this._elements.greenInput.value = this._elements.greenSlider.value;
  130. this._onChangeRgba(event);
  131. }
  132.  
  133. /** @ignore */
  134. _onBlueSliderChange(event) {
  135. this._elements.blueInput.value = this._elements.blueSlider.value;
  136. this._onChangeRgba(event);
  137. }
  138.  
  139. /** @ignore */
  140. _onAlphaSliderChange(event) {
  141. this._elements.alphaInput.value = this._elements.alphaSlider.value;
  142. this._onChangeRgba(event);
  143. }
  144.  
  145. /** @ignore */
  146. _onChangeHex(event) {
  147. event.stopPropagation();
  148.  
  149. // Value of hexInput field is without '#'.
  150. const value = `#${this._elements.hexInput.value}`;
  151. const color = new Color();
  152. color.value = value;
  153.  
  154. if (color.hex === null) {
  155. // no valid color value
  156. this._elements.hexInput.value = '';
  157. // Save last valid color
  158. if (this._colorinput.valueAsColor !== null) {
  159. this.constructor._lastValidColor = this._colorinput.valueAsColor;
  160. }
  161. this._colorinput._setActiveColor(null);
  162. } else {
  163. this._colorinput._setActiveColor(color);
  164. }
  165. }
  166.  
  167. /** @ignore */
  168. _onChangeRgba(event) {
  169. event.stopPropagation();
  170.  
  171. const r = parseInt(this._elements.redInput.value, 10);
  172. const g = parseInt(this._elements.greenInput.value, 10);
  173. const b = parseInt(this._elements.blueInput.value, 10);
  174. const a = parseInt(this._elements.alphaInput.value, 10);
  175.  
  176. let colorValid = true;
  177. if (isNaN(r) || r < 0 || r > 255) {
  178. colorValid = false;
  179. this._elements.redInput.value = '';
  180. }
  181.  
  182. if (isNaN(g) || g < 0 || g > 255) {
  183. colorValid = false;
  184. this._elements.greenInput.value = '';
  185. }
  186.  
  187. if (isNaN(b) || b < 0 || b > 255) {
  188. colorValid = false;
  189. this._elements.blueInput.value = '';
  190. }
  191.  
  192. if (isNaN(a) || a < 0 || a > 100) {
  193. colorValid = false;
  194. this._elements.alphaInput.value = '';
  195. }
  196.  
  197. if (colorValid) {
  198. const color = new Color();
  199. color.rgba = {
  200. r: r,
  201. g: g,
  202. b: b,
  203. a: a / 100
  204. };
  205. this._colorinput._setActiveColor(color);
  206. }
  207. }
  208.  
  209. /** @ignore */
  210. render() {
  211. super.render();
  212.  
  213. this.classList.add(CLASSNAME);
  214.  
  215. // Support cloneNode
  216. const subview = this.querySelector('._coral-ColorInput-propertiesSubview');
  217. if (subview) {
  218. subview.remove();
  219. }
  220.  
  221. this.appendChild(this._elements.propertiesSubview);
  222. }
  223. });
  224.  
  225. export default ColorInputColorProperties;