mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-06-08 04:31:19 +00:00
Refactor how pointerEvents styles are managed
This commit is contained in:
@@ -39,7 +39,7 @@ No benchmark will run for more than 20 seconds.
|
|||||||
|
|
||||||
MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM. Google Chrome 63.
|
MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM. Google Chrome 63.
|
||||||
|
|
||||||
Typical render timings*: mean ± standard deviations.
|
Typical render timings: mean ± standard deviations.
|
||||||
|
|
||||||
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
|
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
|
||||||
| :--- | ---: | ---: | ---: |
|
| :--- | ---: | ---: | ---: |
|
||||||
@@ -66,7 +66,7 @@ Other libraries
|
|||||||
|
|
||||||
Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63
|
Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63
|
||||||
|
|
||||||
Typical render timings*: mean ± standard deviations.
|
Typical render timings: mean ± standard deviations.
|
||||||
|
|
||||||
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
|
| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) |
|
||||||
| :--- | ---: | ---: | ---: |
|
| :--- | ---: | ---: | ---: |
|
||||||
|
|||||||
@@ -21,57 +21,43 @@ const createClassName = (prop, value) => {
|
|||||||
return process.env.NODE_ENV !== 'production' ? `rn-${prop}-${hashed}` : `rn-${hashed}`;
|
return process.env.NODE_ENV !== 'production' ? `rn-${prop}-${hashed}` : `rn-${hashed}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createCssRule = (className, prop, value) => {
|
const createCssRules = (selector, prop, value) => {
|
||||||
const css = generateCss({ [prop]: value });
|
const rules = [];
|
||||||
const selector = `.${className}`;
|
let v = value;
|
||||||
return `${selector}{${css}}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const pointerEvents = {
|
// pointerEvents is a special case that requires custom values and additional css rules
|
||||||
auto: createClassName('pointerEvents', 'auto'),
|
if (prop === 'pointerEvents') {
|
||||||
boxNone: createClassName('pointerEvents', 'box-none'),
|
if (value === 'auto' || value === 'box-only') {
|
||||||
boxOnly: createClassName('pointerEvents', 'box-only'),
|
v = 'auto !important';
|
||||||
none: createClassName('pointerEvents', 'none')
|
if (value === 'box-only') {
|
||||||
|
const css = generateCss({ [prop]: 'none' });
|
||||||
|
rules.push(`${selector} > *{${css}}`);
|
||||||
|
}
|
||||||
|
} else if (value === 'none' || value === 'box-none') {
|
||||||
|
v = 'none !important';
|
||||||
|
if (value === 'box-none') {
|
||||||
|
const css = generateCss({ [prop]: 'auto' });
|
||||||
|
rules.push(`${selector} > *{${css}}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const css = generateCss({ [prop]: v });
|
||||||
|
rules.push(`${selector}{${css}}`);
|
||||||
|
|
||||||
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
// See #513
|
// See #513
|
||||||
const pointerEventsCss =
|
|
||||||
`.${pointerEvents.auto}{pointer-events:auto !important;}\n` +
|
|
||||||
`.${pointerEvents.boxOnly}{pointer-events:auto !important;}\n` +
|
|
||||||
`.${pointerEvents.none}{pointer-events:none !important;}\n` +
|
|
||||||
`.${pointerEvents.boxNone}{pointer-events:none !important;}\n` +
|
|
||||||
`.${pointerEvents.boxNone} > *{pointer-events:auto;}\n` +
|
|
||||||
`.${pointerEvents.boxOnly} > *{pointer-events:none;}`;
|
|
||||||
|
|
||||||
export default class StyleSheetManager {
|
export default class StyleSheetManager {
|
||||||
cache = null;
|
cache = null;
|
||||||
mainSheet = null;
|
mainSheet = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// custom pointer event values are implemented using descendent selectors,
|
|
||||||
// so we manually create the CSS and pre-register the declarations
|
|
||||||
const pointerEventsPropName = 'pointerEvents';
|
|
||||||
this.cache = {
|
this.cache = {
|
||||||
byClassName: {
|
byClassName: {},
|
||||||
[pointerEvents.auto]: { prop: pointerEventsPropName, value: 'auto' },
|
byProp: {}
|
||||||
[pointerEvents.boxNone]: {
|
|
||||||
prop: pointerEventsPropName,
|
|
||||||
value: 'box-none'
|
|
||||||
},
|
|
||||||
[pointerEvents.boxOnly]: {
|
|
||||||
prop: pointerEventsPropName,
|
|
||||||
value: 'box-only'
|
|
||||||
},
|
|
||||||
[pointerEvents.none]: { prop: pointerEventsPropName, value: 'none' }
|
|
||||||
},
|
|
||||||
byProp: {
|
|
||||||
pointerEvents: {
|
|
||||||
auto: pointerEvents.auto,
|
|
||||||
'box-none': pointerEvents.boxNone,
|
|
||||||
'box-only': pointerEvents.boxOnly,
|
|
||||||
none: pointerEvents.none
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// on the client we check for an existing style sheet before injecting style sheets
|
// on the client we check for an existing style sheet before injecting style sheets
|
||||||
@@ -84,6 +70,11 @@ export default class StyleSheetManager {
|
|||||||
this.mainSheet = document.getElementById(STYLE_ELEMENT_ID);
|
this.mainSheet = document.getElementById(STYLE_ELEMENT_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// need to pre-register pointerEvents as they have no inline-style equivalent
|
||||||
|
['box-only', 'box-none', 'auto', 'none'].forEach(v => {
|
||||||
|
this.setDeclaration('pointerEvents', v);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getClassName(prop, value) {
|
getClassName(prop, value) {
|
||||||
@@ -110,13 +101,12 @@ export default class StyleSheetManager {
|
|||||||
|
|
||||||
const mainSheetTextContext = Object.keys(cache)
|
const mainSheetTextContext = Object.keys(cache)
|
||||||
.reduce((rules, prop) => {
|
.reduce((rules, prop) => {
|
||||||
if (prop !== 'pointerEvents') {
|
Object.keys(cache[prop]).forEach(value => {
|
||||||
Object.keys(cache[prop]).forEach(value => {
|
const className = this.getClassName(prop, value);
|
||||||
const className = this.getClassName(prop, value);
|
const moreRules = createCssRules(`.${className}`, prop, value);
|
||||||
const rule = createCssRule(className, prop, value);
|
rules.push(...moreRules);
|
||||||
rules.push(rule);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
return rules;
|
return rules;
|
||||||
}, [])
|
}, [])
|
||||||
.join('\n');
|
.join('\n');
|
||||||
@@ -124,7 +114,7 @@ export default class StyleSheetManager {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 'react-native-stylesheet-static',
|
id: 'react-native-stylesheet-static',
|
||||||
textContent: `${staticCss}\n${pointerEventsCss}`
|
textContent: `${staticCss}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: STYLE_ELEMENT_ID,
|
id: STYLE_ELEMENT_ID,
|
||||||
@@ -142,8 +132,8 @@ export default class StyleSheetManager {
|
|||||||
const sheet = this.mainSheet.sheet;
|
const sheet = this.mainSheet.sheet;
|
||||||
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
||||||
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
||||||
const rule = createCssRule(className, prop, value);
|
const rules = createCssRules(`.${className}`, prop, value);
|
||||||
sheet.insertRule(rule, sheet.cssRules.length);
|
rules.forEach(rule => sheet.insertRule(rule, sheet.cssRules.length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user