diff --git a/packages/demo-html/public/behavioral-html/exit-html.html b/packages/demo-html/public/behavioral-html/exit-html.html new file mode 100644 index 00000000..8765a317 --- /dev/null +++ b/packages/demo-html/public/behavioral-html/exit-html.html @@ -0,0 +1,52 @@ + + + + Open: exit (via embed code) + + + + +
+

This popup opens on exit intent (via embed code)

+

If a user wants to navigate away from your page, they usually need to access the browser toolbar.

+

We detect mouse movement in top part of the page - if the mouse is moving "up", we open the popup.

+

The popup is opened only once (on first detected exit intent).

+ + +

Technical stuff

+

This is not available for customization on "Share" page, but the embed lib allows it.

+
+ + + +
+ + + + diff --git a/packages/demo-html/public/behavioral-html/load-html.html b/packages/demo-html/public/behavioral-html/load-html.html new file mode 100644 index 00000000..92777af8 --- /dev/null +++ b/packages/demo-html/public/behavioral-html/load-html.html @@ -0,0 +1,46 @@ + + + + Open: load (via embed code) + + + +

This popup opens on page load (via embed code)

+

If you see this you very likely already closed the popup.

+

If the popup did not open automatically something is broken.

+ + + + + + + + + + + diff --git a/packages/demo-html/public/behavioral-html/scroll-html.html b/packages/demo-html/public/behavioral-html/scroll-html.html new file mode 100644 index 00000000..499e0749 --- /dev/null +++ b/packages/demo-html/public/behavioral-html/scroll-html.html @@ -0,0 +1,223 @@ + + + + Open: scroll (via embed code) + + + + +
+ The popup will open at 30%
+ You scrolled 0px, that is 0.00% of the page +
+

This popup opens on scroll - at 30% (via embed code)

+

The popup is opened automatically when you scroll past given percentage of the page height.

+

The popup is opened only once (when you scroll past the given percentage for the first time).

+ + +

Customize the percentage

+

This can be set on "Share" page as well.

+
+ + + +
+ + + +
+

Random text to make the page long

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed viverra aliquam augue vitae volutpat. Integer eu turpis elit. +

+

Mauris nec lobortis metus. Quisque commodo quis neque sed volutpat. Integer a bibendum ante, at dapibus arcu.

+

+ Curabitur at suscipit enim. Aliquam ut urna nunc. Praesent nisl elit, iaculis nec lectus vitae, posuere aliquet velit. +

+

Aenean id porttitor nisi. Phasellus vel fermentum elit. In ut maximus risus, quis lobortis elit.

+

+ Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis. +

+

Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.

+

Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.

+

+ Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus + eleifend mi. +

+

Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

Duis a egestas lectus, sed mattis nisl. Ut ultricies id mi vel varius. Donec nec laoreet orci.

+

+ Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus + eleifend mi. +

+

Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

+ Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat + vestibulum. +

+

In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.

+

+ Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt + sollicitudin. +

+

Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.

+

Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.

+

Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.

+

Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.

+

+ In hac habitasse platea dictumst. Nulla sit amet mauris elit. Maecenas consectetur imperdiet nisl, a vestibulum lectus + maximus vel. +

+

Nulla sagittis tempus arcu id vestibulum. Donec at nulla congue, luctus orci sit amet, scelerisque ante.

+

Praesent faucibus, lacus et varius cursus, turpis nibh scelerisque est, sit amet lacinia sapien metus vitae tellus.

+

+ Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis. +

+

Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.

+

Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.

+

Mauris aliquam erat feugiat ligula faucibus, eu imperdiet ante molestie.

+

Donec convallis, nisi at molestie fringilla, mi dolor suscipit risus, vitae gravida nulla libero vitae urna.

+

+ Vestibulum id nisi mauris. In faucibus vitae massa eget feugiat. Morbi in arcu congue, iaculis eros ac, fermentum purus. +

+

