Repository: exadel-inc/esl
Pull request #657 (2021-11-21 20:05:35)

Update `epic/redesign` with the latest `main` changes


Patch:
diff --git a/.commitlintrc.yml b/.commitlintrc.yml
index ed89d2e16..044055c9c 100644
--- a/.commitlintrc.yml
+++ b/.commitlintrc.yml
@@ -2,3 +2,4 @@ extends:
   - "@commitlint/config-conventional"
 rules:
   body-max-length: [1, 'always', 120]
+  body-max-line-length: [1, 'always', 150]
diff --git a/.github/ISSUE_TEMPLATE/site-bug-report.md b/.github/ISSUE_TEMPLATE/site-bug-report.md
new file mode 100644
index 000000000..9af27ae91
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/site-bug-report.md
@@ -0,0 +1,27 @@
+---
+name: "\U0001F41B Demo Site Bug"
+about: Create a bug found on the ESL demo site
+title: "[\U0001F41B in gh-pages]:  ..."
+labels: waits triage
+assignees: ''
+
+---
+
+**Describe the 🐛 bug found on a demo page**
+A clear and concise description of the bug.
+
+**Page(s)**
+Provide the page url or urls where the bug was reproduced.
+
+**Environment**
+- OS: [e.g. OSX 10.13.4, Windows 10]
+- Browser: [e.g. Chrome/87.0.4280.141]
+
+**Screenshots**
+If applicable, add screenshots to help explain.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen (or code).
+
+**Possible Solution**
+<!--- Only if you have suggestions for fixing the bug -->
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 78ffb27bf..17a7c2ea5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,19 @@
+# [3.5.0](https://github.com/exadel-inc/esl/compare/v3.4.1...v3.5.0) (2021-11-15)
+
+
+### Bug Fixes
+
+* **esl-alert:** default alert background color changed ([0243e63](https://github.com/exadel-inc/esl/commit/0243e632efd2a6a27679f3b942fa828f2c5bcfe2))
+* **esl-popup:** fix arrow position for adjacent axis ([b37d550](https://github.com/exadel-inc/esl/commit/b37d55021659c6781f516641f5fc88eda77aaf39))
+* **esl-select:** return min-width ([c07ceba](https://github.com/exadel-inc/esl/commit/c07ceba75b320e4bc7eaa0c4333d7cfb51ee6d43))
+
+
+### Features
+* **gh-pages** new demo site released
+* **esl-utils** add ability to scrollIntoView to detect when scrolling stops ([d1a4845](https://github.com/exadel-inc/esl/commit/d1a48452f1fcdfd7347f86bf6d09eeeb2dc1d80a))
+* **esl-alert:** ability to control initial params ([1cda5ea](https://github.com/exadel-inc/esl/commit/1cda5ea2d4d121cb73b50f2dbf7518151081db85))
+
+
 ## [3.4.1](https://github.com/exadel-inc/esl/compare/v3.4.0...v3.4.1) (2021-11-08)
 
 
diff --git a/CNAME b/CNAME
new file mode 100644
index 000000000..34aa1e0b1
--- /dev/null
+++ b/CNAME
@@ -0,0 +1,1 @@
+esl-ui.com
diff --git a/README.md b/README.md
index 6c700f423..51308182d 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
 
 Exadel Smart Library (**ESL**) is a web components based library that gives you a set of **lightweight** and **flexible** custom elements to easily create basic UX modules and make your websites super fast.
 
-You can visit our **[Demo Site](https://exadel-inc.github.io/esl/)** (*draft*).
+You can visit our **[Demo Site](https://esl-ui.com/)**.
 
 <p align="center" >★ <b>Try out our open library and if you like it please support us with a star on GitHub</b> ★</p>
 
diff --git a/package-lock.json b/package-lock.json
index 6dfc1121e..c8333139f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "@exadel/esl",
-  "version": "3.4.1",
+  "version": "3.5.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -575,16 +575,16 @@
       "dev": true
     },
     "@commitlint/cli": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-14.1.0.tgz",
-      "integrity": "sha512-Orq62jkl9qAGvjFqhehtAqjGY/duJ8hIRPPIHmGR2jIB96D4VTmazS3ZvqJz2Q9kKr61mLAk/171zm0FVzQCYA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-15.0.0.tgz",
+      "integrity": "sha512-Y5xmDCweytqzo4N4lOI2YRiuX35xTjcs8n5hUceBH8eyK0YbwtgWX50BJOH2XbkwEmII9blNhlBog6AdQsqicg==",
       "dev": true,
       "requires": {
-        "@commitlint/format": "^14.1.0",
-        "@commitlint/lint": "^14.1.0",
-        "@commitlint/load": "^14.1.0",
-        "@commitlint/read": "^14.0.0",
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/format": "^15.0.0",
+        "@commitlint/lint": "^15.0.0",
+        "@commitlint/load": "^15.0.0",
+        "@commitlint/read": "^15.0.0",
+        "@commitlint/types": "^15.0.0",
         "lodash": "^4.17.19",
         "resolve-from": "5.0.0",
         "resolve-global": "1.0.0",
@@ -609,71 +609,71 @@
       }
     },
     "@commitlint/config-conventional": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-14.1.0.tgz",
-      "integrity": "sha512-JuhCqkEv8jyqmd54EpXPsQFpYc/8k7sfP1UziRdEvZSJUCLxz+8Pk4cNS0oF1BtjaWO7ITgXPlIZg47PyApGmg==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-15.0.0.tgz",
+      "integrity": "sha512-eZBRL8Lk3hMNHp1wUMYj0qrZQEsST1ai7KHR8J1IDD9aHgT7L2giciibuQ+Og7vxVhR5WtYDvh9xirXFVPaSkQ==",
       "dev": true,
       "requires": {
         "conventional-changelog-conventionalcommits": "^4.3.1"
       }
     },
     "@commitlint/ensure": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-14.1.0.tgz",
-      "integrity": "sha512-xrYvFdqVepT3XA1BmSh88eKbvYKtLuQu98QLfgxVmwS99Kj3yW0sT3D7jGvNsynbIx2dhbXofDyubf/DKkpFrQ==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-15.0.0.tgz",
+      "integrity": "sha512-7DV4iNIald3vycwaWBNGk5FbonaNzOlU8nBe5m5AgU2dIeNKuXwLm+zzJzG27j0Ho56rgz//3F6RIvmsoxY9ZA==",
       "dev": true,
       "requires": {
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/types": "^15.0.0",
         "lodash": "^4.17.19"
       }
     },
     "@commitlint/execute-rule": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-14.0.0.tgz",
-      "integrity": "sha512-Hh/HLpCBDlrD3Rx2x2pDBx6CU+OtVqGXh7mbFpNihAVx6B0zyZqm/vv0cdwdhfGW5OEn1BhCqHf1ZOvL/DwdWA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-15.0.0.tgz",
+      "integrity": "sha512-pyE4ApxjbWhb1TXz5vRiGwI2ssdMMgZbaaheZq1/7WC0xRnqnIhE1yUC1D2q20qPtvkZPstTYvMiRVtF+DvjUg==",
       "dev": true
     },
     "@commitlint/format": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-14.1.0.tgz",
-      "integrity": "sha512-sF6engqqHjvxGctWRKjFs/HQeNowlpbVmmoP481b2UMQnVQnjjfXJvQsoLpaqFUvgc2sHM4L85F8BmAw+iHG1w==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-15.0.0.tgz",
+      "integrity": "sha512-bPhAfqwRhPk92WiuY0ktEJNpRRHSCd+Eg1MdhGyL9Bl3U25E5zvuInA+dNctnzZiOBSH/37ZaD0eOKCpQE6acg==",
       "dev": true,
       "requires": {
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/types": "^15.0.0",
         "chalk": "^4.0.0"
       }
     },
     "@commitlint/is-ignored": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-14.0.0.tgz",
-      "integrity": "sha512-nJltYjXTa+mk+6SPe35nOZCCvt3Gh5mbDz008KQ4OPcn1GX1NG+pEgz1Kx3agDp/pc+JGnsrr5GV00gygIoloA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-15.0.0.tgz",
+      "integrity": "sha512-edtnkf2QZ/7e/YCJDgn1WDw9wfF1WfOitW5YEoSOb4SxjJEb/oE87kxNPZ2j8mnDMuunspcMfGHeg6fRlwaEWg==",
       "dev": true,
       "requires": {
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/types": "^15.0.0",
         "semver": "7.3.5"
       }
     },
     "@commitlint/lint": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-14.1.0.tgz",
-      "integrity": "sha512-CApGJEOtWU/CcuPD8HkOR1jdUYpjKutGPaeby9nSFzJhwl/UQOjxc4Nd+2g2ygsMi5l3N4j2sWQYEgccpFC3lA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-15.0.0.tgz",
+      "integrity": "sha512-hUi2+Im/2dJ5FBvWnodypTkg+5haCgsDzB0fyMApWLUA1IucYUAqRCQCW5em1Mhk9Crw1pd5YzFNikhIclkqCw==",
       "dev": true,
       "requires": {
-        "@commitlint/is-ignored": "^14.0.0",
-        "@commitlint/parse": "^14.0.0",
-        "@commitlint/rules": "^14.1.0",
-        "@commitlint/types": "^14.0.0"
+        "@commitlint/is-ignored": "^15.0.0",
+        "@commitlint/parse": "^15.0.0",
+        "@commitlint/rules": "^15.0.0",
+        "@commitlint/types": "^15.0.0"
       }
     },
     "@commitlint/load": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-14.1.0.tgz",
-      "integrity": "sha512-p+HbgjhkqLsnxyjOUdEYHztHCp8n2oLVUJTmRPuP5FXLNevh6Gwmxf+NYC2J0sgD084aV2CFi3qu1W4yHWIknA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-15.0.0.tgz",
+      "integrity": "sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==",
       "dev": true,
       "requires": {
-        "@commitlint/execute-rule": "^14.0.0",
-        "@commitlint/resolve-extends": "^14.1.0",
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/execute-rule": "^15.0.0",
+        "@commitlint/resolve-extends": "^15.0.0",
+        "@commitlint/types": "^15.0.0",
         "@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2",
         "chalk": "^4.0.0",
         "cosmiconfig": "^7.0.0",
@@ -683,18 +683,18 @@
       }
     },
     "@commitlint/message": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-14.0.0.tgz",
-      "integrity": "sha512-316Pum+bwDcZamOQw0DXSY17Dq9EjvL1zKdYIZqneu4lnXN6uFfi53Y/sP5crW6zlLdnuTHe1MnuewXPLHfH1Q==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-15.0.0.tgz",
+      "integrity": "sha512-L8euabzboKavPuDJsdIYAY2wx97LbiGEYsckMo6NmV8pOun50c8hQx6ouXFSAx4pp+mX9yUGmMiVqfrk2LKDJQ==",
       "dev": true
     },
     "@commitlint/parse": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-14.0.0.tgz",
-      "integrity": "sha512-49qkk0TcwdxJPZUX8MElEzMlRFIL/cg64P4pk8HotFEm2HYdbxxZp6v3cbVw5WOsnRA0frrs+NNoOcIT83ccMQ==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-15.0.0.tgz",
+      "integrity": "sha512-7fweM67tZfBNS7zw1KTuuT5K2u9nGytUJqFqT/1Ln3Na9cBCsoAqR47mfsNOTlRCgGwakm4xiQ7BpS2gN0OGuw==",
       "dev": true,
       "requires": {
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/types": "^15.0.0",
         "conventional-changelog-angular": "^5.0.11",
         "conventional-commits-parser": "^3.2.2"
       },
@@ -716,21 +716,21 @@
       }
     },
     "@commitlint/read": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-14.0.0.tgz",
-      "integrity": "sha512-WXXcSLBqwXTqnEmB0lbU2TrayDJ2G3qI/lxy1ianVmpQol8p9BjodAA6bYxtYYHdQFVXUrIsclzFP/naWG+hlQ==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-15.0.0.tgz",
+      "integrity": "sha512-5yI1o2HKZFVe7RTjL7IhuhHMKar/MDNY34vEHqqz9gMI7BK/rdP8uVb4Di1efl2V0UPnwID0nPKWESjQ8Ti0gw==",
       "dev": true,
       "requires": {
-        "@commitlint/top-level": "^14.0.0",
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/top-level": "^15.0.0",
+        "@commitlint/types": "^15.0.0",
         "fs-extra": "^10.0.0",
         "git-raw-commits": "^2.0.0"
       }
     },
     "@commitlint/resolve-extends": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-14.1.0.tgz",
