tor-browser

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

LetterSpacing.js (3521B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  createFactory,
      9  PureComponent,
     10 } = require("resource://devtools/client/shared/vendor/react.mjs");
     11 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     12 
     13 const FontPropertyValue = createFactory(
     14  require("resource://devtools/client/inspector/fonts/components/FontPropertyValue.js")
     15 );
     16 
     17 const {
     18  getStr,
     19 } = require("resource://devtools/client/inspector/fonts/utils/l10n.js");
     20 const {
     21  getUnitFromValue,
     22  getStepForUnit,
     23 } = require("resource://devtools/client/inspector/fonts/utils/font-utils.js");
     24 
     25 class LetterSpacing extends PureComponent {
     26  static get propTypes() {
     27    return {
     28      disabled: PropTypes.bool.isRequired,
     29      onChange: PropTypes.func.isRequired,
     30      value: PropTypes.string.isRequired,
     31    };
     32  }
     33 
     34  constructor(props) {
     35    super(props);
     36    // Local state for min/max bounds indexed by unit to allow user input that
     37    // goes out-of-bounds while still providing a meaningful default range. The indexing
     38    // by unit is needed to account for unit conversion (ex: em to px) where the operation
     39    // may result in out-of-bounds values. Avoiding React's state and setState() because
     40    // `value` is a prop coming from the Redux store while min/max are local. Reconciling
     41    // value/unit changes is needlessly complicated and adds unnecessary re-renders.
     42    this.historicMin = {};
     43    this.historicMax = {};
     44  }
     45 
     46  getDefaultMinMax(unit) {
     47    let min;
     48    let max;
     49    switch (unit) {
     50      case "px":
     51        min = -10;
     52        max = 10;
     53        break;
     54      default:
     55        min = -0.2;
     56        max = 0.6;
     57        break;
     58    }
     59 
     60    return { min, max };
     61  }
     62 
     63  render() {
     64    // For a unitless or a NaN value, default unit to "em".
     65    const unit = getUnitFromValue(this.props.value) || "em";
     66    // When the initial value of "letter-spacing" is "normal", the parsed value
     67    // is not a number (NaN). Guard by setting the default value to 0.
     68    const isKeywordValue = this.props.value === "normal";
     69    const value = isKeywordValue ? 0 : parseFloat(this.props.value);
     70 
     71    let { min, max } = this.getDefaultMinMax(unit);
     72    min = Math.min(min, value);
     73    max = Math.max(max, value);
     74    // Allow lower and upper bounds to move to accomodate the incoming value.
     75    this.historicMin[unit] = this.historicMin[unit]
     76      ? Math.min(this.historicMin[unit], min)
     77      : min;
     78    this.historicMax[unit] = this.historicMax[unit]
     79      ? Math.max(this.historicMax[unit], max)
     80      : max;
     81 
     82    return FontPropertyValue({
     83      allowOverflow: true,
     84      allowUnderflow: true,
     85      disabled: this.props.disabled,
     86      label: getStr("fontinspector.letterSpacingLabel"),
     87      min: this.historicMin[unit],
     88      max: this.historicMax[unit],
     89      name: "letter-spacing",
     90      onChange: this.props.onChange,
     91      // Increase the increment granularity because letter spacing is very sensitive.
     92      step: getStepForUnit(unit) / 100,
     93      // Show the value input and unit only when the value is not a keyword.
     94      showInput: !isKeywordValue,
     95      showUnit: !isKeywordValue,
     96      unit,
     97      unitOptions: ["em", "rem", "px"],
     98      value,
     99      // Show the value as a read-only label if it's a keyword.
    100      valueLabel: isKeywordValue ? this.props.value : null,
    101    });
    102  }
    103 }
    104 
    105 module.exports = LetterSpacing;