Bug 1478397 - Part 7: Add a flex item selector in the flexbox panel. r=rcaliman

This commit is contained in:
Gabriel Luong 2018-09-07 20:00:27 -04:00
Родитель 22d4bb0074
Коммит 74d7f402ee
5 изменённых файлов: 241 добавлений и 36 удалений

Просмотреть файл

@ -4,11 +4,15 @@
"use strict";
const { createRef, PureComponent } = require("devtools/client/shared/vendor/react");
const { createFactory, createRef, PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
loader.lazyGetter(this, "FlexItemSelector", function() {
return createFactory(require("./FlexItemSelector"));
});
// Reps
const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
const { Rep } = REPS;
@ -25,6 +29,7 @@ class FlexContainer extends PureComponent {
onSetFlexboxOverlayColor: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
onToggleFlexboxHighlighter: PropTypes.func.isRequired,
onToggleFlexItemShown: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
@ -96,6 +101,33 @@ class FlexContainer extends PureComponent {
nodeFront.scrollIntoView().catch(e => console.error(e));
}
renderFlexItemSelector() {
const {
flexbox,
onToggleFlexItemShown,
} = this.props;
const {
flexItems,
highlighted,
} = flexbox;
if (!highlighted || !flexItems.length) {
return null;
}
const selectedFlexItem = flexItems.find(item => item.shown);
if (!selectedFlexItem) {
return null;
}
return FlexItemSelector({
flexItem: selectedFlexItem,
flexItems,
onToggleFlexItemShown,
});
}
render() {
const {
flexbox,
@ -110,47 +142,50 @@ class FlexContainer extends PureComponent {
return (
dom.div({ className: "flex-container devtools-monospace" },
dom.label({},
dom.input(
dom.div({},
dom.label({},
dom.input(
{
className: "devtools-checkbox-toggle",
checked: highlighted,
onChange: this.onFlexboxCheckboxClick,
type: "checkbox",
}
),
Rep(
{
defaultRep: ElementNode,
mode: MODE.TINY,
object: translateNodeFrontToGrip(nodeFront),
onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
onInspectIconClick: () => this.onFlexboxInspectIconClick(nodeFront),
}
)
),
dom.div(
{
className: "devtools-checkbox-toggle",
checked: highlighted,
onChange: this.onFlexboxCheckboxClick,
type: "checkbox",
className: "layout-color-swatch",
ref: this.swatchEl,
style: {
backgroundColor: color,
},
title: color,
}
),
Rep(
// The SwatchColorPicker relies on the nextSibling of the swatch element to
// apply the selected color. This is why we use a span in display: none for
// now. Ideally we should modify the SwatchColorPickerTooltip to bypass this
// requirement. See https://bugzilla.mozilla.org/show_bug.cgi?id=1341578
dom.span(
{
defaultRep: ElementNode,
mode: MODE.TINY,
object: translateNodeFrontToGrip(nodeFront),
onDOMNodeMouseOut: () => onHideBoxModelHighlighter(),
onDOMNodeMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
onInspectIconClick: () => this.onFlexboxInspectIconClick(nodeFront),
}
className: "layout-color-value",
ref: this.colorValueEl,
},
color
)
),
dom.div(
{
className: "layout-color-swatch",
ref: this.swatchEl,
style: {
backgroundColor: color,
},
title: color,
}
),
// The SwatchColorPicker relies on the nextSibling of the swatch element to apply
// the selected color. This is why we use a span in display: none for now.
// Ideally we should modify the SwatchColorPickerTooltip to bypass this
// requirement. See https://bugzilla.mozilla.org/show_bug.cgi?id=1341578
dom.span(
{
className: "layout-color-value",
ref: this.colorValueEl,
},
color
)
this.renderFlexItemSelector()
)
);
}

Просмотреть файл

@ -0,0 +1,119 @@
/* 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/. */
"use strict";
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
// Reps
const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
const { Rep } = REPS;
const ElementNode = REPS.ElementNode;
const Types = require("../types");
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
class FlexItemSelector extends PureComponent {
static get propTypes() {
return {
flexItem: PropTypes.shape(Types.flexItem).isRequired,
flexItems: PropTypes.arrayOf(PropTypes.shape(Types.flexItem)).isRequired,
onToggleFlexItemShown: PropTypes.func.isRequired,
};
}
constructor(props) {
super(props);
this.onShowFlexItemMenu = this.onShowFlexItemMenu.bind(this);
}
onShowFlexItemMenu(event) {
const {
flexItem,
flexItems,
onToggleFlexItemShown,
} = this.props;
const menuItems = [];
for (const item of flexItems) {
const grip = translateNodeFrontToGrip(item.nodeFront);
menuItems.push({
label: getLabel(grip),
type: "checkbox",
checked: item === flexItem,
click: () => onToggleFlexItemShown(item.nodeFront),
});
}
showMenu(menuItems, {
button: event.target,
});
}
render() {
const { flexItem } = this.props;
return (
dom.div({ className: "flex-item-selector-wrapper" },
dom.button(
{
id: "flex-item-selector",
className: "devtools-button devtools-dropdown-button",
onClick: this.onShowFlexItemMenu,
},
Rep(
{
defaultRep: ElementNode,
mode: MODE.TINY,
object: translateNodeFrontToGrip(flexItem.nodeFront)
}
)
)
)
);
}
}
/**
* Returns a selector label of the Element Rep from the grip. This is based on the
* getElements() function in our devtools-reps component for a ElementNode.
*
* @param {Object} grip
* Grip-like object that can be used with Reps.
* @return {String} selector label of the element node.
*/
function getLabel(grip) {
const {
attributes,
nodeName,
isAfterPseudoElement,
isBeforePseudoElement
} = grip.preview;
if (isAfterPseudoElement || isBeforePseudoElement) {
return `::${isAfterPseudoElement ? "after" : "before"}`;
}
let label = nodeName;
if (attributes.id) {
label += `#${attributes.id}`;
}
if (attributes.class) {
label += attributes.class
.trim()
.split(/\s+/)
.map(cls => `.${cls}`)
.join("");
}
return label;
}
module.exports = FlexItemSelector;

Просмотреть файл

@ -95,6 +95,7 @@ class Flexbox extends PureComponent {
onSetFlexboxOverlayColor,
onShowBoxModelHighlighterForNode,
onToggleFlexboxHighlighter,
onToggleFlexItemShown,
setSelectedNode,
} = this.props;
@ -115,6 +116,7 @@ class Flexbox extends PureComponent {
onSetFlexboxOverlayColor,
onShowBoxModelHighlighterForNode,
onToggleFlexboxHighlighter,
onToggleFlexItemShown,
setSelectedNode,
}),
this.renderFlexItemList(),

Просмотреть файл

@ -10,5 +10,6 @@ DevToolsModules(
'FlexContainerProperties.js',
'FlexItem.js',
'FlexItemList.js',
'FlexItemSelector.js',
'FlexItemSizingProperties.js',
)

Просмотреть файл

@ -2,6 +2,14 @@
* 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/. */
:root {
--flex-item-selector-wrapper-border-color: var(--theme-content-color3);
}
:root.theme-dark {
--flex-item-selector-wrapper-border-color: var(--theme-content-color1);
}
#layout-container {
height: 100%;
width: 100%;
@ -112,6 +120,46 @@
background-color: transparent;
}
/**
* Flex Item Selector
*/
.flex-item-selector-wrapper {
margin-inline-start: 25px;
position: relative;
}
.flex-item-selector-wrapper::before {
position: absolute;
left: -12px;
top: 3px;
content: '';
display: block;
border-left: 0.5px solid var(--flex-item-selector-wrapper-border-color);
height: 0.8em;
border-bottom: 0.5px solid var(--flex-item-selector-wrapper-border-color);
width: 10px;
}
#flex-item-selector {
background-position: right 4px center;
padding-left: 0;
vertical-align: middle;
width: 140px;
}
#flex-item-selector .objectBox-node {
display: inline-block;
font-size: 12px;
overflow: hidden;
padding-top: 0.15em;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
width: 85%;
}
/**
* Flex Item Sizing Properties
*/