tor-browser

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

FlexItemSizingProperties.js (10088B)


      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  PureComponent,
      9 } = require("resource://devtools/client/shared/vendor/react.mjs");
     10 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
     11 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     12 const {
     13  getStr,
     14 } = require("resource://devtools/client/inspector/layout/utils/l10n.js");
     15 
     16 const Types = require("resource://devtools/client/inspector/flexbox/types.js");
     17 
     18 const getFlexibilityReasons = ({
     19  lineGrowthState,
     20  computedFlexGrow,
     21  computedFlexShrink,
     22  grew,
     23  shrank,
     24 }) => {
     25  const reasons = [];
     26 
     27  // Tell users whether the item was set to grow or shrink.
     28  if (computedFlexGrow && lineGrowthState === "growing") {
     29    reasons.push(getStr("flexbox.itemSizing.setToGrow"));
     30  }
     31  if (computedFlexShrink && lineGrowthState === "shrinking") {
     32    reasons.push(getStr("flexbox.itemSizing.setToShrink"));
     33  }
     34  if (!computedFlexGrow && !grew && !shrank && lineGrowthState === "growing") {
     35    reasons.push(getStr("flexbox.itemSizing.notSetToGrow"));
     36  }
     37  if (
     38    !computedFlexShrink &&
     39    !grew &&
     40    !shrank &&
     41    lineGrowthState === "shrinking"
     42  ) {
     43    reasons.push(getStr("flexbox.itemSizing.notSetToShrink"));
     44  }
     45 
     46  return reasons;
     47 };
     48 
     49 class FlexItemSizingProperties extends PureComponent {
     50  static get propTypes() {
     51    return {
     52      flexDirection: PropTypes.string.isRequired,
     53      flexItem: PropTypes.shape(Types.flexItem).isRequired,
     54    };
     55  }
     56 
     57  /**
     58   * Rounds some size in pixels and render it.
     59   * The rendered value will end with 'px' (unless the dimension is 0 in which case the
     60   * unit will be omitted)
     61   *
     62   * @param  {number} value
     63   *         The number to be rounded
     64   * @param  {boolean} prependPlusSign
     65   *         If set to true, the + sign will be printed before a positive value
     66   * @return {object}
     67   *         The React component representing this rounded size
     68   */
     69  renderSize(value, prependPlusSign) {
     70    if (value == 0) {
     71      return dom.span({ className: "value" }, "0");
     72    }
     73 
     74    value = Math.round(value * 100) / 100;
     75    if (prependPlusSign && value > 0) {
     76      value = "+" + value;
     77    }
     78 
     79    return dom.span(
     80      { className: "value" },
     81      value,
     82      dom.span({ className: "unit" }, "px")
     83    );
     84  }
     85 
     86  /**
     87   * Render an authored CSS property.
     88   *
     89   * @param  {string} name
     90   *         The name for this CSS property
     91   * @param  {string} value
     92   *         The property value
     93   * @return {object}
     94   *         The React component representing this CSS property
     95   */
     96  renderCssProperty(name, value) {
     97    return dom.span({ className: "css-property-link" }, `(${name}: ${value})`);
     98  }
     99 
    100  /**
    101   * Render a list of sentences to be displayed in the UI as reasons why a certain sizing
    102   * value happened.
    103   *
    104   * @param  {Array} sentences
    105   *         The list of sentences as Strings
    106   * @return {object}
    107   *         The React component representing these sentences
    108   */
    109  renderReasons(sentences) {
    110    return dom.ul(
    111      { className: "reasons" },
    112      sentences.map(sentence => dom.li({}, sentence))
    113    );
    114  }
    115 
    116  renderBaseSizeSection({ mainBaseSize }, properties, dimension) {
    117    const flexBasisValue = properties["flex-basis"];
    118    const dimensionValue = properties[dimension];
    119 
    120    let title = getStr("flexbox.itemSizing.baseSizeSectionHeader");
    121    let property = null;
    122 
    123    if (flexBasisValue) {
    124      // If flex-basis is defined, then that's what is used for the base size.
    125      property = this.renderCssProperty("flex-basis", flexBasisValue);
    126    } else if (dimensionValue) {
    127      // If not and width/height is defined, then that's what defines the base size.
    128      property = this.renderCssProperty(dimension, dimensionValue);
    129    } else {
    130      // Finally, if nothing is set, then the base size is the max-content size.
    131      // In this case replace the section's title.
    132      title = getStr("flexbox.itemSizing.itemContentSize");
    133    }
    134 
    135    const className = "section base";
    136    return dom.li(
    137      { className: className + (property ? "" : " no-property") },
    138      dom.span({ className: "name" }, title, property),
    139      this.renderSize(mainBaseSize)
    140    );
    141  }
    142 
    143  renderFlexibilitySection(
    144    flexItemSizing,
    145    mainFinalSize,
    146    properties,
    147    computedStyle
    148  ) {
    149    const { mainDeltaSize, mainBaseSize, lineGrowthState } = flexItemSizing;
    150 
    151    // Don't display anything if all interesting sizes are 0.
    152    if (!mainFinalSize && !mainBaseSize && !mainDeltaSize) {
    153      return null;
    154    }
    155 
    156    // Also don't display anything if the item did not grow or shrink.
    157    const grew = mainDeltaSize > 0;
    158    const shrank = mainDeltaSize < 0;
    159    if (!grew && !shrank) {
    160      return null;
    161    }
    162 
    163    const definedFlexGrow = properties["flex-grow"];
    164    const computedFlexGrow = computedStyle.flexGrow;
    165    const definedFlexShrink = properties["flex-shrink"];
    166    const computedFlexShrink = computedStyle.flexShrink;
    167 
    168    const reasons = getFlexibilityReasons({
    169      lineGrowthState,
    170      computedFlexGrow,
    171      computedFlexShrink,
    172      grew,
    173      shrank,
    174    });
    175 
    176    let property = null;
    177 
    178    if (grew && definedFlexGrow && computedFlexGrow) {
    179      // If the item grew it's normally because it was set to grow (flex-grow is non 0).
    180      property = this.renderCssProperty("flex-grow", definedFlexGrow);
    181    } else if (shrank && definedFlexShrink && computedFlexShrink) {
    182      // If the item shrank it's either because flex-shrink is non 0.
    183      property = this.renderCssProperty("flex-shrink", definedFlexShrink);
    184    } else if (shrank && computedFlexShrink) {
    185      // Or also because it's default value is 1 anyway.
    186      property = this.renderCssProperty(
    187        "flex-shrink",
    188        computedFlexShrink,
    189        true
    190      );
    191    }
    192 
    193    // Don't display the section at all if there's nothing useful to show users.
    194    if (!property && !reasons.length) {
    195      return null;
    196    }
    197 
    198    const className = "section flexibility";
    199    return dom.li(
    200      { className: className + (property ? "" : " no-property") },
    201      dom.span(
    202        { className: "name" },
    203        getStr("flexbox.itemSizing.flexibilitySectionHeader"),
    204        property
    205      ),
    206      this.renderSize(mainDeltaSize, true),
    207      this.renderReasons(reasons)
    208    );
    209  }
    210 
    211  renderMinimumSizeSection(flexItemSizing, properties, dimension) {
    212    const { clampState, mainMinSize, mainDeltaSize } = flexItemSizing;
    213    const grew = mainDeltaSize > 0;
    214    const shrank = mainDeltaSize < 0;
    215    const minDimensionValue = properties[`min-${dimension}`];
    216 
    217    // We only display the minimum size when the item actually violates that size during
    218    // layout & is clamped.
    219    if (clampState !== "clamped_to_min") {
    220      return null;
    221    }
    222 
    223    const reasons = [];
    224    if (grew || shrank) {
    225      // The item may have wanted to grow less, but was min-clamped to a larger size.
    226      // Or the item may have wanted to shrink more but was min-clamped to a larger size.
    227      reasons.push(getStr("flexbox.itemSizing.clampedToMin"));
    228    }
    229 
    230    return dom.li(
    231      { className: "section min" },
    232      dom.span(
    233        { className: "name" },
    234        getStr("flexbox.itemSizing.minSizeSectionHeader"),
    235        minDimensionValue.length
    236          ? this.renderCssProperty(`min-${dimension}`, minDimensionValue)
    237          : null
    238      ),
    239      this.renderSize(mainMinSize),
    240      this.renderReasons(reasons)
    241    );
    242  }
    243 
    244  renderMaximumSizeSection(flexItemSizing, properties, dimension) {
    245    const { clampState, mainMaxSize, mainDeltaSize } = flexItemSizing;
    246    const grew = mainDeltaSize > 0;
    247    const shrank = mainDeltaSize < 0;
    248    const maxDimensionValue = properties[`max-${dimension}`];
    249 
    250    if (clampState !== "clamped_to_max") {
    251      return null;
    252    }
    253 
    254    const reasons = [];
    255    if (grew || shrank) {
    256      // The item may have wanted to grow more than it did, because it was max-clamped.
    257      // Or the item may have wanted shrink more, but it was clamped to its max size.
    258      reasons.push(getStr("flexbox.itemSizing.clampedToMax"));
    259    }
    260 
    261    return dom.li(
    262      { className: "section max" },
    263      dom.span(
    264        { className: "name" },
    265        getStr("flexbox.itemSizing.maxSizeSectionHeader"),
    266        maxDimensionValue.length
    267          ? this.renderCssProperty(`max-${dimension}`, maxDimensionValue)
    268          : null
    269      ),
    270      this.renderSize(mainMaxSize),
    271      this.renderReasons(reasons)
    272    );
    273  }
    274 
    275  renderFinalSizeSection(mainFinalSize) {
    276    return dom.li(
    277      { className: "section final no-property" },
    278      dom.span(
    279        { className: "name" },
    280        getStr("flexbox.itemSizing.finalSizeSectionHeader")
    281      ),
    282      this.renderSize(mainFinalSize)
    283    );
    284  }
    285 
    286  render() {
    287    const { flexItem } = this.props;
    288    const { computedStyle, flexItemSizing, properties } = flexItem;
    289    const {
    290      mainAxisDirection,
    291      mainBaseSize,
    292      mainDeltaSize,
    293      mainMaxSize,
    294      mainMinSize,
    295    } = flexItemSizing;
    296    const dimension = mainAxisDirection.startsWith("horizontal")
    297      ? "width"
    298      : "height";
    299 
    300    // Calculate the final size. This is base + delta, then clamped by min or max.
    301    let mainFinalSize = mainBaseSize + mainDeltaSize;
    302    mainFinalSize = Math.max(mainFinalSize, mainMinSize);
    303    mainFinalSize =
    304      mainMaxSize === null
    305        ? mainFinalSize
    306        : Math.min(mainFinalSize, mainMaxSize);
    307 
    308    return dom.ul(
    309      { className: "flex-item-sizing" },
    310      this.renderBaseSizeSection(flexItemSizing, properties, dimension),
    311      this.renderFlexibilitySection(
    312        flexItemSizing,
    313        mainFinalSize,
    314        properties,
    315        computedStyle
    316      ),
    317      this.renderMinimumSizeSection(flexItemSizing, properties, dimension),
    318      this.renderMaximumSizeSection(flexItemSizing, properties, dimension),
    319      this.renderFinalSizeSection(mainFinalSize)
    320    );
    321  }
    322 }
    323 
    324 module.exports = FlexItemSizingProperties;