-      "integrity": "sha512-ko80k6QB6E6/OvGNWy4u7gzzWyluDT3VDNL2kfZaDywsnrYntUKyT4Do97gQ7orttITzj2GRtk3KWClVz4rUUQ==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-15.0.0.tgz",
+      "integrity": "sha512-7apfRJjgJsKja7lHsPfEFixKjA/fk/UeD3owkOw1174yYu4u8xBDLSeU3IinGPdMuF9m245eX8wo7vLUy+EBSg==",
       "dev": true,
       "requires": {
         "import-fresh": "^3.0.0",
@@ -740,28 +740,28 @@
       }
     },
     "@commitlint/rules": {
-      "version": "14.1.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-14.1.0.tgz",
-      "integrity": "sha512-6jmv414/1JzGzDI/DS+snAMhcL6roQKPdg0WB3kWTWN52EvWXBFm0HIMGt2H/FlRKxozwVXlQN60/1fNIl98xA==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-15.0.0.tgz",
+      "integrity": "sha512-SqXfp6QUlwBS+0IZm4FEA/NmmAwcFQIkG3B05BtemOVWXQdZ8j1vV6hDwvA9oMPCmUSrrGpHOtZK7HaHhng2yA==",
       "dev": true,
       "requires": {
-        "@commitlint/ensure": "^14.1.0",
-        "@commitlint/message": "^14.0.0",
-        "@commitlint/to-lines": "^14.0.0",
-        "@commitlint/types": "^14.0.0",
+        "@commitlint/ensure": "^15.0.0",
+        "@commitlint/message": "^15.0.0",
+        "@commitlint/to-lines": "^15.0.0",
+        "@commitlint/types": "^15.0.0",
         "execa": "^5.0.0"
       }
     },
     "@commitlint/to-lines": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-14.0.0.tgz",
-      "integrity": "sha512-uIXk54oJDuYyLpI208s3+cGmJ323yvSJ9LB7yUDMWUeJi2LgRxE2EBZL995kLQdnoAsBBXcLq+VDyppg5bV/cg==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-15.0.0.tgz",
+      "integrity": "sha512-mY3MNA9ujPqVpiJjTYG9MDsYCobue5PJFO0MfcIzS1mCVvngH8ZFTPAh1fT5t+t1h876boS88+9WgqjRvbYItw==",
       "dev": true
     },
     "@commitlint/top-level": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-14.0.0.tgz",
-      "integrity": "sha512-MZDKZfWfl9g4KozgWBGTCrI2cXkMHnBFlhwvEfrAu5G8wd5aL1f2uWEUMnBMjUikmhVj99i1pzge4XFWHQ29wQ==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-15.0.0.tgz",
+      "integrity": "sha512-7Gz3t7xcuuUw1d1Nou6YLaztzp2Em+qZ6YdCzrqYc+aquca3Vt0O696nuiBDU/oE+tls4Hx2CNpAbWhTgEwB5A==",
       "dev": true,
       "requires": {
         "find-up": "^5.0.0"
@@ -807,9 +807,9 @@
       }
     },
     "@commitlint/types": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-14.0.0.tgz",
-      "integrity": "sha512-sIls1nP2uSbGL466edYlh8mn7O/WP4i3bcvP+2DMhkscRCSgaPhNRWDilhYVsHt2Vu1HTQ27uT0Bj5/Lt2+EcQ==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-15.0.0.tgz",
+      "integrity": "sha512-OMSLX+QJnyNoTwws54ULv9sOvuw9GdVezln76oyUd4YbMMJyaav62aSXDuCdWyL2sm9hTkSzyEi52PNaIj/vqw==",
       "dev": true,
       "requires": {
         "chalk": "^4.0.0"
@@ -1855,9 +1855,9 @@
       }
     },
     "@types/eslint": {
-      "version": "7.29.0",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz",
-      "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.0.tgz",
+      "integrity": "sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ==",
       "dev": true,
       "requires": {
         "@types/estree": "*",
@@ -1914,9 +1914,9 @@
       }
     },
     "@types/jest": {
-      "version": "27.0.2",
-      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz",
-      "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==",
+      "version": "27.0.3",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.3.tgz",
+      "integrity": "sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg==",
       "dev": true,
       "requires": {
         "jest-diff": "^27.0.0",
@@ -2020,13 +2020,13 @@
       "integrity": "sha512-Yf1Y4bDj/QIn8v+zdy0l7+OW6s1uoUvzVn5cGqPNCsL4iUW4gYUlIdQIRtH9NOHVgwZNLbVeeRDEn6N4RMq6Nw=="
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.3.1.tgz",
-      "integrity": "sha512-cFImaoIr5Ojj358xI/SDhjog57OK2NqlpxwdcgyxDA3bJlZcJq5CPzUXtpD7CxI2Hm6ATU7w5fQnnkVnmwpHqw==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz",
+      "integrity": "sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "5.3.1",
-        "@typescript-eslint/scope-manager": "5.3.1",
+        "@typescript-eslint/experimental-utils": "5.4.0",
+        "@typescript-eslint/scope-manager": "5.4.0",
         "debug": "^4.3.2",
         "functional-red-black-tree": "^1.0.1",
         "ignore": "^5.1.8",
@@ -2053,28 +2053,28 @@
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.3.1.tgz",
-      "integrity": "sha512-RgFn5asjZ5daUhbK5Sp0peq0SSMytqcrkNfU4pnDma2D8P3ElZ6JbYjY8IMSFfZAJ0f3x3tnO3vXHweYg0g59w==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz",
+      "integrity": "sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.9",
-        "@typescript-eslint/scope-manager": "5.3.1",
-        "@typescript-eslint/types": "5.3.1",
-        "@typescript-eslint/typescript-estree": "5.3.1",
+        "@typescript-eslint/scope-manager": "5.4.0",
+        "@typescript-eslint/types": "5.4.0",
+        "@typescript-eslint/typescript-estree": "5.4.0",
         "eslint-scope": "^5.1.1",
         "eslint-utils": "^3.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.3.1.tgz",
-      "integrity": "sha512-TD+ONlx5c+Qhk21x9gsJAMRohWAUMavSOmJgv3JGy9dgPhuBd5Wok0lmMClZDyJNLLZK1JRKiATzCKZNUmoyfw==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.4.0.tgz",
+      "integrity": "sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "5.3.1",
-        "@typescript-eslint/types": "5.3.1",
-        "@typescript-eslint/typescript-estree": "5.3.1",
+        "@typescript-eslint/scope-manager": "5.4.0",
+        "@typescript-eslint/types": "5.4.0",
+        "@typescript-eslint/typescript-estree": "5.4.0",
         "debug": "^4.3.2"
       },
       "dependencies": {
@@ -2096,29 +2096,29 @@
       }
     },
     "@typescript-eslint/scope-manager": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.3.1.tgz",
-      "integrity": "sha512-XksFVBgAq0Y9H40BDbuPOTUIp7dn4u8oOuhcgGq7EoDP50eqcafkMVGrypyVGvDYHzjhdUCUwuwVUK4JhkMAMg==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz",
+      "integrity": "sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "5.3.1",
-        "@typescript-eslint/visitor-keys": "5.3.1"
+        "@typescript-eslint/types": "5.4.0",
+        "@typescript-eslint/visitor-keys": "5.4.0"
       }
     },
     "@typescript-eslint/types": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.3.1.tgz",
-      "integrity": "sha512-bG7HeBLolxKHtdHG54Uac750eXuQQPpdJfCYuw4ZI3bZ7+GgKClMWM8jExBtp7NSP4m8PmLRM8+lhzkYnSmSxQ==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.4.0.tgz",
+      "integrity": "sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.1.tgz",
-      "integrity": "sha512-PwFbh/PKDVo/Wct6N3w+E4rLZxUDgsoII/GrWM2A62ETOzJd4M6s0Mu7w4CWsZraTbaC5UQI+dLeyOIFF1PquQ==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz",
+      "integrity": "sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "5.3.1",
-        "@typescript-eslint/visitor-keys": "5.3.1",
+        "@typescript-eslint/types": "5.4.0",
+        "@typescript-eslint/visitor-keys": "5.4.0",
         "debug": "^4.3.2",
         "globby": "^11.0.4",
         "is-glob": "^4.0.3",
@@ -2167,12 +2167,12 @@
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.1.tgz",
-      "integrity": "sha512-3cHUzUuVTuNHx0Gjjt5pEHa87+lzyqOiHXy/Gz+SJOCW1mpw9xQHIIEwnKn+Thph1mgWyZ90nboOcSuZr/jTTQ==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz",
+      "integrity": "sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "5.3.1",
+        "@typescript-eslint/types": "5.4.0",
         "eslint-visitor-keys": "^3.0.0"
       }
     },
@@ -6949,15 +6949,15 @@
       }
     },
     "jest-diff": {
-      "version": "27.2.0",
-      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.0.tgz",
-      "integrity": "sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw==",
+      "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.0.6",
-        "pretty-format": "^27.2.0"
+        "jest-get-type": "^27.3.1",
+        "pretty-format": "^27.3.1"
       }
     },
     "jest-docblock": {
@@ -7102,9 +7102,9 @@
       }
     },
     "jest-get-type": {
-      "version": "27.0.6",
-      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz",
-      "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==",
+      "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-haste-map": {
@@ -11668,13 +11668,13 @@
       }
     },
     "pretty-format": {
-      "version": "27.2.0",
-      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.0.tgz",
-      "integrity": "sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA==",
+      "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.1.1",
-        "ansi-regex": "^5.0.0",
+        "@jest/types": "^27.2.5",
+        "ansi-regex": "^5.0.1",
         "ansi-styles": "^5.0.0",
         "react-is": "^17.0.1"
       },
