Repository: exadel-inc/esl
Pull request #632 (2021-11-11 11:52:26)

feat(esl-animate): make a new module "esl-animate" to animate elements on viewport intersecting
`esl-animate` module draft.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f50413c91..17a7c2ea5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,19 +1,3 @@
-# [3.6.0](https://github.com/exadel-inc/esl/compare/v3.5.0...v3.6.0) (2021-11-23)
-
-
-### Bug Fixes
-
-* **esl-media:** `preload` and `fill-mode` types restricted ([4c41cb3](https://github.com/exadel-inc/esl/commit/4c41cb338c49559a3425029fd31f9957c741b3aa))
-* **esl-poup:** fix popup positioning ([61b0237](https://github.com/exadel-inc/esl/commit/61b0237f3b7fc9c14f786d382b0900ceffeaa9d0))
-
-
-### Features
-
-* **esl-popup:** add new feature to be able to set position of arrow on popup ([7973e1f](https://github.com/exadel-inc/esl/commit/7973e1f4f2281f538abb7783046463d2b7967fa2))
-* **esl-traversing-query:** add ability to restrict global scope ([3e136c0](https://github.com/exadel-inc/esl/commit/3e136c09245f10dd5bfe24cc0c7deb94551f8aed))
-* **esl-utils:** array unwrap utility ([45c50a0](https://github.com/exadel-inc/esl/commit/45c50a067b9a0de42e1740ae6bba0264d1229280))
-* **esl-utils:** fix `isPrimitive` check and `isObject` return type, add `isArrayLike` ([80b8aa0](https://github.com/exadel-inc/esl/commit/80b8aa04068f9d047c459769ce32a71a5ddaf0d9))
-
 # [3.5.0](https://github.com/exadel-inc/esl/compare/v3.4.1...v3.5.0) (2021-11-15)
 
 
diff --git a/README.md b/README.md
index 37c52b529..51308182d 100644
--- a/README.md
+++ b/README.md
@@ -132,7 +132,6 @@ you can find useful information about the project processes and agreements here:
 [Andrey Belous](https://github.com/andreybelous),
 [Dzianis Mantsevich](https://github.com/dmantsevich), 
 [Feoktyst Shovchko](https://github.com/fshovchko), 
-[Iryna Pavlenko](https://www.linkedin.com/in/iryna-pavlenko-270930107/),
 [Liubou Masiuk](https://github.com/liubou-masiuk), 
 [Natallia Harshunova](https://github.com/nattallius), 
 [Yana Bernatskaya](https://github.com/YanaBr).
diff --git a/package-lock.json b/package-lock.json
index d45afc9fa..c8333139f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "@exadel/esl",
-  "version": "3.6.0",
+  "version": "3.5.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -4669,9 +4669,9 @@
       }
     },
     "eslint": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.3.0.tgz",
-      "integrity": "sha512-aIay56Ph6RxOTC7xyr59Kt3ewX185SaGnAr8eWukoPLeriCrvGjvAubxuvaXOfsxhtwV5g0uBOsyhAom4qJdww==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.2.0.tgz",
+      "integrity": "sha512-erw7XmM+CLxTOickrimJ1SiF55jiNlVSp2qqm0NuBWPtHYQCegD5ZMaW0c3i5ytPqL+SSLaCxdvQXFPLJn+ABw==",
       "dev": true,
       "requires": {
         "@eslint/eslintrc": "^1.0.4",
@@ -4683,10 +4683,10 @@
         "doctrine": "^3.0.0",
         "enquirer": "^2.3.5",
         "escape-string-regexp": "^4.0.0",
-        "eslint-scope": "^7.1.0",
+        "eslint-scope": "^6.0.0",
         "eslint-utils": "^3.0.0",
-        "eslint-visitor-keys": "^3.1.0",
-        "espree": "^9.1.0",
+        "eslint-visitor-keys": "^3.0.0",
+        "espree": "^9.0.0",
         "esquery": "^1.4.0",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
@@ -4736,9 +4736,9 @@
           "dev": true
         },
         "eslint-scope": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz",
-          "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==",
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
+          "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==",
           "dev": true,
           "requires": {
             "esrecurse": "^4.3.0",
@@ -5034,20 +5034,20 @@
       "dev": true
     },
     "espree": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-9.1.0.tgz",
-      "integrity": "sha512-ZgYLvCS1wxOczBYGcQT9DDWgicXwJ4dbocr9uYN+/eresBAUuBu+O4WzB21ufQ/JqQT8gyp7hJ3z8SHii32mTQ==",
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.0.0.tgz",
+      "integrity": "sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==",
       "dev": true,
       "requires": {
-        "acorn": "^8.6.0",
+        "acorn": "^8.5.0",
         "acorn-jsx": "^5.3.1",
-        "eslint-visitor-keys": "^3.1.0"
+        "eslint-visitor-keys": "^3.0.0"
       },
       "dependencies": {
         "acorn": {
-          "version": "8.6.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz",
-          "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==",
+          "version": "8.5.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
+          "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==",
           "dev": true
         }
       }
@@ -5179,6 +5179,12 @@
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
           "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
           "dev": true
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
         }
       }
     },
@@ -6817,6 +6823,12 @@
         "throat": "^6.0.1"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
         "jest-util": {
           "version": "27.3.1",
           "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz",
@@ -6836,6 +6848,18 @@
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
           "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
           "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -6868,6 +6892,18 @@
         "pretty-format": "^27.3.1"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
+        },
         "jest-util": {
           "version": "27.3.1",
           "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz",
@@ -6897,6 +6933,18 @@
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
           "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
           "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -6934,6 +6982,18 @@
         "pretty-format": "^27.3.1"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
+        },
         "jest-util": {
           "version": "27.3.1",
           "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz",
@@ -6953,6 +7013,18 @@
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
           "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
           "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -7114,6 +7186,12 @@
         "throat": "^6.0.1"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
         "jest-util": {
           "version": "27.3.1",
           "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz",
@@ -7133,6 +7211,18 @@
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
           "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
           "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -7144,6 +7234,32 @@
       "requires": {
         "jest-get-type": "^27.3.1",
         "pretty-format": "^27.3.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
+        }
       }
     },
     "jest-matcher-utils": {
@@ -7156,6 +7272,44 @@
         "jest-diff": "^27.3.1",
         "jest-get-type": "^27.3.1",
         "pretty-format": "^27.3.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
+        "jest-diff": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz",
+          "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==",
+          "dev": true,
+          "requires": {
+            "chalk": "^4.0.0",
+            "diff-sequences": "^27.0.6",
+            "jest-get-type": "^27.3.1",
+            "pretty-format": "^27.3.1"
+          }
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
+        }
       }
     },
     "jest-message-util": {
@@ -7175,6 +7329,12 @@
         "stack-utils": "^2.0.3"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
         "micromatch": {
           "version": "4.0.4",
           "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
@@ -7190,6 +7350,18 @@
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
           "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
           "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -7422,6 +7594,30 @@
         "semver": "^7.3.2"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
+        "jest-diff": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz",
+          "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==",
+          "dev": true,
+          "requires": {
+            "chalk": "^4.0.0",
+            "diff-sequences": "^27.0.6",
+            "jest-get-type": "^27.3.1",
+            "pretty-format": "^27.3.1"
+          }
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
+        },
         "jest-util": {
           "version": "27.3.1",
           "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz",
@@ -7441,6 +7637,18 @@
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
           "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
           "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -7480,11 +7688,35 @@
         "pretty-format": "^27.3.1"
       },
       "dependencies": {
+        "ansi-styles": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+          "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+          "dev": true
+        },
         "camelcase": {
           "version": "6.2.0",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
           "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
           "dev": true
+        },
+        "jest-get-type": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz",
+          "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==",
+          "dev": true
+        },
+        "pretty-format": {
+          "version": "27.3.1",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz",
+          "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==",
+          "dev": true,
+          "requires": {
+            "@jest/types": "^27.2.5",
+            "ansi-regex": "^5.0.1",
+            "ansi-styles": "^5.0.0",
+            "react-is": "^17.0.1"
+          }
         }
       }
     },
@@ -13836,9 +14068,9 @@
       "dev": true
     },
     "webpack": {
-      "version": "5.64.2",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.2.tgz",
-      "integrity": "sha512-4KGc0+Ozi0aS3EaLNRvEppfZUer+CaORKqL6OBjDLZOPf9YfN8leagFzwe6/PoBdHFxc/utKArl8LMC0Ivtmdg==",
+      "version": "5.64.1",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.1.tgz",
+      "integrity": "sha512-b4FHmRgaaAjP+aVOVz41a9Qa5SmkUPQ+u8FntTQ1roPHahSComB6rXnLwc976VhUY4CqTaLu5mCswuHiNhOfVw==",
       "dev": true,
       "requires": {
         "@types/eslint-scope": "^3.7.0",
@@ -13868,9 +14100,9 @@
       },
       "dependencies": {
         "acorn": {
-          "version": "8.6.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz",
-          "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==",
+          "version": "8.5.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
+          "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==",
           "dev": true
         }
       }
diff --git a/package.json b/package.json
index d30063637..6eb003244 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@exadel/esl",
-  "version": "3.6.0",
+  "version": "3.5.0",
   "private": false,
   "description": "Exadel Smart Library (ESL) - is the lightweight custom elements library that provide a set of super-flexible components",
   "license": "MIT",
@@ -86,7 +86,7 @@
     "@semantic-release/github": "^8.0.2",
     "@semantic-release/npm": "^8.0.3",
     "@semantic-release/release-notes-generator": "^10.0.2",
-    "@types/jest": "^27.0.3",
+    "@types/jest": "^27.0.2",
     "@types/smoothscroll-polyfill": "^0.3.1",
     "@typescript-eslint/eslint-plugin": "^5.4.0",
     "@typescript-eslint/parser": "^5.4.0",
@@ -98,7 +98,7 @@
     "clean-css-cli": "^5.4.2",
     "concurrently": "^6.4.0",
     "copyfiles": "^2.4.1",
-    "eslint": "^8.3.0",
+    "eslint": "^8.2.0",
     "eslint-plugin-editorconfig": "^3.2.0",
     "eslint-plugin-import": "^2.25.3",
     "eslint-plugin-sonarjs": "^0.10.0",
@@ -121,7 +121,7 @@
     "ts-jest": "^27.0.7",
     "ts-loader": "^9.2.6",
     "typescript": "4.5.2",
-    "webpack": "^5.64.2",
+    "webpack": "^5.64.1",
     "webpack-cli": "^4.9.1"
   },
   "browserslist": [
diff --git a/pages/src/common/flex.less b/pages/src/common/flex.less
index 2a04b3c00..2a552166f 100644
--- a/pages/src/common/flex.less
+++ b/pages/src/common/flex.less
@@ -53,7 +53,7 @@
   margin-left: -15px;
 }
 
-.col, .col-4, .col-6, .col-12, .col-md-4, .col-sm-6, .col-md-6 {
+.col, .col-3, .col-4, .col-6, .col-12, .col-md-4, .col-sm-6, .col-md-6 {
   position: relative;
   width: 100%;
   padding-right: 15px;
@@ -80,10 +80,17 @@
     max-width: 100%;
   }
 
+  @media @sm-xl {
+    &-sm-6 {
+      flex: 0 0 50%;
+      max-width: 50%;
+    }
+  }
+
   @media @md-xl {
     &-md-4 {
-      flex: 0 0 100/3%;
-      max-width: 100/3%;
+      flex: 0 0 33.333333%;
+      max-width: 33.333333%;
     }
 
     &-md-6 {
@@ -91,11 +98,10 @@
       max-width: 50%;
     }
   }
-
-  @media @sm-xl {
-    &-sm-6 {
-      flex: 0 0 50%;
-      max-width: 50%;
+  @media @lg-xl {
+    &-lg-3 {
+      flex: 0 0 25%;
+      max-width: 25%;
     }
   }
 }
diff --git a/pages/src/common/helpers.less b/pages/src/common/helpers.less
index 0088b2d8b..0f29a80c3 100644
--- a/pages/src/common/helpers.less
+++ b/pages/src/common/helpers.less
@@ -1,3 +1,5 @@
+@import (reference) "./variables.less";
+
 // Block
 .d-block {
   display: block !important;
@@ -13,6 +15,14 @@
   position: relative;
 }
 
+.hide {
+  @media @xs {
+    &-xs {
+      display: none;
+    }
+  }
+}
+
 // Margin
 .m {
   &-0 {
@@ -91,6 +101,11 @@
   padding-bottom: 0.5rem !important;
 }
 
+// Border radius
+.round {
+  border-radius: 0.5rem;
+}
+
 // List helpers
 .unstyled-list li {
   list-style-type: none;
diff --git a/pages/src/common/simple-grid.less b/pages/src/common/simple-grid.less
new file mode 100644
index 000000000..db8661d8a
--- /dev/null
+++ b/pages/src/common/simple-grid.less
@@ -0,0 +1,16 @@
+.simple-grid {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-around;
+
+  margin: 30px 0;
+  padding: 20px;
+
+  & > &-cell {
+    list-style-type: none;
+    flex: 1 1 0px;
+    margin: 20px;
+    min-width: 200px;
+    height: 200px;
+  }
+}
diff --git a/pages/src/localdev.less b/pages/src/localdev.less
index 5031d0e8e..94ffad120 100644
--- a/pages/src/localdev.less
+++ b/pages/src/localdev.less
@@ -11,6 +11,7 @@
 @import "./common/links.less";
 @import "./common/close.less";
 @import "./common/containers.less";
+@import "./common/simple-grid.less";
 @import "./common/forms.less";
 @import "./common/flex.less";
 @import "./common/helpers.less";
diff --git a/pages/src/localdev.ts b/pages/src/localdev.ts
index e55edd756..bfead007c 100644
--- a/pages/src/localdev.ts
+++ b/pages/src/localdev.ts
@@ -28,7 +28,8 @@ import {
   ESLSelectList,
   ESLNote,
   ESLFootnotes,
-  ESLTooltip
+  ESLTooltip,
+  ESLAnimate
 } from '../../src/modules/all';
 
 import '../../src/modules/esl-media/providers/iframe-provider';
@@ -87,6 +88,8 @@ ESLFootnotes.register();
 ESLNote.register();
 ESLTooltip.register();
 
+ESLAnimate.register();
+
 ESLCarousel.register();
 ESLCarouselPlugins.Dots.register();
 ESLCarouselPlugins.Link.register();
diff --git a/pages/src/navigation/footer/footer.less b/pages/src/navigation/footer/footer.less
index 7ebf90996..facff08de 100644
--- a/pages/src/navigation/footer/footer.less
+++ b/pages/src/navigation/footer/footer.less
@@ -82,7 +82,7 @@
         display: flex;
         flex-direction: column;
         flex-wrap: wrap;
-        height: 300px;
+        height: 330px; // 8 lines max (+2px)
         list-style-type: none;
       }
     }
diff --git a/pages/src/polyfill-full.ts b/pages/src/polyfill-full.ts
index e5c7cfaaa..efc6ff89c 100644
--- a/pages/src/polyfill-full.ts
+++ b/pages/src/polyfill-full.ts
@@ -7,4 +7,7 @@ import '../../src/polyfills/polyfills.es5';
 
 import '@webcomponents/webcomponents-platform';
 
-import './polyfill-medium';
+import SmoothScroll from 'smoothscroll-polyfill';
+SmoothScroll.polyfill();
+
+import './polyfill-light';
diff --git a/pages/src/polyfill-light.ts b/pages/src/polyfill-light.ts
index d3e2432de..bbc3950a2 100644
--- a/pages/src/polyfill-light.ts
+++ b/pages/src/polyfill-light.ts
@@ -1,12 +1,9 @@
 /**
  * Target: Edge, Safari 9
  */
-import '../../src/polyfills/polyfills.es6';
+import 'intersection-observer/intersection-observer';
 
-// IE, Safari <13.3
 import {ResizeObserver} from '@juggle/resize-observer';
 window.ResizeObserver = window.ResizeObserver || ResizeObserver;
 
-// Safari <14
-import SmoothScroll from 'smoothscroll-polyfill';
-SmoothScroll.polyfill();
+import '@webcomponents/custom-elements/custom-elements.min';
diff --git a/pages/src/polyfill-medium.ts b/pages/src/polyfill-medium.ts
deleted file mode 100644
index a75b910c6..000000000
--- a/pages/src/polyfill-medium.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * Target: iOS, Safari 13.0.0
- */
-// IE, Edge < 18
-import '@webcomponents/custom-elements/custom-elements.min';
-
-// IE, Safari <12, Edge < 14
-import 'intersection-observer/intersection-observer';
-
-import './polyfill-light';
diff --git a/pages/views/_includes/landing/benefits.njk b/pages/views/_includes/landing/benefits.njk
index d38a13f1e..33cdb070a 100644
--- a/pages/views/_includes/landing/benefits.njk
+++ b/pages/views/_includes/landing/benefits.njk
@@ -1,8 +1,9 @@
 <div class="benefit container">
   <h2>{{ benefits.title }}</h2>
+  <esl-animate target="::next::child"></esl-animate>
   <ul class="benefit-container">
     {% for item in landing.benefits.items %}
-      <li class="benefit-item">
+      <li class="benefit-item esl-animate-fade">
         <div class="benefit-icon">
           {% include "static/assets/" + item.icon %}
         </div>
diff --git a/pages/views/_includes/navigation/footer-compact.njk b/pages/views/_includes/navigation/footer-compact.njk
index bc3687a13..d2cdb1c95 100644
--- a/pages/views/_includes/navigation/footer-compact.njk
+++ b/pages/views/_includes/navigation/footer-compact.njk
@@ -10,9 +10,6 @@
       <a target="_blank" href="https://github.com/dshovchko">Dmytro Shovchko</a>,
       <a target="_blank" href="https://github.com/abarmina">Anna Barmina</a>
     </div>
-    <div>
-      Design by
-      <a target="_blank" href="https://www.linkedin.com/in/iryna-pavlenko-270930107/">Iryna Pavlenko</a>
-    </div>
+    <div>Design by Iryna Pavlenko</div>
   </div>
 </div>
diff --git a/pages/views/_includes/navigation/footer.njk b/pages/views/_includes/navigation/footer.njk
index b4d0b16bb..2f2dec7bc 100644
--- a/pages/views/_includes/navigation/footer.njk
+++ b/pages/views/_includes/navigation/footer.njk
@@ -20,7 +20,7 @@
   <div class="footer-common-links-container">
     <div class="footer-common-links">
       <div class="footer-copyright">
-        ESL v{{ env.version }} © 2021 <a class="footer-link" href="https://exadel.com">Exadel</a>, Inc.
+        ESL v{{ env.version }} © 2021 <a class="footer-link" href="exadel.com">Exadel</a>, Inc.
         Code licenced under <a class="footer-link" href="https://github.com/exadel-inc/esl/blob/main/LICENSE">MIT</a>
       </div>
     </div>
diff --git a/pages/views/_includes/navigation/sidebar.njk b/pages/views/_includes/navigation/sidebar.njk
index 82cc2352f..ecc209518 100644
--- a/pages/views/_includes/navigation/sidebar.njk
+++ b/pages/views/_includes/navigation/sidebar.njk
@@ -30,7 +30,7 @@
 </esl-d-sidebar>
 <script>
   if (localStorage.getItem('sidebar-collapsed')) {
-    var sidebar = document.querySelector('#sidebar');
+    const sidebar = document.querySelector('#sidebar');
     sidebar.classList.remove('open');
 
     sidebar.querySelector('.sidebar-trigger-btn').removeAttribute('active');
diff --git a/pages/views/_includes/polyfill.njk b/pages/views/_includes/polyfill.njk
index c01d5dc6a..887081ec3 100644
--- a/pages/views/_includes/polyfill.njk
+++ b/pages/views/_includes/polyfill.njk
@@ -1,11 +1,10 @@
 <script>
+  /* Polyfill */
   (function () {
-    var version = '';
-    if (!window.Promise || !window.CustomEvent){
+    let version = '';
+    if (!window.Promise || !window.CustomEvent) {
       version = 'full';
-    } else if (!('getRootNode' in Element.prototype) || !window.customElements){
-      version = 'medium';
-    } else if (!window.scrollBy || !window.IntersectionObserver || !window.ResizeObserver || !window.ResizeObserver) {
+    } else if (!('getRootNode' in Element.prototype) || !window.customElements || !window.IntersectionObserver || !window.ResizeObserver) {
       version = 'light';
     }
     (version) && document.write('<script type="text/javascript" src="{{ '/bundles/polyfill-' | url }}' + version + '.js"><\/script>');
diff --git a/pages/views/_layouts/popup.njk b/pages/views/_layouts/popup.njk
index c2157db67..4465e1cf6 100644
--- a/pages/views/_layouts/popup.njk
+++ b/pages/views/_layouts/popup.njk
@@ -9,7 +9,7 @@
   <div style="height: 70px; width:250px;"></div>
   <span class="esl-popup-arrow"></span>
 </esl-popup>
-<esl-popup id="popup3" position="left">
+<esl-popup id="popup3" position="left" >
   <div style="height: 250px; width:70px;"></div>
   <span class="esl-popup-arrow"></span>
 </esl-popup>
diff --git a/pages/views/components/esl-animate.njk b/pages/views/components/esl-animate.njk
new file mode 100644
index 000000000..18087c19b
--- /dev/null
+++ b/pages/views/components/esl-animate.njk
@@ -0,0 +1,13 @@
+---
+layout: content
+title: ESL Animate & ESL Animate Service
+seoTitle: ESL Animate - service and component to animate element on viewport intersection
+name: ESL Animate
+tags: [components, beta]
+iconAlt: '<esl-animate/>'
+aside:
+  examples:
+    - animate
+---
+
+{% mdRender 'src/modules/esl-animate/README.md', 'intro' %}
diff --git a/pages/views/examples/animate.njk b/pages/views/examples/animate.njk
new file mode 100644
index 000000000..70457fd03
--- /dev/null
+++ b/pages/views/examples/animate.njk
@@ -0,0 +1,32 @@
+---
+layout: content
+title: Animate
+name: Animate
+tags: [examples, beta]
+iconAlt: '[esl-animate]'
+aside:
+  components:
+    - esl-animate
+---
+
+<section>
+  <h2>Grouped and repetitive animation</h2>
+  <ul class="round simple-grid">
+    <esl-animate target="::parent::child(li)" group repeat></esl-animate>
+    {% for i in range(0, 100) -%}
+      <li class="bg-blue round esl-animate-slide simple-grid-cell {{ 'hide-xs' if i >= 12 }}"
+          is="my-comp my-com-2"></li>
+    {%- endfor %}
+  </ul>
+</section>
+
+<section>
+  <h2>Single animation</h2>
+  <div class="simple-grid">
+    {% for i in range(0, 100) -%}
+      <esl-animate class="esl-animate-fade simple-grid-cell bg-green round">
+
+      </esl-animate>
+    {%- endfor %}
+  </div>
+</section>
diff --git a/pages/views/google632b71fe21328513.njk b/pages/views/google632b71fe21328513.njk
deleted file mode 100644
index a612e77cd..000000000
--- a/pages/views/google632b71fe21328513.njk
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: google632b71fe21328513.html
-eleventyExcludeFromCollections: true
----
-google-site-verification: google632b71fe21328513.html
diff --git a/pages/webpack.config.js b/pages/webpack.config.js
index 25ce412ae..2020bede0 100644
--- a/pages/webpack.config.js
+++ b/pages/webpack.config.js
@@ -6,7 +6,6 @@ module.exports = {
   entry: {
     'localdev': './src/localdev.ts',
     'polyfill-full': './src/polyfill-full.ts',
-    'polyfill-medium': './src/polyfill-medium.ts',
     'polyfill-light': './src/polyfill-light.ts'
   },
   resolve: {
diff --git a/src/modules/all.less b/src/modules/all.less
index 596262221..3e592ab87 100644
--- a/src/modules/all.less
+++ b/src/modules/all.less
@@ -21,3 +21,5 @@
 
 @import "./esl-footnotes/core.less";
 @import "./esl-tooltip/core.less";
+
+@import "./esl-animate/core.less";
diff --git a/src/modules/all.ts b/src/modules/all.ts
index 9e09caeb3..ddbae05a0 100644
--- a/src/modules/all.ts
+++ b/src/modules/all.ts
@@ -25,3 +25,5 @@ export * from './esl-forms/all';
 
 export * from './esl-footnotes/core';
 export * from './esl-tooltip/core';
+
+export * from './esl-animate/core';
diff --git a/src/modules/esl-animate/README.md b/src/modules/esl-animate/README.md
new file mode 100644
index 000000000..36885ed25
--- /dev/null
+++ b/src/modules/esl-animate/README.md
@@ -0,0 +1,10 @@
+[ESL](https://exadel-inc.github.io/esl/) Animate
+
+Version: _1.0.0-beta_.
+
+Authors: *Anna-Mariia Petryk*, *Julia Murashko*, *Alexey Stsefanovich (ala'n)*.
+
+<a name="intro"></a>
+
+**_Important Notice: the component is under beta version, it is tested and ready to use but be aware of its potential critical API changes._**
+
diff --git a/src/modules/esl-animate/core.less b/src/modules/esl-animate/core.less
new file mode 100644
index 000000000..6fc65cbb3
--- /dev/null
+++ b/src/modules/esl-animate/core.less
@@ -0,0 +1,1 @@
+@import "./core/esl-animate.less";
diff --git a/src/modules/esl-animate/core.ts b/src/modules/esl-animate/core.ts
new file mode 100644
index 000000000..d8e2ec459
--- /dev/null
+++ b/src/modules/esl-animate/core.ts
@@ -0,0 +1,1 @@
+export * from './core/esl-animate';
diff --git a/src/modules/esl-animate/core/esl-animate-service.ts b/src/modules/esl-animate/core/esl-animate-service.ts
new file mode 100644
index 000000000..320b59ce6
--- /dev/null
+++ b/src/modules/esl-animate/core/esl-animate-service.ts
@@ -0,0 +1,146 @@
+import {wrap} from '../../esl-utils/misc/array';
+import {bind} from '../../esl-utils/decorators/bind';
+import {debounce} from '../../esl-utils/async/debounce';
+import {memoize} from '../../esl-utils/decorators/memoize';
+
+// /** ESLAnimate service animation options */
+// export interface ESLAnimateConfig {
+//   /** Class to mark element animated*/
+//   cls: string;
+//
+//   /** Delay to display element(s) after previous one. If negative or false then play animation immodestly */
+//   group: string; //number | false;
+//   groupDelay: number;
+//
+//   /** Do not unsubscribe after animate and repeat animation on each viewport intersection */
+//   repeat: 'forward' | boolean;
+//
+//   /** @private animation requested */
+//   _timeout?: number;
+//   /** @private marker to unobserve */
+//   _unsubscribe?: boolean;
+// }
+
+/** ESLAnimate service animation options */
+export interface ESLAnimateConfig {
+  /** Class to mark element animated*/
+  cls: string;
+
+  /** Delay to display element(s) after previous one. If negative or false then play animation immodestly */
+  group: number | false;
+
+  /** Do not unsubscribe after animate and repeat animation on each viewport intersection */
+  repeat: boolean;
+
+  /** @private animation requested */
+  _timeout?: number;
+  /** @private marker to unobserve */
+  _unsubscribe?: boolean;
+}
+
+/** Service to animate elements on viewport intersection */
+export class ESLAnimateService {
+
+  protected static readonly DEFAULT_CONFIG: ESLAnimateConfig = {cls: 'in', repeat: false, group: false};
+  protected static readonly OPTIONS_OBSERVER: IntersectionObserverInit = {threshold: [0.01, 0.4]};
+
+  /**
+   * Subscribe ESlAnimateService on element(s) to animate it on viewport intersection
+   * @param target - element(s) or elements to observe and animate
+   * @param config - optional animation configuration
+   */
+  public static observe(target: Element | Element[], config: string | Partial<ESLAnimateConfig> = {}): void {
+    wrap(target).forEach((item: Element) => this.instance.observe(item, config));
+  }
+
+  /** Unobserve element or elements */
+  public static unobserve(target: Element | Element[]): void {
+    wrap(target).forEach((item: Element) => this.instance.unobserve(item));
+  }
+
+  /** @returns if service observing target */
+  public static isObserved(target: Element): boolean {
+    return !!this.instance.getConfigFor(target);
+  }
+
+  @memoize()
+  private static get instance() {
+    return new ESLAnimateService();
+  }
+
+  protected _io = new IntersectionObserver(this.onIntersect, ESLAnimateService.OPTIONS_OBSERVER);
+  protected _entries: Element[] = [];
+  protected _configMap = new WeakMap<Element, ESLAnimateConfig>();
+
+  protected deferredOnAnimate = debounce(() => this.onAnimate(), 100);
+
+  /**
+   * Subscribe ESlAnimateService on element(s) to animate it on viewport intersection
+   * @param el - element or elements to observe and animate
+   * @param config - optional animation configuration
+   */
+  public observe(el: Element, config: string | Partial<ESLAnimateConfig> = {}): void {
+    if (typeof config === 'string') config = {cls: config};
+    const cfg: ESLAnimateConfig = Object.assign({}, ESLAnimateService.DEFAULT_CONFIG, config);
+    this._configMap.set(el, cfg);
+    el.classList.remove(cfg.cls);
+    this._io.observe(el);
+  }
+
+  /** Unobserve element or elements */
+  public unobserve(el: Element): void {
+    this._io.unobserve(el);
+    this._configMap.delete(el);
+  }
+
+  /** Intersection observable callback */
+  @bind
+  protected onIntersect(entries: IntersectionObserverEntry[]): void {
+    entries.forEach(({target, intersectionRatio, isIntersecting}: IntersectionObserverEntry) => {
+      const config = this.getConfigFor(target);
+      if (!config) return;
+
+      if (intersectionRatio >= 0.4) {
+        this._entries.push(target);
+      }
+
+      if (!isIntersecting) {
+        this._entries = this._entries.filter(item => item !== target);
+      }
+
+      if (intersectionRatio <= 0.1 && config.repeat) {
+        target.classList.remove(config.cls);
+        config._timeout && clearTimeout(config._timeout);
+      }
+    });
+    this.deferredOnAnimate();
+  }
+
+  /** Method to show up HTMLElement */
+  protected onAnimate(): void {
+    this._entries.sort((a: HTMLElement, b: HTMLElement) => a.offsetTop - b.offsetTop);
+    this._entries.reduce((time, target) => {
+      const config = this.getConfigFor(target);
+      if (!config) return;
+
+      if (typeof config.group === 'number' && config.group >= 0) {
+        time += config.group;
+        config._timeout = window.setTimeout(() => target.classList.add(config.cls), time);
+      } else {
+        target.classList.add(config.cls);
+      }
+      if (!config.repeat) {
+        this._io.unobserve(target);
+        config._unsubscribe = true;
+      }
+      config._unsubscribe && this._configMap.delete(target);
+      return time;
+    }, 0);
+    this._entries = [];
+  }
+
+  /** Returns config */
+  protected getConfigFor(el: Element): ESLAnimateConfig | undefined {
+    return this._configMap.get(el);
+  }
+}
diff --git a/src/modules/esl-animate/core/esl-animate.less b/src/modules/esl-animate/core/esl-animate.less
new file mode 100644
index 000000000..091dd61d5
--- /dev/null
+++ b/src/modules/esl-animate/core/esl-animate.less
@@ -0,0 +1,24 @@
+esl-animate {
+  display: inline-block;
+  &:empty {
+    display: none;
+  }
+}
+
+.esl-animate-fade {
+  opacity: 0;
+  &.in {
+    opacity: 1;
+    transition: opacity 1.5s;
+  }
+}
+
+.esl-animate-slide {
+  opacity: 0;
+  transform: translateY(30px);
+  &.in {
+    opacity: 1;
+    transform: translateY(0px);
+    transition: transform 1s, opacity 1s;
+  }
+}
diff --git a/src/modules/esl-animate/core/esl-animate.ts b/src/modules/esl-animate/core/esl-animate.ts
new file mode 100644
index 000000000..e5d461154
--- /dev/null
+++ b/src/modules/esl-animate/core/esl-animate.ts
@@ -0,0 +1,50 @@
+import {memoize, ready, TraversingQuery} from '../../all';
+import {attr, boolAttr, ESLBaseElement} from '../../esl-base-element/core';
+
+import {ESLAnimateService} from './esl-animate-service';
+
+export class ESLAnimate extends ESLBaseElement {
+  static is = 'esl-animate';
+
+  @attr({defaultValue: 'in'}) public cls: string;
+  @attr({defaultValue: '-1'}) public group: string;
+  @attr() public target: string;
+
+  @boolAttr() public repeat: boolean;
+
+  static get observedAttributes() {
+    return ['group', 'repeat', 'target'];
+  }
+
+  @memoize()
+  public get $targets() {
+    return TraversingQuery.all(this.target, this);
+  }
+
+  protected attributeChangedCallback() {
+    if (!this.connected) return;
+    this.reanimate();
+  }
+
+  @ready
+  protected connectedCallback() {
+    super.connectedCallback();
+    this.reanimate();
+  }
+
+  @ready
+  protected disconnectedCallback() {
+    super.disconnectedCallback();
+    ESLAnimateService.unobserve(this.$targets);
+  }
+
+  protected reanimate() {
+    ESLAnimateService.unobserve(this.$targets);
+    memoize.clear(this, '$targets');
+    ESLAnimateService.observe(this.$targets, {
+      cls: this.cls,
+      repeat: this.repeat,
+      group: +(this.group || '100')
+    });
+  }
+}
diff --git a/src/modules/esl-popup/core/esl-popup-position.ts b/src/modules/esl-popup/core/esl-popup-position.ts
index e663fa622..d98ce5b31 100644
--- a/src/modules/esl-popup/core/esl-popup-position.ts
+++ b/src/modules/esl-popup/core/esl-popup-position.ts
@@ -33,6 +33,22 @@ export interface PopupPositionConfig {
   trigger: Rect;
 }
 
+/**
+ * Calculates the base offset of the arrow from the edge of the popup, in pixels,
+ * based on the size of the popup and the value of the arrow offset
+ * @param size - the size of the popup
+ * @param ratio - the value of the arrow offset
+ */
+function calcBasicArrowAdjust(size: number, ratio: number): number {
+  /** Sign should be:
+   *  -1 when ratio less 0.5
+   *   0 when ratio equal 0.5
+   *   1 when ratio greater 0.5
+   */
+  const sign = Math.sign(ratio - 0.5);
+  return sign * size;
+}
+
 /**
  * Calculates the position of the popup on the minor axis
  * @param cfg - popup position config
@@ -40,7 +56,8 @@ export interface PopupPositionConfig {
  * @param dimensionName - the name of dimension (height or width)
  */
 function calcPopupPositionByMinorAxis(cfg: PopupPositionConfig, centerPosition: number, dimensionName: 'height' | 'width'): number {
-  return centerPosition - cfg.arrow[dimensionName] / 2 - cfg.marginArrow - calcUsableSizeForArrow(cfg, dimensionName) * cfg.offsetArrowRatio;
+  return centerPosition - cfg.element[dimensionName] * cfg.offsetArrowRatio +
+    calcBasicArrowAdjust(cfg.marginArrow + cfg.arrow[dimensionName] / 2, cfg.offsetArrowRatio);
 }
 
 /**
diff --git a/src/modules/esl-popup/core/esl-popup.less b/src/modules/esl-popup/core/esl-popup.less
index 479236c6e..4978e44e1 100644
--- a/src/modules/esl-popup/core/esl-popup.less
+++ b/src/modules/esl-popup/core/esl-popup.less
@@ -41,10 +41,11 @@
 
   &[placed-at=right] {
     .esl-popup-arrow {
-      left: (-@popupArrowHalf - @popupBorderWidth - @popupArrowShift);
+      left: auto;
       right: auto;
       transform: rotate(315deg);
       margin-top: @popupArrowShift;
+      margin-left: (-@popupArrowHalf - @popupBorderWidth);
     }
   }
 }
diff --git a/src/modules/esl-traversing-query/core/esl-traversing-query.ts b/src/modules/esl-traversing-query/core/esl-traversing-query.ts
index da5d58fca..5f08ae2c4 100644
--- a/src/modules/esl-traversing-query/core/esl-traversing-query.ts
+++ b/src/modules/esl-traversing-query/core/esl-traversing-query.ts
@@ -94,21 +94,21 @@ export class TraversingQuery {
     return uniq(result);
   }
 
-  static traverse(query: string, findFirst: boolean, base?: Element | null, scope: Element | Document = document) {
+  static traverse(query: string, findFirst: boolean, base?: Element) {
     const parts = query.split(this.PROCESSORS_REGEX).map((term) => term.trim());
     const rootSel = parts.shift();
     const baseCollection = base ? [base] : [];
-    const initial: Element[] = rootSel ? Array.from(scope.querySelectorAll(rootSel)) : baseCollection;
+    const initial: Element[] = rootSel ? Array.from(document.querySelectorAll(rootSel)) : baseCollection;
     return this.traverseChain(initial, tuple(parts), findFirst);
   }
 
   /** @returns first matching element reached via {@link TraversingQuery} rules */
-  static first(query: string, base?: Element | null, scope?: Element): Element | null {
-    return TraversingQuery.traverse(query, true, base, scope)[0] || null;
+  static first(query: string, base?: Element): Element | null {
+    return TraversingQuery.traverse(query, true, base)[0] || null;
   }
   /** @returns Array of all matching elements reached via {@link TraversingQuery} rules */
-  static all(query: string, base?: Element | null, scope?: Element): Element[] {
-    return TraversingQuery.traverse(query, false, base, scope);
+  static all(query: string, base?: Element): Element[] {
+    return TraversingQuery.traverse(query, false, base);
   }
 }
 


Test patch:
diff --git a/src/modules/esl-traversing-query/test/esl-traversing-query.test.ts b/src/modules/esl-traversing-query/test/esl-traversing-query.test.ts
index 9ff01e16c..0fa6fab9c 100644
--- a/src/modules/esl-traversing-query/test/esl-traversing-query.test.ts
+++ b/src/modules/esl-traversing-query/test/esl-traversing-query.test.ts
@@ -40,7 +40,7 @@ describe('Traversing Query tests', () => {
     '::child(.btn)',
     '::parent',
     '::parent(body)'
-  ])('Null check: TraversingQuery.all/one(%s, null)', (sel) => {
+  ])('Null check: TraversingQuery.all/one("%s", null)', (sel) => {
     expect(TraversingQuery.first(sel)).toBe(null);
     expect(TraversingQuery.all(sel)).toEqual([]);
   });
@@ -49,7 +49,6 @@ describe('Traversing Query tests', () => {
     // Simple queries
     ['#null', undefined, []],
     ['#btn3', undefined, [btn3]],
-    ['#btn3', null, [btn3]],
     ['section', undefined, [root]],
     ['section > .row', undefined, [row1, row2]],
     ['section > .row:first-child', undefined, [row1]],
@@ -110,20 +109,10 @@ describe('Traversing Query tests', () => {
     ['::parent::next::find(.col-2)', article1, [article2]],
     ['::parent(.container)::find(.btn)::last', btn5, [btn6]],
     ['::parent(.container)::child(.row)::last::find(.col-2)', article1, [article2]],
-  ])('Main check: TraversingQuery.all/one, Sel: %s, Base: %p.', (sel, base, expectedCollection) => {
-    expect(TraversingQuery.first(sel, base as Element | null))
+  ])('Main check: TraversingQuery.all/one, Sel: "%s", Base: %p.', (sel, base, expectedCollection) => {
+    expect(TraversingQuery.first(sel, base as Element))
       .toBe(expectedCollection.length > 0 ? expectedCollection[0] : null);
-    expect(TraversingQuery.all(sel, base as Element | null))
-      .toEqual(expectedCollection);
-  });
-
-  test.each([
-    ['#row1', null, root, [row1]],
-    ['#row1', null, row2, []],
-  ])('Main check: TraversingQuery.all/one, Sel: %s, Base: %p., Scope: %p.', (sel, base, scope, expectedCollection) => {
-    expect(TraversingQuery.first(sel, base as Element | null, scope as Element))
-      .toBe(expectedCollection.length > 0 ? expectedCollection[0] : null);
-    expect(TraversingQuery.all(sel, base as Element | null, scope as Element))
+    expect(TraversingQuery.all(sel, base as Element))
       .toEqual(expectedCollection);
   });
 });