Bug 1897931 - [devtools] Include starting-style value in var() tooltip. r=devtools-reviewers,bomsy.
This patch adds a new Map that holds CSS variable value for `@starting-style` rules, so we can display the proper value when hovering a variable in a `@starting-style` rule. As regular properties, CSS variables can be overridden by declaration in regular rule, so we ensure this is reflected in the content of the tooltip. We also add a new `@starting-style` section in the tooltip, that we show when it's displayed for a regular rule. Many test cases are added to cover the different situations we can have. The `checkVariableTooltipForProperty` was moved out of browser_rules_registered-custom-properties.js, and refactored to accomodate for the new starting-style section. Differential Revision: https://phabricator.services.mozilla.com/D215100
This commit is contained in:
@@ -62,6 +62,7 @@ class ElementStyle {
|
|||||||
this.rules = [];
|
this.rules = [];
|
||||||
this.cssProperties = this.ruleView.cssProperties;
|
this.cssProperties = this.ruleView.cssProperties;
|
||||||
this.variablesMap = new Map();
|
this.variablesMap = new Map();
|
||||||
|
this.startingStyleVariablesMap = new Map();
|
||||||
|
|
||||||
// We don't want to overwrite this.store.userProperties so we only create it
|
// We don't want to overwrite this.store.userProperties so we only create it
|
||||||
// if it doesn't already exist.
|
// if it doesn't already exist.
|
||||||
@@ -306,6 +307,9 @@ class ElementStyle {
|
|||||||
|
|
||||||
// CSS Variables inherits from the normal element in case of pseudo element.
|
// CSS Variables inherits from the normal element in case of pseudo element.
|
||||||
const variables = new Map(pseudo ? this.variablesMap.get("") : null);
|
const variables = new Map(pseudo ? this.variablesMap.get("") : null);
|
||||||
|
const startingStyleVariables = new Map(
|
||||||
|
pseudo ? this.startingStyleVariablesMap.get("") : null
|
||||||
|
);
|
||||||
|
|
||||||
// Walk over the computed properties. As we see a property name
|
// Walk over the computed properties. As we see a property name
|
||||||
// for the first time, mark that property's name as taken by this
|
// for the first time, mark that property's name as taken by this
|
||||||
@@ -377,6 +381,10 @@ class ElementStyle {
|
|||||||
earlierInStartingStyle._overriddenDirty =
|
earlierInStartingStyle._overriddenDirty =
|
||||||
!earlierInStartingStyle._overriddenDirty;
|
!earlierInStartingStyle._overriddenDirty;
|
||||||
earlierInStartingStyle.overridden = true;
|
earlierInStartingStyle.overridden = true;
|
||||||
|
// which means we also need to remove the variable from startingStyleVariables
|
||||||
|
if (isCssVariable(computedProp.name)) {
|
||||||
|
startingStyleVariables.delete(computedProp.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This computed property is overridden if:
|
// This computed property is overridden if:
|
||||||
@@ -407,12 +415,13 @@ class ElementStyle {
|
|||||||
// get the initial value from the registered property definition.
|
// get the initial value from the registered property definition.
|
||||||
if (
|
if (
|
||||||
isCssVariable(computedProp.name) &&
|
isCssVariable(computedProp.name) &&
|
||||||
!computedProp.textProp.invisible &&
|
!computedProp.textProp.invisible
|
||||||
// variables set in starting-style rules should only impact the starting style
|
|
||||||
// value, not the "final" one.
|
|
||||||
!isPropInStartingStyle
|
|
||||||
) {
|
) {
|
||||||
variables.set(computedProp.name, computedProp.value);
|
if (!isPropInStartingStyle) {
|
||||||
|
variables.set(computedProp.name, computedProp.value);
|
||||||
|
} else {
|
||||||
|
startingStyleVariables.set(computedProp.name, computedProp.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,8 +434,17 @@ class ElementStyle {
|
|||||||
k => variables.get(k) !== previousVariablesMap.get(k)
|
k => variables.get(k) !== previousVariablesMap.get(k)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
const previousStartingStyleVariablesMap = new Map(
|
||||||
|
this.startingStyleVariablesMap.get(pseudo)
|
||||||
|
);
|
||||||
|
const changedStartingStyleVariableNamesSet = new Set(
|
||||||
|
[...variables.keys(), ...previousStartingStyleVariablesMap.keys()].filter(
|
||||||
|
k => variables.get(k) !== previousStartingStyleVariablesMap.get(k)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
this.variablesMap.set(pseudo, variables);
|
this.variablesMap.set(pseudo, variables);
|
||||||
|
this.startingStyleVariablesMap.set(pseudo, startingStyleVariables);
|
||||||
|
|
||||||
// For each TextProperty, mark it overridden if all of its computed
|
// For each TextProperty, mark it overridden if all of its computed
|
||||||
// properties are marked overridden. Update the text property's associated
|
// properties are marked overridden. Update the text property's associated
|
||||||
@@ -440,7 +458,11 @@ class ElementStyle {
|
|||||||
// of the updated CSS variable names.
|
// of the updated CSS variable names.
|
||||||
if (
|
if (
|
||||||
this._updatePropertyOverridden(textProp) ||
|
this._updatePropertyOverridden(textProp) ||
|
||||||
this._hasUpdatedCSSVariable(textProp, changedVariableNamesSet)
|
this._hasUpdatedCSSVariable(textProp, changedVariableNamesSet) ||
|
||||||
|
this._hasUpdatedCSSVariable(
|
||||||
|
textProp,
|
||||||
|
changedStartingStyleVariableNamesSet
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
textProp.updateEditor();
|
textProp.updateEditor();
|
||||||
}
|
}
|
||||||
@@ -912,6 +934,7 @@ class ElementStyle {
|
|||||||
*/
|
*/
|
||||||
getVariableData(name, pseudo = "") {
|
getVariableData(name, pseudo = "") {
|
||||||
const variables = this.variablesMap.get(pseudo);
|
const variables = this.variablesMap.get(pseudo);
|
||||||
|
const startingStyleVariables = this.startingStyleVariablesMap.get(pseudo);
|
||||||
const registeredPropertiesMap =
|
const registeredPropertiesMap =
|
||||||
this.ruleView.getRegisteredPropertiesForSelectedNodeTarget();
|
this.ruleView.getRegisteredPropertiesForSelectedNodeTarget();
|
||||||
|
|
||||||
@@ -921,6 +944,9 @@ class ElementStyle {
|
|||||||
// Will be handled in Bug 1866712
|
// Will be handled in Bug 1866712
|
||||||
data.value = variables.get(name);
|
data.value = variables.get(name);
|
||||||
}
|
}
|
||||||
|
if (startingStyleVariables?.has(name)) {
|
||||||
|
data.startingStyle = startingStyleVariables.get(name);
|
||||||
|
}
|
||||||
if (registeredPropertiesMap?.has(name)) {
|
if (registeredPropertiesMap?.has(name)) {
|
||||||
data.registeredProperty = registeredPropertiesMap.get(name);
|
data.registeredProperty = registeredPropertiesMap.get(name);
|
||||||
}
|
}
|
||||||
@@ -939,26 +965,51 @@ class ElementStyle {
|
|||||||
*/
|
*/
|
||||||
getAllCustomProperties(pseudo = "") {
|
getAllCustomProperties(pseudo = "") {
|
||||||
let customProperties = this.variablesMap.get(pseudo);
|
let customProperties = this.variablesMap.get(pseudo);
|
||||||
|
const startingStyleCustomProperties =
|
||||||
|
this.startingStyleVariablesMap.get(pseudo);
|
||||||
|
|
||||||
const registeredPropertiesMap =
|
const registeredPropertiesMap =
|
||||||
this.ruleView.getRegisteredPropertiesForSelectedNodeTarget();
|
this.ruleView.getRegisteredPropertiesForSelectedNodeTarget();
|
||||||
|
|
||||||
// If there's no registered properties, we can return the Map as is
|
// If there's no registered properties nor starting style ones, we can return the Map as is
|
||||||
if (!registeredPropertiesMap || registeredPropertiesMap.size === 0) {
|
if (
|
||||||
|
(!registeredPropertiesMap || registeredPropertiesMap.size === 0) &&
|
||||||
|
(!startingStyleCustomProperties ||
|
||||||
|
startingStyleCustomProperties.size === 0)
|
||||||
|
) {
|
||||||
return customProperties;
|
return customProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
let newMapCreated = false;
|
let newMapCreated = false;
|
||||||
for (const [name, propertyDefinition] of registeredPropertiesMap) {
|
|
||||||
// Only set the registered property if it's not defined (i.e. not in this.variablesMap)
|
if (startingStyleCustomProperties) {
|
||||||
if (!customProperties.has(name)) {
|
for (const [name, value] of startingStyleCustomProperties) {
|
||||||
// Since we want to return registered property, we need to create a new Map
|
// Only set the starting style property if it's not defined (i.e. not in the "main"
|
||||||
// to not modify the one in this.variablesMap.
|
// variable map)
|
||||||
if (!newMapCreated) {
|
if (!customProperties.has(name)) {
|
||||||
customProperties = new Map(customProperties);
|
// Since we want to return starting style variables, we need to create a new Map
|
||||||
newMapCreated = true;
|
// to not modify the one in the main map.
|
||||||
|
if (!newMapCreated) {
|
||||||
|
customProperties = new Map(customProperties);
|
||||||
|
newMapCreated = true;
|
||||||
|
}
|
||||||
|
customProperties.set(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registeredPropertiesMap) {
|
||||||
|
for (const [name, propertyDefinition] of registeredPropertiesMap) {
|
||||||
|
// Only set the registered property if it's not defined (i.e. not in the variable map)
|
||||||
|
if (!customProperties.has(name)) {
|
||||||
|
// Since we want to return registered property, we need to create a new Map
|
||||||
|
// to not modify the one in the variable map.
|
||||||
|
if (!newMapCreated) {
|
||||||
|
customProperties = new Map(customProperties);
|
||||||
|
newMapCreated = true;
|
||||||
|
}
|
||||||
|
customProperties.set(name, propertyDefinition.initialValue);
|
||||||
}
|
}
|
||||||
customProperties.set(name, propertyDefinition.initialValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,18 @@
|
|||||||
|
|
||||||
const TEST_URI = `
|
const TEST_URI = `
|
||||||
<style>
|
<style>
|
||||||
|
@property --my-registered-color {
|
||||||
|
syntax: "<color>";
|
||||||
|
inherits: true;
|
||||||
|
initial-value: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@property --my-unset-registered-color {
|
||||||
|
syntax: "<color>";
|
||||||
|
inherits: true;
|
||||||
|
initial-value: lavender;
|
||||||
|
}
|
||||||
|
|
||||||
h1, [data-test="top-level"] {
|
h1, [data-test="top-level"] {
|
||||||
color: tomato;
|
color: tomato;
|
||||||
transition: all 1s;
|
transition: all 1s;
|
||||||
@@ -33,6 +45,12 @@ const TEST_URI = `
|
|||||||
|
|
||||||
main, [data-test="in-starting-style"] {
|
main, [data-test="in-starting-style"] {
|
||||||
--my-color: black !important;
|
--my-color: black !important;
|
||||||
|
--my-overridden-color: black;
|
||||||
|
--my-registered-color: black !important;
|
||||||
|
--check-my-color: var(--my-color);
|
||||||
|
--check-my-overridden-color: var(--my-overridden-color);
|
||||||
|
--check-my-registered-color: var(--my-registered-color);
|
||||||
|
--check-my-unset-registered-color: var(--my-unset-registered-color);
|
||||||
background-color: dodgerblue;
|
background-color: dodgerblue;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
margin-top: 1px !important;
|
margin-top: 1px !important;
|
||||||
@@ -60,6 +78,10 @@ const TEST_URI = `
|
|||||||
|
|
||||||
main, [data-test="top-level"] {
|
main, [data-test="top-level"] {
|
||||||
--my-color: white;
|
--my-color: white;
|
||||||
|
--my-overridden-color: white !important;
|
||||||
|
--my-registered-color: white;
|
||||||
|
--check-my-overridden-color: var(--my-overridden-color);
|
||||||
|
--check-my-registered-color: var(--my-registered-color);
|
||||||
color: var(--my-color);
|
color: var(--my-color);
|
||||||
background-color: firebrick;
|
background-color: firebrick;
|
||||||
padding-top: 2px !important;
|
padding-top: 2px !important;
|
||||||
@@ -244,21 +266,126 @@ add_task(async function () {
|
|||||||
!isPropertyOverridden(view, 2, { "--my-color": "white" }),
|
!isPropertyOverridden(view, 2, { "--my-color": "white" }),
|
||||||
"--my-color value in top level rule is not overridden"
|
"--my-color value in top level rule is not overridden"
|
||||||
);
|
);
|
||||||
const variableEl = getRuleViewProperty(
|
|
||||||
|
info(
|
||||||
|
"Check var() in regular rule for a variable set in both regular and starting-style rule"
|
||||||
|
);
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
view,
|
view,
|
||||||
`main, [data-test="top-level"]`,
|
`main, [data-test="top-level"]`,
|
||||||
"color"
|
"color",
|
||||||
).valueSpan.querySelector(".ruleview-variable");
|
{
|
||||||
is(
|
header: "--my-color = white",
|
||||||
variableEl.dataset.variable,
|
// The starting-style value is displayed in the tooltip
|
||||||
"--my-color = white",
|
startingStyle: "--my-color = black",
|
||||||
"variable popup for --my-color has the expected value"
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
info(
|
||||||
|
"Check var() in starting-style rule for a variable set in both regular and starting-style rule"
|
||||||
|
);
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
`main, [data-test="in-starting-style"]`,
|
||||||
|
"--check-my-color",
|
||||||
|
{
|
||||||
|
// The displayed value is the one set in the starting-style rule
|
||||||
|
header: "--my-color = black",
|
||||||
|
// The starting-style section is not displayed when hovering starting-style rule
|
||||||
|
startingStyle: null,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
info(
|
||||||
|
"Check var() in both regular and starting-style rule for a variable overridden in regular rule"
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
isPropertyOverridden(view, 3, { "--my-overridden-color": "black" }),
|
||||||
|
"--my-overridden-color in top-level starting style rule is overridden"
|
||||||
|
);
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
`main, [data-test="top-level"]`,
|
||||||
|
"--check-my-overridden-color",
|
||||||
|
{
|
||||||
|
header: "--my-overridden-color = white",
|
||||||
|
// The starting-style rule is overridden, so we don't show a starting-style section in the tooltip
|
||||||
|
startingStyle: null,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
`main, [data-test="in-starting-style"]`,
|
||||||
|
"--check-my-overridden-color",
|
||||||
|
{
|
||||||
|
// the value is the one from the regular rule, not the one from the starting-style rule
|
||||||
|
header: "--my-overridden-color = white",
|
||||||
|
startingStyle: null,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
info(
|
||||||
|
"Check var() for a registered property in both regular and starting-style rule"
|
||||||
|
);
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
`main, [data-test="top-level"]`,
|
||||||
|
"--check-my-registered-color",
|
||||||
|
{
|
||||||
|
header: "--my-registered-color = white",
|
||||||
|
// The starting-style value is displayed in the tooltip
|
||||||
|
startingStyle: "--my-registered-color = black",
|
||||||
|
// registered property data is displayed
|
||||||
|
registeredProperty: [
|
||||||
|
`syntax:"<color>"`,
|
||||||
|
`inherits:true`,
|
||||||
|
`initial-value:blue`,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
`main, [data-test="in-starting-style"]`,
|
||||||
|
"--check-my-registered-color",
|
||||||
|
{
|
||||||
|
// The displayed value is the one set in the starting-style rule
|
||||||
|
header: "--my-registered-color = black",
|
||||||
|
// The starting-style section is not displayed when hovering starting-style rule
|
||||||
|
startingStyle: null,
|
||||||
|
// registered property data is displayed
|
||||||
|
registeredProperty: [
|
||||||
|
`syntax:"<color>"`,
|
||||||
|
`inherits:true`,
|
||||||
|
`initial-value:blue`,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
info("Check var() for a unset registered property in starting-style rule");
|
||||||
|
await assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
`main, [data-test="in-starting-style"]`,
|
||||||
|
"--check-my-unset-registered-color",
|
||||||
|
{
|
||||||
|
// The displayed value is the registered property initial value
|
||||||
|
header: "--my-unset-registered-color = lavender",
|
||||||
|
// The starting-style section is not displayed when hovering starting-style rule
|
||||||
|
startingStyle: null,
|
||||||
|
// registered property data is displayed
|
||||||
|
registeredProperty: [
|
||||||
|
`syntax:"<color>"`,
|
||||||
|
`inherits:true`,
|
||||||
|
`initial-value:lavender`,
|
||||||
|
],
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
async function assertRules(nodeSelector, expectedRules) {
|
async function assertRules(nodeSelector, expectedRules) {
|
||||||
await selectNode(nodeSelector, inspector);
|
await selectNode(nodeSelector, inspector);
|
||||||
const rulesInView = Array.from(
|
const rulesInView = Array.from(
|
||||||
view.element.querySelectorAll(".ruleview-rule")
|
// don't retrieve @property rules
|
||||||
|
view.element.querySelectorAll(".ruleview-rule:not([data-name])")
|
||||||
);
|
);
|
||||||
is(
|
is(
|
||||||
rulesInView.length,
|
rulesInView.length,
|
||||||
|
|||||||
@@ -148,61 +148,61 @@ add_task(async function () {
|
|||||||
checkRegisteredProperties(view, expectedProperties);
|
checkRegisteredProperties(view, expectedProperties);
|
||||||
|
|
||||||
info("Check that var() tooltips handle registered properties");
|
info("Check that var() tooltips handle registered properties");
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(view, "h1", "background-color", {
|
||||||
view,
|
|
||||||
"h1",
|
|
||||||
"background-color",
|
|
||||||
// The variable value is the initial value since the variable does not inherit
|
// The variable value is the initial value since the variable does not inherit
|
||||||
`--css-no-inherit = ${CSS_NO_INHERIT_INITIAL_VALUE}`,
|
header: `--css-no-inherit = ${CSS_NO_INHERIT_INITIAL_VALUE}`,
|
||||||
[
|
registeredProperty: [
|
||||||
`syntax:"<color>"`,
|
`syntax:"<color>"`,
|
||||||
`inherits:false`,
|
`inherits:false`,
|
||||||
`initial-value:${CSS_NO_INHERIT_INITIAL_VALUE}`,
|
`initial-value:${CSS_NO_INHERIT_INITIAL_VALUE}`,
|
||||||
]
|
],
|
||||||
);
|
});
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(view, "h1", "color", {
|
||||||
view,
|
|
||||||
"h1",
|
|
||||||
"color",
|
|
||||||
// The variable value is the value set in the main selector, since the variable does inherit
|
// The variable value is the value set in the main selector, since the variable does inherit
|
||||||
`--css-inherit = ${CSS_INHERIT_MAIN_VALUE}`,
|
header: `--css-inherit = ${CSS_INHERIT_MAIN_VALUE}`,
|
||||||
[
|
registeredProperty: [
|
||||||
`syntax:"<color>"`,
|
`syntax:"<color>"`,
|
||||||
`inherits:true`,
|
`inherits:true`,
|
||||||
`initial-value:${CSS_INHERIT_INITIAL_VALUE}`,
|
`initial-value:${CSS_INHERIT_INITIAL_VALUE}`,
|
||||||
]
|
],
|
||||||
);
|
});
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(
|
||||||
view,
|
view,
|
||||||
"h1",
|
"h1",
|
||||||
"border-color",
|
"border-color",
|
||||||
// The variable value is the initial value since the variable is not set
|
// The variable value is the initial value since the variable is not set
|
||||||
`--css-not-defined = ${CSS_NOT_DEFINED_INITIAL_VALUE}`,
|
{
|
||||||
[
|
header: `--css-not-defined = ${CSS_NOT_DEFINED_INITIAL_VALUE}`,
|
||||||
`syntax:"<color>"`,
|
registeredProperty: [
|
||||||
`inherits:true`,
|
`syntax:"<color>"`,
|
||||||
`initial-value:${CSS_NOT_DEFINED_INITIAL_VALUE}`,
|
`inherits:true`,
|
||||||
]
|
`initial-value:${CSS_NOT_DEFINED_INITIAL_VALUE}`,
|
||||||
|
],
|
||||||
|
}
|
||||||
);
|
);
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(
|
||||||
view,
|
view,
|
||||||
"h1",
|
"h1",
|
||||||
"height",
|
"height",
|
||||||
// The variable value is the initial value since the variable does not inherit
|
// The variable value is the initial value since the variable does not inherit
|
||||||
`--js-no-inherit = ${JS_NO_INHERIT_INITIAL_VALUE}`,
|
{
|
||||||
[
|
header: `--js-no-inherit = ${JS_NO_INHERIT_INITIAL_VALUE}`,
|
||||||
`syntax:"<length>"`,
|
registeredProperty: [
|
||||||
`inherits:false`,
|
`syntax:"<length>"`,
|
||||||
`initial-value:${JS_NO_INHERIT_INITIAL_VALUE}`,
|
`inherits:false`,
|
||||||
]
|
`initial-value:${JS_NO_INHERIT_INITIAL_VALUE}`,
|
||||||
|
],
|
||||||
|
}
|
||||||
);
|
);
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(
|
||||||
view,
|
view,
|
||||||
"h1",
|
"h1",
|
||||||
"width",
|
"width",
|
||||||
// The variable value is the value set in the main selector, since the variable does inherit
|
// The variable value is the value set in the main selector, since the variable does inherit
|
||||||
`--js-inherit = ${JS_INHERIT_MAIN_VALUE}`,
|
{
|
||||||
[`syntax:"*"`, `inherits:true`]
|
header: `--js-inherit = ${JS_INHERIT_MAIN_VALUE}`,
|
||||||
|
registeredProperty: [`syntax:"*"`, `inherits:true`],
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
info(
|
info(
|
||||||
@@ -241,13 +241,14 @@ add_task(async function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// The var() tooltip should show the initial value of the new property
|
// The var() tooltip should show the initial value of the new property
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(view, "h1", "caret-color", {
|
||||||
view,
|
header: `--css-dynamic-registered = orchid`,
|
||||||
"h1",
|
registeredProperty: [
|
||||||
"caret-color",
|
`syntax:"<color>"`,
|
||||||
`--css-dynamic-registered = orchid`,
|
`inherits:false`,
|
||||||
[`syntax:"<color>"`, `inherits:false`, `initial-value:orchid`]
|
`initial-value:orchid`,
|
||||||
);
|
],
|
||||||
|
});
|
||||||
|
|
||||||
info("Check that updating property does update rules view");
|
info("Check that updating property does update rules view");
|
||||||
onRuleViewRefreshed = view.once("ruleview-refreshed");
|
onRuleViewRefreshed = view.once("ruleview-refreshed");
|
||||||
@@ -281,13 +282,14 @@ add_task(async function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// The var() tooltip should show the new initial value of the updated property
|
// The var() tooltip should show the new initial value of the updated property
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(view, "h1", "caret-color", {
|
||||||
view,
|
header: `--css-dynamic-registered = purple`,
|
||||||
"h1",
|
registeredProperty: [
|
||||||
"caret-color",
|
`syntax:"<color>"`,
|
||||||
`--css-dynamic-registered = purple`,
|
`inherits:true`,
|
||||||
[`syntax:"<color>"`, `inherits:true`, `initial-value:purple`]
|
`initial-value:purple`,
|
||||||
);
|
],
|
||||||
|
});
|
||||||
|
|
||||||
info("Check that removing property does update rules view");
|
info("Check that removing property does update rules view");
|
||||||
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
||||||
@@ -304,12 +306,9 @@ add_task(async function () {
|
|||||||
checkRegisteredProperties(view, expectedProperties);
|
checkRegisteredProperties(view, expectedProperties);
|
||||||
|
|
||||||
// The var() tooltip should indicate that the property isn't set anymore
|
// The var() tooltip should indicate that the property isn't set anymore
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(view, "h1", "caret-color", {
|
||||||
view,
|
header: `--css-dynamic-registered is not set`,
|
||||||
"h1",
|
});
|
||||||
"caret-color",
|
|
||||||
`--css-dynamic-registered is not set`
|
|
||||||
);
|
|
||||||
|
|
||||||
info(
|
info(
|
||||||
"Check that registered properties from new constructed stylesheets are displayed"
|
"Check that registered properties from new constructed stylesheets are displayed"
|
||||||
@@ -353,13 +352,14 @@ add_task(async function () {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// The `var()` tooltip should show the initial-value of the new property
|
// The `var()` tooltip should show the initial-value of the new property
|
||||||
await checkVariableTooltipForProperty(
|
await assertVariableTooltipForProperty(view, "h1", "outline", {
|
||||||
view,
|
header: `--constructed = aqua`,
|
||||||
"h1",
|
registeredProperty: [
|
||||||
"outline",
|
`syntax:"<color>"`,
|
||||||
`--constructed = aqua`,
|
`inherits:true`,
|
||||||
[`syntax:"<color>"`, `inherits:true`, `initial-value:aqua`]
|
`initial-value:aqua`,
|
||||||
);
|
],
|
||||||
|
});
|
||||||
|
|
||||||
info(
|
info(
|
||||||
"Check that selecting a node in another document with no registered property hides the container"
|
"Check that selecting a node in another document with no registered property hides the container"
|
||||||
@@ -552,53 +552,3 @@ function checkRegisteredProperties(view, expectedProperties) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the content of a `var()` tooltip on a given rule and property name.
|
|
||||||
*
|
|
||||||
* @param {CssRuleView} view
|
|
||||||
* @param {String} ruleSelector
|
|
||||||
* @param {String} propertyName
|
|
||||||
* @param {String} expectedTooltipValueContent
|
|
||||||
* @param {Array<String>} expectedTooltipRegisteredPropertyContent
|
|
||||||
*/
|
|
||||||
async function checkVariableTooltipForProperty(
|
|
||||||
view,
|
|
||||||
ruleSelector,
|
|
||||||
propertyName,
|
|
||||||
expectedTooltipValueContent,
|
|
||||||
expectedTooltipRegisteredPropertyContent
|
|
||||||
) {
|
|
||||||
// retrieve tooltip target
|
|
||||||
const variableEl = await waitFor(() =>
|
|
||||||
getRuleViewProperty(
|
|
||||||
view,
|
|
||||||
ruleSelector,
|
|
||||||
propertyName
|
|
||||||
).valueSpan.querySelector(".ruleview-variable,.ruleview-unmatched-variable")
|
|
||||||
);
|
|
||||||
|
|
||||||
const previewTooltip = await assertShowPreviewTooltip(view, variableEl);
|
|
||||||
const [valueEl, registeredPropertyEl] = previewTooltip.panel.querySelectorAll(
|
|
||||||
".variable-value,.registered-property"
|
|
||||||
);
|
|
||||||
is(
|
|
||||||
valueEl.textContent,
|
|
||||||
expectedTooltipValueContent,
|
|
||||||
`CSS variable preview tooltip shows the expected value for ${propertyName} in ${ruleSelector}`
|
|
||||||
);
|
|
||||||
if (!expectedTooltipRegisteredPropertyContent) {
|
|
||||||
is(
|
|
||||||
registeredPropertyEl,
|
|
||||||
undefined,
|
|
||||||
`CSS variable preview tooltip doesn't have registered property section for ${propertyName} in ${ruleSelector}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
is(
|
|
||||||
registeredPropertyEl.innerText,
|
|
||||||
expectedTooltipRegisteredPropertyContent.join("\n"),
|
|
||||||
`CSS variable preview tooltip has expected registered property section for ${propertyName} in ${ruleSelector}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await assertTooltipHiddenOnMouseOut(previewTooltip, variableEl);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ function getNodeInfo(node, elementStyle) {
|
|||||||
sheetHref: rule.domRule.href,
|
sheetHref: rule.domRule.href,
|
||||||
textProperty: declaration,
|
textProperty: declaration,
|
||||||
variable: node.dataset.variable,
|
variable: node.dataset.variable,
|
||||||
|
startingStyleVariable: node.dataset.startingStyleVariable,
|
||||||
registeredProperty: {
|
registeredProperty: {
|
||||||
initialValue: node.dataset.registeredPropertyInitialValue,
|
initialValue: node.dataset.registeredPropertyInitialValue,
|
||||||
syntax: node.dataset.registeredPropertySyntax,
|
syntax: node.dataset.registeredPropertySyntax,
|
||||||
|
|||||||
@@ -611,6 +611,7 @@ TextPropertyEditor.prototype = {
|
|||||||
varName,
|
varName,
|
||||||
this.rule.pseudoElement
|
this.rule.pseudoElement
|
||||||
),
|
),
|
||||||
|
inStartingStyleRule: this.rule.isInStartingStyle(),
|
||||||
};
|
};
|
||||||
const frag = outputParser.parseCssProperty(name, val, parserOptions);
|
const frag = outputParser.parseCssProperty(name, val, parserOptions);
|
||||||
|
|
||||||
|
|||||||
@@ -347,8 +347,13 @@ TooltipsOverlay.prototype = {
|
|||||||
type === TOOLTIP_VARIABLE_TYPE &&
|
type === TOOLTIP_VARIABLE_TYPE &&
|
||||||
nodeInfo.value.value.startsWith("--")
|
nodeInfo.value.value.startsWith("--")
|
||||||
) {
|
) {
|
||||||
const { variable, registeredProperty } = nodeInfo.value;
|
const { variable, registeredProperty, startingStyleVariable } =
|
||||||
await this._setVariablePreviewTooltip(variable, registeredProperty);
|
nodeInfo.value;
|
||||||
|
await this._setVariablePreviewTooltip({
|
||||||
|
topSectionText: variable,
|
||||||
|
registeredProperty,
|
||||||
|
startingStyle: startingStyleVariable,
|
||||||
|
});
|
||||||
|
|
||||||
this.sendOpenScalarToTelemetry(type);
|
this.sendOpenScalarToTelemetry(type);
|
||||||
|
|
||||||
@@ -539,17 +544,16 @@ TooltipsOverlay.prototype = {
|
|||||||
/**
|
/**
|
||||||
* Set the content of the preview tooltip to display a variable preview.
|
* Set the content of the preview tooltip to display a variable preview.
|
||||||
*
|
*
|
||||||
* @param {String} text
|
* @param {Object} tooltipParams
|
||||||
* The text to display for the variable tooltip
|
* See VariableTooltipHelper#setVariableTooltip `params`.
|
||||||
* @return {Promise} A promise that resolves when the preview tooltip content is ready
|
* @return {Promise} A promise that resolves when the preview tooltip content is ready
|
||||||
*/
|
*/
|
||||||
async _setVariablePreviewTooltip(text, registeredProperty) {
|
async _setVariablePreviewTooltip(tooltipParams) {
|
||||||
const doc = this.view.inspector.panelDoc;
|
const doc = this.view.inspector.panelDoc;
|
||||||
await setVariableTooltip(
|
await setVariableTooltip(
|
||||||
this.getTooltip("previewTooltip"),
|
this.getTooltip("previewTooltip"),
|
||||||
doc,
|
doc,
|
||||||
text,
|
tooltipParams
|
||||||
registeredProperty
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -998,6 +998,82 @@ async function assertTooltipHiddenOnMouseOut(tooltip, target) {
|
|||||||
ok(!tooltip.isVisible(), "The tooltip is hidden on mouseout");
|
ok(!tooltip.isVisible(), "The tooltip is hidden on mouseout");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the content of a `var()` tooltip on a given rule and property name.
|
||||||
|
*
|
||||||
|
* @param {CssRuleView} view
|
||||||
|
* @param {String} ruleSelector
|
||||||
|
* @param {String} propertyName
|
||||||
|
* @param {Object} tooltipExpected
|
||||||
|
* @param {String} tooltipExpected.header: The text that is displayed in the top section
|
||||||
|
* (might be the only section when the variable is not a registered property and
|
||||||
|
* there is no starting-style).
|
||||||
|
* @param {String} tooltipExpected.startingStyle: The text that is displayed in the starting-style
|
||||||
|
* section. Pass undefined if the tooltip isn't supposed to have a `@starting-style` section.
|
||||||
|
* @param {Array<String>} tooltipExpected.registeredProperty: Array of the registered property
|
||||||
|
* fields (e.g. [`syntax:"<color>"`, `inherits:true`, `initial-value:aqua`]).
|
||||||
|
* Pass undefined if the tooltip isn't supposed to have a @property section.
|
||||||
|
*/
|
||||||
|
async function assertVariableTooltipForProperty(
|
||||||
|
view,
|
||||||
|
ruleSelector,
|
||||||
|
propertyName,
|
||||||
|
{ header, registeredProperty, startingStyle }
|
||||||
|
) {
|
||||||
|
// retrieve tooltip target
|
||||||
|
const variableEl = await waitFor(() =>
|
||||||
|
getRuleViewProperty(
|
||||||
|
view,
|
||||||
|
ruleSelector,
|
||||||
|
propertyName
|
||||||
|
).valueSpan.querySelector(".ruleview-variable,.ruleview-unmatched-variable")
|
||||||
|
);
|
||||||
|
|
||||||
|
const previewTooltip = await assertShowPreviewTooltip(view, variableEl);
|
||||||
|
const valueEl = previewTooltip.panel.querySelector(".variable-value");
|
||||||
|
const startingStyleEl = previewTooltip.panel.querySelector(
|
||||||
|
".starting-style div"
|
||||||
|
);
|
||||||
|
const registeredPropertyEl = previewTooltip.panel.querySelector(
|
||||||
|
".registered-property dl"
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
valueEl.textContent,
|
||||||
|
header,
|
||||||
|
`CSS variable preview tooltip has expected header text for ${propertyName} in ${ruleSelector}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!registeredProperty) {
|
||||||
|
is(
|
||||||
|
registeredPropertyEl,
|
||||||
|
null,
|
||||||
|
`CSS variable preview tooltip doesn't have registered property section for ${propertyName} in ${ruleSelector}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
is(
|
||||||
|
registeredPropertyEl.innerText,
|
||||||
|
registeredProperty.join("\n"),
|
||||||
|
`CSS variable preview tooltip has expected registered property section for ${propertyName} in ${ruleSelector}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!startingStyle) {
|
||||||
|
is(
|
||||||
|
startingStyleEl,
|
||||||
|
null,
|
||||||
|
`CSS variable preview tooltip doesn't have a starting-style section for ${propertyName} in ${ruleSelector}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
is(
|
||||||
|
startingStyleEl.innerText,
|
||||||
|
startingStyle,
|
||||||
|
`CSS variable preview tooltip has expected starting-style section for ${propertyName} in ${ruleSelector}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await assertTooltipHiddenOnMouseOut(previewTooltip, variableEl);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the text displayed for a given DOM Element's textContent within the
|
* Get the text displayed for a given DOM Element's textContent within the
|
||||||
* markup view.
|
* markup view.
|
||||||
|
|||||||
@@ -297,31 +297,57 @@ class OutputParser {
|
|||||||
const secondOpts = {};
|
const secondOpts = {};
|
||||||
|
|
||||||
let varData;
|
let varData;
|
||||||
let varValue;
|
|
||||||
let varFallbackValue;
|
let varFallbackValue;
|
||||||
|
let varSubsitutedValue;
|
||||||
|
|
||||||
// Get the variable value if it is in use.
|
// Get the variable value if it is in use.
|
||||||
if (tokens && tokens.length === 1) {
|
if (tokens && tokens.length === 1) {
|
||||||
varData = options.getVariableData(tokens[0].text);
|
varData = options.getVariableData(tokens[0].text);
|
||||||
varValue =
|
const varValue =
|
||||||
typeof varData.value === "string"
|
typeof varData.value === "string"
|
||||||
? varData.value
|
? varData.value
|
||||||
: varData.registeredProperty?.initialValue;
|
: varData.registeredProperty?.initialValue;
|
||||||
|
|
||||||
|
const varStartingStyleValue =
|
||||||
|
typeof varData.startingStyle === "string"
|
||||||
|
? varData.startingStyle
|
||||||
|
: // If the variable is not set in starting style, then it will default to either:
|
||||||
|
// - a declaration in a "regular" rule
|
||||||
|
// - or if there's no declaration in regular rule, to the registered property initial-value.
|
||||||
|
varValue;
|
||||||
|
|
||||||
|
varSubsitutedValue = options.inStartingStyleRule
|
||||||
|
? varStartingStyleValue
|
||||||
|
: varValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the variable name.
|
// Get the variable name.
|
||||||
const varName = text.substring(tokens[0].startOffset, tokens[0].endOffset);
|
const varName = text.substring(tokens[0].startOffset, tokens[0].endOffset);
|
||||||
|
|
||||||
if (typeof varValue === "string") {
|
if (typeof varSubsitutedValue === "string") {
|
||||||
// The variable value is valid, set the variable name's title of the first argument
|
// The variable value is valid, set the variable name's title of the first argument
|
||||||
// in var() to display the variable name and value.
|
// in var() to display the variable name and value.
|
||||||
firstOpts["data-variable"] = STYLE_INSPECTOR_L10N.getFormatStr(
|
firstOpts["data-variable"] = STYLE_INSPECTOR_L10N.getFormatStr(
|
||||||
"rule.variableValue",
|
"rule.variableValue",
|
||||||
varName,
|
varName,
|
||||||
varValue
|
varSubsitutedValue
|
||||||
);
|
);
|
||||||
firstOpts.class = options.matchedVariableClass;
|
firstOpts.class = options.matchedVariableClass;
|
||||||
secondOpts.class = options.unmatchedVariableClass;
|
secondOpts.class = options.unmatchedVariableClass;
|
||||||
|
|
||||||
|
// Display starting-style value when not in a starting style rule
|
||||||
|
if (
|
||||||
|
!options.inStartingStyleRule &&
|
||||||
|
typeof varData.startingStyle === "string"
|
||||||
|
) {
|
||||||
|
firstOpts["data-starting-style-variable"] =
|
||||||
|
STYLE_INSPECTOR_L10N.getFormatStr(
|
||||||
|
"rule.variableValue",
|
||||||
|
varName,
|
||||||
|
varData.startingStyle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (varData.registeredProperty) {
|
if (varData.registeredProperty) {
|
||||||
const { initialValue, syntax, inherits } = varData.registeredProperty;
|
const { initialValue, syntax, inherits } = varData.registeredProperty;
|
||||||
firstOpts["data-registered-property-initial-value"] = initialValue;
|
firstOpts["data-registered-property-initial-value"] = initialValue;
|
||||||
@@ -363,7 +389,7 @@ class OutputParser {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
node: variableNode,
|
node: variableNode,
|
||||||
value: varValue,
|
value: varSubsitutedValue,
|
||||||
fallbackValue: varFallbackValue,
|
fallbackValue: varFallbackValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2074,6 +2100,7 @@ class OutputParser {
|
|||||||
baseURI: undefined,
|
baseURI: undefined,
|
||||||
getVariableData: null,
|
getVariableData: null,
|
||||||
unmatchedVariableClass: null,
|
unmatchedVariableClass: null,
|
||||||
|
inStartingStyleRule: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const item in overrides) {
|
for (const item in overrides) {
|
||||||
|
|||||||
@@ -14,23 +14,57 @@ const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
|||||||
* The tooltip instance on which the text preview content should be set.
|
* The tooltip instance on which the text preview content should be set.
|
||||||
* @param {Document} doc
|
* @param {Document} doc
|
||||||
* A document element to create the HTML elements needed for the tooltip.
|
* A document element to create the HTML elements needed for the tooltip.
|
||||||
* @param {String} text
|
* @param {Object} params
|
||||||
* Text to display in tooltip.
|
* @param {String} params.topSectionText
|
||||||
|
* Text to display in the top section of tooltip (e.g. "--x = blue" or "--x is not defined").
|
||||||
|
* @param {Object} params.registeredProperty
|
||||||
|
* Contains the registered property data, if the variable was registered (@property or CSS.registerProperty)
|
||||||
|
* @param {String} params.registeredProperty.syntax
|
||||||
|
* The registered property `syntax` value
|
||||||
|
* @param {Boolean} params.registeredProperty.inherits
|
||||||
|
* The registered property `inherits` value
|
||||||
|
* @param {String} params.registeredProperty.initialValue
|
||||||
|
* The registered property `initial-value`
|
||||||
|
* @param {String} params.startingStyle
|
||||||
|
* The text for @starting-style value (e.g. `--x = red`)
|
||||||
*/
|
*/
|
||||||
function setVariableTooltip(tooltip, doc, text, registeredProperty) {
|
function setVariableTooltip(
|
||||||
|
tooltip,
|
||||||
|
doc,
|
||||||
|
{ topSectionText, registeredProperty, startingStyle }
|
||||||
|
) {
|
||||||
// Create tooltip content
|
// Create tooltip content
|
||||||
const div = doc.createElementNS(XHTML_NS, "div");
|
const div = doc.createElementNS(XHTML_NS, "div");
|
||||||
div.classList.add("devtools-monospace", "devtools-tooltip-css-variable");
|
div.classList.add("devtools-monospace", "devtools-tooltip-css-variable");
|
||||||
|
|
||||||
const valueEl = doc.createElementNS(XHTML_NS, "section");
|
const valueEl = doc.createElementNS(XHTML_NS, "section");
|
||||||
valueEl.classList.add("variable-value");
|
valueEl.classList.add("variable-value");
|
||||||
valueEl.append(doc.createTextNode(text));
|
valueEl.append(doc.createTextNode(topSectionText));
|
||||||
div.appendChild(valueEl);
|
div.appendChild(valueEl);
|
||||||
|
|
||||||
|
// A registered property always have a non-falsy syntax
|
||||||
|
if (typeof startingStyle !== "undefined") {
|
||||||
|
const section = doc.createElementNS(XHTML_NS, "section");
|
||||||
|
section.classList.add("starting-style", "variable-tooltip-section");
|
||||||
|
|
||||||
|
const h2 = doc.createElementNS(XHTML_NS, "h2");
|
||||||
|
h2.append(doc.createTextNode("@starting-style"));
|
||||||
|
const startingStyleValue = doc.createElementNS(XHTML_NS, "div");
|
||||||
|
startingStyleValue.append(doc.createTextNode(startingStyle));
|
||||||
|
section.append(h2, startingStyleValue);
|
||||||
|
|
||||||
|
div.appendChild(section);
|
||||||
|
}
|
||||||
|
|
||||||
// A registered property always have a non-falsy syntax
|
// A registered property always have a non-falsy syntax
|
||||||
if (registeredProperty?.syntax) {
|
if (registeredProperty?.syntax) {
|
||||||
|
const section = doc.createElementNS(XHTML_NS, "section");
|
||||||
|
section.classList.add("registered-property", "variable-tooltip-section");
|
||||||
|
|
||||||
|
const h2 = doc.createElementNS(XHTML_NS, "h2");
|
||||||
|
h2.append(doc.createTextNode("@property"));
|
||||||
|
|
||||||
const dl = doc.createElementNS(XHTML_NS, "dl");
|
const dl = doc.createElementNS(XHTML_NS, "dl");
|
||||||
dl.classList.add("registered-property");
|
|
||||||
const addProperty = (label, value, lineBreak = true) => {
|
const addProperty = (label, value, lineBreak = true) => {
|
||||||
const dt = doc.createElementNS(XHTML_NS, "dt");
|
const dt = doc.createElementNS(XHTML_NS, "dt");
|
||||||
dt.append(doc.createTextNode(label));
|
dt.append(doc.createTextNode(label));
|
||||||
@@ -50,7 +84,8 @@ function setVariableTooltip(tooltip, doc, text, registeredProperty) {
|
|||||||
addProperty("initial-value:", registeredProperty.initialValue, false);
|
addProperty("initial-value:", registeredProperty.initialValue, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.appendChild(dl);
|
section.append(h2, dl);
|
||||||
|
div.appendChild(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
tooltip.panel.innerHTML = "";
|
tooltip.panel.innerHTML = "";
|
||||||
|
|||||||
@@ -94,15 +94,25 @@ strong {
|
|||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
max-inline-size: 100vw;
|
max-inline-size: 100vw;
|
||||||
|
|
||||||
.variable-value:has(+ .registered-property) {
|
.variable-value:has(+ .variable-tooltip-section) {
|
||||||
padding-block-end: var(--block-padding);
|
padding-block-end: var(--block-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
.registered-property {
|
.variable-tooltip-section {
|
||||||
border-block-start: 1px solid var(--theme-splitter-color);
|
border-block-start: 1px solid var(--theme-splitter-color);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding-block: var(--block-padding);
|
||||||
padding-block-start: var(--block-padding);
|
|
||||||
|
h2 {
|
||||||
|
margin-block: 0;
|
||||||
|
padding-block-start: 0;
|
||||||
|
padding-block-end: var(--block-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
dt,dd {
|
dt,dd {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|||||||
Reference in New Issue
Block a user