@@ -13870,9 +13870,9 @@
       }
     },
     "typescript": {
-      "version": "4.4.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
-      "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz",
+      "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==",
       "dev": true
     },
     "ua-parser-js": {
@@ -14068,9 +14068,9 @@
       "dev": true
     },
     "webpack": {
-      "version": "5.64.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.0.tgz",
-      "integrity": "sha512-UclnN24m054HaPC45nmDEosX6yXWD+UGC12YtUs5i356DleAUGMDC9LBAw37xRRfgPKYIdCYjGA7RZ1AA+ZnGg==",
+      "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",
@@ -14096,7 +14096,7 @@
         "tapable": "^2.1.1",
         "terser-webpack-plugin": "^5.1.3",
         "watchpack": "^2.2.0",
-        "webpack-sources": "^3.2.0"
+        "webpack-sources": "^3.2.2"
       },
       "dependencies": {
         "acorn": {
diff --git a/package.json b/package.json
index 39ff729fb..6eb003244 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,10 @@
 {
   "name": "@exadel/esl",
-  "version": "3.4.1",
+  "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",
-  "homepage": "https://exadel-inc.github.io/esl/",
+  "homepage": "https://esl-ui.com/",
   "keywords": [
     "esl",
     "lightweight",
@@ -77,8 +77,8 @@
   },
   "devDependencies": {
     "@11ty/eleventy": "^0.12.1",
-    "@commitlint/cli": "^14.1.0",
-    "@commitlint/config-conventional": "^14.1.0",
+    "@commitlint/cli": "^15.0.0",
+    "@commitlint/config-conventional": "^15.0.0",
     "@juggle/resize-observer": "^3.3.1",
     "@semantic-release/changelog": "^6.0.1",
     "@semantic-release/commit-analyzer": "^9.0.1",
@@ -88,8 +88,8 @@
     "@semantic-release/release-notes-generator": "^10.0.2",
     "@types/jest": "^27.0.2",
     "@types/smoothscroll-polyfill": "^0.3.1",
-    "@typescript-eslint/eslint-plugin": "^5.3.1",
-    "@typescript-eslint/parser": "^5.3.1",
+    "@typescript-eslint/eslint-plugin": "^5.4.0",
+    "@typescript-eslint/parser": "^5.4.0",
     "@webcomponents/custom-elements": "1.5.0",
     "@webcomponents/webcomponents-platform": "1.0.1",
     "browser-sync": "^2.27.7",
@@ -120,8 +120,8 @@
     "stylelint": "^14.1.0",
     "ts-jest": "^27.0.7",
     "ts-loader": "^9.2.6",
-    "typescript": "4.4.4",
-    "webpack": "^5.64.0",
+    "typescript": "4.5.2",
+    "webpack": "^5.64.1",
     "webpack-cli": "^4.9.1"
   },
   "browserslist": [
diff --git a/pages/.eleventy.js b/pages/.eleventy.js
index 5c2bc0518..c175295eb 100644
--- a/pages/.eleventy.js
+++ b/pages/.eleventy.js
@@ -47,6 +47,6 @@ module.exports = (config) => {
     htmlTemplateEngine: 'njk',
     passthroughFileCopy: true,
     templateFormats: ['md', 'njk'],
-    pathPrefix: '/esl/'
+    pathPrefix: '/'
   };
 };
diff --git a/pages/11ty/markdown.shortcut.js b/pages/11ty/markdown.shortcut.js
index a5710debe..a3581b8e5 100644
--- a/pages/11ty/markdown.shortcut.js
+++ b/pages/11ty/markdown.shortcut.js
@@ -56,20 +56,19 @@ class MDRenderer {
 
   static resolveLinks(dom, basePath) {
     dom.querySelectorAll('a[href^="."]').forEach((link) => {
-      const absolutePath = path.join(path.dirname(basePath), link.href);
+      const absolutePath = path.join(path.dirname(basePath), link.href).replace(/\\/g, '/');
       const resultPath = MDRenderer.processRewriteRules(absolutePath);
       console.info(`Rewrite link "${link.href}" to "${resultPath}"`);
       link.href = resultPath;
     });
   }
-  static processRewriteRules(_path) {
-    const linkPath = _path.replace(/\\/g, '/');
+  static processRewriteRules(linkPath) {
     for (const [key, value] of Object.entries(rewriteRules)) {
       if (!linkPath.endsWith(key)) continue;
       if (value.startsWith('/')) return urlPrefix + value;
       return value;
     }
-    return github.srcUrl + _path;
+    return github.srcUrl + linkPath;
   }
 }
 
diff --git a/pages/src/common/reboot.less b/pages/src/common/reboot.less
index 2d3f98be6..3b6265c77 100644
--- a/pages/src/common/reboot.less
+++ b/pages/src/common/reboot.less
@@ -62,6 +62,7 @@ code {
   font-size: 87.5%;
   color: #DD4A68;
   word-wrap: break-word;
+  padding: 2px;
 }
 
 pre {
diff --git a/pages/src/page/base-layout.less b/pages/src/page/base-layout.less
index e6082c3a0..3f208d14a 100644
--- a/pages/src/page/base-layout.less
+++ b/pages/src/page/base-layout.less
@@ -1,11 +1,17 @@
 @import "../common/variables.less";
 
+html {
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+}
+
 body {
+  width: 100%;
   /* stylelint-disable */
   height: 100vh;
   height: var(--100vh, 100vh);
   /* stylelint-enable */
-  flex-direction: column;
 }
 
 .page {
diff --git a/pages/static/tools/config.yml b/pages/static/tools/config.yml
index ab2f88efa..92968ced7 100644
--- a/pages/static/tools/config.yml
+++ b/pages/static/tools/config.yml
@@ -1,3 +1,3 @@
 languageCode:           "en"
 title:                  "ESL"
-baseURL:                "https://exadel-inc.github.io/esl/"
+baseURL:                "https://esl-ui.com/"
diff --git a/pages/views/404.njk b/pages/views/404.njk
index cbef8eacf..fc8f3ebab 100644
--- a/pages/views/404.njk
+++ b/pages/views/404.njk
@@ -1,5 +1,6 @@
 ---
 layout: content
+title: 404
 containerCls: page-404
 permalink: 404.html
 eleventyExcludeFromCollections: true
diff --git a/pages/views/_data/site.json b/pages/views/_data/site.json
index c510c9b76..edbd21ddc 100644
--- a/pages/views/_data/site.json
+++ b/pages/views/_data/site.json
@@ -1,13 +1,19 @@
 {
   "name": "Exadel Smart Library",
-  "url": "https://exadel-inc.github.io/esl",
-  "urlPrefix": "/esl",
+  "description": "ESL - UI web components open-source library",
+  "url": "https://esl-ui.com",
+  "urlPrefix": "",
   "github": {
     "url": "https://github.com/exadel-inc/esl",
     "srcUrl": "https://github.com/exadel-inc/esl/tree/main/"
   },
   "rewriteRules": {
     "docs/INSTALLATION_GUIDE.md": "/introduction",
-    "docs/BROWSER_SUPPORT.md": "/introduction/browser-support"
+    "docs/BROWSER_SUPPORT.md": "/introduction/browser-support",
+    "src/modules/esl-base-element/README.md": "/utils/esl-base-element",
+    "src/modules/esl-media-query/README.md": "/utils/esl-media-query",
+    "src/modules/esl-traversing-query/README.md": "/utils/esl-traversing-query",
+    "src/modules/esl-trigger/README.md": "/components/esl-trigger",
+    "src/modules/esl-toggleable/README.md": "/components/esl-toggleable"
   }
 }
diff --git a/pages/views/_includes/landing/browser-support.njk b/pages/views/_includes/landing/browser-support.njk
index ff2cf19e6..cbf4ba277 100644
--- a/pages/views/_includes/landing/browser-support.njk
+++ b/pages/views/_includes/landing/browser-support.njk
@@ -2,8 +2,8 @@
   <div class="browser-support-content">
     <h2>Browser Support</h2>
     <div class="browser-support-text">
-      <p>Exadel Smart Library uses built-in browser features - Web API and ECMAScript 6 features that all fully supported by modern browsers such as Chrome, Firefox, Safari or Edge.</p>
-      <p>If you want the ESL to work in older browsers, you can use a different polyfill list - &quot;light&quot; and &quot;full&quot;.</p>
+      <p>Exadel Smart Library uses built-in browser features — Web API and ECMAScript 6 features that all fully supported by modern browsers such as Chrome, Firefox, Safari or Edge.</p>
+      <p>If you want the ESL to work in older browsers, you can use a different polyfill list — &quot;light&quot; and &quot;full&quot;.</p>
     </div>
     <a class="arrow-link browser-support-link" href="{{ '/introduction/browser-support' | url }}">Read more</a>
   </div>
diff --git a/pages/views/_includes/landing/marquee.njk b/pages/views/_includes/landing/marquee.njk
index 6d2878f4d..dae354bd8 100644
--- a/pages/views/_includes/landing/marquee.njk
+++ b/pages/views/_includes/landing/marquee.njk
@@ -4,7 +4,8 @@
       <h1 class="marquee-heading">Exadel Smart Library</h1>
     </div>
     <div class="marquee-body">
-      <p>Open-source UI component library that helps developers create modern-looking, effective, and user-friendly interfaces faster.</p>
+      <p>Open-source UI components library that helps developers create modern-looking, effective, and user-friendly interfaces faster.</p>
+      {#<p>ESL based on the Custom Elements browser native feature.</p>#}
     </div>
     <div class="btn-container">
       <a class="btn btn-lg btn-sec-blue" href="{{ '/introduction' | url }}">Get started</a>
diff --git a/pages/views/_includes/landing/promo-banner.njk b/pages/views/_includes/landing/promo-banner.njk
index 15290fe43..83eeeb54f 100644
--- a/pages/views/_includes/landing/promo-banner.njk
+++ b/pages/views/_includes/landing/promo-banner.njk
@@ -12,7 +12,7 @@
       </p>
     </div>
     <div class="btn-container promo-banner-btn-container">
-      <a class="btn btn-spaced btn-sec-green" href="{{ '/introduction' | url }}">Getting started</a>
+      <a class="btn btn-spaced btn-sec-green" href="{{ '/introduction' | url }}">Get started</a>
       <a class="btn btn-spaced btn-sec-blue" href="{{ '/components' | url }}">Components Docs</a>
     </div>
   </div>
diff --git a/pages/views/_includes/navigation/footer-compact.njk b/pages/views/_includes/navigation/footer-compact.njk
index 01ffb89e3..d2cdb1c95 100644
--- a/pages/views/_includes/navigation/footer-compact.njk
+++ b/pages/views/_includes/navigation/footer-compact.njk
@@ -4,11 +4,11 @@
     <div>ESL v{{ env.version }} © 2021 Exadel, Inc</div>
     <div>
       Core Team Contributors:
-      <a href="mailto:astsefanovich@exadel.com">Alexey Stsefanovich</a>,
-      <a href="mailto:ymurashka@exadel.com">Julia Murashko</a>,
-      <a href="mailto:yadamska@exadel.com">Yuliya Adamskaya</a>,
-      <a href="mailto:dshovchko@exadel.com">Dmytro Shovchko</a>,
-      <a href="mailto:abarmina@exadel.com">Anna Barmina</a>
+      <a target="_blank" href="https://github.com/ala-n">Alexey Stsefanovich</a>,
+      <a target="_blank" href="https://github.com/julia-murashko">Julia Murashko</a>,
+      <a target="_blank" href="https://github.com/yadamskaya">Yuliya Adamskaya</a>,
+      <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 Iryna Pavlenko</div>
   </div>
diff --git a/pages/views/_layouts/base.njk b/pages/views/_layouts/base.njk
index 7ff5f7489..2fef09915 100644
--- a/pages/views/_layouts/base.njk
+++ b/pages/views/_layouts/base.njk
@@ -1,10 +1,15 @@
 <!DOCTYPE html>
 <html lang="{{ lang or 'en' }}" {% if scrollbar %} class="esl-scrollable-content" {% endif %}>
 <head>
-  <title>{{ title or 'Home' }}</title>
+  <title>{{ seoTitle or title or site.description }}</title>
   {# Site meta information #}
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  {% if description %}
+    <meta name="description" content="{{ description | escape}}">
+  {% endif %}
+
+  {# Additional site meta information #}
   {% block meta %}{% endblock meta %}
   {# Site icon #}
   <link rel="icon" type="image/png" href="{{ '/assets/logo-64x64.png' | url }}" />
diff --git a/pages/views/_layouts/popup.njk b/pages/views/_layouts/popup.njk
index 841d3f2aa..4465e1cf6 100644
--- a/pages/views/_layouts/popup.njk
+++ b/pages/views/_layouts/popup.njk
@@ -2,27 +2,32 @@
 
 {% block body %}
 <esl-popup id="popup1" position="top">
-  Exadel Smart Library Popup content
+  <div style="height: 70px; width:250px;"></div>
   <span class="esl-popup-arrow"></span>
 </esl-popup>
 <esl-popup id="popup2" position="bottom">
-  Exadel Smart Library Popup content
+  <div style="height: 70px; width:250px;"></div>
   <span class="esl-popup-arrow"></span>
 </esl-popup>
-<esl-popup id="popup3" position="left">
-  <p>Exadel</p>
-  <p>Smart</p>
-  <p>Library</p>
-  <p>Popup</p>
-  <p>content</p>
+<esl-popup id="popup3" position="left" >
+  <div style="height: 250px; width:70px;"></div>
   <span class="esl-popup-arrow"></span>
 </esl-popup>
 <esl-popup id="popup4" position="right">
-  <p>Exadel</p>
-  <p>Smart</p>
-  <p>Library</p>
-  <p>Popup</p>
-  <p>content</p>
+  <div style="height: 250px; width:70px;"></div>
   <span class="esl-popup-arrow"></span>
 </esl-popup>
+
+<esl-popup id="popup01" position="top">
+  <div style="height: 70px; width:250px;"></div>
+</esl-popup>
+<esl-popup id="popup02" position="bottom">
+  <div style="height: 70px; width:250px;"></div>
+</esl-popup>
+<esl-popup id="popup03" position="left">
+  <div style="height: 250px; width:50px;"></div>
+</esl-popup>
+<esl-popup id="popup04" position="right">
+  <div style="height: 250px; width:50px;"></div>
+</esl-popup>
 {% endblock %}
diff --git a/pages/views/components/esl-alert.njk b/pages/views/components/esl-alert.njk
index c22f124a3..1caf55c6f 100644
--- a/pages/views/components/esl-alert.njk
+++ b/pages/views/components/esl-alert.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Alert
+seoTitle: ESL Alert - custom element to show notifications on the page
 name: ESL Alert
 tags: components
 iconAlt: '<esl-alert/>'
diff --git a/pages/views/components/esl-footnotes.njk b/pages/views/components/esl-footnotes.njk
index d2f0b8535..6419fc2bb 100644
--- a/pages/views/components/esl-footnotes.njk
+++ b/pages/views/components/esl-footnotes.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Footnotes
+seoTitle: ESL Footnotes - custom elements for auto-collected footnotes in the page content
 name: ESL Footnotes
 tags: [components, draft]
 iconAlt: '<esl-footnotes/>'
diff --git a/pages/views/components/esl-image.njk b/pages/views/components/esl-image.njk
index 80856beba..c68f39d3b 100644
--- a/pages/views/components/esl-image.njk
+++ b/pages/views/components/esl-image.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Image
+seoTitle: ESL Image - custom image element with lazy loading, renditions, and different modes of embedding
 name: ESL Image
 tags: components
 iconAlt: '<esl-image/>'
diff --git a/pages/views/components/esl-media.njk b/pages/views/components/esl-media.njk
index ad15426de..b8f7435f0 100644
--- a/pages/views/components/esl-media.njk
+++ b/pages/views/components/esl-media.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Media
+seoTitle: ESL Media - custom element to embed video and audio with a different sources like MP4, YouTube, Brightcove, etc
 name: ESL Media
 tags: components
 iconAlt: '<esl-media/>'
diff --git a/pages/views/components/esl-panel-group.njk b/pages/views/components/esl-panel-group.njk
new file mode 100644
index 000000000..a0d478226
--- /dev/null
+++ b/pages/views/components/esl-panel-group.njk
@@ -0,0 +1,18 @@
+---
+layout: content
+title: ESL Panel Group
+seoTitle: ESL Panel Group - custom element to group ESLPanel-s to have Tabs or Accordion behaviour
+name: ESL Panel Group
+tags: components
+iconAlt: '<esl-panel-group/>'
+aside:
+  components:
+    - esl-panel
+    - esl-toggleable
+    - esl-trigger
+  examples:
+    - accordion
+    - tabs
+---
+
+{% mdRender 'src/modules/esl-panel-group/README.md', 'intro' %}
diff --git a/pages/views/components/esl-panel.njk b/pages/views/components/esl-panel.njk
index e3b241b09..e290b889f 100644
--- a/pages/views/components/esl-panel.njk
+++ b/pages/views/components/esl-panel.njk
@@ -1,11 +1,13 @@
 ---
 layout: content
 title: ESL Panel
+seoTitle: ESL Panel - custom element to collapse / expand content on the page (accordion behavior)
 name: ESL Panel
 tags: components
 iconAlt: '<esl-panel/>'
 aside:
   components:
+    - esl-panel-group
     - esl-toggleable
     - esl-trigger
   examples:
diff --git a/pages/views/components/esl-popup.njk b/pages/views/components/esl-popup.njk
index b7dc65fa6..10ffb0f5f 100644
--- a/pages/views/components/esl-popup.njk
+++ b/pages/views/components/esl-popup.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Popup
+seoTitle: ESL Popup - custom element to show absolutely positioned popup area
 name: ESL Popup
 tags: [components, beta]
 iconAlt: '<esl-popup/>'
diff --git a/pages/views/components/esl-scrollbar.njk b/pages/views/components/esl-scrollbar.njk
index a31a46e6c..4da6b86cd 100644
--- a/pages/views/components/esl-scrollbar.njk
+++ b/pages/views/components/esl-scrollbar.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Scrollbar
+seoTitle: ESL Scrollbar - custom scrollbar element fully customizable from CSS
 name: ESL Scrollbar
 tags: components
 iconAlt: '<esl-scrollbar/>'
diff --git a/pages/views/components/esl-select-list.njk b/pages/views/components/esl-select-list.njk
index 6a8297249..fcf5818a2 100644
--- a/pages/views/components/esl-select-list.njk
+++ b/pages/views/components/esl-select-list.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Select List
+seoTitle: ESL Select List - web component for custom select list UI
 name: ESL Select List
 tags: [components, forms, beta]
 iconAlt: '<esl-select-list/>'
diff --git a/pages/views/components/esl-select.njk b/pages/views/components/esl-select.njk
index 83fd48458..f56c68a2c 100644
--- a/pages/views/components/esl-select.njk
+++ b/pages/views/components/esl-select.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Select
+seoTitle: ESL Select - web component for custom select dropdown UI
 name: ESL Select
 tags: [components, forms, beta]
 iconAlt: '<esl-select/>'
diff --git a/pages/views/components/esl-tabs.njk b/pages/views/components/esl-tabs.njk
index 4f8b153d3..6a579402a 100644
--- a/pages/views/components/esl-tabs.njk
+++ b/pages/views/components/esl-tabs.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Tabs
+seoTitle: ESL Tabs - custom element for tab controls
 name: ESL Tabs
 tags: components
 iconAlt: '<esl-tabs/>'
@@ -8,6 +9,7 @@ aside:
   components:
     - esl-trigger
     - esl-panel
+    - esl-panel-group
     - esl-toggleable
   examples:
     - tabs
diff --git a/pages/views/components/esl-toggleable.njk b/pages/views/components/esl-toggleable.njk
index 6bcc1a432..514727a32 100644
--- a/pages/views/components/esl-toggleable.njk
+++ b/pages/views/components/esl-toggleable.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Toggleable
+seoTitle: ESL Toggleable - custom element to have basic show/hide or other state-full behaviour
 name: ESL Toggleable
 tags: components
 iconAlt: '<esl-toggleable/>'
diff --git a/pages/views/components/esl-trigger.njk b/pages/views/components/esl-trigger.njk
index 86f9dadd1..364921946 100644
--- a/pages/views/components/esl-trigger.njk
+++ b/pages/views/components/esl-trigger.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Trigger
+seoTitle: ESL Trigger - custom element to control "Toggleables"
 name: ESL Trigger
 tags: components
 iconAlt: '<esl-trigger/>'
diff --git a/pages/views/components/index.njk b/pages/views/components/index.njk
index 547b6f7ed..09bad956e 100644
--- a/pages/views/components/index.njk
+++ b/pages/views/components/index.njk
@@ -1,6 +1,7 @@
 ---
 layout: collection-grid
-title: Components
+title: Components List
+seoTitle: Components List of Exadel Smart Library (ESL)
 name: All
 order: -1
 tags: components
diff --git a/pages/views/examples/accordion.njk b/pages/views/examples/accordion.njk
index e53223e90..1286d6c8e 100644
--- a/pages/views/examples/accordion.njk
+++ b/pages/views/examples/accordion.njk
@@ -1,12 +1,14 @@
 ---
 layout: content
 title: Accordion
+seoTitle: Accordion UI examples based on ESL web components
 name: Accordion
 tags: examples
 icon: examples/accordion.svg
 aside:
   components:
     - esl-panel
+    - esl-panel-group
     - esl-trigger
     - esl-toggleable
   examples:
diff --git a/pages/views/examples/carousel.njk b/pages/views/examples/carousel.njk
index e58f1b7cb..e087b2e7b 100644
--- a/pages/views/examples/carousel.njk
+++ b/pages/views/examples/carousel.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Carousel
+seoTitle: Carousel UI examples based on ESL web components
 name: Carousel
 tags: [examples, draft]
 icon: examples/carousel.svg
diff --git a/pages/views/examples/embedded-audio.njk b/pages/views/examples/embedded-audio.njk
index e08d4efc3..3a02135d5 100644
--- a/pages/views/examples/embedded-audio.njk
+++ b/pages/views/examples/embedded-audio.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Embedded Audio
+seoTitle: Embedded audio examples based on ESL web components
 name: Embedded Audio
 tags: examples
 icon: examples/embedded-audio.svg
diff --git a/pages/views/examples/embedded-video.njk b/pages/views/examples/embedded-video.njk
index 7b88119ee..9e6876062 100644
--- a/pages/views/examples/embedded-video.njk
+++ b/pages/views/examples/embedded-video.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Embedded Video
+seoTitle: Embedded video (MP4, Youtube) examples based on ESL web components
 name: Embedded Video
 tags: examples
 icon: examples/embedded-video.svg
diff --git a/pages/views/examples/footnotes.njk b/pages/views/examples/footnotes.njk
index aa6a610e7..32f2211c1 100644
--- a/pages/views/examples/footnotes.njk
+++ b/pages/views/examples/footnotes.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Footnotes
+seoTitle: Auto-collected footnotes custom elements example based on ESL web components
 name: Footnotes
 tags: [examples, beta]
 icon: examples/footnotes.svg
diff --git a/pages/views/examples/forms-select-list.njk b/pages/views/examples/forms-select-list.njk
index 36fc8c3ac..c06230e70 100644
--- a/pages/views/examples/forms-select-list.njk
+++ b/pages/views/examples/forms-select-list.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Forms - Select List
+seoTitle: Custom select list examples based on ESL web components
 name: Select List
 tags: [examples, beta]
 icon: examples/select-list.svg
diff --git a/pages/views/examples/forms-select.njk b/pages/views/examples/forms-select.njk
index ba9f349fc..2e610802c 100644
--- a/pages/views/examples/forms-select.njk
+++ b/pages/views/examples/forms-select.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Forms - Select Dropdown
+seoTitle: Custom select dropdown examples based on ESL web components
 name: Select Dropdown
 tags: [examples, beta]
 icon: examples/select-dropdown.svg
diff --git a/pages/views/examples/image.njk b/pages/views/examples/image.njk
index 58c02ec4c..cbe20edc7 100644
--- a/pages/views/examples/image.njk
+++ b/pages/views/examples/image.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Image
+seoTitle: Lazy-loaded configurable images examples based on ESL web components
 name: Image
 tags: examples
 icon: examples/image.svg
diff --git a/pages/views/examples/index.njk b/pages/views/examples/index.njk
index b8dcfd969..f7f6d9fd6 100644
--- a/pages/views/examples/index.njk
+++ b/pages/views/examples/index.njk
@@ -1,6 +1,7 @@
 ---
 layout: collection-grid
 title: Examples
+seoTitle: List of examples based on Exadel Smart Library (ESL) components
 name: All
 order: -1
 tags: examples
diff --git a/pages/views/examples/menu.njk b/pages/views/examples/menu.njk
index 64c861b08..305f62fb5 100644
--- a/pages/views/examples/menu.njk
+++ b/pages/views/examples/menu.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Menu
+seoTitle: Simple menu ui example based on ESL web components
 name: Menu
 tags: examples
 icon: examples/menu.svg
diff --git a/pages/views/examples/notification.njk b/pages/views/examples/notification.njk
index a9ef7578c..d35d8fd09 100644
--- a/pages/views/examples/notification.njk
+++ b/pages/views/examples/notification.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Notification
+seoTitle: Notifications UI example based on ESL web components
 name: Notification
 tags: examples
 icon: examples/notification.svg
diff --git a/pages/views/examples/popup.njk b/pages/views/examples/popup.njk
index f4f3512e0..75791023c 100644
--- a/pages/views/examples/popup.njk
+++ b/pages/views/examples/popup.njk
@@ -1,8 +1,9 @@
 ---
 layout: popup
 title: Popup
+seoTitle: Popup UI examples based on ESL web components
 name: Popup
-tags: [examples, draft]
+tags: [examples, beta]
 icon: examples/popup.svg
 aside:
   components:
@@ -11,7 +12,36 @@ aside:
     - esl-trigger
 ---
 
-<section class="row justify-content-between">
+<section id="popup-controls">
+  <div>
+    <label for="marginArrow">Arrow margin:</label>
+    <input type="text" id="marginArrow" name="marginArrow" min="0" max="100" value="5" size="3">
+  </div>
+  <div>
+    <label for="offsetArrow">Arrow offset:</label>
+    <input type="range" id="offsetArrow" name="offsetArrow" min="0" max="100" value="50" step="1">
+  </div>
+  <script>
+    var elMarginArrow = document.querySelector('#marginArrow');
+    var handlerMarginArrowChange = function() {
+      Array.from(document.querySelectorAll('esl-popup')).forEach(function(el) {
+        el.setAttribute('margin-arrow', elMarginArrow.value);
+      });
+    };
+    elMarginArrow.addEventListener('change', handlerMarginArrowChange);
+  </script>
+  <script>
+    var elOffsetArrow = document.querySelector('#offsetArrow');
+    var handlerOffsetArrowChange = function() {
+      Array.from(document.querySelectorAll('esl-popup')).forEach(function(el) {
+        el.setAttribute('offset-arrow', elOffsetArrow.value);
+      });
+    };
+    elOffsetArrow.addEventListener('change', handlerOffsetArrowChange);
+  </script>
+</section>
+
+<section class="row justify-content-between"">
   <esl-trigger target="#popup1" mode="toggle" class="btn btn-sec-blue">Top</esl-trigger>
   <esl-trigger target="#popup1" mode="toggle" class="btn btn-sec-blue">Top</esl-trigger>
   <esl-trigger target="#popup1" mode="toggle" class="btn btn-sec-blue">Top</esl-trigger>
@@ -28,6 +58,23 @@ aside:
   <esl-trigger target="#popup2" mode="toggle" class="btn btn-sec-blue">Bottom</esl-trigger>
 </section>
 
+<section class="row justify-content-between">
+  <esl-trigger target="#popup01" mode="toggle" class="btn btn-sec-blue">Top</esl-trigger>
+  <esl-trigger target="#popup01" mode="toggle" class="btn btn-sec-blue">Top</esl-trigger>
+  <esl-trigger target="#popup01" mode="toggle" class="btn btn-sec-blue">Top</esl-trigger>
+</section>
+
+<section class="row justify-content-between">
+  <esl-trigger target="#popup03" mode="toggle" class="btn btn-sec-blue">Left</esl-trigger>
+  <esl-trigger target="#popup04" mode="toggle" class="btn btn-sec-blue">Right</esl-trigger>
+</section>
+
+<section class="row justify-content-between">
+  <esl-trigger target="#popup02" mode="toggle" class="btn btn-sec-blue">Bottom</esl-trigger>
+  <esl-trigger target="#popup02" mode="toggle" class="btn btn-sec-blue">Bottom</esl-trigger>
+  <esl-trigger target="#popup02" mode="toggle" class="btn btn-sec-blue">Bottom</esl-trigger>
+</section>
+
 <section class="row">
   <div id="a" style="margin: 599px 0; height: 800px; overflow-y: auto; width: 100%; background-color: azure;">
     <p>Lorem</p><p>ipsum</p><p>dot</p><p>color</p>
diff --git a/pages/views/examples/scrollbar.njk b/pages/views/examples/scrollbar.njk
index 0558c39d7..77b3c0b4c 100644
--- a/pages/views/examples/scrollbar.njk
+++ b/pages/views/examples/scrollbar.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Scrollbar
+seoTitle: Custom scroll ui examples based on ESL web components
 name: Scrollbar
 tags: examples
 icon: examples/scrollbar.svg
diff --git a/pages/views/examples/tabs.njk b/pages/views/examples/tabs.njk
index 579be8ca7..3ce28176b 100644
--- a/pages/views/examples/tabs.njk
+++ b/pages/views/examples/tabs.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Tabs
+seoTitle: Tabs UI examples based on ESL web components
 name: Tabs
 tags: examples
 icon: examples/tabs.svg
@@ -8,6 +9,7 @@ aside:
   components:
     - esl-tabs
     - esl-panel
+    - esl-panel-group
     - esl-trigger
     - esl-toggleable
   examples:
diff --git a/pages/views/examples/toggleable.njk b/pages/views/examples/toggleable.njk
index 359a6b302..92867aa6f 100644
--- a/pages/views/examples/toggleable.njk
+++ b/pages/views/examples/toggleable.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Toggleable
+seoTitle: Toggleable panels examples based on ESL web components
 name: Toggleable
 tags: examples
 icon: examples/toggleable.svg
diff --git a/pages/views/index.njk b/pages/views/index.njk
index ce2512e35..88d1545c9 100644
--- a/pages/views/index.njk
+++ b/pages/views/index.njk
@@ -1,5 +1,6 @@
 ---
 layout: landing
+description: Open-source UI component library that helps developers create modern-looking, effective, and user-friendly interfaces faster.
 ---
 
 {% include 'landing/marquee.njk' %}
diff --git a/pages/views/introduction/browser-support.njk b/pages/views/introduction/browser-support.njk
index c99ac282e..775fc4cdf 100644
--- a/pages/views/introduction/browser-support.njk
+++ b/pages/views/introduction/browser-support.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Browser Support
+seoTitle: Browser Support and Polyfills required for Exadel Smart Library (ESL)
 name: Browser Support
 tags: introduction
 ---
diff --git a/pages/views/introduction/index.njk b/pages/views/introduction/index.njk
index fd372bb2b..764d533e4 100644
--- a/pages/views/introduction/index.njk
+++ b/pages/views/introduction/index.njk
@@ -1,6 +1,8 @@
 ---
 layout: content
 title: Installation Guide
+seoTitle: ESL Installation Guide and Configuration
+description: Get started with installing Exadel Smart Library on the project. Configuring and using ESL components.
 name: Installation Guide
 order: -1
 tags: introduction
diff --git a/pages/views/introduction/roadmap.njk b/pages/views/introduction/roadmap.njk
index 7d4ea668f..fe345be62 100644
--- a/pages/views/introduction/roadmap.njk
+++ b/pages/views/introduction/roadmap.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: Our Roadmap
+seoTitle: ESL Future Plans
 name: Our Roadmap
 tags: introduction
 ---
diff --git a/pages/views/utils/esl-a11ty-group.njk b/pages/views/utils/esl-a11ty-group.njk
index 359923f3f..2881b1d76 100644
--- a/pages/views/utils/esl-a11ty-group.njk
+++ b/pages/views/utils/esl-a11ty-group.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL A11y Group
+seoTitle: Custom element that adds a group a11y behavior to targets
 name: ESL A11y Group
 tags: [utils, beta]
 iconAlt: '<esl-a11y-group/>'
diff --git a/pages/views/utils/esl-base.njk b/pages/views/utils/esl-base.njk
index ab9f09ceb..df80cf5f7 100644
--- a/pages/views/utils/esl-base.njk
+++ b/pages/views/utils/esl-base.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Base Element
+seoTitle: ESL Smart Library Base custom element definition
 name: ESL Base Element
 tags: utils
 iconAlt: '<esl-.../>'
diff --git a/pages/views/utils/esl-media-query.njk b/pages/views/utils/esl-media-query.njk
index 44abd449f..4723e1e07 100644
--- a/pages/views/utils/esl-media-query.njk
+++ b/pages/views/utils/esl-media-query.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Media Query
+seoTitle: Extended syntax of Media Queries that allows shortcuts, complex logical operators and custom conditions
 name: ESL Media Query
 tags: utils
 iconAlt: '@+xs, @x1, not @ie, @mobile'
diff --git a/pages/views/utils/esl-traversing-query.njk b/pages/views/utils/esl-traversing-query.njk
index 8fda7c445..e067b60dc 100644
--- a/pages/views/utils/esl-traversing-query.njk
+++ b/pages/views/utils/esl-traversing-query.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Traversing Query
+seoTitle: Extended CSS selector syntax that allows easily traverse in DOM nodes
 name: ESL Traversing Query
 tags: utils
 iconAlt: '#id::parent .class::next [attr]::nth(2)'
diff --git a/pages/views/utils/esl-utils.njk b/pages/views/utils/esl-utils.njk
index 364f4c3e1..2223de1d9 100644
--- a/pages/views/utils/esl-utils.njk
+++ b/pages/views/utils/esl-utils.njk
@@ -1,6 +1,7 @@
 ---
 layout: content
 title: ESL Utils
+seoTitle: Universal JS, TS and Web API utilities set from Exadel Smart Library
 name: ESL Utils
 tags: utils
 iconAlt: '@bind @memoize @prop'
diff --git a/pages/views/utils/index.njk b/pages/views/utils/index.njk
index f1ad3a5f9..46c278b66 100644
--- a/pages/views/utils/index.njk
+++ b/pages/views/utils/index.njk
@@ -1,6 +1,7 @@
 ---
 layout: collection-grid
 title: Utils
+seoTitle: Utility list of Exadel Smart Library (ESL)
 name: All
 order: -1
 tags: utils
diff --git a/src/modules/esl-a11y-group/README.md b/src/modules/esl-a11y-group/README.md
index c643ad1d8..87513b7a4 100644
--- a/src/modules/esl-a11y-group/README.md
+++ b/src/modules/esl-a11y-group/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) A11yGroup
+# [ESL](../../../) A11yGroup
 
 Version: _1.0.0_
 
@@ -11,7 +11,7 @@ ESLA11yGroup tracks keyboard to loop focus of the targeting elements (with arrow
 
 ### Attributes / Properties
 
-- `targets` - property to declare targets for the group using [TraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/) syntax. Use group parent element as a base element
+- `targets` - property to declare targets for the group using [TraversingQuery](../esl-traversing-query/README.md) syntax. Use group parent element as a base element
 - `activate-selected` - activates the element using `click` event on selection change via esl-a11y-group
 - `prevent-scroll` - prevents scroll when target receives focus
 
diff --git a/src/modules/esl-alert/README.md b/src/modules/esl-alert/README.md
index 6e313688d..fee69b296 100644
--- a/src/modules/esl-alert/README.md
+++ b/src/modules/esl-alert/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Alert
+# [ESL](../../../) Alert
 
 Version: *1.0.0*
 
@@ -19,7 +19,7 @@ Then you can attach `<esl-alert>` component to the expected place in the documen
 
 ESL Alert listens to DOM events to control its state. 
 By default, the target to catch alerts is the `esl-alert` parent element. 
-Target can be changed using `target` attribute with the [TraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/) support, 
+Target can be changed using `target` attribute with the [TraversingQuery](../esl-traversing-query/README.md) support, 
 or through the `$target` property that accepts any EventTarget instance (including the window). 
 
 ESL Alert listens to the following events: 
diff --git a/src/modules/esl-base-element/README.md b/src/modules/esl-base-element/README.md
index f408601c1..8c2d03bf6 100644
--- a/src/modules/esl-base-element/README.md
+++ b/src/modules/esl-base-element/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Base Element
+# [ESL](../../../) Base Element
 
 Version: *1.0.0*
 
diff --git a/src/modules/esl-footnotes/README.md b/src/modules/esl-footnotes/README.md
index 17aed4ed1..a1527b671 100644
--- a/src/modules/esl-footnotes/README.md
+++ b/src/modules/esl-footnotes/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Footnotes
+# [ESL](../../../) Footnotes
 
 Version: *1.0.0-beta*.
 
@@ -31,6 +31,6 @@ The elements are interrelated and don't make sense on their own. This is because
 
 - `html` - content of note tooltip. If not present, it fills with innerHTML of ESLNote
 
-- `track-click` - `ESLMediaQuery` to define allowed to track click event media. (`all` by default)
+- `track-click` - [MediaQuery](../esl-media-query/README.md) to define allowed to track click event media. (`all` by default)
   
-- `track-hover` - `ESLMediaQuery` to define allowed to track hover event media. (`all` by default)
+- `track-hover` - [MediaQuery](../esl-media-query/README.md) to define allowed to track hover event media. (`all` by default)
diff --git a/src/modules/esl-forms/esl-select-list/README.md b/src/modules/esl-forms/esl-select-list/README.md
index 1566134ef..e01042f89 100644
--- a/src/modules/esl-forms/esl-select-list/README.md
+++ b/src/modules/esl-forms/esl-select-list/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Select List
+# [ESL](../../../../) Select List
 
 Version: *1.0.0*
 
diff --git a/src/modules/esl-forms/esl-select/README.md b/src/modules/esl-forms/esl-select/README.md
index a20d3d7b6..fac36d6ec 100644
--- a/src/modules/esl-forms/esl-select/README.md
+++ b/src/modules/esl-forms/esl-select/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Select
+# [ESL](../../../../) Select
 
 Version: *1.1.0*
 
diff --git a/src/modules/esl-image/README.md b/src/modules/esl-image/README.md
index e3f017e08..a1bce536d 100644
--- a/src/modules/esl-image/README.md
+++ b/src/modules/esl-image/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Image
+# [ESL](../../../) Image
 
 Version: *1.2.1*
 
@@ -36,7 +36,7 @@ In case `alt` is not provided then an empty value is used as a fallback.
 
 ### Attributes:
 
-- **data-src** - src paths with queriy congitions. See [ESLMediaQuery](https://exadel-inc.github.io/esl/utils/esl-media-query/) (watched value)
+- **data-src** - src paths with query conditions. See [ESLMediaQuery](../esl-media-query/README.md) (watched value)
 
 - **data-src-base** - base src path for paths described in data-src (watched value)
 
@@ -63,7 +63,7 @@ In case `alt` is not provided then an empty value is used as a fallback.
 
 - **container-class-state** (optional) - image state in which the container will be marked with `container-class` (can be 'ready', 'loaded' or 'error')
 
-- **container-class-target** (optional) - [TraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/) to find the target to add `container-class` to ('::parent' by default).
+- **container-class-target** (optional) - [TraversingQuery](../esl-traversing-query/README.md) to find the target to add `container-class` to ('::parent' by default).
 
 NOTE: ESL Image supports `title` attribute like any HTML element, no additional reflection for that attribute is needed - it will work correctly according to HTML5.* REC
 
diff --git a/src/modules/esl-media-query/README.md b/src/modules/esl-media-query/README.md
index 10cb86d16..f323d9de8 100644
--- a/src/modules/esl-media-query/README.md
+++ b/src/modules/esl-media-query/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Media Query Utils
+# [ESL](../../../) Media Query Utils
 
 Version: *2.0.0*
 
@@ -16,7 +16,7 @@ having extra conditions inside the query (`all and all` still a valid condition)
 
 - Native [Media Query Features](https://www.w3.org/TR/css3-mediaqueries/#media1)  
   (e.g. `(min-wigth: 300px)`, `(orientation: landscape)`, `(min-wigth: 300px) and (orientation: landscape)`).
-- Shortcuts for DPR (Device Pixel Ratio) detection  
+- Shortcuts for DPR (Device Pixel Ratio) detection.  
   Syntax `@x<dpr_value>` (e.g. `@x1`, `@x2`, `@x1.5`).
 - Can block queries with DPR value greater than 1 for PageSpeedBots.
 - Screen breakpoints shortcuts (e.g. `@XS`, `@md`, `@+LG`, `@-MD`)  
@@ -94,8 +94,8 @@ Note: ESLMediaQuery has no real instances and represents `IMediaQueryConditionIn
 `IMediaQueryConditionInterface` is implemented by 4 types of inner conditions:
   - `MediaQueryConstCondition` with only two possible instances `ALL` and `NOT_ALL`
   - `MediaQueryCondition` - simple wrapper around native MediaQueryList object
-  - `MediaQueryConjunction` - `and` condition container
-  - `MediaQueryDisjunction` - `or` condition container
+  - `MediaQueryConjunction` - group of conditions unified by `and` operator
+  - `MediaQueryDisjunction` - group of conditions unified by `or` operator
 
 The `ESLMediaQuery`(`IMediaQueryConditionInterface`) instances provide the following set of properties and methods:
   - `matches` - boolean getter that returns if the current environment configuration is acceptable for current query condition
@@ -129,8 +129,8 @@ ESLMediaRuleList should be generalized with the result value type and according
 - `ESLMediaRuleList.OBJECT_PARSER` - out of the box object payload parser (uses evaluation).
 
 Examples:
-- ` 1 | @XS => 2` - the RuleList result depends on environment and equals '1' on all screen breakpoints except XS, 
-  on XS it changes to '2'.  
+- ` 1 | @XS => 2` - the RuleList result depends on environment and equals `'1'` on all screen breakpoints except XS, 
+  on XS it changes to `'2'`.  
 
 - ` @XS => {option: 1} | @+SM => {option: 2}` - the RuleList result depends on environment and equals `{option: 1}` 
   on XS breakpoint, and equals `{option: 2}` on SM and upper breakpoints.
diff --git a/src/modules/esl-media/README.md b/src/modules/esl-media/README.md
index e8c189b0d..3bdec2006 100644
--- a/src/modules/esl-media/README.md
+++ b/src/modules/esl-media/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Media
+# [ESL](../../../) Media
 
 Version: *1.2.0*
 
@@ -20,7 +20,7 @@ using a single tag as well as work with external providers using simple native-l
    - Brightcove (`brightcove` type)
    - Abstract Iframe (`iframe` type)
  
- - `load-conditions` - restriction to load esl-media. Uses [ESLMediaQuery](https://exadel-inc.github.io/esl/utils/esl-media-query/) syntax.
+ - `load-conditions` - restriction to load esl-media. Uses [ESLMediaQuery](../esl-media-query/README.md) syntax.
  
  - `play-in-viewport` - feature that restricts active state to only visible components on the page.
  
@@ -43,7 +43,7 @@ using a single tag as well as work with external providers using simple native-l
  - `group` (optional) - group name, only one media player can be active in bounds of the group
  
  - `ready-class` - class to add when the resource is ready
- - `ready-class-target` - [TraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/) to define a target for `ready-class`
+ - `ready-class-target` - [TraversingQuery](../esl-traversing-query/README.md) to define a target for `ready-class`
 
  - `disabled` (boolean) - marker that prevents media api initialization
  
diff --git a/src/modules/esl-media/core/esl-media-provider.ts b/src/modules/esl-media/core/esl-media-provider.ts
index 173a30f62..4351bcd5d 100644
--- a/src/modules/esl-media/core/esl-media-provider.ts
+++ b/src/modules/esl-media/core/esl-media-provider.ts
@@ -20,7 +20,7 @@ export interface MediaProviderConfig {
   controls: boolean;
   autoplay: boolean;
   title: string;
-  preload?: string;
+  preload?: 'none' | 'metadata' | 'auto' | '';
   playsinline?: boolean;
 }
 
diff --git a/src/modules/esl-media/core/esl-media.shape.ts b/src/modules/esl-media/core/esl-media.shape.ts
index 8dd67de50..ef29bddac 100644
--- a/src/modules/esl-media/core/esl-media.shape.ts
+++ b/src/modules/esl-media/core/esl-media.shape.ts
@@ -1,5 +1,5 @@
 import type {ESLBaseElementShape} from '../../esl-base-element/core/esl-base-element.shape';
-import type {ESLMedia} from './esl-media';
+import type {ESLMedia, ESLMediaFillMode} from './esl-media';
 
 /**
  * Tag declaration interface of ESLMedia element
@@ -19,7 +19,7 @@ export type ESLMediaTagShape = ({
   /** Define media player group */
   group: string;
   /** Define media fill mode */
-  'fill-mode'?: string;
+  'fill-mode'?: ESLMediaFillMode;
   /** Define preferable aspect ratio */
   'aspect-ratio'?: string;
 
@@ -38,7 +38,7 @@ export type ESLMediaTagShape = ({
   /** Define viewport control marker */
   'play-in-viewport'?: boolean;
   /** Define preload media param */
-  'preload'?: string;
+  'preload'?: 'none' | 'metadata' | 'auto' | '';
   /** Allow play media inline */
   'playsinline'?: boolean;
 
diff --git a/src/modules/esl-media/core/esl-media.ts b/src/modules/esl-media/core/esl-media.ts
index 7e46cef1d..a22d997a2 100644
--- a/src/modules/esl-media/core/esl-media.ts
+++ b/src/modules/esl-media/core/esl-media.ts
@@ -64,7 +64,7 @@ export class ESLMedia extends ESLBaseElement {
   @boolAttr() public playInViewport: boolean;
 
   /** Preload resource */
-  @attr({defaultValue: 'auto'}) public preload: string;
+  @attr({defaultValue: 'auto'}) public preload: 'none' | 'metadata' | 'auto' | '';
 
   /** Ready state class/classes */
   @attr() public readyClass: string;
diff --git a/src/modules/esl-media/providers/html5/media-provider.ts b/src/modules/esl-media/providers/html5/media-provider.ts
index 25cd9d461..db54faa86 100644
--- a/src/modules/esl-media/providers/html5/media-provider.ts
+++ b/src/modules/esl-media/providers/html5/media-provider.ts
@@ -21,7 +21,7 @@ export abstract class HTMLMediaProvider extends BaseProvider {
   protected static applyElementSettings(el: HTMLMediaElement, cfg: MediaProviderConfig) {
     el.classList.add('esl-media-inner');
     el.autoplay = cfg.autoplay;
-    el.preload = cfg.preload || 'auto';
+    el.preload = cfg.preload || 'auto' ;
     el.loop = cfg.loop;
     el.muted = cfg.muted;
     el.controls = cfg.controls;
diff --git a/src/modules/esl-panel-group/README.md b/src/modules/esl-panel-group/README.md
index 3e7737091..5be10a256 100644
--- a/src/modules/esl-panel-group/README.md
+++ b/src/modules/esl-panel-group/README.md
@@ -1,8 +1,10 @@
-# [ESL](https://exadel-inc.github.io/esl/) Panel Group
+# [ESL](../../../) Panel Group
 
 Version: *2.1.0*.  
 
-Authors: *Julia Murashko*.
+Authors: *Julia Murashko*
+
+<a name="intro"></a>
 
 ESLPanelGroup is a custom element that is used as a container for a group of ESLPanels.
 ESLPanelGroup provides group behaviour, such as synchronized content state change.
@@ -16,7 +18,7 @@ ESLPanelGroup.register();
 ### ESLPanelGroup Attributes | Properties:
  
 - `mode` - rendering mode of the component (takes values from list of supported modes; 'accordion' by default).
-- `mode-cls-target` - Element [ESLTraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/)  selector to add class that identifies mode (ESLPanelGroup itself by default)
+- `mode-cls-target` - Element [ESLTraversingQuery](../esl-traversing-query/README.md)  selector to add class that identifies mode (ESLPanelGroup itself by default)
 - `animation-class` - class(es) to be added during animation ('animate' by default)
 - `fallback-duration` - time to clear animation common params (max-height style + classes) (2s by default)
 - `no-collapse` - list of comma-separated "modes" to disable collapse/expand animation (for both Group and Panel animations)
diff --git a/src/modules/esl-panel/README.md b/src/modules/esl-panel/README.md
index 86f7b9ca8..51dc89a96 100644
--- a/src/modules/esl-panel/README.md
+++ b/src/modules/esl-panel/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Panel
+# [ESL](../../../) Panel
 
 Version: *2.1.0*.  
 
@@ -23,4 +23,4 @@ ESLPanel.register();
  - `initial-params` - initial params for current ESLPanel instance
  - `animating` - marker of animation process running
 
-ESLPanel extends [ESLToggleable](https://exadel-inc.github.io/esl/components/esl-toggleable/) you can find other supported options in its documentation.
+ESLPanel extends [ESLToggleable](../esl-toggleable/README.md) you can find other supported options in its documentation.
diff --git a/src/modules/esl-popup/README.md b/src/modules/esl-popup/README.md
index d76006da2..1fd8bb254 100644
--- a/src/modules/esl-popup/README.md
+++ b/src/modules/esl-popup/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Popup
+# [ESL](../../../) Popup
 
 Version: *2.0.0-beta*.  
 
@@ -19,7 +19,7 @@ ESLPopup is based on ESLToggleable and works in pair with ESLTrigger that allows
   - `fit` - default, popup will always be positioned in the right place. Position dynamically updates so it will always be visible
   - empty or unsupported value - will not be prevented from overflowing clipping boundaries, such as the viewport
 
-ESLPopup extends [ESLToggleable](https://exadel-inc.github.io/esl/components/esl-toggleable/) you can find other supported options in its documentation.
+ESLPopup extends [ESLToggleable](../esl-toggleable/README.md) you can find other supported options in its documentation.
 
 ### Readonly Attributes
 
diff --git a/src/modules/esl-popup/core/esl-popup-position.ts b/src/modules/esl-popup/core/esl-popup-position.ts
index f56dbe4a4..d98ce5b31 100644
--- a/src/modules/esl-popup/core/esl-popup-position.ts
+++ b/src/modules/esl-popup/core/esl-popup-position.ts
@@ -23,31 +23,61 @@ export interface IntersectionRatioRect {
 export interface PopupPositionConfig {
   position: PositionType;
   behavior: string;
+  marginArrow: number;
+  offsetArrowRatio: number;
   intersectionRatio: IntersectionRatioRect;
+  arrow: DOMRect | Rect;
   element: DOMRect;
   inner: Rect;
   outer: Rect;
   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
+ * @param centerPosition - position of the center of the trigger on the minor axis
+ * @param dimensionName - the name of dimension (height or width)
+ */
+function calcPopupPositionByMinorAxis(cfg: PopupPositionConfig, centerPosition: number, dimensionName: 'height' | 'width'): number {
+  return centerPosition - cfg.element[dimensionName] * cfg.offsetArrowRatio +
+    calcBasicArrowAdjust(cfg.marginArrow + cfg.arrow[dimensionName] / 2, cfg.offsetArrowRatio);
+}
+
 /**
  * Calculate Rect for given popup position config.
  * @param cfg - popup position config
  * */
 function calcPopupBasicRect(cfg: PopupPositionConfig): Rect {
-  let x = cfg.inner.cx - cfg.element.width / 2;
+  let x = calcPopupPositionByMinorAxis(cfg, cfg.inner.cx, 'width');
   let y = cfg.inner.y - cfg.element.height;
   switch (cfg.position) {
     case 'left':
       x = cfg.inner.x - cfg.element.width;
-      y = cfg.inner.cy - cfg.element.height / 2;
+      y = calcPopupPositionByMinorAxis(cfg, cfg.inner.cy, 'height');
       break;
     case 'right':
       x = cfg.inner.right;
-      y = cfg.inner.cy - cfg.element.height / 2;
+      y = calcPopupPositionByMinorAxis(cfg, cfg.inner.cy, 'height');
       break;
     case 'bottom':
-      x = cfg.inner.cx - cfg.element.width / 2;
+      x = calcPopupPositionByMinorAxis(cfg, cfg.inner.cx, 'width');
       y = cfg.inner.bottom;
       break;
   }
@@ -114,7 +144,7 @@ function fitByMajorAxis(cfg: PopupPositionConfig, rect: Rect, arrow: Point): Pos
  * @param rect - popup position rect
  * @param arrow - arrow position value
  * */
-function fitByMinorAxisHorizontal(cfg: PopupPositionConfig, rect: Rect, arrow: Point) {
+function fitByMinorAxisHorizontal(cfg: PopupPositionConfig, rect: Rect, arrow: Point): void {
   if (cfg.trigger.x < cfg.outer.x || cfg.trigger.right > cfg.outer.right) return; // cancel fit mode if the element is out of window offset bounds
 
   let arrowAdjust = 0;
@@ -136,7 +166,7 @@ function fitByMinorAxisHorizontal(cfg: PopupPositionConfig, rect: Rect, arrow: P
  * @param rect - popup position rect
  * @param arrow - arrow position value
  * */
-function fitByMinorAxisVertical(cfg: PopupPositionConfig, rect: Rect, arrow: Point) {
+function fitByMinorAxisVertical(cfg: PopupPositionConfig, rect: Rect, arrow: Point): void {
   if (cfg.trigger.y < cfg.outer.y || cfg.trigger.bottom > cfg.outer.bottom) return; // cancel fit mode if the element is out of window offset bounds
 
   let arrowAdjust = 0;
@@ -157,7 +187,7 @@ function fitByMinorAxisVertical(cfg: PopupPositionConfig, rect: Rect, arrow: Poi
  * @param rect - popup position rect
  * @param arrow - arrow position value
  * */
-function fitByMinorAxis(cfg: PopupPositionConfig, rect: Rect, arrow: Point) {
+function fitByMinorAxis(cfg: PopupPositionConfig, rect: Rect, arrow: Point): void {
   if (cfg.behavior !== 'fit') return;
 
   if (['left', 'right'].includes(cfg.position)) {
@@ -167,6 +197,15 @@ function fitByMinorAxis(cfg: PopupPositionConfig, rect: Rect, arrow: Point) {
   }
 }
 
+/**
+ * Calculate the usable size available for the arrow
+ * @param cfg - popup position config
+ * @param dimensionName - the name of dimension (height or width)
+ */
+function calcUsableSizeForArrow(cfg: PopupPositionConfig, dimensionName: 'height' | 'width'): number {
+  return cfg.element[dimensionName] - cfg.arrow[dimensionName] - 2 * cfg.marginArrow;
+}
+
 /**
  * Calculate popup and arrow popup positions.
  * @param cfg - popup position config
@@ -174,8 +213,8 @@ function fitByMinorAxis(cfg: PopupPositionConfig, rect: Rect, arrow: Point) {
 export function calcPopupPosition(cfg: PopupPositionConfig): PopupPositionValue {
   const popup = calcPopupBasicRect(cfg);
   const arrow = {
-    x: cfg.element.width / 2,
-    y: cfg.element.height / 2,
+    x: cfg.marginArrow + calcUsableSizeForArrow(cfg, 'width') * cfg.offsetArrowRatio,
+    y: cfg.marginArrow + calcUsableSizeForArrow(cfg, 'height') * cfg.offsetArrowRatio,
     position: cfg.position
   };
 
diff --git a/src/modules/esl-popup/core/esl-popup.less b/src/modules/esl-popup/core/esl-popup.less
index 7c6474552..4978e44e1 100644
--- a/src/modules/esl-popup/core/esl-popup.less
+++ b/src/modules/esl-popup/core/esl-popup.less
@@ -1,62 +1,41 @@
 @POPUP_ARROW_SIZE: 20px;
-@POPUP_ARROW_HALF: (@POPUP_ARROW_SIZE / 2);
+@POPUP_BACKGROUND_COLOR: #FFF;
 @POPUP_BORDER_COLOR: #DBDBDB;
+@POPUP_BORDER_WIDTH: 1px;
 @POPUP_Z_INDEX: 999;
 
-.esl-popup {
-  display: block;
-  position: absolute;
-  left: 0;
-  top: 0;
-  box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
-  border: 1px solid @POPUP_BORDER_COLOR;
-  background: #FFF;
-  cursor: default;
-  opacity: 0;
-  will-change: auto;
-  transition: visibility 0.5s 0.2s;
-  visibility: hidden;
-  box-sizing: border-box;
-
-  &[open] {
-    opacity: 1;
-    z-index: @POPUP_Z_INDEX;
-    visibility: visible;
-    transition: opacity 0.15s, transform 0.2s;
-  }
-
-  &:not([open]) {
-    display: none;
-  }
+.esl-popup-arrow(@popupArrowSize, @popupBackgroundColor, @popupBorderColor, @popupBorderWidth) {
+  @popupArrowHalf: (@popupArrowSize / 2);
+  @popupArrowShift: (@popupArrowSize * 0.2071 - @popupBorderWidth);  // 0.2071 = (sqrt(2) - 1) / 2  (Don't ask why, it's an axiom)
 
   .esl-popup-arrow {
     position: absolute;
+    top: (-@popupArrowHalf - @popupBorderWidth);
     bottom: 100%;
-    background: #FFF;
-    width: @POPUP_ARROW_SIZE;
-    height: @POPUP_ARROW_SIZE;
-    transform: rotate(45deg);
-    margin-left: -@POPUP_ARROW_HALF;
-    top: (-@POPUP_ARROW_HALF - 1);
-    border-left: 1px solid @POPUP_BORDER_COLOR;
-    border-top: 1px solid @POPUP_BORDER_COLOR;
     z-index: -1;
+    transform: rotate(45deg);
+    width: @popupArrowSize;
+    height: @popupArrowSize;
+    margin-left: @popupArrowShift;
+    border-left: @popupBorderWidth solid @popupBorderColor;
+    border-top: @popupBorderWidth solid @popupBorderColor;
+    background: @popupBackgroundColor;
   }
 
   &[placed-at=top] {
     .esl-popup-arrow {
-      bottom: (-@POPUP_ARROW_HALF - 1);
       top: auto;
+      bottom: (-@popupArrowHalf - @popupBorderWidth);
       transform: rotate(225deg);
     }
   }
 
   &[placed-at=left] {
     .esl-popup-arrow {
-      right: (-@POPUP_ARROW_HALF - 1);
+      right: (-@popupArrowHalf - @popupBorderWidth);
       left: auto;
-      margin-top: -@POPUP_ARROW_HALF;
       transform: rotate(135deg);
+      margin-top: @popupArrowShift;
     }
   }
 
@@ -64,8 +43,38 @@
     .esl-popup-arrow {
       left: auto;
       right: auto;
-      margin-top: -@POPUP_ARROW_HALF;
       transform: rotate(315deg);
+      margin-top: @popupArrowShift;
+      margin-left: (-@popupArrowHalf - @popupBorderWidth);
     }
   }
 }
+
+.esl-popup {
+  position: absolute;
+  left: 0;
+  top: 0;
+  display: block;
+  opacity: 0;
+  visibility: hidden;
+  transition: visibility 0.5s 0.2s;
+  box-sizing: border-box;
+  box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
+  border: @POPUP_BORDER_WIDTH solid @POPUP_BORDER_COLOR;
+  background: @POPUP_BACKGROUND_COLOR;
+  cursor: default;
+  will-change: auto;
+
+  &[open] {
+    z-index: @POPUP_Z_INDEX;
+    opacity: 1;
+    visibility: visible;
+    transition: opacity 0.15s, transform 0.2s;
+  }
+
+  &:not([open]) {
+    display: none;
+  }
+
+  .esl-popup-arrow(@POPUP_ARROW_SIZE, @POPUP_BACKGROUND_COLOR, @POPUP_BORDER_COLOR, @POPUP_BORDER_WIDTH);
+}
diff --git a/src/modules/esl-popup/core/esl-popup.ts b/src/modules/esl-popup/core/esl-popup.ts
index bbd418ee1..3e1885e7b 100644
--- a/src/modules/esl-popup/core/esl-popup.ts
+++ b/src/modules/esl-popup/core/esl-popup.ts
@@ -9,18 +9,29 @@ import {ESLToggleable} from '../../esl-toggleable/core';
 import {Rect} from '../../esl-utils/dom/rect';
 import {getListScrollParents} from '../../esl-utils/dom/scroll';
 import {getWindowRect} from '../../esl-utils/dom/window';
+import {parseNumber} from '../../esl-utils/misc/format';
 import {calcPopupPosition} from './esl-popup-position';
 
 import type {ToggleableActionParams} from '../../esl-toggleable/core';
 import type {PositionType, IntersectionRatioRect} from './esl-popup-position';
 
 const INTERSECTION_LIMIT_FOR_ADJACENT_AXIS = 0.7;
+const DEFAULT_OFFSET_ARROW = 50;
+
+const parsePercent = (value: string | number, nanValue: number = 0): number => {
+  const rawValue = parseNumber(value, nanValue);
+  return Math.max(0, Math.min(rawValue !== undefined ? rawValue : nanValue, 100));
+};
 
 export interface PopupActionParams extends ToggleableActionParams {
   /** popup position relative to trigger */
   position?: PositionType;
   /** popup behavior if it does not fit in the window */
   behavior?: string;
+  /** Margins on the edges of the arrow. */
+  marginArrow?: string;
+  /** offset of the arrow as a percentage of the popup edge (0% - at the left edge, 100% - at the right edge, for RTL it is vice versa) */
+  offsetArrow?: string;
   /** offset in pixels from trigger element */
   offsetTrigger?: number;
   /** offset in pixels from the edges of the window */
@@ -53,6 +64,20 @@ export class ESLPopup extends ESLToggleable {
   /** Popup behavior if it does not fit in the window ('fit' by default) */
   @attr({defaultValue: 'fit'}) public behavior: string;
 
+  /**
+   * Margins on the edges of the arrow.
+   * This is the value in pixels that will be between the edge of the popup and
+   * the arrow at extreme positions of the arrow (when offsetArrow is set to 0 or 100)
+   */
+  @attr({defaultValue: '5'}) public marginArrow: string;
+
+  /**
+   * Offset of the arrow as a percentage of the popup edge
+   * (0% - at the left edge,
+   *  100% - at the right edge,
+   *  for RTL it is vice versa) */
+  @attr({defaultValue: `${DEFAULT_OFFSET_ARROW}`}) public offsetArrow: string;
+
   /** Default params to merge into passed action params */
   @jsonAttr<PopupActionParams>({defaultValue: {
     offsetTrigger: 3,
@@ -77,6 +102,10 @@ export class ESLPopup extends ESLToggleable {
     return ['top', 'bottom'].includes(this.position);
   }
 
+  protected get _offsetArrowRatio() {
+    return parsePercent(this.offsetArrow, DEFAULT_OFFSET_ARROW) / 100;
+  }
+
   public onShow(params: PopupActionParams) {
     super.onShow(params);
 
@@ -86,6 +115,12 @@ export class ESLPopup extends ESLToggleable {
     if (params.behavior) {
       this.behavior = params.behavior;
     }
+    if (params.marginArrow) {
+      this.marginArrow = params.marginArrow;
+    }
+    if (params.offsetArrow) {
+      this.offsetArrow = params.offsetArrow;
+    }
     this._offsetTrigger = params.offsetTrigger || 0;
     this._offsetWindow = params.offsetWindow || 0;
 
@@ -191,7 +226,10 @@ export class ESLPopup extends ESLToggleable {
     const config = {
       position: this.position,
       behavior: this.behavior,
+      marginArrow: +this.marginArrow,
+      offsetArrowRatio: this._offsetArrowRatio,
       intersectionRatio: this._intersectionRatio,
+      arrow: arrowRect,
       element: popupRect,
       trigger,
       inner: Rect.from(trigger).grow(innerMargin),
diff --git a/src/modules/esl-scrollbar/README.md b/src/modules/esl-scrollbar/README.md
index cc3225980..306f50dec 100644
--- a/src/modules/esl-scrollbar/README.md
+++ b/src/modules/esl-scrollbar/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Scrollbar
+# [ESL](../../../) Scrollbar
 
 Version: *1.3.0*
 
@@ -16,7 +16,7 @@ ESLScrollbar is entirely configurable and can be styled through CSS.
 - both scroll directions: `vertical` and `horizontal`.  
   Direction can be defined with the boolean `horizontal` attribute.
 
-- independent target scrollable element definition using [TraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/)
+- independent target scrollable element definition using [TraversingQuery](../esl-traversing-query/README.md)
 
 - complete customization from CSS
 
@@ -54,7 +54,7 @@ Use the full module path to import it
 
 - `horizontal` \[boolean] - horizontal scroll direction marker
 
-- `target` - [TraversingQuery](https://exadel-inc.github.io/esl/utils/esl-traversing-query/) to find the container of scrollable content
+- `target` - [TraversingQuery](../esl-traversing-query/README.md) to find the container of scrollable content
 
 - `thumb-class` (default `scrollbar-thumb`) - class(es) that will be added to the scroll thumb
 
diff --git a/src/modules/esl-tab/README.md b/src/modules/esl-tab/README.md
index b97f3498f..1afc47c95 100644
--- a/src/modules/esl-tab/README.md
+++ b/src/modules/esl-tab/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Tab & Tab Container
+# [ESL](h../../../) Tab & Tab Container
 
 Version: *1.0.0*
 
diff --git a/src/modules/esl-toggleable/README.md b/src/modules/esl-toggleable/README.md
index bd291d999..a5197dec0 100644
--- a/src/modules/esl-toggleable/README.md
+++ b/src/modules/esl-toggleable/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Toggleable
+# [ESL](https://esl-ui.com/) Toggleable
 
 Version: *2.2.0*
 
diff --git a/src/modules/esl-traversing-query/README.md b/src/modules/esl-traversing-query/README.md
index 5236bef43..fb18c9fd6 100644
--- a/src/modules/esl-traversing-query/README.md
+++ b/src/modules/esl-traversing-query/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Traversing Query
+# [ESL](../../../) Traversing Query
 
 Version: *1.0.0*.
 
@@ -9,20 +9,20 @@ Authors: *Alexey Stsefanovich (ala'n)*.
 ESLTraversingQuery is a utility to find element via extended selector query.
 
 Extended query supports:
- - plain CSS selectors;
- - relative selectors;  
+ - plain CSS selectors
+ - relative selectors  
 NOTE: Selectors that don't start from a plain selector will use passed base Element as a root
- - `::next` and `::prev` sibling pseudo-selectors;
- - `::parent` and `::child` pseudo-selectors;
- - `::find` pseudo-selector;
- - `::first`, `::last` and `:nth(#)` limitation pseudo-selectors.
+ - `::next` and `::prev` sibling pseudo-selectors
+ - `::parent` and `::child` pseudo-selectors
+ - `::find` pseudo-selector
+ - `::first`, `::last` and `:nth(#)` limitation pseudo-selectors
 
 ---
 
 ### Query examples and explanation
 
 - `#id .class [attr]` - find by CSS selector in a current document
-- `` (empty query) - returns current base element
+- ` ` (empty query) - returns current base element
 - `::next` - get next sibling element
 - `::prev` - get previous sibling element
 - `::parent` - get base element parent
diff --git a/src/modules/esl-trigger/README.md b/src/modules/esl-trigger/README.md
index 38783a6bf..1d7482103 100644
--- a/src/modules/esl-trigger/README.md
+++ b/src/modules/esl-trigger/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Trigger
+# [ESL](../../../) Trigger
 
 Version: *2.0.0*
 
@@ -18,9 +18,9 @@ ESLTrigger - a custom element, that allows to trigger ESLToggleable instances st
 
 - `target` - target Toggleable TraversingQuery selector (`next` by default)
 
-- `track-click` - `ESLMediaQuery` to define allowed to track click event media. (Default: `all`)
+- `track-click` - [MediaQuery](../esl-media-query/README.md) to define allowed to track click event media. (Default: `all`)
   
-- `track-hover` - `ESLMediaQuery` to define allowed to track hover event media. (Default: `not all`)
+- `track-hover` - [MediaQuery](../esl-media-query/README.md) to define allowed to track hover event media. (Default: `not all`)
 
 - `mode` - action to pass to the Toggleable. Supports `show`, `hide` and `toggle` values (`toggle` by default)
 
diff --git a/src/modules/esl-utils/README.md b/src/modules/esl-utils/README.md
index da150f7ca..eb12afece 100644
--- a/src/modules/esl-utils/README.md
+++ b/src/modules/esl-utils/README.md
@@ -1,4 +1,4 @@
-# [ESL](https://exadel-inc.github.io/esl/) Utils
+# [ESL](https://esl-ui.com/) Utils
 
 <a name="intro"></a>
 
@@ -53,7 +53,7 @@ Even if you use the whole utils module, it is still tiny.
 
 - #### DOM Helpers
 
-    - ##### <a href="./dom/api.ts" target="_blank">DOM API Utils</a> - a basic dom api helpers
+    - ##### <a href="./dom/api.ts" target="_blank">DOM API Utils</a> - a basic dom api helpers.
 
     - ##### <a href="./dom/class.ts" target="_blank">CSSClass</a> - a utility to work with CSS classes. 
       Supports JQuery-like enumeration, inversion syntax and locks.  
@@ -85,7 +85,7 @@ Even if you use the whole utils module, it is still tiny.
 
     - ##### <a href="./misc/array.ts" target="_blank">Array</a> - an array utils (uniq, flat, wrap, etc.).
   
-    - ##### <a href="./misc/set.ts" target="_blank">Set</a> - a set or an array with uniq values utils
+    - ##### <a href="./misc/set.ts" target="_blank">Set</a> - a set or an array with uniq values utils.
 
     - ##### <a href="./misc/format.ts" target="_blank">Format</a> - string format utils.
   
diff --git a/src/modules/esl-utils/misc/array.ts b/src/modules/esl-utils/misc/array.ts
index 5a9e48031..b988324be 100644
--- a/src/modules/esl-utils/misc/array.ts
+++ b/src/modules/esl-utils/misc/array.ts
@@ -1,4 +1,5 @@
 import {identity} from './functions';
+import {isArrayLike} from './object';
 
 type Tuple<T> = [T?, T?];
 
@@ -13,14 +14,23 @@ export const tuple = <T>(arr: T[]): Tuple<T>[] => arr.reduce((acc: Tuple<T>[], e
 export const flat = <T>(arr: (null | T | T[])[]): T[] =>
   arr.reduce((acc: T[], el) => el ? acc.concat(el) : acc, []) as T[];
 
-/** Wrap passed object to array */
+/** Wraps passed object or primitive to array */
 export const wrap = <T>(arr: undefined | null | T | T[]): T[] => {
   if (arr === undefined || arr === null) return [];
   if (Array.isArray(arr)) return arr;
   return [arr];
 };
 
-/** Make array values unique */
+/** Unwraps and returns the first element if passed object is array-like, returns original object otherwise */
+export function unwrap(value: []): undefined;
+export function unwrap<T>(value: (ArrayLike<T> & {0: T}) | T): T;
+export function unwrap<T extends Node>(value: NodeListOf<T>): T | undefined;
+export function unwrap(value: any): any;
+export function unwrap(value: any): any {
+  return isArrayLike(value) ? value[0] : value;
+}
+
+/** Makes array values unique */
 export const uniq = <T> (arr: T[]): T[] => {
   const result: T[] = [];
   const set = new Set<T>();
diff --git a/src/modules/esl-utils/misc/object.ts b/src/modules/esl-utils/misc/object.ts
index ce38f9458..44da161b8 100644
--- a/src/modules/esl-utils/misc/object.ts
+++ b/src/modules/esl-utils/misc/object.ts
@@ -1,10 +1,31 @@
-export const isObject = (obj: any): obj is Record<string, any> => obj && typeof obj === 'object';
+/** Checks that passed value is object, but not a callable-object (function) */
+export const isObject = (obj: any): obj is Record<string, any> => !!obj && typeof obj === 'object';
+/** Checks that passed value is an object or function */
 export const isObjectLike = (obj: any) => isObject(obj) || typeof obj === 'function';
-export const isPrimitive = (obj: any): obj is string | number | boolean =>
-  typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean';
-
+/** Checks if the passed value is primitive */
+export const isPrimitive = (obj: any): obj is string | number | boolean | symbol | undefined | null =>
+  obj === null ||
+  typeof obj === 'undefined' ||
+  typeof obj === 'string' ||
+  typeof obj === 'number' ||
+  typeof obj === 'boolean' ||
+  typeof obj === 'symbol';
+/** Checks that passed object is prototype of some class */
 export const isPrototype = (obj: any) => Object.hasOwnProperty.call(obj, 'constructor');
 
+/** Array-like type definition */
+export type ArrayLike<T = any> = {
+  [key: number]: T;
+  length: number;
+};
+/** Checks that passed object is array-like */
+export const isArrayLike = (value: any): value is ArrayLike => {
+  if (!value || typeof value !== 'object') return false;
+  if (Array.isArray(value)) return true;
+  if (typeof value.length !== 'number' || value.length < 0) return false;
+  return !value.length || Object.hasOwnProperty.call(value, value.length - 1);
+};
+
 export type CopyPredicate = (key: string, value: any) => boolean;
 
 /** Deep object compare */


Test patch:
diff --git a/src/modules/esl-utils/misc/test/array.test.ts b/src/modules/esl-utils/misc/test/array.test.ts
index 0a08ab7b8..292c5a8d0 100644
--- a/src/modules/esl-utils/misc/test/array.test.ts
+++ b/src/modules/esl-utils/misc/test/array.test.ts
@@ -1,4 +1,4 @@
-import {flat, range, tuple, uniq, wrap, groupBy} from '../array';
+import {flat, range, tuple, uniq, wrap, unwrap, groupBy} from '../array';
 
 describe('misc/array helper tests', () => {
   test('tuple', () => {
@@ -44,48 +44,85 @@ describe('misc/array helper tests', () => {
     expect(range(3)).toEqual([0, 1, 2]);
     expect(range(9, (x) => x / 8)).toEqual([...Array(9).keys()].map((x) => x / 8));
   });
-});
 
-type V = string | number;
+  type V = string | number;
+
+  describe('unwrap', () => {
+    document.body.innerHTML = '<div>1</div><div>2</div>';
+
+    test('NodeList to unwrap into first Node', () => {
+      expect(unwrap(document.querySelectorAll('div'))).toEqual(document.querySelector('div'));
+    });
+
+    test.each([
+      [[1], 1],
+      [[1, 2], 1],
+      [[[1, 2], 3], [1, 2]],
+      [[{a: 2}, {a: 2, b:3}, {a: 2, b:3}], {a: 2}]
+    ])('array %p to unwrap into %o', (a: any, expected: any) => {
+      expect(unwrap(a)).toEqual(expected);
+    });
+
+    test.each([
+      [1, 1],
+      [{a: 1, b: 2}, {a: 1, b: 2}],
+      [{0: 1, 1: 2, length: 2}, 1],
+      [{length: 2}, {length: 2}]
+    ])('non-array value %p to unwrap into %o', (a: any, expected: any) => {
+      expect(unwrap(a)).toEqual(expected);
+    });
+
+    test.each([
+      [undefined],
+      [[]]
+    ])('value %p to unwrap into undefined', (a: any) => {
+      expect(unwrap(a)).toEqual(undefined);
+    });
+
+    test('null to be returned', () => {
+      expect(unwrap(null)).toEqual(null);
+    });
+  });
 
-describe('misc/groupBy', () => {
-  test.each([
-    [
-      [1, 2, 10, 4, 3],
-      (i: number) => i % 2 > 0 ? 'odd' : 'even',
-      {odd: [1, 3], even: [2, 10, 4]}
-    ],
-    [
-      ['cat', 'fat', 'kitten'],
-      (i: string) => i.length,
-      {3: ['cat', 'fat'], 6: ['kitten']}
-    ],
-    [
-      ['Fog', 'Tea', 'ocean', 'rain'],
-      (i: string) => i[0] === i[0].toUpperCase() ? 'uppercase' : 'lowercase',
-      {uppercase: ['Fog', 'Tea'], lowercase: ['ocean', 'rain']}
-    ],
-    [
-      [{a: 2, b: 1}, {b: 2}, {a: 1}, {}],
-      (i: Record<string, number>) => i['a'] ? i['a'] : 'undefined',
-      {2: [{a: 2, b: 1}], undefined: [{b: 2}, {}], 1: [{a: 1}]}
-    ],
-    [
-      [100, 20, 10, 101, 300],
-      (i: number) => String(i)[0],
-      {'1': [100, 10, 101], '2': [20], '3': [300]}
-    ],
-    [
-      [],
-      (i: any) => i,
-      {}
-    ],
-    [
-      [[5, 2], [1, 0], [5, 4]],
-      (i: number[]) => i[0],
-      {5: [[5, 2], [5, 4]], 1: [[1, 0]]}
-    ]
-  ])('array %p with criteria %p to transform into %o', (a: any[], b: (t: any) => V, expected: Record<V, any>) => {
-    expect(groupBy(a, b)).toEqual(expected);
+  describe('groupBy', () => {
+    test.each([
+      [
+        [1, 2, 10, 4, 3],
+        (i: number) => i % 2 > 0 ? 'odd' : 'even',
+        {odd: [1, 3], even: [2, 10, 4]}
+      ],
+      [
+        ['cat', 'fat', 'kitten'],
+        (i: string) => i.length,
+        {3: ['cat', 'fat'], 6: ['kitten']}
+      ],
+      [
+        ['Fog', 'Tea', 'ocean', 'rain'],
+        (i: string) => i[0] === i[0].toUpperCase() ? 'uppercase' : 'lowercase',
+        {uppercase: ['Fog', 'Tea'], lowercase: ['ocean', 'rain']}
+      ],
+      [
+        [{a: 2, b: 1}, {b: 2}, {a: 1}, {}],
+        (i: Record<string, number>) => i['a'] ? i['a'] : 'undefined',
+        {2: [{a: 2, b: 1}], undefined: [{b: 2}, {}], 1: [{a: 1}]}
+      ],
+      [
+        [100, 20, 10, 101, 300],
+        (i: number) => String(i)[0],
+        {'1': [100, 10, 101], '2': [20], '3': [300]}
+      ],
+      [
+        [],
+        (i: any) => i,
+        {}
+      ],
+      [
+        [[5, 2], [1, 0], [5, 4]],
+        (i: number[]) => i[0],
+        {5: [[5, 2], [5, 4]], 1: [[1, 0]]}
+      ]
+    ])('array %p with criteria %p to transform into %o', (a: any[], b: (t: any) => V, expected: Record<V, any>) => {
+      expect(groupBy(a, b)).toEqual(expected);
+    });
   });
 });
diff --git a/src/modules/esl-utils/misc/test/object.test.ts b/src/modules/esl-utils/misc/test/object.test.ts
index e44c9f725..1d3448fda 100644
--- a/src/modules/esl-utils/misc/test/object.test.ts
+++ b/src/modules/esl-utils/misc/test/object.test.ts
@@ -1,6 +1,63 @@
-import {defined, deepCompare, getPropertyDescriptor, get, set, copyDefinedKeys, copy, omit, deepMerge} from '../object';
+import {
+  defined,
+  deepCompare,
+  getPropertyDescriptor,
+  get,
+  set,
+  copyDefinedKeys,
+  copy,
+  omit,
+  deepMerge,
+  isObject,
+  isObjectLike,
+  isPrimitive,
+  isPrototype,
+  isArrayLike
+} from '../object';
 
 describe('misc/object', () => {
+  describe('Type Guards', () => {
+    test('isObject', () => {
+      expect(isObject(undefined)).toBe(false);
+      expect(isObject(null)).toBe(false);
+      expect(isObject('1')).toBe(false);
+      expect(isObject({})).toBe(true);
+      expect(isObject([])).toBe(true);
+      expect(isObject(() => true)).toBe(false);
+    });
+    test('isObjectLike', () => {
+      expect(isObjectLike(null)).toBe(false);
+      expect(isObjectLike({})).toBe(true);
+      expect(isObjectLike([])).toBe(true);
+      expect(isObjectLike(() => true)).toBe(true);
+    });
+    test('isPrimitive', () => {
+      expect(isPrimitive(undefined)).toBe(true);
+      expect(isPrimitive(null)).toBe(true);
+      expect(isPrimitive(0)).toBe(true);
+      expect(isPrimitive('')).toBe(true);
+      expect(isPrimitive(Symbol())).toBe(true);
+      expect(isPrimitive({})).toBe(false);
+      expect(isPrimitive(() => true)).toBe(false);
+    });
+    test('isPrototype', () => {
+      expect(isPrototype({})).toBe(false);
+      class Test {}
+      expect(isPrototype(Test)).toBe(false);
+      expect(isPrototype(Test.prototype)).toBe(true);
+      expect(isPrototype(Array)).toBe(false);
+      expect(isPrototype(Array.prototype)).toBe(true);
+    });
+    test('isArrayLike', () => {
+      expect(isArrayLike({})).toBe(false);
+      expect(isArrayLike([])).toBe(true);
+      expect(isArrayLike([1])).toBe(true);
+      expect(isArrayLike({length: 0})).toBe(true);
+      expect(isArrayLike({length: 1, 0: null})).toBe(true);
+      expect(isArrayLike(document.querySelectorAll('*'))).toBe(true);
+    });
+  });
+
   describe('deepCompare', () => {
     test.each([
       [null, null],
@@ -40,7 +97,7 @@ describe('misc/object', () => {
   });
 
   describe('getPropertyDescriptor', () => {
-    test('simple', ()=> {
+    test('simple', () => {
       const object = {
         a: 1,
         get b() { return 2; }
@@ -59,7 +116,7 @@ describe('misc/object', () => {
       expect(getPropertyDescriptor(object, 'f')).toBeFalsy();
     });
 
-    test('1 lvl', ()=> {
+    test('1 lvl', () => {
       class A {
         a = 1;
         b() { return 2; }
@@ -73,7 +130,7 @@ describe('misc/object', () => {
       expect(getPropertyDescriptor(obj, 'c')).toHaveProperty('get');
     });
 
-    test('2 lvl', ()=> {
+    test('2 lvl', () => {
       class A {
         a() { return 3; }
         get b() { return 3; }
@@ -206,7 +263,7 @@ describe('misc/object', () => {
       expect(deepMerge(...args)).toEqual(result);
     });
 
-    test('merge array + object', ()  => {
+    test('merge array + object', () => {
       const res = deepMerge([1, 2], {a: 1});
       const exp: any = [1, 2];
       exp.a = 1;