+ Fusce lectus tortor, facilisis tincidunt varius ac, sodales quis eros. Pellentesque quis nulla a nisl feugiat pretium. +

+

Duis et magna finibus, hendrerit ligula non, rutrum nunc.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

+ Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat + vestibulum. +

+

In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.

+

+ Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt + sollicitudin. +

+

Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.

+

Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.

+

Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.

+

Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.

+

+ In hac habitasse platea dictumst. Nulla sit amet mauris elit. Maecenas consectetur imperdiet nisl, a vestibulum lectus + maximus vel. +

+

Nulla sagittis tempus arcu id vestibulum. Donec at nulla congue, luctus orci sit amet, scelerisque ante.

+

Praesent faucibus, lacus et varius cursus, turpis nibh scelerisque est, sit amet lacinia sapien metus vitae tellus.

+

+ Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis. +

+

Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.

+

Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.

+

+ Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus + eleifend mi. +

+

Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

+ Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat + vestibulum. +

+

In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.

+

+ Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt + sollicitudin. +

+

Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.

+

Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.

+

Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.

+

Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.

+

Mauris aliquam erat feugiat ligula faucibus, eu imperdiet ante molestie.

+
+ + diff --git a/packages/demo-html/public/behavioral-html/time-html.html b/packages/demo-html/public/behavioral-html/time-html.html new file mode 100644 index 00000000..cd055d03 --- /dev/null +++ b/packages/demo-html/public/behavioral-html/time-html.html @@ -0,0 +1,40 @@ + + + + Open: time (via embed code) + + + +

This popup opens in 5 seconds (via embed code)

+

The popup is opened automatically after the given time has passed.

+ + Open the popup manually instead + + +

Customize the time

+

This can be set on "Share" page as well.

+
+ + + +
+ + + + + + diff --git a/packages/demo-html/public/behavioral-js/exit-js.html b/packages/demo-html/public/behavioral-js/exit-js.html new file mode 100644 index 00000000..982f3c5c --- /dev/null +++ b/packages/demo-html/public/behavioral-js/exit-js.html @@ -0,0 +1,47 @@ + + + + Open: exit (via API) + + + + +
+

This popup opens on exit intent (via API)

+

If a user wants to navigate away from your page, they usually need to access the browser toolbar.

+

We detect mouse movement in top part of the page - if the mouse is moving "up", we open the popup.

+

The popup is opened only once (on first detected exit intent).

+ +

Technical stuff

+

This is not available for customization on "Share" page, but the embed lib allows it.

+
+ + + +
+ + + + diff --git a/packages/demo-html/public/behavioral-js/load-js.html b/packages/demo-html/public/behavioral-js/load-js.html new file mode 100644 index 00000000..4d505503 --- /dev/null +++ b/packages/demo-html/public/behavioral-js/load-js.html @@ -0,0 +1,26 @@ + + + + Open: load (via API) + + + +

This popup opens on page load (via API)

+

If you see this you very likely already closed the popup.

+

If the popup did not open automatically something is broken.

+

+ Popover embed does not have a close button by default and needs to be explicitly provided when embedding via API. + See popup API demo for details. +

+ + + + + diff --git a/packages/demo-html/public/behavioral-js/scroll-js.html b/packages/demo-html/public/behavioral-js/scroll-js.html new file mode 100644 index 00000000..39990c0c --- /dev/null +++ b/packages/demo-html/public/behavioral-js/scroll-js.html @@ -0,0 +1,206 @@ + + + + Open: scroll (via API) + + + + +
+ The popup will open at 30%
+ You scrolled 0px, that is 0.00% of the page +
+

This popup opens on scroll - at 30% (via API)

+

The popup is opened automatically when you scroll past given percentage of the page height.

+

The popup is opened only once (when you scroll past the given percentage for the first time).

+ +

Customize the percentage

+

This can be set on "Share" page as well.

+
+ + + +
+ + + + +
+

Random text to make the page long

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed viverra aliquam augue vitae volutpat. Integer eu turpis elit. +

