mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-06-07 20:21:25 +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.
|
||||
|
||||
Typical render timings*: mean ± standard deviations.
|
||||
Typical render timings: mean ± standard deviations.
|
||||
|
||||
| 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
|
||||
|
||||
Typical render timings*: mean ± standard deviations.
|
||||
Typical render timings: mean ± standard deviations.
|
||||
|
||||
| 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}`;
|
||||
};
|
||||
|
||||
const createCssRule = (className, prop, value) => {
|
||||
const css = generateCss({ [prop]: value });
|
||||
const selector = `.${className}`;
|
||||
return `${selector}{${css}}`;
|
||||
};
|
||||
const createCssRules = (selector, prop, value) => {
|
||||
const rules = [];
|
||||
let v = value;
|
||||
|
||||
const pointerEvents = {
|
||||
auto: createClassName('pointerEvents', 'auto'),
|
||||
boxNone: createClassName('pointerEvents', 'box-none'),
|
||||
boxOnly: createClassName('pointerEvents', 'box-only'),
|
||||
none: createClassName('pointerEvents', 'none')
|
||||
// pointerEvents is a special case that requires custom values and additional css rules
|
||||
if (prop === 'pointerEvents') {
|
||||
if (value === 'auto' || value === 'box-only') {
|
||||
v = 'auto !important';
|
||||
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
|
||||
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 {
|
||||
cache = null;
|
||||
mainSheet = null;
|
||||
|
||||
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 = {
|
||||
byClassName: {
|
||||
[pointerEvents.auto]: { prop: pointerEventsPropName, value: 'auto' },
|
||||
[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
|
||||
}
|
||||
}
|
||||
byClassName: {},
|
||||
byProp: {}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -110,13 +101,12 @@ export default class StyleSheetManager {
|
||||
|
||||
const mainSheetTextContext = Object.keys(cache)
|
||||
.reduce((rules, prop) => {
|
||||
if (prop !== 'pointerEvents') {
|
||||
Object.keys(cache[prop]).forEach(value => {
|
||||
const className = this.getClassName(prop, value);
|
||||
const rule = createCssRule(className, prop, value);
|
||||
rules.push(rule);
|
||||
});
|
||||
}
|
||||
Object.keys(cache[prop]).forEach(value => {
|
||||
const className = this.getClassName(prop, value);
|
||||
const moreRules = createCssRules(`.${className}`, prop, value);
|
||||
rules.push(...moreRules);
|
||||
});
|
||||
|
||||
return rules;
|
||||
}, [])
|
||||
.join('\n');
|
||||
@@ -124,7 +114,7 @@ export default class StyleSheetManager {
|
||||
return [
|
||||
{
|
||||
id: 'react-native-stylesheet-static',
|
||||
textContent: `${staticCss}\n${pointerEventsCss}`
|
||||
textContent: `${staticCss}`
|
||||
},
|
||||
{
|
||||
id: STYLE_ELEMENT_ID,
|
||||
@@ -142,8 +132,8 @@ export default class StyleSheetManager {
|
||||
const sheet = this.mainSheet.sheet;
|
||||
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
||||
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
||||
const rule = createCssRule(className, prop, value);
|
||||
sheet.insertRule(rule, sheet.cssRules.length);
|
||||
const rules = createCssRules(`.${className}`, prop, value);
|
||||
rules.forEach(rule => sheet.insertRule(rule, sheet.cssRules.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user