tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit bb5b4322e10ab27810d333e7a152e75ec4c47a97
parent c8778fb3b8da1d2102029a4b1c95456319c7c107
Author: Sandor Molnar <smolnar@mozilla.com>
Date:   Fri, 19 Dec 2025 12:20:52 +0200

Revert "Bug 2000644 - Introduce a superclass of color picker to prepare for multiple subclasses r=devtools-reviewers,nchevobbe,desktop-theme-reviewers,frontend-codestyle-reviewers,hjones" for causing mochitest failures

This reverts commit 2c7d7e1bba19205d56a8105035c966581b4eb1e2.

Diffstat:
M.stylelintrc.js | 1-
Mdevtools/client/shared/widgets/Spectrum.js | 355++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mdevtools/client/shared/widgets/spectrum.css | 178++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mdevtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js | 3+++
Mtoolkit/content/jar.mn | 1-
Dtoolkit/content/widgets/colorpicker-common.mjs | 371-------------------------------------------------------------------------------
Dtoolkit/themes/shared/colorpicker-common.css | 183-------------------------------------------------------------------------------
Mtoolkit/themes/shared/desktop-jar.inc.mn | 1-
8 files changed, 522 insertions(+), 571 deletions(-)

diff --git a/.stylelintrc.js b/.stylelintrc.js @@ -421,7 +421,6 @@ module.exports = { // Testing does not use design tokens "testing/**", // UA Widgets should not use design tokens - "toolkit/themes/shared/colorpicker-common.css", "toolkit/themes/shared/media/pipToggle.css", "toolkit/themes/shared/media/videocontrols.css", "toolkit/content/widgets/datetimebox.css", diff --git a/devtools/client/shared/widgets/Spectrum.js b/devtools/client/shared/widgets/Spectrum.js @@ -4,10 +4,6 @@ "use strict"; -const { ColorPickerCommon } = ChromeUtils.importESModule( - "chrome://global/content/bindings/colorpicker-common.mjs" -); - const EventEmitter = require("resource://devtools/shared/event-emitter.js"); const { MultiLocalizationHelper, @@ -27,7 +23,21 @@ const L10N = new MultiLocalizationHelper( "devtools/client/locales/accessibility.properties", "devtools/client/locales/inspector.properties" ); +const ARROW_KEYS = ["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"]; +const [ArrowUp, ArrowRight, ArrowDown, ArrowLeft] = ARROW_KEYS; const XHTML_NS = "http://www.w3.org/1999/xhtml"; +const SLIDER = { + hue: { + MIN: "0", + MAX: "128", + STEP: "1", + }, + alpha: { + MIN: "0", + MAX: "1", + STEP: "0.01", + }, +}; /** * Spectrum creates a color picker widget in any container you give it. @@ -52,15 +62,22 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml"; * Fires the following events: * - changed : When the user changes the current color */ -class Spectrum extends ColorPickerCommon { +class Spectrum { constructor(parentEl, rgb) { - const element = parentEl.ownerDocument.createElement("div"); + EventEmitter.decorate(this); + + this.document = parentEl.ownerDocument; + this.element = parentEl.ownerDocument.createElementNS(XHTML_NS, "div"); + this.parentEl = parentEl; + + this.element.className = "spectrum-container"; // eslint-disable-next-line no-unsanitized/property - element.innerHTML = ` + this.element.innerHTML = ` <section class="spectrum-color-picker"> <div class="spectrum-color spectrum-box" tabindex="0" role="slider" + title="${ColorPickerBundle.formatValueSync("colorpicker-tooltip-spectrum-dragger-title")}" aria-describedby="spectrum-dragger"> <div class="spectrum-sat"> <div class="spectrum-val"> @@ -94,10 +111,20 @@ class Spectrum extends ColorPickerCommon { </div> </section> `; - super(element); - EventEmitter.decorate(this); - parentEl.appendChild(this.element); + this.onElementClick = this.onElementClick.bind(this); + this.element.addEventListener("click", this.onElementClick); + + this.parentEl.appendChild(this.element); + + // Color spectrum dragger. + this.dragger = this.element.querySelector(".spectrum-color"); + this.dragHelper = this.element.querySelector(".spectrum-dragger"); + draggable(this.dragger, this.dragHelper, this.onDraggerMove.bind(this)); + + // Here we define the components for the "controls" section of the color picker. + this.controls = this.element.querySelector(".spectrum-controls"); + this.colorPreview = this.element.querySelector(".spectrum-color-preview"); // Create the eyedropper. const eyedropper = this.document.createElementNS(XHTML_NS, "button"); @@ -110,6 +137,14 @@ class Spectrum extends ColorPickerCommon { ); this.controls.insertBefore(eyedropper, this.colorPreview); + // Hue slider and alpha slider + this.hueSlider = this.createSlider("hue", this.onHueSliderMove.bind(this)); + this.hueSlider.setAttribute("aria-describedby", this.dragHelper.id); + this.alphaSlider = this.createSlider( + "alpha", + this.onAlphaSliderMove.bind(this) + ); + // Color contrast this.spectrumContrast = this.element.querySelector( ".spectrum-color-contrast" @@ -143,6 +178,11 @@ class Spectrum extends ColorPickerCommon { : null; } + /** @param {[number, number, number, number]} color */ + set rgb([r, g, b, a]) { + this.hsv = [...InspectorUtils.rgbToHsv(r / 255, g / 255, b / 255), a]; + } + set backgroundColorData(colorData) { this._backgroundColorData = colorData; } @@ -155,11 +195,117 @@ class Spectrum extends ColorPickerCommon { return this._textProps; } + #toRgbInt(rgbFloat) { + return rgbFloat.map(c => Math.round(c * 255)); + } + + get rgbFloat() { + const [h, s, v, a] = this.hsv; + return [...InspectorUtils.hsvToRgb(h, s, v), a]; + } + + get rgb() { + const [r, g, b, a] = this.rgbFloat; + return [...this.#toRgbInt([r, g, b]), a]; + } + + /** + * Map current rgb to the closest color available in the database by + * calculating the delta-E between each available color and the current rgb + * + * @return {string} + * Color name or closest color name + */ + get colorName() { + const [r, g, b] = this.rgbFloat; + const { exact, colorName } = InspectorUtils.rgbToNearestColorName(r, g, b); + return exact + ? colorName + : ColorPickerBundle.formatValueSync( + "colorpicker-tooltip-color-name-title", + { colorName } + ); + } + + get rgbNoSatVal() { + return [ + ...this.#toRgbInt(InspectorUtils.hsvToRgb(this.hsv[0], 1, 1)), + this.hsv[3], + ]; + } + + get rgbCssString() { + const rgb = this.rgb; + return ( + "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " + rgb[3] + ")" + ); + } + + show() { + this.dragWidth = this.dragger.offsetWidth; + this.dragHeight = this.dragger.offsetHeight; + this.dragHelperHeight = this.dragHelper.offsetHeight; + + this.updateUI(); + } + + onElementClick(e) { + e.stopPropagation(); + } + + onHueSliderMove() { + this.hsv[0] = this.hueSlider.value / this.hueSlider.max; + this.updateUI(); + this.onChange(); + } + + onDraggerMove(dragX, dragY) { + this.hsv[1] = dragX / this.dragWidth; + this.hsv[2] = (this.dragHeight - dragY) / this.dragHeight; + this.updateUI(); + this.onChange(); + } + + onAlphaSliderMove() { + this.hsv[3] = this.alphaSlider.value / this.alphaSlider.max; + this.updateUI(); + this.onChange(); + } + onChange() { this.emit("changed", this.rgb, this.rgbCssString); } /** + * Creates and initializes a slider element, attaches it to its parent container + * based on the slider type and returns it + * + * @param {string} sliderType + * The type of the slider (i.e. alpha or hue) + * @param {Function} onSliderMove + * The function to tie the slider to on input + * @return {DOMNode} + * Newly created slider + */ + createSlider(sliderType, onSliderMove) { + const container = this.element.querySelector(`.spectrum-${sliderType}`); + + const slider = this.document.createElementNS(XHTML_NS, "input"); + slider.className = `spectrum-${sliderType}-input`; + slider.type = "range"; + slider.min = SLIDER[sliderType].MIN; + slider.max = SLIDER[sliderType].MAX; + slider.step = SLIDER[sliderType].STEP; + slider.title = ColorPickerBundle.formatValueSync( + `colorpicker-tooltip-${sliderType}-slider-title` + ); + slider.addEventListener("input", onSliderMove); + + container.appendChild(slider); + return slider; + } + + /** * Updates the contrast label with appropriate content (i.e. large text indicator * if the contrast is calculated for large text, or a base label otherwise) * @@ -228,6 +374,81 @@ class Spectrum extends ColorPickerCommon { ); } + updateAlphaSlider() { + // Set alpha slider background + const rgb = this.rgb; + + const rgbNoAlpha = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")"; + const rgbAlpha0 = "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ", 0)"; + const alphaGradient = + "linear-gradient(to right, " + rgbAlpha0 + ", " + rgbNoAlpha + ")"; + this.alphaSlider.style.background = alphaGradient; + } + + updateColorPreview() { + // Overlay the rgba color over a checkered image background. + this.colorPreview.style.setProperty("--overlay-color", this.rgbCssString); + + // We should be able to distinguish the color preview on high luminance rgba values. + // Give the color preview a light grey border if the luminance of the current rgba + // tuple is great. + const colorLuminance = InspectorUtils.relativeLuminance(...this.rgbFloat); + this.colorPreview.classList.toggle("high-luminance", colorLuminance > 0.85); + + // Set title on color preview for better UX + this.colorPreview.title = this.colorName; + } + + updateDragger() { + // Set dragger background color + const flatColor = + "rgb(" + + this.rgbNoSatVal[0] + + ", " + + this.rgbNoSatVal[1] + + ", " + + this.rgbNoSatVal[2] + + ")"; + this.dragger.style.backgroundColor = flatColor; + + // Set dragger aria attributes + this.dragger.setAttribute("aria-valuetext", this.rgbCssString); + } + + updateHueSlider() { + // Set hue slider aria attributes + this.hueSlider.setAttribute("aria-valuetext", this.rgbCssString); + } + + updateHelperLocations() { + const h = this.hsv[0]; + const s = this.hsv[1]; + const v = this.hsv[2]; + + // Placing the color dragger + let dragX = s * this.dragWidth; + let dragY = this.dragHeight - v * this.dragHeight; + const helperDim = this.dragHelperHeight / 2; + + dragX = Math.max( + -helperDim, + Math.min(this.dragWidth - helperDim, dragX - helperDim) + ); + dragY = Math.max( + -helperDim, + Math.min(this.dragHeight - helperDim, dragY - helperDim) + ); + + this.dragHelper.style.top = dragY + "px"; + this.dragHelper.style.left = dragX + "px"; + + // Placing the hue slider + this.hueSlider.value = h * this.hueSlider.max; + + // Placing the alpha slider + this.alphaSlider.value = this.hsv[3] * this.alphaSlider.max; + } + /* Calculates the contrast ratio for the currently selected * color against a single or range of background colors and displays contrast ratio section * components depending on the contrast ratio calculated. @@ -324,18 +545,128 @@ class Spectrum extends ColorPickerCommon { } updateUI() { - super.updateUI(); + this.updateHelperLocations(); + + this.updateColorPreview(); + this.updateDragger(); + this.updateHueSlider(); + this.updateAlphaSlider(); this.updateContrast(); } destroy() { - super.destroy(); + this.element.removeEventListener("click", this.onElementClick); + this.hueSlider.removeEventListener("input", this.onHueSliderMove); + this.alphaSlider.removeEventListener("input", this.onAlphaSliderMove); + + this.parentEl.removeChild(this.element); + + this.dragger = this.dragHelper = null; + this.alphaSlider = null; + this.hueSlider = null; + this.colorPreview = null; + this.element = null; + this.parentEl = null; this.spectrumContrast = null; this.contrastValue = this.contrastValueMin = this.contrastValueMax = null; this.contrastLabel = null; } } +function draggable(element, dragHelper, onmove) { + onmove = onmove || function () {}; + + const doc = element.ownerDocument; + let dragging = false; + let offset = {}; + let maxHeight = 0; + let maxWidth = 0; + + function setDraggerDimensionsAndOffset() { + maxHeight = element.offsetHeight; + maxWidth = element.offsetWidth; + offset = element.getBoundingClientRect(); + } + + function prevent(e) { + e.stopPropagation(); + e.preventDefault(); + } + + function move(e) { + if (dragging) { + if (e.buttons === 0) { + // The button is no longer pressed but we did not get a mouseup event. + stop(); + return; + } + const pageX = e.pageX; + const pageY = e.pageY; + + const dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); + const dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); + + onmove.apply(element, [dragX, dragY]); + } + } + + function start(e) { + const rightClick = e.which === 3; + + if (!rightClick && !dragging) { + dragging = true; + setDraggerDimensionsAndOffset(); + + move(e); + + doc.addEventListener("selectstart", prevent); + doc.addEventListener("dragstart", prevent); + doc.addEventListener("mousemove", move); + doc.addEventListener("mouseup", stop); + + prevent(e); + } + } + + function stop() { + if (dragging) { + doc.removeEventListener("selectstart", prevent); + doc.removeEventListener("dragstart", prevent); + doc.removeEventListener("mousemove", move); + doc.removeEventListener("mouseup", stop); + } + dragging = false; + } + + function onKeydown(e) { + const { key } = e; + + if (!ARROW_KEYS.includes(key)) { + return; + } + + setDraggerDimensionsAndOffset(); + const { offsetHeight, offsetTop, offsetLeft } = dragHelper; + let dragX = offsetLeft + offsetHeight / 2; + let dragY = offsetTop + offsetHeight / 2; + + if (key === ArrowLeft && dragX > 0) { + dragX -= 1; + } else if (key === ArrowRight && dragX < maxWidth) { + dragX += 1; + } else if (key === ArrowUp && dragY > 0) { + dragY -= 1; + } else if (key === ArrowDown && dragY < maxHeight) { + dragY += 1; + } + + onmove.apply(element, [dragX, dragY]); + } + + element.addEventListener("mousedown", start); + element.addEventListener("keydown", onKeydown); +} + /** * Calculates the contrast ratio for a DOM node's computed style against * a given background. diff --git a/devtools/client/shared/widgets/spectrum.css b/devtools/client/shared/widgets/spectrum.css @@ -2,8 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -@import "chrome://global/skin/colorpicker-common.css"; - :root { --accessibility-contrast-swatch-border-color: var(--grey-40); --learn-more-underline: light-dark(var(--grey-30), var(--grey-50)); @@ -29,10 +27,45 @@ /* Mix-in classes */ +.spectrum-checker { + background-color: #eee; + background-image: + linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc), + linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc); + background-size: 12px 12px; + background-position: + 0 0, + 6px 6px; + /* Make sure that the background color is properly set in High Contrast Mode */ + forced-color-adjust: none; +} + +.spectrum-box { + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 2px; + background-clip: content-box; + + :root[forced-colors-active] & { + border-color: initial; + } +} + +/* Elements */ + #spectrum-tooltip { padding: 5px; } +/** + * Spectrum controls set the layout for the controls section of the color picker. + */ +.spectrum-controls { + display: flex; + justify-content: space-between; + margin-block-start: 10px; + margin-inline-end: 5px; +} + .spectrum-controls { width: 200px; } @@ -44,6 +77,147 @@ padding-block-end: 6px; } +/** + * This styles the color preview and adds a checkered background overlay inside of it. The overlay + * can be manipulated using the --overlay-color variable. + */ +.spectrum-color-preview { + --overlay-color: transparent; + border: 1px solid transparent; + border-radius: 50%; + width: 27px; + height: 27px; + background-color: #fff; + background-image: + linear-gradient(var(--overlay-color), var(--overlay-color)), linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%), + linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%); + background-size: 12px 12px; + background-position: + 0 0, + 6px 6px; + /* Make sure that the background color is properly set in High Contrast Mode */ + forced-color-adjust: none; + + :root[forced-colors-active] & { + border-color: CanvasText; + } +} + +.spectrum-color-preview.high-luminance { + border-color: #ccc; +} + +.spectrum-slider-container { + display: flex; + flex-direction: column; + justify-content: space-around; + width: 130px; + margin-inline-start: 10px; + height: 30px; +} + +/* Keep aspect ratio: +http://www.briangrinstead.com/blog/keep-aspect-ratio-with-html-and-css */ +.spectrum-color-picker { + position: relative; + width: 205px; + height: 120px; + /* Make sure that the background color is properly set in High Contrast Mode */ + forced-color-adjust: none; +} + +.spectrum-color { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 100%; +} + +.spectrum-sat, +.spectrum-val { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.spectrum-alpha { + margin-block-start: 3px; +} + +.spectrum-alpha, +.spectrum-hue { + position: relative; + height: 8px; +} + +.spectrum-alpha-input, +.spectrum-hue-input { + width: 100%; + margin: 0; + position: absolute; + height: 8px; + border-radius: 2px; + direction: initial; +} + +.spectrum-hue-input, +.spectrum-alpha-input { + outline-offset: 4px; +} + +.spectrum-hue-input::-moz-range-thumb, +.spectrum-alpha-input::-moz-range-thumb { + cursor: pointer; + height: 12px; + width: 12px; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); + background: #fff; + border-radius: 50%; + opacity: 0.9; + border: none; +} + +:root[forced-colors-active] :is(.spectrum-hue-input, .spectrum-alpha-input)::-moz-range-thumb { + background: ButtonFace; + border: 2px solid ButtonText; +} + +:root[forced-colors-active] :is(.spectrum-hue-input, .spectrum-alpha-input):is(:hover, :focus-visible)::-moz-range-thumb { + border-color: SelectedItem; +} + +.spectrum-hue-input::-moz-range-track { + border-radius: 2px; + height: 8px; + background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + /* Make sure that the background color is properly set in High Contrast Mode */ + forced-color-adjust: none; +} + +.spectrum-sat { + background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); +} + +.spectrum-val { + background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0)); +} + +.spectrum-dragger { + user-select: none; + position: absolute; + top: 0; + left: 0; + cursor: pointer; + border-radius: 50%; + height: 8px; + width: 8px; + border: 1px solid white; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); +} + .spectrum-color-contrast { padding-block-start: 8px; padding-inline-start: 4px; diff --git a/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js b/devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip.js @@ -189,6 +189,9 @@ class SwatchColorPickerTooltip extends SwatchBasedEditorTooltip { learnMoreButton.addEventListener("keydown", e => e.stopPropagation()); } + // Add focus to the first focusable element in the tooltip and attach keydown + // event listener to tooltip + this.focusableElements[0].focus(); this.tooltip.container.addEventListener( "keydown", this._onTooltipKeydown, diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn @@ -77,7 +77,6 @@ toolkit.jar: #endif content/global/widgets.css content/global/bindings/calendar.js (widgets/calendar.js) - content/global/bindings/colorpicker-common.mjs (widgets/colorpicker-common.mjs) content/global/bindings/datekeeper.js (widgets/datekeeper.js) content/global/bindings/datepicker.js (widgets/datepicker.js) content/global/bindings/datetimebox.css (widgets/datetimebox.css) diff --git a/toolkit/content/widgets/colorpicker-common.mjs b/toolkit/content/widgets/colorpicker-common.mjs @@ -1,371 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// @ts-nocheck Do this after migration from devtools - -const lazy = {}; -ChromeUtils.defineLazyGetter(lazy, "l10n", function () { - return new Localization(["devtools/client/inspector.ftl"], true); -}); - -const ARROW_KEYS = ["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"]; -const [ArrowUp, ArrowRight, ArrowDown, ArrowLeft] = ARROW_KEYS; -const SLIDER = { - hue: { - MIN: "0", - MAX: "128", - STEP: "1", - }, - alpha: { - MIN: "0", - MAX: "1", - STEP: "0.01", - }, -}; - -/** - * ColorPickerCommon creates a color picker widget in a container you give it. - */ -export class ColorPickerCommon { - constructor(element) { - this.document = element.ownerDocument; - this.element = element; - - this.element.className = "spectrum-container"; - - this.onElementClick = this.onElementClick.bind(this); - this.element.addEventListener("click", this.onElementClick); - - // Color spectrum dragger. - this.dragger = this.element.querySelector(".spectrum-color"); - this.dragger.title = lazy.l10n.formatValueSync( - "colorpicker-tooltip-spectrum-dragger-title" - ); - - this.dragHelper = this.element.querySelector(".spectrum-dragger"); - draggable(this.dragger, this.dragHelper, this.onDraggerMove.bind(this)); - - // Here we define the components for the "controls" section of the color picker. - this.controls = this.element.querySelector(".spectrum-controls"); - this.colorPreview = this.element.querySelector(".spectrum-color-preview"); - - // Hue slider and alpha slider - this.hueSlider = this.createSlider("hue", this.onHueSliderMove.bind(this)); - this.hueSlider.setAttribute("aria-describedby", this.dragHelper.id); - this.alphaSlider = this.createSlider( - "alpha", - this.onAlphaSliderMove.bind(this) - ); - } - - /** @param {[number, number, number, number]} color */ - set rgb([r, g, b, a]) { - this.rgbFloat = [r / 255, g / 255, b / 255, a]; - } - - /** @param {[number, number, number, number]} color */ - set rgbFloat([r, g, b, a]) { - this.hsv = [...InspectorUtils.rgbToHsv(r, g, b), a]; - } - - #toRgbInt(rgbFloat) { - return rgbFloat.map(c => Math.round(c * 255)); - } - - get rgbFloat() { - const [h, s, v, a] = this.hsv; - return [...InspectorUtils.hsvToRgb(h, s, v), a]; - } - - get rgb() { - const [r, g, b, a] = this.rgbFloat; - return [...this.#toRgbInt([r, g, b]), a]; - } - - /** - * Map current rgb to the closest color available in the database by - * calculating the delta-E between each available color and the current rgb - * - * @return {string} - * Color name or closest color name - */ - get colorName() { - const [r, g, b] = this.rgbFloat; - const { exact, colorName } = InspectorUtils.rgbToNearestColorName(r, g, b); - return exact - ? colorName - : lazy.l10n.formatValueSync("colorpicker-tooltip-color-name-title", { - colorName, - }); - } - - get rgbNoSatVal() { - return [ - ...this.#toRgbInt(InspectorUtils.hsvToRgb(this.hsv[0], 1, 1)), - this.hsv[3], - ]; - } - - get rgbCssString() { - const rgb = this.rgb; - return ( - "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " + rgb[3] + ")" - ); - } - - show() { - this.dragWidth = this.dragger.offsetWidth; - this.dragHeight = this.dragger.offsetHeight; - this.dragHelperHeight = this.dragHelper.offsetHeight; - this.dragger.focus({ focusVisible: false }); - - this.updateUI(); - } - - onElementClick(e) { - e.stopPropagation(); - } - - onHueSliderMove() { - this.hsv[0] = this.hueSlider.value / this.hueSlider.max; - this.updateUI(); - this.onChange(); - } - - onDraggerMove(dragX, dragY) { - this.hsv[1] = dragX / this.dragWidth; - this.hsv[2] = (this.dragHeight - dragY) / this.dragHeight; - this.updateUI(); - this.onChange(); - } - - onAlphaSliderMove() { - this.hsv[3] = this.alphaSlider.value / this.alphaSlider.max; - this.updateUI(); - this.onChange(); - } - - onChange() { - throw new Error("Not implemented"); - } - - /** - * Creates and initializes a slider element, attaches it to its parent container - * based on the slider type and returns it - * - * @param {"alpha" | "hue"} sliderType - * The type of the slider (i.e. alpha or hue) - * @param {Function} onSliderMove - * The function to tie the slider to on input - * @return {HTMLInputElement} - * Newly created slider - */ - createSlider(sliderType, onSliderMove) { - const container = this.element.querySelector(`.spectrum-${sliderType}`); - - const slider = this.document.createElement("input"); - slider.className = `spectrum-${sliderType}-input`; - slider.type = "range"; - slider.min = SLIDER[sliderType].MIN; - slider.max = SLIDER[sliderType].MAX; - slider.step = SLIDER[sliderType].STEP; - slider.title = lazy.l10n.formatValueSync( - `colorpicker-tooltip-${sliderType}-slider-title` - ); - slider.addEventListener("input", onSliderMove); - - container.appendChild(slider); - return slider; - } - - updateAlphaSlider() { - // Set alpha slider background - const rgb = this.rgb; - - const rgbNoAlpha = "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")"; - const rgbAlpha0 = "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ", 0)"; - const alphaGradient = - "linear-gradient(to right, " + rgbAlpha0 + ", " + rgbNoAlpha + ")"; - this.alphaSlider.style.background = alphaGradient; - } - - updateColorPreview() { - // Overlay the rgba color over a checkered image background. - this.colorPreview.style.setProperty("--overlay-color", this.rgbCssString); - - // We should be able to distinguish the color preview on high luminance rgba values. - // Give the color preview a light grey border if the luminance of the current rgba - // tuple is great. - const colorLuminance = InspectorUtils.relativeLuminance(...this.rgbFloat); - this.colorPreview.classList.toggle("high-luminance", colorLuminance > 0.85); - - // Set title on color preview for better UX - this.colorPreview.title = this.colorName; - } - - updateDragger() { - // Set dragger background color - const flatColor = - "rgb(" + - this.rgbNoSatVal[0] + - ", " + - this.rgbNoSatVal[1] + - ", " + - this.rgbNoSatVal[2] + - ")"; - this.dragger.style.backgroundColor = flatColor; - - // Set dragger aria attributes - this.dragger.setAttribute("aria-valuetext", this.rgbCssString); - } - - updateHueSlider() { - // Set hue slider aria attributes - this.hueSlider.setAttribute("aria-valuetext", this.rgbCssString); - } - - updateHelperLocations() { - const h = this.hsv[0]; - const s = this.hsv[1]; - const v = this.hsv[2]; - - // Placing the color dragger - let dragX = s * this.dragWidth; - let dragY = this.dragHeight - v * this.dragHeight; - const helperDim = this.dragHelperHeight / 2; - - dragX = Math.max( - -helperDim, - Math.min(this.dragWidth - helperDim, dragX - helperDim) - ); - dragY = Math.max( - -helperDim, - Math.min(this.dragHeight - helperDim, dragY - helperDim) - ); - - this.dragHelper.style.top = dragY + "px"; - this.dragHelper.style.left = dragX + "px"; - - // Placing the hue slider - this.hueSlider.value = h * this.hueSlider.max; - - // Placing the alpha slider - this.alphaSlider.value = this.hsv[3] * this.alphaSlider.max; - } - - updateUI() { - this.updateHelperLocations(); - - this.updateColorPreview(); - this.updateDragger(); - this.updateHueSlider(); - this.updateAlphaSlider(); - } - - destroy() { - this.element.removeEventListener("click", this.onElementClick); - this.hueSlider.removeEventListener("input", this.onHueSliderMove); - this.alphaSlider.removeEventListener("input", this.onAlphaSliderMove); - - this.element.remove(); - - this.dragger = this.dragHelper = null; - this.alphaSlider = null; - this.hueSlider = null; - this.colorPreview = null; - this.element = null; - } -} - -function draggable(element, dragHelper, onmove) { - const doc = element.ownerDocument; - let dragging = false; - let offset = {}; - let maxHeight = 0; - let maxWidth = 0; - - function setDraggerDimensionsAndOffset() { - maxHeight = element.offsetHeight; - maxWidth = element.offsetWidth; - offset = element.getBoundingClientRect(); - } - - function prevent(e) { - e.stopPropagation(); - e.preventDefault(); - } - - function move(e) { - if (dragging) { - if (e.buttons === 0) { - // The button is no longer pressed but we did not get a pointerup event. - stop(); - return; - } - const pageX = e.pageX; - const pageY = e.pageY; - - const dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); - const dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); - - onmove.apply(element, [dragX, dragY]); - } - } - - function start(e) { - const rightClick = e.which === 3; - - if (!rightClick && !dragging) { - dragging = true; - setDraggerDimensionsAndOffset(); - - move(e); - - doc.addEventListener("selectstart", prevent); - doc.addEventListener("dragstart", prevent); - doc.addEventListener("mousemove", move); - doc.addEventListener("mouseup", stop); - - prevent(e); - } - } - - function stop() { - if (dragging) { - doc.removeEventListener("selectstart", prevent); - doc.removeEventListener("dragstart", prevent); - doc.removeEventListener("mousemove", move); - doc.removeEventListener("mouseup", stop); - } - dragging = false; - } - - function onKeydown(e) { - const { key } = e; - - if (!ARROW_KEYS.includes(key)) { - return; - } - - setDraggerDimensionsAndOffset(); - const { offsetHeight, offsetTop, offsetLeft } = dragHelper; - let dragX = offsetLeft + offsetHeight / 2; - let dragY = offsetTop + offsetHeight / 2; - - if (key === ArrowLeft && dragX > 0) { - dragX -= 1; - } else if (key === ArrowRight && dragX < maxWidth) { - dragX += 1; - } else if (key === ArrowUp && dragY > 0) { - dragY -= 1; - } else if (key === ArrowDown && dragY < maxHeight) { - dragY += 1; - } - - onmove.apply(element, [dragX, dragY]); - } - - element.addEventListener("mousedown", start); - element.addEventListener("keydown", onKeydown); -} diff --git a/toolkit/themes/shared/colorpicker-common.css b/toolkit/themes/shared/colorpicker-common.css @@ -1,183 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Mix-in classes */ - -.spectrum-checker { - background-color: #eee; - background-image: - linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc), - linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc); - background-size: 12px 12px; - background-position: - 0 0, - 6px 6px; - /* Make sure that the background color is properly set in High Contrast Mode */ - forced-color-adjust: none; -} - -.spectrum-box { - background-clip: content-box; - - :root[forced-colors-active] & { - border-color: initial; - } -} - -/* Elements */ - -/** - * Spectrum controls set the layout for the controls section of the color picker. - */ -.spectrum-controls { - display: flex; - justify-content: space-between; - align-items: center; - margin-block-start: 10px; -} - -/** - * This styles the color preview and adds a checkered background overlay inside of it. The overlay - * can be manipulated using the --overlay-color variable. - */ -.spectrum-color-preview { - --overlay-color: transparent; - border: 1px solid transparent; - border-radius: 50%; - box-sizing: border-box; - width: 25px; - height: 25px; - background-color: #fff; - background-image: - linear-gradient(var(--overlay-color), var(--overlay-color)), linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%), - linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%); - background-size: 12px 12px; - background-position: - 0 0, - 6px 6px; - /* Make sure that the background color is properly set in High Contrast Mode */ - forced-color-adjust: none; - - :root[forced-colors-active] & { - border-color: CanvasText; - } -} - -.spectrum-color-preview.high-luminance { - border-color: #ccc; -} - -.spectrum-slider-container { - display: flex; - flex-direction: column; - justify-content: space-around; - flex: 1; - margin-inline-start: 10px; - height: 30px; -} - -/* Keep aspect ratio: -http://www.briangrinstead.com/blog/keep-aspect-ratio-with-html-and-css */ -.spectrum-color-picker { - position: relative; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 2px; - box-sizing: border-box; - width: 205px; - height: 120px; - /* Make sure that the background color is properly set in High Contrast Mode */ - forced-color-adjust: none; -} - -.spectrum-color { - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 100%; -} - -.spectrum-sat, -.spectrum-val { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} - -.spectrum-alpha { - margin-block-start: 3px; -} - -.spectrum-alpha, -.spectrum-hue { - position: relative; - height: 8px; -} - -.spectrum-alpha-input, -.spectrum-hue-input { - width: 100%; - margin: 0; - position: absolute; - height: 8px; - border-radius: 2px; - direction: initial; -} - -.spectrum-hue-input, -.spectrum-alpha-input { - outline-offset: 4px; -} - -.spectrum-hue-input::-moz-range-thumb, -.spectrum-alpha-input::-moz-range-thumb { - cursor: pointer; - height: 12px; - width: 12px; - box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); - background: #fff; - border-radius: 50%; - opacity: 0.9; - border: none; -} - -:root[forced-colors-active] :is(.spectrum-hue-input, .spectrum-alpha-input)::-moz-range-thumb { - background: ButtonFace; - border: 2px solid ButtonText; -} - -:root[forced-colors-active] :is(.spectrum-hue-input, .spectrum-alpha-input):is(:hover, :focus-visible)::-moz-range-thumb { - border-color: SelectedItem; -} - -.spectrum-hue-input::-moz-range-track { - border-radius: 2px; - height: 8px; - background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); - /* Make sure that the background color is properly set in High Contrast Mode */ - forced-color-adjust: none; -} - -.spectrum-sat { - background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); -} - -.spectrum-val { - background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0)); -} - -.spectrum-dragger { - user-select: none; - position: absolute; - top: 0; - left: 0; - cursor: pointer; - border-radius: 50%; - height: 8px; - width: 8px; - border: 1px solid white; - box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); -} diff --git a/toolkit/themes/shared/desktop-jar.inc.mn b/toolkit/themes/shared/desktop-jar.inc.mn @@ -25,7 +25,6 @@ skin/classic/global/checkbox.css (../../shared/checkbox.css) skin/classic/global/radio.css (../../shared/radio.css) skin/classic/global/close-icon.css (../../shared/close-icon.css) - skin/classic/global/colorpicker-common.css (../../shared/colorpicker-common.css) skin/classic/global/commonDialog.css (../../shared/commonDialog.css) skin/classic/global/datetimeinputpickers.css (../../shared/datetimeinputpickers.css) skin/classic/global/design-system/text-and-typography.css(../../shared/design-system/src/text-and-typography.css)