+

Mauris nec lobortis metus. Quisque commodo quis neque sed volutpat. Integer a bibendum ante, at dapibus arcu.

+

+ Curabitur at suscipit enim. Aliquam ut urna nunc. Praesent nisl elit, iaculis nec lectus vitae, posuere aliquet velit. +

+

Aenean id porttitor nisi. Phasellus vel fermentum elit. In ut maximus risus, quis lobortis elit.

+

+ Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis. +

+

Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.

+

Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.

+

+ Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus + eleifend mi. +

+

Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

Duis a egestas lectus, sed mattis nisl. Ut ultricies id mi vel varius. Donec nec laoreet orci.

+

+ Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus + eleifend mi. +

+

Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

+ Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat + vestibulum. +

+

In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.

+

+ Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt + sollicitudin. +

+

Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.

+

Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.

+

Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.

+

Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.

+

+ In hac habitasse platea dictumst. Nulla sit amet mauris elit. Maecenas consectetur imperdiet nisl, a vestibulum lectus + maximus vel. +

+

Nulla sagittis tempus arcu id vestibulum. Donec at nulla congue, luctus orci sit amet, scelerisque ante.

+

Praesent faucibus, lacus et varius cursus, turpis nibh scelerisque est, sit amet lacinia sapien metus vitae tellus.

+

+ Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis. +

+

Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.

+

Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.

+

Mauris aliquam erat feugiat ligula faucibus, eu imperdiet ante molestie.

+

Donec convallis, nisi at molestie fringilla, mi dolor suscipit risus, vitae gravida nulla libero vitae urna.

+

+ Vestibulum id nisi mauris. In faucibus vitae massa eget feugiat. Morbi in arcu congue, iaculis eros ac, fermentum purus. +

+

+ Fusce lectus tortor, facilisis tincidunt varius ac, sodales quis eros. Pellentesque quis nulla a nisl feugiat pretium. +

+

Duis et magna finibus, hendrerit ligula non, rutrum nunc.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

+ Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat + vestibulum. +

+

In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.

+

+ Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt + sollicitudin. +

+

Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.

+

Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.

+

Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.

+

Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.

+

+ In hac habitasse platea dictumst. Nulla sit amet mauris elit. Maecenas consectetur imperdiet nisl, a vestibulum lectus + maximus vel. +

+

Nulla sagittis tempus arcu id vestibulum. Donec at nulla congue, luctus orci sit amet, scelerisque ante.

+

Praesent faucibus, lacus et varius cursus, turpis nibh scelerisque est, sit amet lacinia sapien metus vitae tellus.

+

+ Phasellus pellentesque placerat turpis ac semper. Duis ligula enim, vulputate sed erat vitae, vehicula bibendum turpis. +

+

Donec nibh purus, vehicula at mauris volutpat, placerat molestie diam.

+

Mauris tristique posuere ipsum vitae venenatis. Donec ut orci id massa ullamcorper pulvinar.

+

+ Morbi pulvinar ante mauris, at sollicitudin lorem molestie sit amet. Morbi tellus nisi, rutrum ut lectus et, luctus + eleifend mi. +

+

Quisque felis enim, blandit in convallis in, bibendum non metus. Proin consectetur ut ante nec malesuada.

+

Pellentesque interdum id metus condimentum varius. Nullam fringilla lacinia posuere.

+

+ Morbi pellentesque ante vitae tellus ullamcorper sollicitudin. Proin leo dolor, molestie quis diam id, tempor ullamcorper + diam. +

+

Donec sed pulvinar nunc, et posuere purus. Morbi ornare, diam eget blandit molestie, massa leo sollicitudin nisi.

+

Id tempus ex nisi quis lectus. Etiam laoreet dui est, quis tempus augue pharetra et. Nullam sed elit turpis.

+

Donec et mi tellus. Aliquam ut interdum dolor. Aliquam dapibus velit non nunc porttitor finibus.

+

