mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-06 16:32:24 +00:00
refactor: simplify style element inlining
This commit is contained in:
+48
-60
@@ -118,7 +118,8 @@ function specificity(selector) {
|
|||||||
|
|
||||||
case 'TypeSelector':
|
case 'TypeSelector':
|
||||||
// ignore universal selector
|
// ignore universal selector
|
||||||
if (node.name.charAt(node.name.length - 1) !== '*') {
|
const { name } = node;
|
||||||
|
if (name.charAt(name.length - 1) !== '*') {
|
||||||
C++;
|
C++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -171,26 +172,19 @@ function flattenToSelectors(cssAst, selectors) {
|
|||||||
* Filter selectors by Media Query.
|
* Filter selectors by Media Query.
|
||||||
*
|
*
|
||||||
* @param {Array} selectors to filter
|
* @param {Array} selectors to filter
|
||||||
* @param {Array} useMqs Array with strings of media queries that should pass (<name> <expression>)
|
|
||||||
* @return {Array} Filtered selectors that match the passed media queries
|
* @return {Array} Filtered selectors that match the passed media queries
|
||||||
*/
|
*/
|
||||||
function filterByMqs(selectors, useMqs) {
|
function filterByMqs(selectors) {
|
||||||
return selectors.filter(selector => {
|
return selectors.filter(({ atrule }) => {
|
||||||
if (selector.atrule === null) {
|
if (atrule === null) {
|
||||||
return ~useMqs.indexOf('');
|
return ~useMqs.indexOf('');
|
||||||
}
|
}
|
||||||
|
const { name, expression } = atrule;
|
||||||
const mqName = selector.atrule.name;
|
return ~useMqs.indexOf(
|
||||||
let mqStr = mqName;
|
expression && expression.children.first().type === 'MediaQueryList'
|
||||||
if (
|
? [name, csstree.generate(expression)].join(' ')
|
||||||
selector.atrule.expression &&
|
: name,
|
||||||
selector.atrule.expression.children.first().type === 'MediaQueryList'
|
);
|
||||||
) {
|
|
||||||
const mqExpr = csstree.generate(selector.atrule.expression);
|
|
||||||
mqStr = [mqName, mqExpr].join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
return ~useMqs.indexOf(mqStr);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,21 +192,20 @@ function filterByMqs(selectors, useMqs) {
|
|||||||
* Filter selectors by the pseudo-elements and/or -classes they contain.
|
* Filter selectors by the pseudo-elements and/or -classes they contain.
|
||||||
*
|
*
|
||||||
* @param {Array} selectors to filter
|
* @param {Array} selectors to filter
|
||||||
* @param {Array} usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass
|
|
||||||
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
|
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
|
||||||
*/
|
*/
|
||||||
function filterByPseudos(selectors, usePseudos) {
|
function filterByPseudos(selectors) {
|
||||||
return selectors.filter(selector => {
|
return selectors.filter(
|
||||||
const pseudoSelectorsStr = csstree.generate({
|
({ pseudos }) =>
|
||||||
type: 'Selector',
|
~usePseudos.indexOf(
|
||||||
children: new List().fromArray(
|
csstree.generate({
|
||||||
selector.pseudos.map(pseudo => {
|
type: 'Selector',
|
||||||
return pseudo.item.data;
|
children: new List().fromArray(
|
||||||
|
pseudos.map(pseudo => pseudo.item.data),
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
});
|
);
|
||||||
return ~usePseudos.indexOf(pseudoSelectorsStr);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -222,11 +215,9 @@ function filterByPseudos(selectors, usePseudos) {
|
|||||||
* @return {Array} Selectors without pseudo-elements and/or -classes
|
* @return {Array} Selectors without pseudo-elements and/or -classes
|
||||||
*/
|
*/
|
||||||
function cleanPseudos(selectors) {
|
function cleanPseudos(selectors) {
|
||||||
selectors.forEach(selector => {
|
selectors.forEach(({ pseudos }) =>
|
||||||
selector.pseudos.forEach(pseudo => {
|
pseudos.forEach(pseudo => pseudo.list.remove(pseudo.item)),
|
||||||
pseudo.list.remove(pseudo.item);
|
);
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,7 +236,6 @@ function compareSpecificity(aSpecificity, bSpecificity) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +262,10 @@ function sortSelectors(selectors) {
|
|||||||
return stable(selectors, bySelectorSpecificity);
|
return stable(selectors, bySelectorSpecificity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const declarationParseProps = {
|
||||||
|
context: 'declarationList',
|
||||||
|
parseValue: false,
|
||||||
|
};
|
||||||
function CSSStyleDeclaration(node) {
|
function CSSStyleDeclaration(node) {
|
||||||
const style = {
|
const style = {
|
||||||
style: node.props.style,
|
style: node.props.style,
|
||||||
@@ -281,13 +275,9 @@ function CSSStyleDeclaration(node) {
|
|||||||
if (!styles || styles.length === 0) {
|
if (!styles || styles.length === 0) {
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
csstree
|
csstree
|
||||||
.parse(styles, {
|
.parse(styles, declarationParseProps)
|
||||||
context: 'declarationList',
|
|
||||||
parseValue: false,
|
|
||||||
})
|
|
||||||
.children.each(({ property, value, important }) => {
|
.children.each(({ property, value, important }) => {
|
||||||
try {
|
try {
|
||||||
setProperty(style, property, csstree.generate(value), important);
|
setProperty(style, property, csstree.generate(value), important);
|
||||||
@@ -306,7 +296,6 @@ function CSSStyleDeclaration(node) {
|
|||||||
parseError,
|
parseError,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,9 +330,7 @@ function setProperty({ properties, style }, name, value, important) {
|
|||||||
*/
|
*/
|
||||||
function closestElem(node, elemName) {
|
function closestElem(node, elemName) {
|
||||||
let elem = node;
|
let elem = node;
|
||||||
|
|
||||||
while ((elem = elem.parent) && elem.tag !== elemName) {}
|
while ((elem = elem.parent) && elem.tag !== elemName) {}
|
||||||
|
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +343,17 @@ function initStyle(selectedEl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// useMqs Array with strings of media queries that should pass (<name> <expression>)
|
||||||
|
const useMqs = ['', 'screen'];
|
||||||
|
|
||||||
|
// usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass
|
||||||
|
const usePseudos = [''];
|
||||||
|
|
||||||
|
const parseProps = {
|
||||||
|
parseValue: false,
|
||||||
|
parseCustomProperty: false,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves + merges styles from style elements to element styles
|
* Moves + merges styles from style elements to element styles
|
||||||
*
|
*
|
||||||
@@ -369,14 +367,10 @@ function initStyle(selectedEl) {
|
|||||||
* empty string element for all non-pseudo-classes and/or -elements
|
* empty string element for all non-pseudo-classes and/or -elements
|
||||||
*
|
*
|
||||||
* @param {Object} document document element
|
* @param {Object} document document element
|
||||||
* @param {Object} opts plugin params
|
|
||||||
*
|
*
|
||||||
* @author strarsis <strarsis@gmail.com>
|
* @author strarsis <strarsis@gmail.com>
|
||||||
|
* @author modified by: msand <msand@abo.fim>
|
||||||
*/
|
*/
|
||||||
const opts = {
|
|
||||||
useMqs: ['', 'screen'],
|
|
||||||
usePseudos: [''],
|
|
||||||
};
|
|
||||||
export function inlineStyles(document) {
|
export function inlineStyles(document) {
|
||||||
// collect <style/>s
|
// collect <style/>s
|
||||||
const styleElements = querySelectorAll(document, 'style');
|
const styleElements = querySelectorAll(document, 'style');
|
||||||
@@ -397,13 +391,7 @@ export function inlineStyles(document) {
|
|||||||
|
|
||||||
// collect <style/>s and their css ast
|
// collect <style/>s and their css ast
|
||||||
try {
|
try {
|
||||||
flattenToSelectors(
|
flattenToSelectors(csstree.parse(children, parseProps), selectors);
|
||||||
csstree.parse(children, {
|
|
||||||
parseValue: false,
|
|
||||||
parseCustomProperty: false,
|
|
||||||
}),
|
|
||||||
selectors,
|
|
||||||
);
|
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'Warning: Parse error of styles of <style/> element, skipped. Error details: ' +
|
'Warning: Parse error of styles of <style/> element, skipped. Error details: ' +
|
||||||
@@ -413,10 +401,10 @@ export function inlineStyles(document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter for mediaqueries to be used or without any mediaquery
|
// filter for mediaqueries to be used or without any mediaquery
|
||||||
const selectorsMq = filterByMqs(selectors, opts.useMqs);
|
const selectorsMq = filterByMqs(selectors);
|
||||||
|
|
||||||
// filter for pseudo elements to be used
|
// filter for pseudo elements to be used
|
||||||
const selectorsPseudo = filterByPseudos(selectorsMq, opts.usePseudos);
|
const selectorsPseudo = filterByPseudos(selectorsMq);
|
||||||
|
|
||||||
// remove PseudoClass from its SimpleSelector for proper matching
|
// remove PseudoClass from its SimpleSelector for proper matching
|
||||||
cleanPseudos(selectorsPseudo);
|
cleanPseudos(selectorsPseudo);
|
||||||
@@ -425,18 +413,18 @@ export function inlineStyles(document) {
|
|||||||
const sortedSelectors = sortSelectors(selectorsPseudo).reverse();
|
const sortedSelectors = sortSelectors(selectorsPseudo).reverse();
|
||||||
|
|
||||||
// match selectors
|
// match selectors
|
||||||
for (let selector of sortedSelectors) {
|
for (let { rule, item } of sortedSelectors) {
|
||||||
if (selector.rule === null) {
|
if (rule === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const selectorStr = csstree.generate(selector.item.data);
|
const selectorStr = csstree.generate(item.data);
|
||||||
try {
|
try {
|
||||||
// apply <style/> to matched elements
|
// apply <style/> to matched elements
|
||||||
for (let element of querySelectorAll(document, selectorStr)) {
|
for (let element of querySelectorAll(document, selectorStr)) {
|
||||||
initStyle(element);
|
initStyle(element);
|
||||||
const { style } = element;
|
const { style } = element;
|
||||||
const { properties } = style;
|
const { properties } = style;
|
||||||
csstree.walk(selector.rule, {
|
csstree.walk(rule, {
|
||||||
visit: 'Declaration',
|
visit: 'Declaration',
|
||||||
enter({ property, value, important }) {
|
enter({ property, value, important }) {
|
||||||
// existing inline styles have higher priority
|
// existing inline styles have higher priority
|
||||||
|
|||||||
Reference in New Issue
Block a user