diff --git a/packages/interact/src/core/css.ts b/packages/interact/src/core/css.ts index 7890157f..aba27765 100644 --- a/packages/interact/src/core/css.ts +++ b/packages/interact/src/core/css.ts @@ -250,8 +250,16 @@ function effectToCSS( media, selectorCondition, childSelector, - declarations: animationDeclarations.concat(DEFAULT_INITIAL), - addInitialSelector: true, + declarations: DEFAULT_INITIAL, + dataInteractEnterSelector: ':not([data-interact-enter])', + }); + rules.push({ + key, + media, + selectorCondition, + childSelector, + declarations: animationDeclarations, + dataInteractEnterSelector: ':not([data-interact-enter="done"])', }); } else { // declare animation and composition custom properties diff --git a/packages/interact/src/core/cssUtils.ts b/packages/interact/src/core/cssUtils.ts index 889820db..93bbf235 100644 --- a/packages/interact/src/core/cssUtils.ts +++ b/packages/interact/src/core/cssUtils.ts @@ -102,8 +102,15 @@ export function keyframesToCSS(name: string, keyframes: Keyframe[]): string { } export function CSSRuleToString(rule: CSSRuleData): string { - const { key, childSelector, declarations, media, states, selectorCondition, addInitialSelector } = - rule; + const { + key, + childSelector, + declarations, + media, + states, + selectorCondition, + dataInteractEnterSelector, + } = rule; if (!declarations.length) { return ''; } @@ -123,8 +130,8 @@ export function CSSRuleToString(rule: CSSRuleData): string { selector = `${selector} ${childSelector}`; } - if (addInitialSelector) { - selector = `${selector}:not([data-interact-enter])`; + if (dataInteractEnterSelector) { + selector = `${selector}${dataInteractEnterSelector}`; } // maybe nesting is simpler? - diff --git a/packages/interact/src/types/css.ts b/packages/interact/src/types/css.ts index c1160b4b..433dd02d 100644 --- a/packages/interact/src/types/css.ts +++ b/packages/interact/src/types/css.ts @@ -23,5 +23,5 @@ export type CSSRuleData = { media?: string; states?: string[]; selectorCondition?: string; - addInitialSelector?: boolean; + dataInteractEnterSelector?: string; }; diff --git a/packages/interact/test/css.spec.ts b/packages/interact/test/css.spec.ts index 24cef88a..88c9ac3d 100644 --- a/packages/interact/test/css.spec.ts +++ b/packages/interact/test/css.spec.ts @@ -435,7 +435,9 @@ describe('css._generate', () => { const { cssRules } = _generate(config); - const initialRule = cssRules.find((r) => r.addInitialSelector)!; + const initialRule = cssRules.find( + (r) => r.dataInteractEnterSelector === ':not([data-interact-enter])', + )!; expect(initialRule).toBeDefined(); DEFAULT_INITIAL.forEach(({ name, value }) => { @@ -444,7 +446,12 @@ describe('css._generate', () => { expect(decl!.value).toBe(value); }); - const animDeclOnInitial = findDecl(initialRule.declarations, (d) => isAnimationProp(d.name)); + const animationRule = cssRules.find( + (r) => r.dataInteractEnterSelector === ':not([data-interact-enter="done"])', + )!; + const animDeclOnInitial = findDecl(animationRule.declarations, (d) => + isAnimationProp(d.name), + ); expect(animDeclOnInitial).toBeDefined(); expect(animDeclOnInitial!.value).toContain('myAnim'); }); @@ -472,7 +479,7 @@ describe('css._generate', () => { const { cssRules } = _generate(config); - expect(cssRules.every((r) => !r.addInitialSelector)).toBe(true); + expect(cssRules.every((r) => !r.dataInteractEnterSelector)).toBe(true); const effectRule = cssRules.find((r) => r.declarations.some((d) => isAnimationProp(d.name)))!; expect(effectRule).toBeDefined(); @@ -492,7 +499,7 @@ describe('css._generate', () => { const { cssRules } = _generate(config); - expect(cssRules.every((r) => !r.addInitialSelector)).toBe(true); + expect(cssRules.every((r) => !r.dataInteractEnterSelector)).toBe(true); }); }); @@ -654,7 +661,7 @@ describe('css._generate', () => { const { cssRules } = _generate(config); - expect(cssRules.every((r) => !r.addInitialSelector)).toBe(true); + expect(cssRules.every((r) => !r.dataInteractEnterSelector)).toBe(true); }); it('should emit auto duration in animation shorthand for viewProgress (SSR-safe)', () => { @@ -796,7 +803,9 @@ describe('css._generate', () => { const { cssRules } = _generate(config); - const initialRule = cssRules.find((r) => r.addInitialSelector)!; + const initialRule = cssRules.find( + (r) => r.dataInteractEnterSelector === ':not([data-interact-enter="done"])', + )!; expect(initialRule).toBeDefined(); const timelineDecl = findDecl(initialRule.declarations, (d) => isTimelineProp(d.name)); @@ -1150,7 +1159,7 @@ describe('css._generate', () => { }; const { cssRules } = _generate(config); - const initialRule = cssRules.find((r) => r.addInitialSelector)!; + const initialRule = cssRules.find((r) => r.dataInteractEnterSelector)!; expect(initialRule).toBeDefined(); expect(initialRule.media).toContain('min-width: 1024px'); diff --git a/packages/interact/test/cssUtils.spec.ts b/packages/interact/test/cssUtils.spec.ts index a270e186..09349e9e 100644 --- a/packages/interact/test/cssUtils.spec.ts +++ b/packages/interact/test/cssUtils.spec.ts @@ -207,13 +207,14 @@ describe('CSSRuleToString', () => { expect(CSSRuleToString(rule)).toEqual(expected); }); - it('should add :not([data-interact-enter]) when addInitialSelector is true', () => { + it('should dataInteractEnterSelector when provided', () => { const rule: CSSRuleData = { key: 'my-el', - addInitialSelector: true, + dataInteractEnterSelector: ':not([data-interact-enter="done"])', declarations: [{ name: 'opacity', value: '0' }], }; - const expected = '[data-interact-key="my-el"]:not([data-interact-enter]) {\nopacity: 0;\n}'; + const expected = + '[data-interact-key="my-el"]:not([data-interact-enter="done"]) {\nopacity: 0;\n}'; expect(CSSRuleToString(rule)).toEqual(expected); }); @@ -253,7 +254,7 @@ describe('CSSRuleToString', () => { const rule: CSSRuleData = { key: 'my-el', childSelector: '.child', - addInitialSelector: true, + dataInteractEnterSelector: ':not([data-interact-enter="done"])', states: ['hover'], media: '(min-width: 1024px)', declarations: [ @@ -262,7 +263,7 @@ describe('CSSRuleToString', () => { ], }; const expected = - '@media (min-width: 1024px) {\n[data-interact-key="my-el"]:is(:state(hover), :--hover, [data-interact-effect~="hover"]) .child:not([data-interact-enter]) {\nopacity: 1;\ncolor: blue;\n}\n}'; + '@media (min-width: 1024px) {\n[data-interact-key="my-el"]:is(:state(hover), :--hover, [data-interact-effect~="hover"]) .child:not([data-interact-enter="done"]) {\nopacity: 1;\ncolor: blue;\n}\n}'; expect(CSSRuleToString(rule)).toEqual(expected); }); });