Proin elementum risus et molestie aliquam.

+

+ Phasellus sagittis iaculis nisi at molestie. Aliquam id justo orci. Aenean cursus nulla sit amet lectus consequat + vestibulum. +

+

In volutpat neque at egestas pellentesque. Vivamus in viverra eros, non facilisis mi.

+

+ Suspendisse sed metus molestie dolor convallis porta eu vitae mauris. Curabitur pharetra, lorem non tincidunt + sollicitudin. +

+

Odio tortor consequat nisi, et feugiat lectus odio sit amet nisi. Curabitur et tempor purus.

+

Maecenas commodo lorem augue, sed varius est maximus auctor. Proin finibus justo eu ante bibendum mollis.

+

Proin laoreet dapibus lorem a euismod. Integer dignissim eleifend efficitur. Pellentesque vitae pellentesque nisl.

+

Suspendisse vitae sem vitae risus sollicitudin sagittis ac sed urna.

+

Mauris aliquam erat feugiat ligula faucibus, eu imperdiet ante molestie.

+
+ + diff --git a/packages/demo-html/public/behavioral-js/time-js.html b/packages/demo-html/public/behavioral-js/time-js.html new file mode 100644 index 00000000..a43483d2 --- /dev/null +++ b/packages/demo-html/public/behavioral-js/time-js.html @@ -0,0 +1,34 @@ + + + + Open: time (via API) + + + +

This popup opens in 5 seconds (via API)

+

The popup is opened automatically after the given time has passed.

+ +

Customize the time

+

This can be set on "Share" page as well.

