diff --git a/packages/rrdom/src/index.ts b/packages/rrdom/src/index.ts index eeddb03e1c..df0b9bf4b0 100644 --- a/packages/rrdom/src/index.ts +++ b/packages/rrdom/src/index.ts @@ -15,6 +15,7 @@ import type { styleSheetRuleData, styleDeclarationData, } from '@rrweb/types'; +import { IncrementalSource } from '@rrweb/types'; import { BaseRRNode as RRNode, BaseRRCDATASectionImpl, @@ -248,6 +249,30 @@ export function buildFromNode( for (const { name, value } of Array.from(elementNode.attributes)) { rrElement.attributes[name] = value; } + + // CSSRules inserted by earlier mutations can be dropped if diff'ing + // results in the style element's position in the DOM changing + // since inserted rules are not persisted with the element to it's new location + if (tagName === 'STYLE') { + const cssElementNode = elementNode as HTMLStyleElement; + + if (cssElementNode.sheet?.cssRules.length) { + const cssRules = cssElementNode.sheet.cssRules; + + for (let i = 0; i < cssRules.length; i++) { + (rrNode as RRStyleElement).rules.push({ + source: IncrementalSource.StyleSheetRule, + adds: [ + { + index: i, + rule: cssRules[i].cssText, + }, + ], + }); + } + } + } + elementNode.scrollLeft && (rrElement.scrollLeft = elementNode.scrollLeft); elementNode.scrollTop && (rrElement.scrollTop = elementNode.scrollTop); /** diff --git a/packages/rrdom/test/virtual-dom.test.ts b/packages/rrdom/test/virtual-dom.test.ts index b99aca5ae4..3677cb1067 100644 --- a/packages/rrdom/test/virtual-dom.test.ts +++ b/packages/rrdom/test/virtual-dom.test.ts @@ -24,6 +24,7 @@ import { RRCanvasElement, RRDocument, RRElement, + RRStyleElement, BaseRRNode as RRNode, } from '../src'; import { compileTSCode } from './utils'; @@ -207,6 +208,37 @@ describe('RRDocument for browser environment', () => { expect((rrNode as RRElement).tagName).toEqual('SHADOWROOT'); expect(rrNode).toBe(parentRRNode.shadowRoot); }); + + it('can copy CSSRules for style elements to RRNode', () => { + const styleElement = document.createElement('style') as HTMLStyleElement; + styleElement.innerHTML = + '.new-element-class {font-size: 32px; color: tomato;}'; + document.body.appendChild(styleElement); + styleElement.sheet?.insertRule( + '.target-element {background-color: teal;}', + ); + const rrdom = new RRDocument(); + + let rrNode = buildFromNode(styleElement, rrdom, mirror); + + expect((rrNode as RRStyleElement).rules).toEqual([ + { + adds: [ + { index: 0, rule: '.target-element {background-color: teal;}' }, + ], + source: 8, + }, + { + adds: [ + { + index: 1, + rule: '.new-element-class {font-size: 32px; color: tomato;}', + }, + ], + source: 8, + }, + ]); + }); }); describe('create a RRDocument from a html document', () => {