774 lines
22 KiB
JavaScript
774 lines
22 KiB
JavaScript
/* 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 {
|
|
createFactory,
|
|
PureComponent,
|
|
} = require("resource://devtools/client/shared/vendor/react.mjs");
|
|
const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
|
|
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
|
|
const { KeyCodes } = require("resource://devtools/client/shared/keycodes.js");
|
|
const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
|
|
|
|
const BoxModelEditable = createFactory(
|
|
require("resource://devtools/client/inspector/boxmodel/components/BoxModelEditable.js")
|
|
);
|
|
|
|
const Types = require("resource://devtools/client/inspector/boxmodel/types.js");
|
|
|
|
const {
|
|
highlightSelectedNode,
|
|
unhighlightNode,
|
|
} = require("resource://devtools/client/inspector/boxmodel/actions/box-model-highlighter.js");
|
|
|
|
const SHARED_STRINGS_URI = "devtools/client/locales/shared.properties";
|
|
const SHARED_L10N = new LocalizationHelper(SHARED_STRINGS_URI);
|
|
|
|
class BoxModelMain extends PureComponent {
|
|
static get propTypes() {
|
|
return {
|
|
boxModel: PropTypes.shape(Types.boxModel).isRequired,
|
|
boxModelContainer: PropTypes.object,
|
|
dispatch: PropTypes.func.isRequired,
|
|
onShowBoxModelEditor: PropTypes.func.isRequired,
|
|
onShowRulePreviewTooltip: PropTypes.func.isRequired,
|
|
};
|
|
}
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {
|
|
activeDescendant: null,
|
|
focusable: false,
|
|
};
|
|
|
|
this.getActiveDescendant = this.getActiveDescendant.bind(this);
|
|
this.getBorderOrPaddingValue = this.getBorderOrPaddingValue.bind(this);
|
|
this.getContextBox = this.getContextBox.bind(this);
|
|
this.getDisplayPosition = this.getDisplayPosition.bind(this);
|
|
this.getHeightValue = this.getHeightValue.bind(this);
|
|
this.getMarginValue = this.getMarginValue.bind(this);
|
|
this.getPositionValue = this.getPositionValue.bind(this);
|
|
this.getWidthValue = this.getWidthValue.bind(this);
|
|
this.moveFocus = this.moveFocus.bind(this);
|
|
this.onHighlightMouseOver = this.onHighlightMouseOver.bind(this);
|
|
this.onKeyDown = this.onKeyDown.bind(this);
|
|
this.onLevelClick = this.onLevelClick.bind(this);
|
|
this.setActive = this.setActive.bind(this);
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
const displayPosition = this.getDisplayPosition();
|
|
const isContentBox = this.getContextBox();
|
|
|
|
this.layouts = {
|
|
position: new Map([
|
|
[KeyCodes.DOM_VK_ESCAPE, this.positionLayout],
|
|
[KeyCodes.DOM_VK_DOWN, this.marginLayout],
|
|
[KeyCodes.DOM_VK_RETURN, this.positionEditable],
|
|
[KeyCodes.DOM_VK_UP, null],
|
|
["click", this.positionLayout],
|
|
]),
|
|
margin: new Map([
|
|
[KeyCodes.DOM_VK_ESCAPE, this.marginLayout],
|
|
[KeyCodes.DOM_VK_DOWN, this.borderLayout],
|
|
[KeyCodes.DOM_VK_RETURN, this.marginEditable],
|
|
[KeyCodes.DOM_VK_UP, displayPosition ? this.positionLayout : null],
|
|
["click", this.marginLayout],
|
|
]),
|
|
border: new Map([
|
|
[KeyCodes.DOM_VK_ESCAPE, this.borderLayout],
|
|
[KeyCodes.DOM_VK_DOWN, this.paddingLayout],
|
|
[KeyCodes.DOM_VK_RETURN, this.borderEditable],
|
|
[KeyCodes.DOM_VK_UP, this.marginLayout],
|
|
["click", this.borderLayout],
|
|
]),
|
|
padding: new Map([
|
|
[KeyCodes.DOM_VK_ESCAPE, this.paddingLayout],
|
|
[KeyCodes.DOM_VK_DOWN, isContentBox ? this.contentLayout : null],
|
|
[KeyCodes.DOM_VK_RETURN, this.paddingEditable],
|
|
[KeyCodes.DOM_VK_UP, this.borderLayout],
|
|
["click", this.paddingLayout],
|
|
]),
|
|
content: new Map([
|
|
[KeyCodes.DOM_VK_ESCAPE, this.contentLayout],
|
|
[KeyCodes.DOM_VK_DOWN, null],
|
|
[KeyCodes.DOM_VK_RETURN, this.contentEditable],
|
|
[KeyCodes.DOM_VK_UP, this.paddingLayout],
|
|
["click", this.contentLayout],
|
|
]),
|
|
};
|
|
}
|
|
|
|
getActiveDescendant() {
|
|
let { activeDescendant } = this.state;
|
|
|
|
if (!activeDescendant) {
|
|
const displayPosition = this.getDisplayPosition();
|
|
const nextLayout = displayPosition
|
|
? this.positionLayout
|
|
: this.marginLayout;
|
|
activeDescendant = nextLayout.getAttribute("data-box");
|
|
this.setActive(nextLayout);
|
|
}
|
|
|
|
return activeDescendant;
|
|
}
|
|
|
|
getBorderOrPaddingValue(property) {
|
|
const { layout } = this.props.boxModel;
|
|
return layout[property] ? parseFloat(layout[property]) : "-";
|
|
}
|
|
|
|
/**
|
|
* Returns true if the layout box sizing is context box and false otherwise.
|
|
*/
|
|
getContextBox() {
|
|
const { layout } = this.props.boxModel;
|
|
return layout["box-sizing"] == "content-box";
|
|
}
|
|
|
|
/**
|
|
* Returns true if the position is displayed and false otherwise.
|
|
*/
|
|
getDisplayPosition() {
|
|
const { layout } = this.props.boxModel;
|
|
return layout.position && layout.position != "static";
|
|
}
|
|
|
|
getHeightValue(property) {
|
|
if (property == undefined) {
|
|
return "-";
|
|
}
|
|
|
|
const { layout } = this.props.boxModel;
|
|
|
|
property -=
|
|
parseFloat(layout["border-top-width"]) +
|
|
parseFloat(layout["border-bottom-width"]) +
|
|
parseFloat(layout["padding-top"]) +
|
|
parseFloat(layout["padding-bottom"]);
|
|
property = parseFloat(property.toPrecision(6));
|
|
|
|
return property >= 0 ? property : "auto";
|
|
}
|
|
|
|
getMarginValue(property, direction) {
|
|
const { layout } = this.props.boxModel;
|
|
const autoMargins = layout.autoMargins || {};
|
|
let value = "-";
|
|
|
|
if (direction in autoMargins) {
|
|
value = autoMargins[direction];
|
|
} else if (layout[property]) {
|
|
const parsedValue = parseFloat(layout[property]);
|
|
|
|
if (Number.isNaN(parsedValue)) {
|
|
// Not a number. We use the raw string.
|
|
// Useful for pseudo-elements with auto margins since they
|
|
// don't appear in autoMargins.
|
|
value = layout[property];
|
|
} else {
|
|
value = parsedValue;
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
getPositionValue(property) {
|
|
const { layout } = this.props.boxModel;
|
|
let value = "-";
|
|
|
|
if (!layout[property]) {
|
|
return value;
|
|
}
|
|
|
|
const parsedValue = parseFloat(layout[property]);
|
|
|
|
if (Number.isNaN(parsedValue)) {
|
|
// Not a number. We use the raw string.
|
|
value = layout[property];
|
|
} else {
|
|
value = parsedValue;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
getWidthValue(property) {
|
|
if (property == undefined) {
|
|
return "-";
|
|
}
|
|
|
|
const { layout } = this.props.boxModel;
|
|
|
|
property -=
|
|
parseFloat(layout["border-left-width"]) +
|
|
parseFloat(layout["border-right-width"]) +
|
|
parseFloat(layout["padding-left"]) +
|
|
parseFloat(layout["padding-right"]);
|
|
property = parseFloat(property.toPrecision(6));
|
|
|
|
return property >= 0 ? property : "auto";
|
|
}
|
|
|
|
/**
|
|
* Move the focus to the next/previous editable element of the current layout.
|
|
*
|
|
* @param {Element} target
|
|
* Node to be observed
|
|
* @param {Boolean} shiftKey
|
|
* Determines if shiftKey was pressed
|
|
*/
|
|
moveFocus({ target, shiftKey }) {
|
|
const editBoxes = [
|
|
...this.positionLayout.querySelectorAll("[data-box].boxmodel-editable"),
|
|
];
|
|
const editingMode = target.tagName === "input";
|
|
// target.nextSibling is input field
|
|
let position = editingMode
|
|
? editBoxes.indexOf(target.nextSibling)
|
|
: editBoxes.indexOf(target);
|
|
|
|
if (position === editBoxes.length - 1 && !shiftKey) {
|
|
position = 0;
|
|
} else if (position === 0 && shiftKey) {
|
|
position = editBoxes.length - 1;
|
|
} else {
|
|
shiftKey ? position-- : position++;
|
|
}
|
|
|
|
const editBox = editBoxes[position];
|
|
this.setActive(editBox);
|
|
editBox.focus();
|
|
|
|
if (editingMode) {
|
|
editBox.click();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Active level set to current layout.
|
|
*
|
|
* @param {Element} nextLayout
|
|
* Element of next layout that user has navigated to
|
|
*/
|
|
setActive(nextLayout) {
|
|
const { boxModelContainer } = this.props;
|
|
|
|
// We set this attribute for testing purposes.
|
|
if (boxModelContainer) {
|
|
boxModelContainer.dataset.activeDescendantClassName =
|
|
nextLayout.className;
|
|
}
|
|
|
|
this.setState({
|
|
activeDescendant: nextLayout.getAttribute("data-box"),
|
|
});
|
|
}
|
|
|
|
onHighlightMouseOver(event) {
|
|
let region = event.target.getAttribute("data-box");
|
|
|
|
if (!region) {
|
|
let el = event.target;
|
|
|
|
do {
|
|
el = el.parentNode;
|
|
|
|
if (el && el.getAttribute("data-box")) {
|
|
region = el.getAttribute("data-box");
|
|
break;
|
|
}
|
|
} while (el.parentNode);
|
|
|
|
this.props.dispatch(unhighlightNode());
|
|
}
|
|
|
|
this.props.dispatch(
|
|
highlightSelectedNode({
|
|
region,
|
|
showOnly: region,
|
|
onlyRegionArea: true,
|
|
})
|
|
);
|
|
|
|
event.preventDefault();
|
|
}
|
|
|
|
/**
|
|
* Handle keyboard navigation and focus for box model layouts.
|
|
*
|
|
* Updates active layout on arrow key navigation
|
|
* Focuses next layout's editboxes on enter key
|
|
* Unfocuses current layout's editboxes when active layout changes
|
|
* Controls tabbing between editBoxes
|
|
*
|
|
* @param {Event} event
|
|
* The event triggered by a keypress on the box model
|
|
*/
|
|
onKeyDown(event) {
|
|
const { target, keyCode } = event;
|
|
const isEditable = target._editable || target.editor;
|
|
|
|
const level = this.getActiveDescendant();
|
|
const editingMode = target.tagName === "input";
|
|
|
|
switch (keyCode) {
|
|
case KeyCodes.DOM_VK_RETURN:
|
|
if (!isEditable) {
|
|
this.setState({ focusable: true }, () => {
|
|
const editableBox = this.layouts[level].get(keyCode);
|
|
if (editableBox) {
|
|
editableBox.boxModelEditable.focus();
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case KeyCodes.DOM_VK_DOWN:
|
|
case KeyCodes.DOM_VK_UP:
|
|
if (!editingMode) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.setState({ focusable: false }, () => {
|
|
const nextLayout = this.layouts[level].get(keyCode);
|
|
|
|
if (!nextLayout) {
|
|
return;
|
|
}
|
|
|
|
this.setActive(nextLayout);
|
|
|
|
if (target?._editable) {
|
|
target.blur();
|
|
}
|
|
|
|
this.props.boxModelContainer.focus();
|
|
});
|
|
}
|
|
break;
|
|
case KeyCodes.DOM_VK_TAB:
|
|
if (isEditable) {
|
|
event.preventDefault();
|
|
this.moveFocus(event);
|
|
}
|
|
break;
|
|
case KeyCodes.DOM_VK_ESCAPE:
|
|
if (target._editable) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.setState({ focusable: false }, () => {
|
|
this.props.boxModelContainer.focus();
|
|
});
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update active on mouse click.
|
|
*
|
|
* @param {Event} event
|
|
* The event triggered by a mouse click on the box model
|
|
*/
|
|
onLevelClick(event) {
|
|
const { target } = event;
|
|
const displayPosition = this.getDisplayPosition();
|
|
const isContentBox = this.getContextBox();
|
|
|
|
// Avoid switching the active descendant to the position or content layout
|
|
// if those are not editable.
|
|
if (
|
|
(!displayPosition && target == this.positionLayout) ||
|
|
(!isContentBox && target == this.contentLayout)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const nextLayout =
|
|
this.layouts[target.getAttribute("data-box")].get("click");
|
|
this.setActive(nextLayout);
|
|
|
|
if (target?._editable) {
|
|
target.blur();
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
boxModel,
|
|
dispatch,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
} = this.props;
|
|
const { layout } = boxModel;
|
|
let { height, width } = layout;
|
|
const { activeDescendant: level, focusable } = this.state;
|
|
|
|
const borderTop = this.getBorderOrPaddingValue("border-top-width");
|
|
const borderRight = this.getBorderOrPaddingValue("border-right-width");
|
|
const borderBottom = this.getBorderOrPaddingValue("border-bottom-width");
|
|
const borderLeft = this.getBorderOrPaddingValue("border-left-width");
|
|
|
|
const paddingTop = this.getBorderOrPaddingValue("padding-top");
|
|
const paddingRight = this.getBorderOrPaddingValue("padding-right");
|
|
const paddingBottom = this.getBorderOrPaddingValue("padding-bottom");
|
|
const paddingLeft = this.getBorderOrPaddingValue("padding-left");
|
|
|
|
const displayPosition = this.getDisplayPosition();
|
|
const positionTop = this.getPositionValue("top");
|
|
const positionRight = this.getPositionValue("right");
|
|
const positionBottom = this.getPositionValue("bottom");
|
|
const positionLeft = this.getPositionValue("left");
|
|
|
|
const marginTop = this.getMarginValue("margin-top", "top");
|
|
const marginRight = this.getMarginValue("margin-right", "right");
|
|
const marginBottom = this.getMarginValue("margin-bottom", "bottom");
|
|
const marginLeft = this.getMarginValue("margin-left", "left");
|
|
|
|
height = this.getHeightValue(height);
|
|
width = this.getWidthValue(width);
|
|
|
|
const contentBox =
|
|
layout["box-sizing"] == "content-box"
|
|
? dom.div(
|
|
{ className: "boxmodel-size" },
|
|
BoxModelEditable({
|
|
box: "content",
|
|
focusable,
|
|
level,
|
|
property: "width",
|
|
ref: editable => {
|
|
this.contentEditable = editable;
|
|
},
|
|
textContent: width,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
dom.span({}, "\u00D7"),
|
|
BoxModelEditable({
|
|
box: "content",
|
|
focusable,
|
|
level,
|
|
property: "height",
|
|
textContent: height,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
})
|
|
)
|
|
: dom.p(
|
|
{
|
|
className: "boxmodel-size",
|
|
id: "boxmodel-size-id",
|
|
},
|
|
dom.span(
|
|
{ title: "content" },
|
|
SHARED_L10N.getFormatStr("dimensions", width, height)
|
|
)
|
|
);
|
|
|
|
return dom.div(
|
|
{
|
|
className: "boxmodel-main devtools-monospace",
|
|
"data-box": "position",
|
|
ref: div => {
|
|
this.positionLayout = div;
|
|
},
|
|
onClick: this.onLevelClick,
|
|
onKeyDown: this.onKeyDown,
|
|
onMouseOver: this.onHighlightMouseOver,
|
|
onMouseOut: () => dispatch(unhighlightNode()),
|
|
},
|
|
displayPosition
|
|
? dom.span(
|
|
{
|
|
className: "boxmodel-legend",
|
|
"data-box": "position",
|
|
title: "position",
|
|
},
|
|
"position"
|
|
)
|
|
: null,
|
|
dom.div(
|
|
{ className: "boxmodel-box" },
|
|
dom.span(
|
|
{
|
|
className: "boxmodel-legend",
|
|
"data-box": "margin",
|
|
title: "margin",
|
|
role: "region",
|
|
"aria-level": "1", // margin, outermost box
|
|
"aria-owns":
|
|
"margin-top-id margin-right-id margin-bottom-id margin-left-id margins-div",
|
|
},
|
|
"margin"
|
|
),
|
|
dom.div(
|
|
{
|
|
className: "boxmodel-margins",
|
|
id: "margins-div",
|
|
"data-box": "margin",
|
|
title: "margin",
|
|
ref: div => {
|
|
this.marginLayout = div;
|
|
},
|
|
},
|
|
dom.span(
|
|
{
|
|
className: "boxmodel-legend",
|
|
"data-box": "border",
|
|
title: "border",
|
|
role: "region",
|
|
"aria-level": "2", // margin -> border, second box
|
|
"aria-owns":
|
|
"border-top-width-id border-right-width-id border-bottom-width-id border-left-width-id borders-div",
|
|
},
|
|
"border"
|
|
),
|
|
dom.div(
|
|
{
|
|
className: "boxmodel-borders",
|
|
id: "borders-div",
|
|
"data-box": "border",
|
|
title: "border",
|
|
ref: div => {
|
|
this.borderLayout = div;
|
|
},
|
|
},
|
|
dom.span(
|
|
{
|
|
className: "boxmodel-legend",
|
|
"data-box": "padding",
|
|
title: "padding",
|
|
role: "region",
|
|
"aria-level": "3", // margin -> border -> padding
|
|
"aria-owns":
|
|
"padding-top-id padding-right-id padding-bottom-id padding-left-id padding-div",
|
|
},
|
|
"padding"
|
|
),
|
|
dom.div(
|
|
{
|
|
className: "boxmodel-paddings",
|
|
id: "padding-div",
|
|
"data-box": "padding",
|
|
title: "padding",
|
|
"aria-owns": "boxmodel-contents-id",
|
|
ref: div => {
|
|
this.paddingLayout = div;
|
|
},
|
|
},
|
|
dom.div({
|
|
className: "boxmodel-contents",
|
|
id: "boxmodel-contents-id",
|
|
"data-box": "content",
|
|
title: "content",
|
|
role: "region",
|
|
"aria-level": "4", // margin -> border -> padding -> content
|
|
"aria-label": SHARED_L10N.getFormatStr(
|
|
"boxModelSize.accessibleLabel",
|
|
width,
|
|
height
|
|
),
|
|
"aria-owns": "boxmodel-size-id",
|
|
ref: div => {
|
|
this.contentLayout = div;
|
|
},
|
|
})
|
|
)
|
|
)
|
|
)
|
|
),
|
|
displayPosition
|
|
? BoxModelEditable({
|
|
box: "position",
|
|
direction: "top",
|
|
focusable,
|
|
level,
|
|
property: "position-top",
|
|
ref: editable => {
|
|
this.positionEditable = editable;
|
|
},
|
|
textContent: positionTop,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
})
|
|
: null,
|
|
displayPosition
|
|
? BoxModelEditable({
|
|
box: "position",
|
|
direction: "right",
|
|
focusable,
|
|
level,
|
|
property: "position-right",
|
|
textContent: positionRight,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
})
|
|
: null,
|
|
displayPosition
|
|
? BoxModelEditable({
|
|
box: "position",
|
|
direction: "bottom",
|
|
focusable,
|
|
level,
|
|
property: "position-bottom",
|
|
textContent: positionBottom,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
})
|
|
: null,
|
|
displayPosition
|
|
? BoxModelEditable({
|
|
box: "position",
|
|
direction: "left",
|
|
focusable,
|
|
level,
|
|
property: "position-left",
|
|
textContent: positionLeft,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
})
|
|
: null,
|
|
BoxModelEditable({
|
|
box: "margin",
|
|
direction: "top",
|
|
focusable,
|
|
level,
|
|
property: "margin-top",
|
|
ref: editable => {
|
|
this.marginEditable = editable;
|
|
},
|
|
textContent: marginTop,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "margin",
|
|
direction: "right",
|
|
focusable,
|
|
level,
|
|
property: "margin-right",
|
|
textContent: marginRight,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "margin",
|
|
direction: "bottom",
|
|
focusable,
|
|
level,
|
|
property: "margin-bottom",
|
|
textContent: marginBottom,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "margin",
|
|
direction: "left",
|
|
focusable,
|
|
level,
|
|
property: "margin-left",
|
|
textContent: marginLeft,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "border",
|
|
direction: "top",
|
|
focusable,
|
|
level,
|
|
property: "border-top-width",
|
|
ref: editable => {
|
|
this.borderEditable = editable;
|
|
},
|
|
textContent: borderTop,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "border",
|
|
direction: "right",
|
|
focusable,
|
|
level,
|
|
property: "border-right-width",
|
|
textContent: borderRight,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "border",
|
|
direction: "bottom",
|
|
focusable,
|
|
level,
|
|
property: "border-bottom-width",
|
|
textContent: borderBottom,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "border",
|
|
direction: "left",
|
|
focusable,
|
|
level,
|
|
property: "border-left-width",
|
|
textContent: borderLeft,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "padding",
|
|
direction: "top",
|
|
focusable,
|
|
level,
|
|
property: "padding-top",
|
|
ref: editable => {
|
|
this.paddingEditable = editable;
|
|
},
|
|
textContent: paddingTop,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "padding",
|
|
direction: "right",
|
|
focusable,
|
|
level,
|
|
property: "padding-right",
|
|
textContent: paddingRight,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "padding",
|
|
direction: "bottom",
|
|
focusable,
|
|
level,
|
|
property: "padding-bottom",
|
|
textContent: paddingBottom,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
BoxModelEditable({
|
|
box: "padding",
|
|
direction: "left",
|
|
focusable,
|
|
level,
|
|
property: "padding-left",
|
|
textContent: paddingLeft,
|
|
onShowBoxModelEditor,
|
|
onShowRulePreviewTooltip,
|
|
}),
|
|
contentBox
|
|
);
|
|
}
|
|
}
|
|
|
|
module.exports = BoxModelMain;
|