+
+ + + +
+ + + + + diff --git a/packages/demo-html/public/popup-html.html b/packages/demo-html/public/popup-html.html index 035a2066..28f0f8cf 100644 --- a/packages/demo-html/public/popup-html.html +++ b/packages/demo-html/public/popup-html.html @@ -3,6 +3,7 @@ Static HTML Demo + diff --git a/packages/embed/e2e/cypress-utils.ts b/packages/embed/e2e/cypress-utils.ts index b4dbb9c5..519562c0 100644 --- a/packages/embed/e2e/cypress-utils.ts +++ b/packages/embed/e2e/cypress-utils.ts @@ -3,7 +3,6 @@ export type Viewport = { height: number } -export const IFRAME_SELECTOR = '[data-qa="iframe"]' export const screenSizeDesktop: Viewport = { width: 1024, height: 768 } export const screenSizeMobile: Viewport = { width: 375, height: 667 } diff --git a/packages/embed/e2e/spec/functional/behavioral-popup.spec.ts b/packages/embed/e2e/spec/functional/behavioral-popup.spec.ts new file mode 100644 index 00000000..f4a61c34 --- /dev/null +++ b/packages/embed/e2e/spec/functional/behavioral-popup.spec.ts @@ -0,0 +1,110 @@ +import { open } from '../../cypress-utils' + +const pages = { + '-html': 'embed code', + '-js': 'API', +} + +const getPageUrl = (name: string, suffix: string, query = '') => { + return `/behavioral${suffix}/${name}${suffix}.html?${query}` +} + +Object.keys(pages).forEach((pageSuffix) => { + describe(`Behavioral Embeds using ${pages[pageSuffix]}`, () => { + describe('Open: exit', () => { + before(() => { + open(getPageUrl('exit', pageSuffix, 'threshold=100')) + }) + + it('should not display the popup on mouse movement in the area downwards', () => { + cy.get('body') + .trigger('mousemove', { clientY: 200 }) + .trigger('mousemove', { clientY: 300 }) + .trigger('mousemove', { clientY: 350 }) + cy.get('iframe').should('not.exist') + }) + + it('should not display the popup on mouse movement outside the area', () => { + cy.get('body').trigger('mousemove', { clientY: 120 }).trigger('mousemove', { clientY: 200 }) + cy.get('iframe').should('not.exist') + }) + + it('should display the popup on mouse movement in the area upwards', () => { + cy.get('body') + .trigger('mousemove', { clientY: 90 }) + .trigger('mousemove', { clientY: 80 }) + .trigger('mousemove', { clientY: 70 }) + cy.get('iframe').should('be.visible') + }) + }) + + describe('Open: load', () => { + before(() => { + open(getPageUrl('load', pageSuffix)) + }) + + it('should display the popup', () => { + cy.get('iframe').should('be.visible') + }) + }) + + describe('Open: scroll', () => { + before(() => { + open(getPageUrl('scroll', pageSuffix, 'percent=30')) + }) + + it('should not display the popup', () => { + cy.get('iframe').should('not.exist') + }) + + it('should display the popup after scrolling down', () => { + cy.scrollTo(0, 950) // 950px is over 30% of the page height + cy.get('iframe').should('be.visible') + }) + + it('should display the popup immediately after reloading the page on the same position', () => { + if (Cypress.isBrowser('chrome')) { + cy.reload() + cy.get('iframe').should('be.visible') + } + }) + }) + + describe('Open: time', () => { + const timeout = 1000 // the popup is opened after 1 seconds + + before(() => { + open(getPageUrl('time', pageSuffix, `ms=${1000}`)) + }) + + it('should not display the popup', () => { + cy.get('iframe').should('not.exist') + }) + + it('should display the popup after 1 second', () => { + cy.wait(timeout) + cy.get('iframe').should('be.visible') + }) + }) + }) +}) + +describe('Open: load (via embed code)', () => { + before(() => { + open(getPageUrl('load', '-html')) + }) + + it('should display close button', () => { + cy.get('.typeform-close').should('be.visible') + }) + + describe('when popup is closed', () => { + before(() => { + cy.get('.typeform-close').click() + }) + + it('should not display the popup', () => { + cy.get('iframe').should('not.be.visible') + }) + }) +}) diff --git a/packages/embed/src/factories/create-popup/create-popup.ts b/packages/embed/src/factories/create-popup/create-popup.ts index 28dd93db..9158413c 100644 --- a/packages/embed/src/factories/create-popup/create-popup.ts +++ b/packages/embed/src/factories/create-popup/create-popup.ts @@ -1,5 +1,6 @@ import { createIframe, hasDom, isDefined } from '../../utils' import { POPUP_SIZE } from '../../constants' +import { handleCustomOpen } from '../../utils/create-custom-launch-options' import { PopupOptions } from './popup-options' @@ -112,6 +113,10 @@ export const createPopup = (formId: string, userOptions: PopupOptions): Popup => iframe.contentWindow?.location.reload() } + if (options.open && !isOpen(popup)) { + handleCustomOpen(open, options.open, options.openValue) + } + return { open, close, diff --git a/packages/embed/src/factories/create-popup/popup-options.ts b/packages/embed/src/factories/create-popup/popup-options.ts index 64d3a8f9..2b7bccf5 100644 --- a/packages/embed/src/factories/create-popup/popup-options.ts +++ b/packages/embed/src/factories/create-popup/popup-options.ts @@ -39,4 +39,16 @@ export type PopupOptions = UrlOptions & * @type {HTMLElement} */ container?: HTMLElement + /** + * Specify custom launch options for Popup + * + * @type {string} + */ + open?: 'exit' | 'load' | 'scroll' | 'time' + /** + * Specify threshold for trigger custom launch option + * + * @type {string} + */ + openValue?: number } diff --git a/packages/embed/src/initializers/build-options-from-attributes.spec.ts b/packages/embed/src/initializers/build-options-from-attributes.spec.ts index 9a7fa4c3..7c8a6570 100644 --- a/packages/embed/src/initializers/build-options-from-attributes.spec.ts +++ b/packages/embed/src/initializers/build-options-from-attributes.spec.ts @@ -14,6 +14,8 @@ describe('build-options-from-attributes', () => { data-tf-on-ready="onTypeformReady" data-tf-on-submit="onTypeformSubmit" data-tf-on-question-changed="onTypeformQuestionChanged" + data-tf-open="exit" + data-tf-open-value="3000" >` it('should load correct options', () => { @@ -30,6 +32,8 @@ describe('build-options-from-attributes', () => { source: 'string', medium: 'string', mediumVersion: 'string', + open: 'string', + openValue: 'integer', hideFooter: 'boolean', hideHeaders: 'boolean', opacity: 'integer', @@ -50,6 +54,8 @@ describe('build-options-from-attributes', () => { onReady: win.onTypeformReady, onSubmit: win.onTypeformSubmit, onQuestionChanged: win.onTypeformQuestionChanged, + open: 'exit', + openValue: 3000, }) }) }) diff --git a/packages/embed/src/initializers/build-options-from-attributes.ts b/packages/embed/src/initializers/build-options-from-attributes.ts index 3bf0d498..77e1e98c 100644 --- a/packages/embed/src/initializers/build-options-from-attributes.ts +++ b/packages/embed/src/initializers/build-options-from-attributes.ts @@ -8,6 +8,8 @@ export const buildOptionsFromAttributes = ( source: 'string', medium: 'string', mediumVersion: 'string', + open: 'string', + openValue: 'integer', hideFooter: 'boolean', hideHeaders: 'boolean', opacity: 'integer', diff --git a/packages/embed/src/utils/create-custom-launch-options.spec.ts b/packages/embed/src/utils/create-custom-launch-options.spec.ts new file mode 100644 index 00000000..ad7260ff --- /dev/null +++ b/packages/embed/src/utils/create-custom-launch-options.spec.ts @@ -0,0 +1,131 @@ +import { handleCustomOpen } from './create-custom-launch-options' + +describe('handleCustomOpen', () => { + const mockOpen = jest.fn() + + afterEach(() => { + jest.clearAllMocks() + }) + + describe('on load', () => { + beforeAll(() => { + handleCustomOpen(mockOpen, 'load') + }) + + it('should open the popup', () => { + expect(mockOpen).toHaveBeenCalledTimes(1) + }) + }) + + describe('on exit', () => { + let handler: any + + beforeAll(() => { + jest.spyOn(document, 'addEventListener').mockImplementation((_event, fn) => { + handler = fn // retrieve the auto-open handler method for testing + }) + jest.spyOn(document, 'removeEventListener') + }) + + it('should not open the popup when mouse moves outside the threshold', () => { + handleCustomOpen(mockOpen, 'exit', 50) + handler({ clientY: 105 }) + handler({ clientY: 110 }) + handler({ clientY: 115 }) + handler({ clientY: 110 }) + handler({ clientY: 105 }) + expect(mockOpen).toHaveBeenCalledTimes(0) + expect(document.removeEventListener).toHaveBeenCalledTimes(0) + }) + + it('should not open the popup when mouse moves down', () => { + handleCustomOpen(mockOpen, 'exit', 50) + handler({ clientY: 5 }) + handler({ clientY: 10 }) + handler({ clientY: 11 }) + handler({ clientY: 12 }) + expect(mockOpen).toHaveBeenCalledTimes(0) + expect(document.removeEventListener).toHaveBeenCalledTimes(0) + }) + + it('should open the popup (and remove event listener) when mouse moves up', () => { + handleCustomOpen(mockOpen, 'exit', 50) + handler({ clientY: 10 }) + handler({ clientY: 8 }) + expect(mockOpen).toHaveBeenCalledTimes(1) + expect(document.removeEventListener).toHaveBeenCalledTimes(1) + }) + }) + + describe('on time', () => { + beforeAll(() => { + jest.useFakeTimers() + handleCustomOpen(mockOpen, 'time', 5000) + }) + + it('should not open the popup right away', () => { + expect(mockOpen).toHaveBeenCalledTimes(0) + }) + + it('should open the popup after the time has passed', () => { + jest.runAllTimers() + expect(mockOpen).toHaveBeenCalledTimes(1) + }) + }) + + describe('on scroll', () => { + let handler: any + const win = window as any // Avoid to set any time window as any + beforeAll(() => { + jest.spyOn(document, 'addEventListener').mockImplementation((_event, fn) => { + handler = fn // retrieve the auto-open handler method for testing + }) + jest.spyOn(document, 'removeEventListener') + win.pageYOffset = 0 + win.innerHeight = 500 + Object.defineProperty(window.HTMLHtmlElement.prototype, 'scrollHeight', { value: 1000 }) + }) + + it('should not open the popup when the page has not scrolled past the threshold', () => { + handleCustomOpen(mockOpen, 'scroll', 30) + + win.pageYOffset = 0 + handler() + + win.pageYOffset = 100 + handler() + + win.pageYOffset = 299 + handler() + + expect(mockOpen).toHaveBeenCalledTimes(0) + expect(document.removeEventListener).toHaveBeenCalledTimes(0) + }) + + it('should open the popup when the page has scrolled past the threshold', () => { + handleCustomOpen(mockOpen, 'scroll', 30) + win.pageYOffset = 300 + handler() + expect(mockOpen).toHaveBeenCalledTimes(1) + expect(document.removeEventListener).toHaveBeenCalledTimes(1) + }) + + it('should open the popup when the page is scrolled at the end and threshold is beyond the end', () => { + handleCustomOpen(mockOpen, 'scroll', 90) + win.pageYOffset = 500 + handler() + expect(mockOpen).toHaveBeenCalledTimes(1) + expect(document.removeEventListener).toHaveBeenCalledTimes(1) + }) + }) + + describe('on unknown value', () => { + beforeAll(() => { + handleCustomOpen(mockOpen, 'unknown') + }) + + it('should not open the popup', () => { + expect(mockOpen).toHaveBeenCalledTimes(0) + }) + }) +}) diff --git a/packages/embed/src/utils/create-custom-launch-options.ts b/packages/embed/src/utils/create-custom-launch-options.ts new file mode 100644 index 00000000..c716299d --- /dev/null +++ b/packages/embed/src/utils/create-custom-launch-options.ts @@ -0,0 +1,52 @@ +const openOnExit = (exitThreshold: number, open: () => void) => { + let prevY = 0 + const handleMouseMove = (event: MouseEvent) => { + // open popup if the mouse is in top part of the page and moving towards top of the screen + if (event.clientY < exitThreshold && event.clientY < prevY) { + document.removeEventListener('mousemove', handleMouseMove) + open() + } else { + prevY = event.clientY + } + } + document.addEventListener('mousemove', handleMouseMove) +} + +const openOnScroll = (scrollThreshold: number, open: () => void) => { + const handleScroll = () => { + const offsetTop = window.pageYOffset || document.documentElement.scrollTop + const clientTop = document.documentElement.clientTop || 0 + const pageHeight = document.documentElement.scrollHeight + const scrollTopPixels = offsetTop - clientTop + const scrollTopPercentage = (scrollTopPixels / pageHeight) * 100 + const scrolledToTheBottom = scrollTopPixels + window.innerHeight >= pageHeight + + if (scrollTopPercentage >= scrollThreshold || scrolledToTheBottom) { + open() + document.removeEventListener('scroll', handleScroll) + } + } + document.addEventListener('scroll', handleScroll) +} + +export const handleCustomOpen = (open: () => void, openType: string, value?: number) => { + switch (openType) { + case 'load': + open() + break + case 'exit': + value && openOnExit(value, open) + break + case 'time': + setTimeout(() => { + open() + }, value) + break + case 'scroll': + value && openOnScroll(value, open) + break + default: + // do not open automatically + break + } +}