FlexItemSizingOutline.js (5528B)
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 13 const Types = require("resource://devtools/client/inspector/flexbox/types.js"); 14 15 class FlexItemSizingOutline extends PureComponent { 16 static get propTypes() { 17 return { 18 flexDirection: PropTypes.string.isRequired, 19 flexItem: PropTypes.shape(Types.flexItem).isRequired, 20 }; 21 } 22 23 renderBasisOutline(mainBaseSize) { 24 return dom.div({ 25 className: "flex-outline-basis" + (!mainBaseSize ? " zero-basis" : ""), 26 }); 27 } 28 29 renderDeltaOutline(mainDeltaSize) { 30 if (!mainDeltaSize) { 31 return null; 32 } 33 34 return dom.div({ 35 className: "flex-outline-delta", 36 }); 37 } 38 39 renderFinalOutline(isClamped) { 40 return dom.div({ 41 className: "flex-outline-final" + (isClamped ? " clamped" : ""), 42 }); 43 } 44 45 renderPoint(className, label = className) { 46 return dom.div({ 47 key: className, 48 className: `flex-outline-point ${className}`, 49 "data-label": label, 50 }); 51 } 52 53 render() { 54 const { flexItemSizing } = this.props.flexItem; 55 const { 56 mainAxisDirection, 57 mainBaseSize, 58 mainDeltaSize, 59 mainMaxSize, 60 mainMinSize, 61 clampState, 62 } = flexItemSizing; 63 64 // Calculate the final size. This is base + delta, then clamped by min or max. 65 let mainFinalSize = mainBaseSize + mainDeltaSize; 66 mainFinalSize = Math.max(mainFinalSize, mainMinSize); 67 mainFinalSize = 68 mainMaxSize === null 69 ? mainFinalSize 70 : Math.min(mainFinalSize, mainMaxSize); 71 72 // Just don't display anything if there isn't anything useful. 73 if (!mainFinalSize && !mainBaseSize && !mainDeltaSize) { 74 return null; 75 } 76 77 // The max size is only interesting to show if it did clamp the item. 78 const showMax = clampState === "clamped_to_max"; 79 80 // The min size is only really interesting if it actually clamped the item. 81 // TODO: We might also want to check if the min-size property is defined. 82 const showMin = clampState === "clamped_to_min"; 83 84 // Create an array of all of the sizes we want to display that we can use to create 85 // a grid track template. 86 let sizes = [ 87 { name: "basis-start", size: 0 }, 88 { name: "basis-end", size: mainBaseSize }, 89 { name: "final-start", size: 0 }, 90 { name: "final-end", size: mainFinalSize }, 91 ]; 92 93 // Because mainDeltaSize is just a delta from base, make sure to make it absolute like 94 // the other sizes in the array, so we can later sort all sizes in the same way. 95 if (mainDeltaSize > 0) { 96 sizes.push({ name: "delta-start", size: mainBaseSize }); 97 sizes.push({ name: "delta-end", size: mainBaseSize + mainDeltaSize }); 98 } else { 99 sizes.push({ name: "delta-start", size: mainBaseSize + mainDeltaSize }); 100 sizes.push({ name: "delta-end", size: mainBaseSize }); 101 } 102 103 if (showMax) { 104 sizes.push({ name: "max", size: mainMaxSize }); 105 } 106 if (showMin) { 107 sizes.push({ name: "min", size: mainMinSize }); 108 } 109 110 // Sort all of the dimensions so we can create the grid track template correctly. 111 sizes = sizes.sort((a, b) => a.size - b.size); 112 113 // In some cases, the delta-start may be negative (when an item wanted to shrink more 114 // than the item's base size). As a negative value would break the grid track template 115 // offset all values so they're all positive. 116 const offsetBy = sizes.reduce( 117 (acc, curr) => (curr.size < acc ? curr.size : acc), 118 0 119 ); 120 sizes = sizes.map(entry => ({ 121 size: entry.size - offsetBy, 122 name: entry.name, 123 })); 124 125 let gridTemplateColumns = "["; 126 let accumulatedSize = 0; 127 for (const { name, size } of sizes) { 128 const breadth = Math.round(size - accumulatedSize); 129 if (breadth === 0) { 130 gridTemplateColumns += ` ${name}`; 131 continue; 132 } 133 134 gridTemplateColumns += `] ${breadth}fr [${name}`; 135 accumulatedSize = size; 136 } 137 gridTemplateColumns += "]"; 138 139 // Check the final and basis points to see if they are the same and if so, combine 140 // them into a single rendered point. 141 const renderedBaseAndFinalPoints = []; 142 if (mainFinalSize === mainBaseSize) { 143 renderedBaseAndFinalPoints.push( 144 this.renderPoint("basisfinal", "basis/final") 145 ); 146 } else { 147 renderedBaseAndFinalPoints.push(this.renderPoint("basis")); 148 renderedBaseAndFinalPoints.push(this.renderPoint("final")); 149 } 150 151 return dom.div( 152 { className: "flex-outline-container" }, 153 dom.div( 154 { 155 className: 156 `flex-outline ${mainAxisDirection}` + 157 (mainDeltaSize > 0 ? " growing" : " shrinking"), 158 style: { 159 gridTemplateColumns, 160 }, 161 }, 162 renderedBaseAndFinalPoints, 163 showMin ? this.renderPoint("min") : null, 164 showMax ? this.renderPoint("max") : null, 165 this.renderBasisOutline(mainBaseSize), 166 this.renderDeltaOutline(mainDeltaSize), 167 this.renderFinalOutline(clampState !== "unclamped") 168 ) 169 ); 170 } 171 } 172 173 module.exports = FlexItemSizingOutline;