diff --git a/.changeset/simplifify-hover-replacement.md b/.changeset/simplifify-hover-replacement.md new file mode 100644 index 0000000000..155333302c --- /dev/null +++ b/.changeset/simplifify-hover-replacement.md @@ -0,0 +1,6 @@ +--- +"rrweb-snapshot": patch +"rrweb": patch +--- + +Slight simplification to how we replace :hover after #1458 diff --git a/packages/rrweb-snapshot/src/css.ts b/packages/rrweb-snapshot/src/css.ts index 8538c4a687..ec85468af6 100644 --- a/packages/rrweb-snapshot/src/css.ts +++ b/packages/rrweb-snapshot/src/css.ts @@ -17,7 +17,7 @@ const mediaSelectorPlugin: AcceptedPlugin = { }, }; -// Adapted from https://github.com/giuseppeg/postcss-pseudo-classes/blob/master/index.js +// Simplified from https://github.com/giuseppeg/postcss-pseudo-classes/blob/master/index.js const pseudoClassPlugin: AcceptedPlugin = { postcssPlugin: 'postcss-hover-classes', prepare: function () { @@ -28,58 +28,9 @@ const pseudoClassPlugin: AcceptedPlugin = { return; } fixed.push(rule); - rule.selectors.forEach(function (selector) { - if (!selector.includes(':')) { - return; - } - - const selectorParts = selector.replace(/\n/g, ' ').split(' '); - const pseudoedSelectorParts: string[] = []; - - selectorParts.forEach(function (selectorPart) { - const pseudos = selectorPart.match(/::?([^:]+)/g); - - if (!pseudos) { - pseudoedSelectorParts.push(selectorPart); - return; - } - - const baseSelector = selectorPart.substr( - 0, - selectorPart.length - pseudos.join('').length, - ); - - const classPseudos = pseudos.map(function (pseudo) { - const pseudoToCheck = pseudo.replace(/\(.*/g, ''); - if (pseudoToCheck !== ':hover') { - return pseudo; - } - - // Ignore pseudo-elements! - if (pseudo.match(/^::/)) { - return pseudo; - } - - // Kill the colon - pseudo = pseudo.substr(1); - - // Replace left and right parens - pseudo = pseudo.replace(/\(/g, '\\('); - pseudo = pseudo.replace(/\)/g, '\\)'); - - return '.' + '\\:' + pseudo; - }); - - pseudoedSelectorParts.push(baseSelector + classPseudos.join('')); - }); - - addSelector(pseudoedSelectorParts.join(' ')); - - function addSelector(newSelector: string) { - if (newSelector && newSelector !== selector) { - rule.selector += ',\n' + newSelector; - } + if (selector.includes(':hover')) { + rule.selector += ',\n' + selector.replace(/:hover/g, '.\\:hover'); } }); }, diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index d51fad363f..75e261c102 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -50,10 +50,18 @@ describe('css parser', () => { describe('pseudoClassPlugin', () => { it('parses nested commas in selectors correctly', () => { const cssText = - 'body > ul :is(li:not(:first-of-type) a:hover, li:not(:first-of-type).active a) {background: red;}'; + 'body > ul :is(li:not(:first-of-type) a.current, li:not(:first-of-type).active a) {background: red;}'; expect(parse(pseudoClassPlugin, cssText)).toEqual(cssText); }); + it("doesn't ignore :hover within :is brackets", () => { + const cssText = + 'body > ul :is(li:not(:first-of-type) a:hover, li:not(:first-of-type).active a) {background: red;}'; + expect(parse(pseudoClassPlugin, cssText)) + .toEqual(`body > ul :is(li:not(:first-of-type) a:hover, li:not(:first-of-type).active a), +body > ul :is(li:not(:first-of-type) a.\\:hover, li:not(:first-of-type).active a) {background: red;}`); + }); + it('should parse selector with comma nested inside ()', () => { const cssText = '[_nghost-ng-c4172599085]:not(.fit-content).aim-select:hover:not(:disabled, [_nghost-ng-c4172599085]:not(.fit-content).aim-select--disabled, [_nghost-ng-c4172599085]:not(.fit-content).aim-select--invalid, [_nghost-ng-c4172599085]:not(.fit-content).aim-select--active) { border-color: rgb(84, 84, 84); }';